diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock
index cb5b349..b55e36b 100644
--- a/contracts/Cargo.lock
+++ b/contracts/Cargo.lock
@@ -73,9 +73,9 @@ checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d"
[[package]]
name = "cc"
-version = "1.2.25"
+version = "1.2.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951"
+checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac"
dependencies = [
"shlex",
]
@@ -84,8 +84,13 @@ dependencies = [
name = "certificate"
version = "0.1.0"
dependencies = [
- "serde",
- "serde_json",
+ "ink",
+ "ink_env",
+ "ink_metadata",
+ "ink_prelude",
+ "ink_storage",
+ "parity-scale-codec",
+ "scale-info",
]
[[package]]
@@ -138,12 +143,14 @@ name = "dao-governance"
version = "0.1.0"
dependencies = [
"ink",
+ "ink_env",
"ink_metadata",
"ink_prelude",
"ink_storage",
"parity-scale-codec",
"scale-info",
"serde",
+ "thiserror",
]
[[package]]
@@ -272,9 +279,9 @@ dependencies = [
[[package]]
name = "hashbrown"
-version = "0.15.3"
+version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
+checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
[[package]]
name = "heck"
@@ -639,7 +646,7 @@ version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35"
dependencies = [
- "toml_edit 0.22.26",
+ "toml_edit 0.22.27",
]
[[package]]
@@ -881,9 +888,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "smallvec"
-version = "1.15.0"
+version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "static_assertions"
@@ -951,11 +958,31 @@ dependencies = [
"winapi-util",
]
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.101",
+]
+
[[package]]
name = "toml_datetime"
-version = "0.6.9"
+version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
+checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
[[package]]
name = "toml_edit"
@@ -970,9 +997,9 @@ dependencies = [
[[package]]
name = "toml_edit"
-version = "0.22.26"
+version = "0.22.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
+checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
dependencies = [
"indexmap",
"toml_datetime",
diff --git a/contracts/certificate/Cargo.toml b/contracts/certificate/Cargo.toml
index b2ea46a..468f12f 100644
--- a/contracts/certificate/Cargo.toml
+++ b/contracts/certificate/Cargo.toml
@@ -3,9 +3,36 @@ name = "certificate"
version = "0.1.0"
edition = "2021"
+[dependencies]
+ink = { version = "4.2.0", default-features = false }
+ink_metadata = { version = "4.2.0", default-features = false }
+ink_storage = { version = "4.2.0", default-features = false }
+ink_prelude = { version = "4.2.0", default-features = false }
+scale = { package = "parity-scale-codec", version = "3.6.5", default-features = false, features = [
+ "derive",
+] }
+scale-info = { version = "2.9.0", default-features = false, features = [
+ "derive",
+] }
+
+[dev-dependencies]
+ink_env = { version = "4.2.0", default-features = false }
+
[lib]
-crate-type = ["cdylib", "rlib"]
+name = "certificate"
+path = "src/lib.rs"
+# crate-type = ["cdylib", "rlib"]
-[dependencies]
-serde = { version = "1.0", features = ["derive"] }
-serde_json = "1.0"
+[features]
+default = ["std"]
+std = [
+ "ink/std",
+ "ink_metadata/std",
+ "ink_storage/std",
+ "ink_prelude/std",
+ "scale/std",
+ "scale-info/std",
+]
+
+# For testing with cargo-contract
+ink-as-dependency = []
diff --git a/contracts/certificate/README.md b/contracts/certificate/README.md
new file mode 100644
index 0000000..c956ce0
--- /dev/null
+++ b/contracts/certificate/README.md
@@ -0,0 +1,228 @@
+# Certificate Smart Contract
+
+A secure and immutable ink! smart contract for issuing verifiable educational
+certificates on Polkadot/Substrate-based blockchains.
+
+## Features
+
+### 🔐 Security & Authorization
+
+- **Admin-only issuance**: Only authorized administrators can issue certificates
+- **Owner controls**: Contract owner can add/remove admins
+- **Immutable records**: Certificates cannot be modified once issued
+
+### 📜 Certificate Management
+
+- **Unique certificates**: Prevents duplicate certificates for same
+ student/course
+- **Comprehensive metadata**: Stores student address, course details,
+ timestamps, and completion proofs
+- **Verification system**: Public functions to verify certificate ownership and
+ authenticity
+
+### 🎯 Key Functions
+
+#### Admin Functions
+
+- `issue_certificate()` - Issue new certificates to students
+- `add_admin()` - Add new administrators (owner only)
+- `remove_admin()` - Remove administrators (owner only)
+
+#### Public Query Functions
+
+- `verify_certificate()` - Get certificate details by ID
+- `has_certificate()` - Check if student has certificate for specific course
+- `get_student_certificates()` - Get all certificates for a student
+- `get_certificate_id()` - Get certificate ID for student/course combination
+- `is_admin()` - Check if account is an admin
+- `get_owner()` - Get contract owner address
+- `get_total_certificates()` - Get total number of certificates issued
+
+## Data Structures
+
+### Certificate
+
+```rust
+pub struct Certificate {
+ pub student_address: AccountId, // Student's wallet address
+ pub course_id: String, // Unique course identifier
+ pub issued_at: u64, // Timestamp of issuance
+ pub completion_proof_hash: [u8; 32], // Hash of completion proof
+ pub course_name: String, // Human-readable course name
+ pub issuer: AccountId, // Admin who issued the certificate
+}
+```
+
+### Events
+
+- `CertificateIssued` - Emitted when a certificate is issued
+- `AdminAdded` - Emitted when a new admin is added
+- `AdminRemoved` - Emitted when an admin is removed
+
+## Usage Examples
+
+### Deploying the Contract
+
+```rust
+// Constructor creates the contract with the deployer as the first admin
+let contract = CertificateContract::new();
+```
+
+### Issuing a Certificate
+
+```rust
+// Only admins can issue certificates
+let result = contract.issue_certificate(
+ student_account_id,
+ "RUST101".to_string(),
+ "Introduction to Rust Programming".to_string(),
+ completion_proof_hash, // [u8; 32] hash of completion proof
+);
+```
+
+### Verifying a Certificate
+
+```rust
+// Anyone can verify a certificate by ID
+let certificate = contract.verify_certificate(certificate_id);
+if let Some(cert) = certificate {
+ println!("Student: {:?}", cert.student_address);
+ println!("Course: {}", cert.course_name);
+ println!("Issued: {}", cert.issued_at);
+}
+```
+
+### Checking Student Certificates
+
+```rust
+// Check if student has completed a specific course
+let has_cert = contract.has_certificate(student_address, "RUST101".to_string());
+
+// Get all certificates for a student
+let all_certs = contract.get_student_certificates(student_address);
+```
+
+## Error Handling
+
+The contract includes comprehensive error handling:
+
+```rust
+pub enum CertificateError {
+ Unauthorized, // Caller lacks required permissions
+ CertificateAlreadyExists, // Duplicate certificate attempted
+ CertificateNotFound, // Certificate ID doesn't exist
+ InvalidCourseId, // Empty course ID provided
+ InvalidCourseName, // Empty course name provided
+}
+```
+
+## Testing
+
+The contract includes comprehensive unit tests covering:
+
+- ✅ Certificate issuance by authorized admins
+- ✅ Authorization checks (prevents unauthorized access)
+- ✅ Duplicate prevention (same student + course)
+- ✅ Certificate verification and ownership
+- ✅ Admin management (add/remove)
+- ✅ Input validation
+- ✅ Event emission
+
+### Running Tests
+
+```bash
+cd contracts/certificate
+cargo test
+```
+
+### Test Coverage
+
+- `new_works` - Contract initialization
+- `issue_certificate_works` - Successful certificate issuance
+- `issue_certificate_unauthorized` - Authorization enforcement
+- `prevent_duplicate_certificates` - Duplicate prevention
+- `has_certificate_works` - Certificate existence checks
+- `get_student_certificates_works` - Student certificate retrieval
+- `admin_management_works` - Admin add/remove functionality
+- `admin_management_unauthorized` - Admin permission checks
+- `invalid_inputs_rejected` - Input validation
+
+## Security Considerations
+
+1. **Admin Authorization**: Only contract owner can manage admins
+2. **Immutable Records**: Certificates cannot be modified after issuance
+3. **Duplicate Prevention**: Smart prevention of duplicate certificates
+4. **Input Validation**: Proper validation of all inputs
+5. **Event Emission**: All critical actions emit events for transparency
+
+## Deployment
+
+### Prerequisites
+
+- Rust with ink! toolchain
+- cargo-contract tool
+- Access to a Substrate-based chain with contracts pallet
+
+### Build Commands
+
+```bash
+# Check compilation
+cargo check
+
+# Run tests
+cargo test
+
+# Build for deployment (requires cargo-contract)
+cargo contract build
+
+# Generate metadata
+cargo contract build --release
+```
+
+### Compatible Chains
+
+- Polkadot parachains with contracts pallet
+- Substrate-based development chains
+- Canvas Network (testnet)
+- Astar Network
+- Any chain supporting ink! smart contracts
+
+## Gas Optimization
+
+The contract is optimized for minimal gas usage:
+
+- Efficient storage mappings
+- Minimal redundant data
+- Optimized query functions
+- Event-based tracking
+
+## Integration
+
+### Frontend Integration
+
+The contract exposes standard ink! interfaces that can be integrated with:
+
+- Polkadot.js apps
+- Custom React/Vue.js applications using @polkadot/api
+- Mobile applications using polkadot-js
+
+### Example Integration (JavaScript)
+
+```javascript
+const { ApiPromise, WsProvider } = require("@polkadot/api");
+const { ContractPromise } = require("@polkadot/api-contract");
+
+// Connect to node
+const wsProvider = new WsProvider("ws://localhost:9944");
+const api = await ApiPromise.create({ provider: wsProvider });
+
+// Load contract
+const contract = new ContractPromise(api, abi, contractAddress);
+
+// Verify certificate
+const { result } = await contract.query.verifyCertificate(
+ caller,
+ { gasLimit: -1 },
+ certificateId,
+);
+```
diff --git a/contracts/certificate/src/certification.rs b/contracts/certificate/src/certification.rs
deleted file mode 100644
index 4ad5f7d..0000000
--- a/contracts/certificate/src/certification.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-use alephium_sdk::{prelude::*, worldcoin::*};
-
-#[contract]
-pub struct CertificationContract {
- // Contract storage
- certificates: StorageMap
,
- course_completions: StorageMap<(Address, CourseId), bool>,
-}
-
-#[derive(Encode, Decode, Clone)]
-pub struct Certificate {
- student_address: Address,
- course_id: CourseId,
- completion_date: u64,
- worldcoin_proof: WorldcoinProof,
-}
-
-#[derive(Encode, Decode, Clone)]
-pub struct CourseId(pub Vec);
-
-#[derive(Encode, Decode, Clone)]
-pub struct WorldcoinProof {
- nullifier_hash: [u8; 32],
- proof: Vec,
- verification_key: Vec,
-}
-
-impl CertificationContract {
- #[endpoint]
- pub fn mint_certificate(
- &mut self,
- course_id: CourseId,
- worldcoin_proof: WorldcoinProof,
- ) -> Result<(), ContractError> {
- let student_address = self.get_caller();
-
- // Verify course completion
- if !self.course_completions.get(&(student_address.clone(), course_id.clone())).unwrap_or(false) {
- return Err(ContractError::CourseNotCompleted);
- }
-
- // Verify Worldcoin proof
- self.verify_worldcoin_proof(&worldcoin_proof)?;
-
- // Create certificate
- let certificate = Certificate {
- student_address: student_address.clone(),
- course_id,
- completion_date: self.get_block_timestamp(),
- worldcoin_proof,
- };
-
- // Store certificate
- self.certificates.insert(student_address, certificate);
-
- Ok(())
- }
-
- #[endpoint]
- pub fn verify_certificate(
- &self,
- student_address: Address,
- ) -> Result