Skip to content

civicteam/civic-icp-canister

Repository files navigation

Introduction

The Civic Canister is a component of a decentralized application deployed on the Internet Computer Protocol (ICP) blockchain by Civic. It is designed to handle secure storage and retrieval of credentials under Internet Identity, the authentication service for the Internet Computer. Internet Identity provides different, unlinkable identities for each app a user logs in to.

Civic (or other issuers) can issue credentials for the user as part of its identity verification flow. 3rd parties integrating Civic Pass on ICP can request these credentials from the Civic Canister. Through Internet Identity, the credential can be shared securely between the two dApps without linking the user's identities between the two dApps.

Overview of how the Civic Canister works

As you can see in the diagram, the user has two "versions" of their Internet Identity, Identity A and Identity B. Identity A is the one used in the Civic Canister while Identity B is the one used by the 3rd party dApp (Relying Party). When the credential data is shared between the two dApps, the two identities are not linked to each other, thanks to the attribute sharing of Internet Identity which the Civic Canister implements.

This repository contains the code to demo the above flow. civic_canister_backend contains the code for the Civic Canister, relying_canister_frontend contains the code for the example 3rd party, and civic_canister_frontend contains the code for an example frontend through which credentials can be issued to the canister. See CI Build and Test (Local Setup) for instructions how to run the demo locally.

What does the Credential issued by the Civic Canister look like?

The credentials issued by the Civic Canister adhere to the W3C Verifiable Credentials specification, ensuring compatibility and interoperability with various systems and platforms.

Here is an example of a credential the Civic Canister can issue:

{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://www.w3.org/ns/credentials/examples/v2"
  ],
  "id": "urn:uuid:6a9c92a9-2530-4e2b-9776-530467e9bbe0",
  "type": ["VerifiableCredential", "CivicPass"],
  "issuer": "did:icp:v0:tglqb-kbqlj-to66e-3w5sg-kkz32-c6ffi-nsnta-vj2gf-vdcc5-5rzjk-jae",
  "expiry": "2024-04-04T00:00:00Z",
  "credentialSubject": {
    "id": "did:icp:user-principal",
    "passType": "uniqobk8oGh4XBLMqM68K8M2zNu3CdYX7q5go7whQiv",
    "status": "ACTIVE",
    "expirationDate": "2024-12-31T23:59:59Z"
  }
}

CI Build and Test (Local Setup)

This section provides steps to set up and run the project locally. Follow the steps below to configure your environment, build the project, and run tests.

Prerequisites

Setup

  1. Clone the repository:

    git clone https://github.com/civicteam/civic-icp-canister.git
    cd civic-icp-canister
  2. Install DFX: Follow the official DFX installation guide here.

  3. Install Rust: Follow the official Rust installation guide here.

  4. Install Node.js dependencies:

    npm install
  5. Install Rust target and dependencies:

    rustup target add wasm32-unknown-unknown
    cargo install ic-wasm

Deploy the canisters

To simplify the deployment of the canisters we provide a script deploy-civic.sh you can find under scripts. To execute it make sure that you have run npm install beforehand inside the project.

./scripts/deploy-civic.sh local 

Manual deployment

Steps for the manual deployment:

  1. Create canisters and start the local Internet Computer replica:

    dfx start --clean --background
    dfx canister create --all
  2. Set environment variables:

    First set

    export VITE_ENV="development"

    Run the scripts/set-env-vars.sh script to set the environment variables for local deployment:

    source scripts/set-env-vars.sh
  3. Deploy the Civic Canister and Internet Identity:

    ./scripts/deploy-civic.sh
    dfx deploy internet_identity
  4. Deploy the Civic Frontend Canister:

    Note: If it fails to deploy, try to deploy the RP canister first and then go back to the Civic Frontend Canister. (If you start with the RP first and it fails, try to deploy the Civic Frontend Canister and then go back to the RP.)

    dfx deploy civic_canister_frontend
  5. Deploy the Relying Party (RP) canister:

    dfx deploy relying_canister_frontend

Testing

To run the tests ensure the test state machine binary is executable first:

chmod +x ic-test-state-machine
cargo test --test integration_tests

Storing and Fetching Credentials

The following script is located in src/civic_frontend_canister. It demonstrates how to store and fetch credentials from the Civic Canister backend. The script uses environment variables to configure the canister ID and other settings.

Script Explanation

This script performs the following tasks:

  1. Load Environment Variables: Uses the dotenv package to load environment variables from .env.local.
  2. Configure Canister IDs: Reads the canister IDs from the environment variables.
  3. Dummy Credential Data: Sets up dummy credential data for testing purposes.
  4. Store Credential: Stores a credential in the Civic Canister backend.
  5. Fetch Credentials: Fetches and logs all credentials associated with a specified principal.

Usage Instructions

  1. Ensure Environment Variables are Set: Make sure the .env.local file contains the necessary environment variables.

  2. Run the Script: Navigate to the directory containing the script and run it using Node.js:

    cd src/civic_canister_frontend
    npm run issue-credential

Notes

  • Ensure you have the required binaries in the ic-test-machine-binaries directory.
  • Modify the setup and deployment scripts as needed to suit your project's requirements.

Mainnet Deployment

This section describes the steps to deploy the Civic frontend, relying and backend canisters on the Internet Computer (IC) network.

Prerequisites

  • Ensure you can deploy locally.
  • Ensure you have an ICP wallet to add cycles.
  • Create a new identity for secure mainnet operations.

Setup

1. Create and Use a Secure Identity

Create and use a new identity for secure operations on the mainnet.

2. Ensure the Wallet Has Enough Cycles

Check your wallet balance and add cycles if necessary.

Check Wallet Balance

dfx wallet --network ic balance

Get Wallet Address

dfx identity get-wallet

Transfer Cycles to Wallet

Use an external ICP wallet or exchange to transfer cycles to your wallet address. For example, to add 10 trillion cycles:

# Transfer ICP equivalent to 10 trillion cycles to your wallet address obtained from `dfx identity get-wallet`.

Deploy the canisters

You can use the deploy script to deploy the canisters to mainnet in one step. Be sure that you have deployed locally first (see), this is necessary for it to work.

Ensure you have run npm install in your project folder. Deploy locally with

./scripts/deploy-civic.sh local 

Afterwards you can deploy to mainnet with

./scripts/deploy-civic.sh ic 

Manual deployment

Alternatively you can deploy manually with the following steps:

  1. Create the canister IDs

  2. Deploy the Frontend Canister

  3. Deploy the Relying Canister

  4. Deploy the Backend Canister

3. Create the canister IDs

Verify if the canister IDs were already created by running

dfx canister id civic_canister_backend --network ic
dfx canister id civic_canister_frontend --network ic
dfx canister id relying_canister_frontend --network ic

If this prints the IDs for for all three canisters, then they were already created. If not run

dfx canister --network ic create --all

Export the IDs so that the frontend canisters are configured correctly for production.

export VITE_ENV="production"
source scripts/set-env-vars.sh

4. Deploy the Frontend Canister

Note:

If it fails to deploy, try to deploy the RP canister first and then go back to the Civic Frontend Canister. (If you start with the RP first and it fails, try to deploy the Civic Frontend Canister and then go back to the RP.)

Top-Up the Frontend Canister with Cycles

dfx canister --network ic deposit-cycles 1000000000000 civic_canister_frontend

Adjust the number of cycles as needed.

Deploy the Frontend Canister

dfx deploy civic_canister_frontend --network ic --identity mainnet_identity

5. Deploy the Relying Canister

Follow the sames steps that you followed when deploying the frontend canister

6. Deploy the Backend Canister

Top-Up the Backend Canister with Cycles

dfx canister --network ic deposit-cycles 1000000000000 civic_canister_backend

Adjust the number of cycles as needed.

Deploy the Backend Canister

To deploy run

DFX_NETWORK=ic ./scripts/deploy-civic.sh

To upgrade run

DFX_NETWORK=ic ./scripts/upgrade-civic.sh

Upgrading the Civic Canister

The Civic Canister supports stable storage and the credential data and configuration (including whitelisted issuers) will be restored when the canister is upgraded. To upgrade the canister run

DFX_NETWORK=network ./scripts/upgrade-civic.sh

setting network to ic or local. This also allows you to test the stable storage without having to change the canister code.