diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index f10a85a..79281be 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -19,24 +19,21 @@ jobs: - uses: actions/checkout@v3 - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} - run: rustup target add wasm32-unknown-unknown - - name: Build required wasm - run: | - cargo build --target wasm32-unknown-unknown --release --package vault_contract - - name: Contract Build + - run: cargo install --locked --version 20.0.0-rc2 soroban-cli + - name: Build contracts run: | - cargo build --target wasm32-unknown-unknown --release + soroban contract build - name: Code Tests run: | cargo test - - run: cargo install --locked --version 20.0.0-rc2 soroban-cli - - name: Contract Deployment VC issuance contract to testnet + - name: Deploy VC issuance contract to testnet run: | soroban contract deploy \ --wasm target/wasm32-unknown-unknown/release/vc_issuance_contract.wasm \ --source ${{ secrets.DEPLOYER_SECRET }} \ --rpc-url https://soroban-testnet.stellar.org:443/ \ --network-passphrase 'Test SDF Network ; September 2015' - - name: Contract Deployment Vault contract to testnet + - name: Deploy Vault contract to testnet run: | soroban contract deploy \ --wasm target/wasm32-unknown-unknown/release/vault_contract.wasm \ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 46158a3..b069cbd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: - run: rustup target add wasm32-unknown-unknown - name: Build required wasm run: | - cargo build --target wasm32-unknown-unknown --release --package vault_contract + cargo build --target wasm32-unknown-unknown --release --package vault-contract - name: Contract Build run: | cargo build --target wasm32-unknown-unknown --release diff --git a/.gitignore b/.gitignore index 4fffb2f..aea5def 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target /Cargo.lock +tarpaulin-report.html diff --git a/Cargo.toml b/Cargo.toml index 4af6cb2..23a17cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,9 +3,14 @@ resolver = "2" members = ["deployer_contract", "vault_contract", "vc_issuance_contract"] -[profile.release-with-logs] -inherits = "release" -debug-assertions = true +[workspace.package] +version = "0.0.0" +edition = "2021" +license = "Apache-2.0" +repository = "https://github.com/kommitters/chaincerts-smart-contracts" + +[workspace.dependencies] +soroban-sdk = { version = "=20.0.0-rc2.2" } [profile.release] opt-level = "z" @@ -17,8 +22,6 @@ panic = "abort" codegen-units = 1 lto = true -[workspace.dependencies.soroban-sdk] -version = "20.0.0-rc2" - -[workspace.dependencies.soroban-auth] -version = "0.8.3" +[profile.release-with-logs] +inherits = "release" +debug-assertions = true diff --git a/deployer_contract/Cargo.toml b/deployer_contract/Cargo.toml index 5e78659..b9dfc65 100644 --- a/deployer_contract/Cargo.toml +++ b/deployer_contract/Cargo.toml @@ -1,7 +1,9 @@ [package] -name = "deployer_contract" -version = "0.11.1" -edition = "2021" +name = "deployer-contract" +version = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/did_contract b/did_contract index 324010b..e353d8a 160000 --- a/did_contract +++ b/did_contract @@ -1 +1 @@ -Subproject commit 324010bd299c467b3fe5805e9781c48062793681 +Subproject commit e353d8a1ca52f458d5fa55802295398aff39ccdd diff --git a/vault_contract/Cargo.toml b/vault_contract/Cargo.toml index 4f4c276..27a84e7 100644 --- a/vault_contract/Cargo.toml +++ b/vault_contract/Cargo.toml @@ -1,7 +1,9 @@ [package] -name = "vault_contract" -version = "0.1.0" -edition = "2021" +name = "vault-contract" +version = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/vault_contract/src/contract.rs b/vault_contract/src/contract.rs index 379dab2..89328ff 100644 --- a/vault_contract/src/contract.rs +++ b/vault_contract/src/contract.rs @@ -1,13 +1,11 @@ -use crate::did; -use crate::did::{Did, DidWithVCs}; use crate::error::ContractError; use crate::issuer; use crate::issuer::Issuer; use crate::storage; -use crate::verifiable_credential; -use crate::verifiable_credential::VerifiableCredential; - +use crate::vault; +use crate::vault::Vault; use crate::vault_trait::VaultTrait; +use crate::verifiable_credential; use soroban_sdk::{ contract, contractimpl, contractmeta, panic_with_error, Address, Env, IntoVal, Map, String, Vec, }; @@ -31,7 +29,7 @@ impl VaultTrait for VaultContract { } storage::write_admin(&e, &admin); - did::set_initial_dids(&e, &dids); + vault::set_initial_vaults(&e, &dids); e.storage() .instance() @@ -40,14 +38,18 @@ impl VaultTrait for VaultContract { fn authorize_issuer(e: Env, admin: Address, issuer: Address, did: String) { validate_admin(&e, admin); - validate_did(&e, &did); + + let vaults = storage::read_vaults(&e); + validate_vault(&e, &vaults, &did); issuer::authorize_issuer(&e, &issuer, &did); } fn revoke_issuer(e: Env, admin: Address, issuer: Address, did: String) { validate_admin(&e, admin); - validate_did(&e, &did); + + let vaults = storage::read_vaults(&e); + validate_vault(&e, &vaults, &did); issuer::revoke_issuer(&e, &issuer, &did) } @@ -57,96 +59,77 @@ impl VaultTrait for VaultContract { vc_id: String, vc_data: String, recipient_did: String, - issuer_pk: Address, - issuance_contract_address: Address, + issuer: Address, + issuance_contract: Address, ) { - validate_did(&e, &recipient_did); - validate_issuer( - &e, - &issuer_pk, - &recipient_did, - &vc_data, - &issuance_contract_address, - ); + let mut vaults = storage::read_vaults(&e); + validate_vault(&e, &vaults, &recipient_did); + + validate_issuer(&e, &issuer, &recipient_did, &vc_data, &issuance_contract); verifiable_credential::store_vc( &e, - &vc_id, - &vc_data, - &issuance_contract_address, - &recipient_did, + &mut vaults, + vc_id, + vc_data, + issuance_contract, + recipient_did, ); } - fn get_vc(e: Env, vc_id: String) -> VerifiableCredential { - let vcs = storage::read_vcs(&e); + fn register_vault(e: Env, admin: Address, did: String) { + validate_admin(&e, admin); + let mut vaults = storage::read_vaults(&e); - match vcs.get(vc_id) { - Some(vc) => vc, - None => panic_with_error!(&e, ContractError::VCNotFound), + if vault::is_registered(&vaults, &did) { + panic_with_error!(e, ContractError::VaultAlreadyRegistered) } - } - fn list_vcs(e: Env) -> Map { - let vcs = storage::read_vcs(&e); - let dids = storage::read_dids(&e); - let mut dids_with_vcs = Map::new(&e); - - for (did, did_struct) in dids { - let mut did_vcs = Vec::new(&e); - for vc in did_struct.vcs { - did_vcs.push_front(vcs.get_unchecked(vc)); - } - - dids_with_vcs.set( - did.clone(), - DidWithVCs { - did: did.clone(), - is_revoked: did_struct.is_revoked, - vcs: did_vcs, - }, - ) - } + vaults.set( + did.clone(), + Vault { + did, + revoked: false, + vcs: Vec::new(&e), + }, + ); - dids_with_vcs + storage::write_vaults(&e, &vaults) } - fn revoke_did(e: Env, admin: Address, did: String) { + fn revoke_vault(e: Env, admin: Address, did: String) { validate_admin(&e, admin); - let mut dids = storage::read_dids(&e); - if !did::is_registered(&dids, &did) { - panic_with_error!(e, ContractError::DidNotFound) + let mut vaults = storage::read_vaults(&e); + + if !vault::is_registered(&vaults, &did) { + panic_with_error!(e, ContractError::VaultNotFound) } - let did_struct = dids.get_unchecked(did.clone()); - dids.set( + let vault = vaults.get_unchecked(did.clone()); + + vaults.set( did.clone(), - Did { - did, - is_revoked: true, - vcs: did_struct.vcs, + Vault { + revoked: true, + ..vault }, ); - storage::write_dids(&e, &dids); + + storage::write_vaults(&e, &vaults); } - fn register_did(e: Env, admin: Address, did: String) { - validate_admin(&e, admin); - let mut dids = storage::read_dids(&e); + fn get_vault(e: Env, did: String) -> Vault { + let vaults = storage::read_vaults(&e); - if did::is_registered(&dids, &did) { - panic_with_error!(e, ContractError::DuplicatedDID) + match vaults.get(did) { + Some(vault) => vault, + None => panic_with_error!(&e, ContractError::VaultNotFound), } + } - dids.set( - did.clone(), - Did { - did, - is_revoked: false, - vcs: Vec::new(&e), - }, - ); - storage::write_dids(&e, &dids) + fn list_vaults(e: Env) -> Vec { + let vaults = storage::read_vaults(&e); + vaults.values() } } @@ -158,14 +141,13 @@ fn validate_admin(e: &Env, admin: Address) { admin.require_auth(); } -fn validate_did(e: &Env, did: &String) { - let dids = storage::read_dids(e); - - if !did::is_registered(&dids, did) { - panic_with_error!(e, ContractError::DidNotFound) +fn validate_vault(e: &Env, vaults: &Map, did: &String) { + if !vault::is_registered(vaults, did) { + panic_with_error!(e, ContractError::VaultNotFound) } - if did::is_revoked(&dids, did) { - panic_with_error!(e, ContractError::DidRevoked) + + if vault::is_revoked(vaults, did) { + panic_with_error!(e, ContractError::VaultRevoked) } } @@ -174,7 +156,7 @@ fn validate_issuer( issuer: &Address, did: &String, vc_data: &String, - issuance_contract_address: &Address, + issuance_contract: &Address, ) { let issuers: Map = storage::read_issuers(e, did); @@ -190,7 +172,7 @@ fn validate_issuer( vc_data.clone(), did.clone(), issuer.clone(), - issuance_contract_address.clone(), + issuance_contract.clone(), ) .into_val(e), ); diff --git a/vault_contract/src/did.rs b/vault_contract/src/did.rs deleted file mode 100644 index 71c1e25..0000000 --- a/vault_contract/src/did.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::error::ContractError; -use crate::storage; -use crate::verifiable_credential::VerifiableCredential; -use soroban_sdk::{contracttype, panic_with_error, Env, Map, String, Vec}; - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Did { - pub did: String, - pub is_revoked: bool, - pub vcs: Vec, -} - -#[contracttype] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct DidWithVCs { - pub did: String, - pub is_revoked: bool, - pub vcs: Vec, -} - -pub fn set_initial_dids(e: &Env, dids: &Vec) { - if dids.is_empty() { - panic_with_error!(e, ContractError::EmptyDIDs); - } - - let mut dids_map: Map = Map::new(e); - - for did in dids.iter() { - dids_map.set( - did.clone(), - Did { - did: did.clone(), - is_revoked: false, - vcs: Vec::new(e), - }, - ) - } - - storage::write_dids(e, &dids_map); -} - -pub fn is_registered(dids: &Map, did: &String) -> bool { - dids.contains_key(did.clone()) -} - -pub fn is_revoked(dids: &Map, did: &String) -> bool { - dids.get_unchecked(did.clone()).is_revoked -} diff --git a/vault_contract/src/error.rs b/vault_contract/src/error.rs index 048f6cf..9fca1ea 100644 --- a/vault_contract/src/error.rs +++ b/vault_contract/src/error.rs @@ -8,9 +8,8 @@ pub enum ContractError { NotAuthorized = 2, EmptyDIDs = 3, IssuerNotFound = 4, - DidRevoked = 5, - DidNotFound = 6, - IssuerRevoked = 7, - VCNotFound = 8, - DuplicatedDID = 9, + IssuerRevoked = 5, + VaultNotFound = 6, + VaultRevoked = 7, + VaultAlreadyRegistered = 8, } diff --git a/vault_contract/src/issuer.rs b/vault_contract/src/issuer.rs index 4e25d70..b8c5526 100644 --- a/vault_contract/src/issuer.rs +++ b/vault_contract/src/issuer.rs @@ -9,13 +9,13 @@ pub struct Issuer { pub is_revoked: bool, } -pub fn authorize_issuer(e: &Env, issuer_pk: &Address, did: &String) { +pub fn authorize_issuer(e: &Env, issuer: &Address, did: &String) { let mut issuers: Map = storage::read_issuers(e, did); issuers.set( - issuer_pk.clone(), + issuer.clone(), Issuer { - public_key: issuer_pk.clone(), + public_key: issuer.clone(), is_revoked: false, }, ); diff --git a/vault_contract/src/lib.rs b/vault_contract/src/lib.rs index 4067fec..cd08c23 100644 --- a/vault_contract/src/lib.rs +++ b/vault_contract/src/lib.rs @@ -1,9 +1,9 @@ #![no_std] mod contract; -mod did; mod error; mod issuer; mod storage; +mod vault; mod vault_trait; mod verifiable_credential; diff --git a/vault_contract/src/storage.rs b/vault_contract/src/storage.rs index c2910c8..2b47830 100644 --- a/vault_contract/src/storage.rs +++ b/vault_contract/src/storage.rs @@ -1,14 +1,13 @@ use crate::issuer::Issuer; -use crate::{did::Did, verifiable_credential::VerifiableCredential}; +use crate::vault::Vault; use soroban_sdk::{contracttype, Address, Env, Map, String}; #[derive(Clone)] #[contracttype] pub enum DataKey { Admin, // Address - Dids, // Map Issuers(String), // Map - VCs, // Map + Vaults, // Map } pub fn has_admin(e: &Env) -> bool { @@ -26,16 +25,6 @@ pub fn write_admin(e: &Env, id: &Address) { e.storage().instance().set(&key, id); } -pub fn read_dids(e: &Env) -> Map { - let key = DataKey::Dids; - e.storage().instance().get(&key).unwrap() -} - -pub fn write_dids(e: &Env, dids: &Map) { - let key = DataKey::Dids; - e.storage().instance().set(&key, dids); -} - pub fn read_issuers(e: &Env, did: &String) -> Map { let key = DataKey::Issuers(did.clone()); e.storage().instance().get(&key).unwrap_or(Map::new(e)) @@ -46,12 +35,12 @@ pub fn write_issuers(e: &Env, issuers: &Map, did: &String) { e.storage().instance().set(&key, issuers) } -pub fn read_vcs(e: &Env) -> Map { - let key = DataKey::VCs; +pub fn read_vaults(e: &Env) -> Map { + let key = DataKey::Vaults; e.storage().instance().get(&key).unwrap_or(Map::new(e)) } -pub fn write_vcs(e: &Env, vc: &Map) { - let vc_key = DataKey::VCs; - e.storage().instance().set(&vc_key, vc) +pub fn write_vaults(e: &Env, vaults: &Map) { + let key = DataKey::Vaults; + e.storage().instance().set(&key, vaults) } diff --git a/vault_contract/src/test/contract.rs b/vault_contract/src/test/contract.rs index 3e51ea8..cb02b54 100644 --- a/vault_contract/src/test/contract.rs +++ b/vault_contract/src/test/contract.rs @@ -83,7 +83,7 @@ fn test_authorize_issuer_with_invalid_admin() { #[test] #[should_panic(expected = "HostError: Error(Contract, #6)")] -fn test_authorize_issuer_with_not_registered_did() { +fn test_authorize_issuer_with_not_registered_vault() { let VaultContractTest { env, admin, @@ -99,8 +99,8 @@ fn test_authorize_issuer_with_not_registered_did() { } #[test] -#[should_panic(expected = "HostError: Error(Contract, #5)")] -fn test_authorize_issuer_with_revoked_did() { +#[should_panic(expected = "HostError: Error(Contract, #7)")] +fn test_authorize_issuer_with_revoked_vault() { let VaultContractTest { env: _, admin, @@ -111,7 +111,7 @@ fn test_authorize_issuer_with_revoked_did() { } = VaultContractTest::setup(); contract.initialize(&admin, &dids); - contract.revoke_did(&admin, &did); + contract.revoke_vault(&admin, &did); contract.authorize_issuer(&admin, &issuer, &did); } @@ -187,8 +187,8 @@ fn test_revoke_issuer_with_not_registered_did() { } #[test] -#[should_panic(expected = "HostError: Error(Contract, #5)")] -fn test_revoke_issuer_with_revoked_did() { +#[should_panic(expected = "HostError: Error(Contract, #7)")] +fn test_revoke_issuer_with_revoked_vault() { let VaultContractTest { env: _, admin, @@ -199,7 +199,7 @@ fn test_revoke_issuer_with_revoked_did() { } = VaultContractTest::setup(); contract.initialize(&admin, &dids); - contract.revoke_did(&admin, &did); + contract.revoke_vault(&admin, &did); contract.revoke_issuer(&admin, &issuer, &did); } @@ -279,7 +279,7 @@ fn test_store_vc_with_issuer_not_found() { } #[test] -#[should_panic(expected = "HostError: Error(Contract, #7)")] +#[should_panic(expected = "HostError: Error(Contract, #5)")] fn test_store_vc_with_revoked_issuer() { let VaultContractTest { env, @@ -305,7 +305,7 @@ fn test_store_vc_with_revoked_issuer() { #[test] #[should_panic(expected = "HostError: Error(Contract, #6)")] -fn test_store_vc_with_did_not_found() { +fn test_store_vc_with_vault_not_found() { let VaultContractTest { env, admin, @@ -324,6 +324,7 @@ fn test_store_vc_with_did_not_found() { contract.initialize(&admin, &dids); contract.authorize_issuer(&admin, &issuer, &did); + contract.store_vc( &vc_id, &vc_data, @@ -334,59 +335,40 @@ fn test_store_vc_with_did_not_found() { } #[test] -fn test_get_vc() { +#[should_panic(expected = "HostError: Error(Contract, #6)")] +fn test_get_vault_not_found() { let VaultContractTest { env, admin, - did, + did: _, dids, - issuer, + issuer: _, contract, } = VaultContractTest::setup(); - let VCVaultContractTest { - vc_id, - vc_data, - issuance_contract_address, - } = get_vc_setup(&env); - contract.initialize(&admin, &dids); - contract.authorize_issuer(&admin, &issuer, &did); - contract.store_vc(&vc_id, &vc_data, &did, &issuer, &issuance_contract_address); - let vc = contract.get_vc(&vc_id); - assert_eq!(vc_id, vc.id); - assert_eq!(vc_data, vc.data); + let bad_vault_did: String = String::from_slice(&env, "did:chaincerts:xyz123"); + contract.get_vault(&bad_vault_did); } #[test] -#[should_panic(expected = "HostError: Error(Contract, #8)")] -fn test_get_vc_not_found() { +fn test_get_vault() { let VaultContractTest { - env, + env: _, admin, did, dids, - issuer, + issuer: _, contract, } = VaultContractTest::setup(); - - let VCVaultContractTest { - vc_id, - vc_data, - issuance_contract_address, - } = get_vc_setup(&env); - contract.initialize(&admin, &dids); - contract.authorize_issuer(&admin, &issuer, &did); - contract.store_vc(&vc_id, &vc_data, &did, &issuer, &issuance_contract_address); - let vc_id2 = String::from_slice(&env, "vc_id2"); - contract.get_vc(&vc_id2); + contract.get_vault(&did); } #[test] -fn test_list_vcs() { +fn test_list_vaults() { let VaultContractTest { env, admin, @@ -421,19 +403,22 @@ fn test_list_vcs() { &issuance_contract_address, ); - let dids_with_vcs = contract.list_vcs(); - let did_with_vc1 = dids_with_vcs.get_unchecked(did.clone()); - let did_with_vc2 = dids_with_vcs.get_unchecked(did2.clone()); + let vaults = contract.list_vaults(); - assert_eq!(dids_with_vcs.len(), 2); - assert_eq!(did_with_vc1.did, did); - assert_eq!(did_with_vc2.did, did2); - assert_eq!(did_with_vc1.vcs.len(), 2); - assert_eq!(did_with_vc2.vcs.len(), 1); + assert_eq!(vaults.len(), 2); + + let vault1 = contract.get_vault(&did); + let vault2 = contract.get_vault(&did2); + + vaults.contains(&vault1); + vaults.contains(&vault2); + + assert_eq!(vault1.vcs.len(), 2); + assert_eq!(vault2.vcs.len(), 1); } #[test] -fn test_register_did() { +fn test_register_vault() { let VaultContractTest { env, admin, @@ -445,12 +430,12 @@ fn test_register_did() { let did2 = String::from_slice(&env, "did:chaincerts:3mtjfbxad3wzh7qa4w5f7q4h"); contract.initialize(&admin, &dids); - contract.register_did(&admin, &did2); + contract.register_vault(&admin, &did2); } #[test] -#[should_panic(expected = "HostError: Error(Contract, #9)")] -fn test_register_did_with_duplicated_did() { +#[should_panic(expected = "HostError: Error(Contract, #8)")] +fn test_register_vault_with_duplicated_did() { let VaultContractTest { env: _, admin, @@ -461,12 +446,12 @@ fn test_register_did_with_duplicated_did() { } = VaultContractTest::setup(); contract.initialize(&admin, &dids); - contract.register_did(&admin, &duplicated_did); + contract.register_vault(&admin, &duplicated_did); } #[test] #[should_panic(expected = "HostError: Error(Contract, #2)")] -fn test_register_did_with_invalid_admin() { +fn test_register_vault_with_invalid_admin() { let VaultContractTest { env, admin, @@ -479,11 +464,11 @@ fn test_register_did_with_invalid_admin() { let invalid_admin = Address::random(&env); contract.initialize(&admin, &dids); - contract.register_did(&invalid_admin, &did2); + contract.register_vault(&invalid_admin, &did2); } #[test] -fn test_revoke_did() { +fn test_revoke_vault() { let VaultContractTest { env: _, admin, @@ -494,12 +479,12 @@ fn test_revoke_did() { } = VaultContractTest::setup(); contract.initialize(&admin, &dids); - contract.revoke_did(&admin, &did); + contract.revoke_vault(&admin, &did); } #[test] #[should_panic(expected = "HostError: Error(Contract, #2)")] -fn test_revoke_did_with_invalid_admin() { +fn test_revoke_vault_with_invalid_admin() { let VaultContractTest { env, admin, @@ -511,12 +496,12 @@ fn test_revoke_did_with_invalid_admin() { let invalid_admin = Address::random(&env); contract.initialize(&admin, &dids); - contract.revoke_did(&invalid_admin, &did); + contract.revoke_vault(&invalid_admin, &did); } #[test] #[should_panic(expected = "HostError: Error(Contract, #6)")] -fn test_revoke_did_with_no_registered_did() { +fn test_revoke_vault_with_no_registered_did() { let VaultContractTest { env, admin, @@ -528,5 +513,5 @@ fn test_revoke_did_with_no_registered_did() { let invalid_did = String::from_slice(&env, "did:chaincerts:3mtjfbxad3wzh7qa4w5f7q4h"); contract.initialize(&admin, &dids); - contract.revoke_did(&admin, &invalid_did); + contract.revoke_vault(&admin, &invalid_did); } diff --git a/vault_contract/src/test/setup.rs b/vault_contract/src/test/setup.rs index 5dda9ee..f5930c3 100644 --- a/vault_contract/src/test/setup.rs +++ b/vault_contract/src/test/setup.rs @@ -41,6 +41,7 @@ pub fn get_vc_setup(env: &Env) -> VCVaultContractTest { let vc_id = String::from_slice(env, "vc_id"); let vc_data = String::from_slice(env, "vc_data"); let issuance_contract_address = Address::random(env); + VCVaultContractTest { vc_id, vc_data, diff --git a/vault_contract/src/vault.rs b/vault_contract/src/vault.rs new file mode 100644 index 0000000..fa32b49 --- /dev/null +++ b/vault_contract/src/vault.rs @@ -0,0 +1,41 @@ +use crate::error::ContractError; +use crate::storage; +use crate::verifiable_credential::VerifiableCredential; +use soroban_sdk::{contracttype, panic_with_error, Env, Map, String, Vec}; + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Vault { + pub did: String, + pub revoked: bool, + pub vcs: Vec, +} + +pub fn set_initial_vaults(e: &Env, dids: &Vec) { + if dids.is_empty() { + panic_with_error!(e, ContractError::EmptyDIDs); + } + + let mut vaults: Map = Map::new(e); + + for did in dids.iter() { + vaults.set( + did.clone(), + Vault { + did: did.clone(), + revoked: false, + vcs: Vec::new(e), + }, + ) + } + + storage::write_vaults(e, &vaults); +} + +pub fn is_registered(vaults: &Map, vault_did: &String) -> bool { + vaults.contains_key(vault_did.clone()) +} + +pub fn is_revoked(vaults: &Map, vault_did: &String) -> bool { + vaults.get_unchecked(vault_did.clone()).revoked +} diff --git a/vault_contract/src/vault_trait.rs b/vault_contract/src/vault_trait.rs index 539d3e8..fda5001 100644 --- a/vault_contract/src/vault_trait.rs +++ b/vault_contract/src/vault_trait.rs @@ -1,36 +1,35 @@ -use crate::did::DidWithVCs; -use crate::verifiable_credential::VerifiableCredential; -use soroban_sdk::{Address, Env, Map, String, Vec}; +use crate::vault::Vault; +use soroban_sdk::{Address, Env, String, Vec}; pub trait VaultTrait { - /// Initializes the Vault Contract by setting the admin and the initial DIDs. + /// Initializes the vault contract by setting the admin and creating a vault for each DID. fn initialize(e: Env, admin: Address, dids: Vec); - /// Authorizes an issuer adding it to the issuers map. + /// Authorizes an issuer for a vault. fn authorize_issuer(e: Env, admin: Address, issuer: Address, did: String); - /// Revokes an issuer setting its is_revoked property to true. + /// Revokes an issuer for a vault. fn revoke_issuer(e: Env, admin: Address, issuer: Address, did: String); - /// Stores the verifiable credential. + /// Stores a verifiable credential in the recipient's vault. fn store_vc( e: Env, vc_id: String, vc_data: String, recipient_did: String, - issuer_pk: Address, - issuance_contract_address: Address, + issuer: Address, + issuance_contract: Address, ); - /// Retrieves a verifiable credential using its unique identifier. - fn get_vc(e: Env, vc_id: String) -> VerifiableCredential; + /// Registers a vault given its DID. + fn register_vault(e: Env, admin: Address, did: String); - /// Retrieves the list of verifiable credentials from the storage grouped by DID. - fn list_vcs(e: Env) -> Map; + /// Revokes a vault given its DID. + fn revoke_vault(e: Env, admin: Address, did: String); - /// Revokes a DID given its DID URI. - fn revoke_did(e: Env, admin: Address, did: String); + /// Retrieves a vault given its DID. + fn get_vault(e: Env, did: String) -> Vault; - /// Registers a new DID given a DID URI. - fn register_did(e: Env, admin: Address, did: String); + /// Retrieves the list of vaults. + fn list_vaults(e: Env) -> Vec; } diff --git a/vault_contract/src/verifiable_credential.rs b/vault_contract/src/verifiable_credential.rs index f1de3a1..bef6bee 100644 --- a/vault_contract/src/verifiable_credential.rs +++ b/vault_contract/src/verifiable_credential.rs @@ -1,37 +1,40 @@ -use soroban_sdk::{contracttype, Address, Env, String}; - use crate::storage; +use crate::vault::Vault; +use soroban_sdk::{contracttype, Address, Env, Map, String, Vec}; #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub struct VerifiableCredential { pub id: String, pub data: String, - pub holder_did: String, pub issuance_contract: Address, } pub fn store_vc( e: &Env, - vc_id: &String, - vc_data: &String, - issuance_contract: &Address, - recipient_did: &String, + vaults: &mut Map, + id: String, + data: String, + issuance_contract: Address, + recipient_did: String, ) { - let vc = VerifiableCredential { - id: vc_id.clone(), - data: vc_data.clone(), - holder_did: recipient_did.clone(), - issuance_contract: issuance_contract.clone(), + let mut vcs: Vec = vaults.get_unchecked(recipient_did.clone()).vcs; + let new_vc: VerifiableCredential = VerifiableCredential { + id, + data, + issuance_contract, }; - let mut vcs = storage::read_vcs(e); - let mut dids = storage::read_dids(e); - let mut did = dids.get_unchecked(recipient_did.clone()); - did.vcs.push_back(vc_id.clone()); - dids.set(recipient_did.clone(), did); - storage::write_dids(e, &dids); + vcs.push_back(new_vc); + + vaults.set( + recipient_did.clone(), + Vault { + did: recipient_did, + revoked: false, + vcs, + }, + ); - vcs.set(vc_id.clone(), vc); - storage::write_vcs(e, &vcs); + storage::write_vaults(e, vaults); } diff --git a/vc_issuance_contract/Cargo.toml b/vc_issuance_contract/Cargo.toml index 97714ea..40f6e32 100644 --- a/vc_issuance_contract/Cargo.toml +++ b/vc_issuance_contract/Cargo.toml @@ -1,7 +1,9 @@ [package] -name = "vc_issuance_contract" -version = "0.1.0" -edition = "2021" +name = "vc-issuance-contract" +version = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/vc_issuance_contract/src/contract.rs b/vc_issuance_contract/src/contract.rs index d5eab5b..5add1a3 100644 --- a/vc_issuance_contract/src/contract.rs +++ b/vc_issuance_contract/src/contract.rs @@ -47,14 +47,14 @@ impl VCIssuanceTrait for VCIssuanceContract { admin: Address, vc_data: String, recipient_did: String, - storage_address: Address, + vault_contract: Address, ) -> String { validate_admin(&e, &admin); let vc_id = verifiable_credential::generate_id(&e); let contract_address = e.current_contract_address(); - let client = vault_contract::Client::new(&e, &storage_address); + let client = vault_contract::Client::new(&e, &vault_contract); client.store_vc(&vc_id, &vc_data, &recipient_did, &admin, &contract_address); verifiable_credential::add_vc(&e, &vc_id); diff --git a/vc_issuance_contract/src/test/contract.rs b/vc_issuance_contract/src/test/contract.rs index ba7003b..71dc012 100644 --- a/vc_issuance_contract/src/test/contract.rs +++ b/vc_issuance_contract/src/test/contract.rs @@ -107,7 +107,7 @@ fn test_revoke_vc_with_invalid_vc() { contract.initialize(&admin, &Some(10)); let vc_id = String::from_slice(&env, "vc_id1"); - let date = String::from_slice(&env, "28-11-2023"); + let date = String::from_slice(&env, "2023-12-05T21:37:44.389Z"); contract.revoke(&admin, &vc_id, &date); } @@ -125,7 +125,7 @@ fn test_revoke_vc() { let vault_contract_id = create_vc(&env, &admin, &contract, &recipient_did); let vc_id = contract.issue(&admin, &vc_data, &recipient_did, &vault_contract_id); - let date = String::from_slice(&env, "28-11-2023"); + let date = String::from_slice(&env, "2023-12-05T21:37:44.389Z"); contract.revoke(&admin, &vc_id, &date); } @@ -159,7 +159,7 @@ fn test_verify_vc_with_revoked_vc() { } = VCIssuanceContractTest::setup(); let vault_contract_id = create_vc(&env, &admin, &contract, &recipient_did); let vc_id = contract.issue(&admin, &vc_data, &recipient_did, &vault_contract_id); - let date = String::from_slice(&env, "28-11-2023"); + let date = String::from_slice(&env, "2023-12-05T21:37:44.389Z"); contract.revoke(&admin, &vc_id, &date); diff --git a/vc_issuance_contract/src/vc_issuance_trait.rs b/vc_issuance_contract/src/vc_issuance_trait.rs index 8fa58ea..679dc4b 100644 --- a/vc_issuance_contract/src/vc_issuance_trait.rs +++ b/vc_issuance_contract/src/vc_issuance_trait.rs @@ -10,7 +10,7 @@ pub trait VCIssuanceTrait { admin: Address, recipient_did: String, vc_data: String, - storage_address: Address, + vault_contract: Address, ) -> String; /// Verifies if the Verifiable Credential is not revoked