From c541e3c1202d05ae548c817b78ac458956d3a4e9 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Sun, 18 Aug 2024 08:27:17 +0000 Subject: [PATCH 1/4] test --- a.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 a.md diff --git a/a.md b/a.md new file mode 100644 index 0000000..e69de29 From 1981ca29725e1d103b758e07016b811306a3cbed Mon Sep 17 00:00:00 2001 From: Sheetal Ojha Date: Tue, 27 Aug 2024 04:21:04 +0000 Subject: [PATCH 2/4] completed base development for Multichain acquirer addresses --- pallets/algorithms/src/lib.rs | 8 ++-- pallets/credentials/Cargo.toml | 2 + pallets/credentials/src/lib.rs | 77 ++++++++++++++++++++++++++++++---- 3 files changed, 75 insertions(+), 12 deletions(-) diff --git a/pallets/algorithms/src/lib.rs b/pallets/algorithms/src/lib.rs index ca7087e..161534e 100644 --- a/pallets/algorithms/src/lib.rs +++ b/pallets/algorithms/src/lib.rs @@ -14,7 +14,7 @@ pub mod pallet { use frame_support::dispatch::Vec; use sp_runtime::traits::Hash; - use pallet_credentials::{Attestations, CredAttestation, CredSchema}; + use pallet_credentials::{self as credentials, Attestations, CredAttestation, CredSchema, AcquirerAddress}; use super::*; @@ -157,15 +157,17 @@ pub mod pallet { #[pallet::call_index(2)] #[pallet::weight(100_000)] - pub fn run_algo_for(origin: OriginFor, account_id: T::AccountId, algorithm_id: u64) -> DispatchResult { + pub fn run_algo_for(origin: OriginFor, account_id: Vec, algorithm_id: u64) -> DispatchResult { let who = ensure_signed(origin)?; + let acquirer_address = credentials::Pallet::::parse_acquirer_address(account_id)?; + let algorithm = Algorithms::::get(algorithm_id).ok_or(Error::::AlgoNotFound)?; let mut attestations: Vec = Vec::<>::with_capacity(algorithm.schema_hashes.len()); for schema_hash in algorithm.schema_hashes { - let attestation = Attestations::::get(account_id.clone(), schema_hash).ok_or(crate::pallet::Error::::AttestationNotFound)?; + let attestation = Attestations::::get(acquirer_address.clone(), schema_hash).ok_or(crate::pallet::Error::::AttestationNotFound)?; attestations.push(attestation); } diff --git a/pallets/credentials/Cargo.toml b/pallets/credentials/Cargo.toml index 68b6104..63ee53f 100644 --- a/pallets/credentials/Cargo.toml +++ b/pallets/credentials/Cargo.toml @@ -23,6 +23,7 @@ frame-support = { version = "4.0.0-dev", default-features = false, git = "https: frame-system = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } sp-runtime = { version = "24.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } pallet-issuers = { path = "../issuers", default-features = false } +sp-core = { version = "21.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } [dev-dependencies] sp-core = { version = "21.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } @@ -39,6 +40,7 @@ std = [ "scale-info/std", "sp-runtime/std", "pallet-issuers/std", + "sp-core/std" ] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] diff --git a/pallets/credentials/src/lib.rs b/pallets/credentials/src/lib.rs index 865dfc8..cfa7421 100644 --- a/pallets/credentials/src/lib.rs +++ b/pallets/credentials/src/lib.rs @@ -12,6 +12,8 @@ pub mod pallet { use frame_system::pallet_prelude::*; use scale_info::prelude::vec; use sp_runtime::traits::Hash; + use sp_core::{H160, crypto::Ss58Codec}; + // use sp_core::hash::keccak_256; use pallet_issuers::Issuers; @@ -35,6 +37,15 @@ pub mod pallet { Hash } + ///wallet addresss attestation can be being issued to + + #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] + #[scale_info(skip_type_params(T))] + pub enum AcquirerAddress{ + Ethereum([u8; 20]), + Solana([u8; 32]), + } + #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] pub enum SizeInBytes { Limited(u8), @@ -84,7 +95,7 @@ pub mod pallet { pub type Attestations = StorageDoubleMap< _, Blake2_128Concat, - T::AccountId, + AcquirerAddress, Twox64Concat, T::Hash, CredAttestation, @@ -99,7 +110,7 @@ pub mod pallet { schema: CredSchema, }, AttestationCreated { - account_id: T::AccountId, + account_id: AcquirerAddress, schema_hash: T::Hash, attestation: CredAttestation, }, @@ -158,11 +169,13 @@ pub mod pallet { origin: OriginFor, issuer_hash: T::Hash, schema_hash: T::Hash, - for_account: T::AccountId, + for_account: Vec, attestation: CredAttestation, ) -> DispatchResult { let who = ensure_signed(origin)?; + let acquirer_address = Pallet::::parse_acquirer_address(for_account)?; + let issuer = Issuers::::get(issuer_hash).ok_or(pallet_issuers::Error::::IssuerNotFound)?; ensure!(issuer.controllers.contains(&who), pallet_issuers::Error::::NotAuthorized); @@ -174,13 +187,15 @@ pub mod pallet { log::debug!(target: "algo", "Creds:{:?}", attestation); - Attestations::::insert(for_account.clone(), schema_hash, attestation.clone()); + // validate acquirer address - Self::deposit_event(Event::AttestationCreated { - account_id: for_account, - schema_hash, - attestation, - }); + Attestations::::insert(acquirer_address.clone(), schema_hash, attestation.clone()); + + // Self::deposit_event(Event::AttestationCreated { + // account_id: acquirer_address, + // schema_hash, + // attestation, + // }); Ok(()) } @@ -245,6 +260,50 @@ pub mod pallet { Some(formatted) } + + pub fn is_valid_ethereum_address(address: &[u8]) -> bool { + address.len() == 20 && H160::from_slice(address).to_fixed_bytes() == *address + } + + pub fn is_valid_solana_address(address: &[u8]) -> bool { + // Check if the address is exactly 32 bytes long + if address.len() != 32 { + return false; + } + // let public_key = Public(address_array); + + // // Attempt to encode the public key to Base58 + // match public_key.to_ss58check() { + // Ok(_) => true, + // Err(_) => false, + // } + true + } + + // fn is_valid_substrate_address(address: &T::AccountId) -> bool { + // // This assumes T::AccountId implements Ss58Codec + // address.to_ss58check().len() > 0 + // } + + pub fn parse_acquirer_address(address: Vec) -> Result { + match address.len() { + 20 => { + if Pallet::::is_valid_ethereum_address(&address) { + Ok(AcquirerAddress::Ethereum(address.try_into().unwrap())) + } else { + Err(DispatchError::Other("Invalid Ethereum address format")) + } + }, + 32 => { + if Self::is_valid_solana_address(&address) { + Ok(AcquirerAddress::Solana(address.try_into().unwrap())) + } else { + Err(DispatchError::Other("Invalid Solana address format")) + } + }, + _ => Err(DispatchError::Other("Invalid address length")) + } + } } } From f23426ac0216eaafaaeb769df1bf15d4abbadd99 Mon Sep 17 00:00:00 2001 From: Sheetal Ojha Date: Fri, 30 Aug 2024 18:40:56 +0000 Subject: [PATCH 3/4] added substrate address validation --- pallets/credentials/src/lib.rs | 65 ++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/pallets/credentials/src/lib.rs b/pallets/credentials/src/lib.rs index cfa7421..039f8c1 100644 --- a/pallets/credentials/src/lib.rs +++ b/pallets/credentials/src/lib.rs @@ -12,8 +12,8 @@ pub mod pallet { use frame_system::pallet_prelude::*; use scale_info::prelude::vec; use sp_runtime::traits::Hash; - use sp_core::{H160, crypto::Ss58Codec}; - // use sp_core::hash::keccak_256; + use sp_core::{H160, crypto::Ss58Codec, crypto::AccountId32}; + use sp_core::sr25519::Public; use pallet_issuers::Issuers; @@ -42,6 +42,7 @@ pub mod pallet { #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] #[scale_info(skip_type_params(T))] pub enum AcquirerAddress{ + Substrate([u8; 32]), Ethereum([u8; 20]), Solana([u8; 32]), } @@ -187,15 +188,13 @@ pub mod pallet { log::debug!(target: "algo", "Creds:{:?}", attestation); - // validate acquirer address - Attestations::::insert(acquirer_address.clone(), schema_hash, attestation.clone()); - // Self::deposit_event(Event::AttestationCreated { - // account_id: acquirer_address, - // schema_hash, - // attestation, - // }); + Self::deposit_event(Event::AttestationCreated { + account_id: acquirer_address, + schema_hash, + attestation, + }); Ok(()) } @@ -267,23 +266,36 @@ pub mod pallet { pub fn is_valid_solana_address(address: &[u8]) -> bool { // Check if the address is exactly 32 bytes long - if address.len() != 32 { - return false; - } - // let public_key = Public(address_array); - // // Attempt to encode the public key to Base58 - // match public_key.to_ss58check() { - // Ok(_) => true, - // Err(_) => false, - // } - true + let address_array: [u8; 32] = match address.try_into() { + Ok(arr) => arr, + Err(_) => return false, + }; + + let public_key = Public(address_array); + + // Attempt to encode the public key to Base58 + public_key.to_ss58check().len() == 44 } - // fn is_valid_substrate_address(address: &T::AccountId) -> bool { - // // This assumes T::AccountId implements Ss58Codec - // address.to_ss58check().len() > 0 - // } + // need to make this generic over the chain configurations + fn is_valid_substrate_address(address: &[u8]) -> bool { + // Check if the address is exactly 32 bytes long + let address_array: [u8; 32] = match address.try_into() { + Ok(arr) => arr, + Err(_) => return false, + }; + + // Create an AccountId32 from the address bytes + let account_id = AccountId32::new(address_array); + + // Encode the AccountId32 to SS58 and then try to decode it + // This checks if the address is valid in any SS58 format + match AccountId32::from_ss58check(&account_id.to_ss58check()) { + Ok(_) => true, + Err(_) => false, + } + } pub fn parse_acquirer_address(address: Vec) -> Result { match address.len() { @@ -301,6 +313,13 @@ pub mod pallet { Err(DispatchError::Other("Invalid Solana address format")) } }, + _ if address.len() == T::AccountId::max_encoded_len() => { + if Self::is_valid_substrate_address(&address) { + Ok(AcquirerAddress::Substrate(address.try_into().unwrap())) + } else { + Err(DispatchError::Other("Invalid Substrate address format")) + } + }, _ => Err(DispatchError::Other("Invalid address length")) } } From f18516f7035defd335c4f964755161228319ac2c Mon Sep 17 00:00:00 2001 From: Sheetal Ojha Date: Sun, 1 Sep 2024 14:30:10 +0000 Subject: [PATCH 4/4] fixed solana wallet attestation --- Cargo.lock | 299 +++++++++++----- pallets/credentials/Cargo.toml | 6 +- pallets/credentials/src/lib.rs | 631 ++++++++++++++++----------------- 3 files changed, 519 insertions(+), 417 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c64b453..9ac1a02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -692,6 +692,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" + [[package]] name = "bstr" version = "1.6.0" @@ -792,11 +798,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "e9e8aabfac534be767c909e0690571677d49f41bd8465ae876fe043d52ba5292" dependencies = [ "jobserver", + "libc", ] [[package]] @@ -842,25 +849,24 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chacha20" -version = "0.8.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", - "cipher 0.3.0", + "cipher 0.4.4", "cpufeatures", - "zeroize", ] [[package]] name = "chacha20poly1305" -version = "0.9.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" dependencies = [ - "aead 0.4.3", + "aead 0.5.2", "chacha20", - "cipher 0.3.0", + "cipher 0.4.4", "poly1305", "zeroize", ] @@ -919,6 +925,7 @@ checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", + "zeroize", ] [[package]] @@ -1376,18 +1383,31 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-rc.1" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", "fiat-crypto", - "packed_simd_2", - "platforms", + "rustc_version", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.27", +] + [[package]] name = "cxx" version = "1.0.102" @@ -1763,6 +1783,15 @@ dependencies = [ "signature 1.6.4", ] +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature 2.1.0", +] + [[package]] name = "ed25519-dalek" version = "1.0.1" @@ -1770,13 +1799,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ "curve25519-dalek 3.2.0", - "ed25519", + "ed25519 1.5.3", "rand 0.7.3", "serde", "sha2 0.9.9", "zeroize", ] +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek 4.1.3", + "ed25519 2.2.3", + "sha2 0.10.7", + "subtle", +] + [[package]] name = "ed25519-zebra" version = "3.1.0" @@ -1988,9 +2029,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.1.20" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "file-per-thread-logger" @@ -3144,9 +3185,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] @@ -3373,9 +3414,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libloading" @@ -3387,12 +3428,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "libm" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" - [[package]] name = "libm" version = "0.2.8" @@ -3527,8 +3562,8 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e2d584751cecb2aabaa56106be6be91338a60a0f4e420cf2af639204f596fc1" dependencies = [ - "bs58", - "ed25519-dalek", + "bs58 0.4.0", + "ed25519-dalek 1.0.1", "log", "multiaddr", "multihash", @@ -3739,7 +3774,7 @@ dependencies = [ "libp2p-core", "libp2p-identity", "rcgen 0.10.0", - "ring", + "ring 0.16.20", "rustls 0.20.8", "thiserror", "webpki 0.22.0", @@ -4108,9 +4143,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memfd" @@ -4692,16 +4727,6 @@ dependencies = [ "sha2 0.10.7", ] -[[package]] -name = "packed_simd_2" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" -dependencies = [ - "cfg-if", - "libm 0.1.4", -] - [[package]] name = "pallet-algorithms" version = "4.0.0-dev" @@ -4769,12 +4794,16 @@ dependencies = [ name = "pallet-credentials" version = "4.0.0-dev" dependencies = [ + "bs58 0.5.1", + "ed25519-dalek 2.1.1", "frame-benchmarking", "frame-support", "frame-system", + "hex", "log", "pallet-issuers", "parity-scale-codec", + "regex", "scale-info", "sp-core", "sp-io", @@ -5223,12 +5252,6 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" -[[package]] -name = "platforms" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" - [[package]] name = "polling" version = "2.8.0" @@ -5247,13 +5270,13 @@ dependencies = [ [[package]] name = "poly1305" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", "opaque-debug 0.3.0", - "universal-hash 0.4.1", + "universal-hash 0.5.1", ] [[package]] @@ -5562,7 +5585,7 @@ checksum = "f31999cfc7927c4e212e60fd50934ab40e8e8bfd2d493d6095d2d306bc0764d9" dependencies = [ "bytes", "rand 0.8.5", - "ring", + "ring 0.16.20", "rustc-hash", "rustls 0.20.8", "slab", @@ -5702,7 +5725,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" dependencies = [ "pem", - "ring", + "ring 0.16.20", "time 0.3.23", "x509-parser 0.13.2", "yasna", @@ -5715,7 +5738,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", - "ring", + "ring 0.16.20", "time 0.3.23", "yasna", ] @@ -5783,14 +5806,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.1" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.3", - "regex-syntax 0.7.4", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -5804,13 +5827,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.4", + "regex-syntax 0.8.4", ] [[package]] @@ -5821,9 +5844,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "resolv-conf" @@ -5866,11 +5889,26 @@ dependencies = [ "libc", "once_cell", "spin 0.5.2", - "untrusted", + "untrusted 0.7.1", "web-sys", "winapi", ] +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.10", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + [[package]] name = "rocksdb" version = "0.21.0" @@ -6027,7 +6065,7 @@ checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" dependencies = [ "base64 0.13.1", "log", - "ring", + "ring 0.16.20", "sct 0.6.1", "webpki 0.21.4", ] @@ -6039,7 +6077,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", - "ring", + "ring 0.16.20", "sct 0.7.0", "webpki 0.22.0", ] @@ -6051,7 +6089,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79ea77c539259495ce8ca47f53e66ae0330a8819f67e23ac96ca02f50e7b7d36" dependencies = [ "log", - "ring", + "ring 0.16.20", "rustls-webpki", "sct 0.7.0", ] @@ -6083,8 +6121,8 @@ version = "0.101.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513722fd73ad80a71f72b61009ea1b584bcfa1483ca93949c8f290298837fa59" dependencies = [ - "ring", - "untrusted", + "ring 0.16.20", + "untrusted 0.7.1", ] [[package]] @@ -7110,8 +7148,8 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" dependencies = [ - "ring", - "untrusted", + "ring 0.16.20", + "untrusted 0.7.1", ] [[package]] @@ -7120,8 +7158,8 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "ring", - "untrusted", + "ring 0.16.20", + "untrusted 0.7.1", ] [[package]] @@ -7440,16 +7478,16 @@ checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snow" -version = "0.9.2" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ccba027ba85743e09d15c03296797cad56395089b832b48b5a5217880f57733" +checksum = "850948bee068e713b8ab860fe1adc4d109676ab4c3b621fd8147f06b261f2f85" dependencies = [ - "aes-gcm 0.9.4", + "aes-gcm 0.10.2", "blake2", "chacha20poly1305", - "curve25519-dalek 4.0.0-rc.1", + "curve25519-dalek 4.1.3", "rand_core 0.6.4", - "ring", + "ring 0.17.8", "rustc_version", "sha2 0.10.7", "subtle", @@ -7673,7 +7711,7 @@ dependencies = [ "bitflags 1.3.2", "blake2", "bounded-collections", - "bs58", + "bs58 0.4.0", "dyn-clonable", "ed25519-zebra", "futures", @@ -7782,8 +7820,8 @@ version = "23.0.0" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" dependencies = [ "bytes", - "ed25519", - "ed25519-dalek", + "ed25519 1.5.3", + "ed25519-dalek 1.0.1", "libsecp256k1", "log", "parity-scale-codec", @@ -8276,7 +8314,7 @@ dependencies = [ "lazy_static", "md-5", "rand 0.8.5", - "ring", + "ring 0.16.20", "subtle", "thiserror", "tokio", @@ -9010,7 +9048,7 @@ dependencies = [ "log", "md-5", "rand 0.8.5", - "ring", + "ring 0.16.20", "stun", "thiserror", "tokio", @@ -9124,6 +9162,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.4.0" @@ -9382,7 +9426,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf1a7db34bff95b85c261002720c00c3a6168256dcb93041d3fa2054d19856a" dependencies = [ "downcast-rs", - "libm 0.2.8", + "libm", "num-traits", "paste", ] @@ -9617,8 +9661,8 @@ version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" dependencies = [ - "ring", - "untrusted", + "ring 0.16.20", + "untrusted 0.7.1", ] [[package]] @@ -9627,8 +9671,8 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" dependencies = [ - "ring", - "untrusted", + "ring 0.16.20", + "untrusted 0.7.1", ] [[package]] @@ -9656,7 +9700,7 @@ dependencies = [ "rand 0.8.5", "rcgen 0.9.3", "regex", - "ring", + "ring 0.16.20", "rtcp", "rtp", "rustls 0.19.1", @@ -9721,7 +9765,7 @@ dependencies = [ "rand 0.8.5", "rand_core 0.6.4", "rcgen 0.9.3", - "ring", + "ring 0.16.20", "rustls 0.19.1", "sec1 0.3.0", "serde", @@ -9947,6 +9991,15 @@ dependencies = [ "windows-targets 0.48.1", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -9977,6 +10030,22 @@ dependencies = [ "windows_x86_64_msvc 0.48.0", ] +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -9989,6 +10058,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + [[package]] name = "windows_aarch64_msvc" version = "0.34.0" @@ -10007,6 +10082,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + [[package]] name = "windows_i686_gnu" version = "0.34.0" @@ -10025,6 +10106,18 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + [[package]] name = "windows_i686_msvc" version = "0.34.0" @@ -10043,6 +10136,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + [[package]] name = "windows_x86_64_gnu" version = "0.34.0" @@ -10061,6 +10160,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -10073,6 +10178,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + [[package]] name = "windows_x86_64_msvc" version = "0.34.0" @@ -10091,6 +10202,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "winnow" version = "0.5.1" @@ -10154,7 +10271,7 @@ dependencies = [ "lazy_static", "nom", "oid-registry 0.4.0", - "ring", + "ring 0.16.20", "rusticata-macros", "thiserror", "time 0.3.23", diff --git a/pallets/credentials/Cargo.toml b/pallets/credentials/Cargo.toml index 63ee53f..664cc68 100644 --- a/pallets/credentials/Cargo.toml +++ b/pallets/credentials/Cargo.toml @@ -24,6 +24,10 @@ frame-system = { version = "4.0.0-dev", default-features = false, git = "https:/ sp-runtime = { version = "24.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } pallet-issuers = { path = "../issuers", default-features = false } sp-core = { version = "21.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } +ed25519-dalek = { version = "2.0.0", default-features = false } +regex = { version = "1.10.6", default-features = false } +hex = { version = "0.4", default-features = false } +bs58 = { version = "0.5.1", default-features = false } [dev-dependencies] sp-core = { version = "21.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } @@ -44,4 +48,4 @@ std = [ ] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] -try-runtime = ["frame-support/try-runtime"] \ No newline at end of file +try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/credentials/src/lib.rs b/pallets/credentials/src/lib.rs index 039f8c1..c6db581 100644 --- a/pallets/credentials/src/lib.rs +++ b/pallets/credentials/src/lib.rs @@ -4,332 +4,313 @@ pub use pallet::*; #[frame_support::pallet] pub mod pallet { - use frame_support::{ - dispatch::Vec, - log, - pallet_prelude::{OptionQuery, *}, - }; - use frame_system::pallet_prelude::*; - use scale_info::prelude::vec; - use sp_runtime::traits::Hash; - use sp_core::{H160, crypto::Ss58Codec, crypto::AccountId32}; - use sp_core::sr25519::Public; - - use pallet_issuers::Issuers; - - use super::*; - - #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] - #[scale_info(skip_type_params(T))] - pub enum CredType { - // String, - Char, - U8, - I8, - U16, - I16, - U32, - I32, - U64, - I64, - F32, - F64, - Hash - } - - ///wallet addresss attestation can be being issued to - - #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] - #[scale_info(skip_type_params(T))] - pub enum AcquirerAddress{ - Substrate([u8; 32]), - Ethereum([u8; 20]), - Solana([u8; 32]), - } - - #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] - pub enum SizeInBytes { - Limited(u8), - // Unlimited, - } - - impl CredType { - pub fn size_in_bytes(&self) -> SizeInBytes { - match self { - // CredType::String => SizeInBytes::Unlimited, - CredType::Char => SizeInBytes::Limited(1), - CredType::U8 => SizeInBytes::Limited(1), - CredType::I8 => SizeInBytes::Limited(1), - CredType::U16 => SizeInBytes::Limited(2), - CredType::I16 => SizeInBytes::Limited(2), - CredType::U32 => SizeInBytes::Limited(4), - CredType::I32 => SizeInBytes::Limited(4), - CredType::U64 => SizeInBytes::Limited(8), - CredType::I64 => SizeInBytes::Limited(8), - CredType::F32 => SizeInBytes::Limited(4), - CredType::F64 => SizeInBytes::Limited(8), - CredType::Hash => SizeInBytes::Limited(32) - } - } - } - - pub type CredVal = (Vec, CredType); - pub type CredSchema = Vec; - pub type CredAttestation = Vec>; - - #[pallet::pallet] - #[pallet::without_storage_info] - pub struct Pallet(_); - - /// Configure the pallet by specifying the parameters and types on which it depends. - #[pallet::config] - pub trait Config: frame_system::Config + pallet_issuers::Config { - /// Because this pallet emits events, it depends on the runtime's definition of an event. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - type Hashing: Hash; - } - - #[pallet::storage] - pub type Schemas = StorageMap<_, Blake2_128Concat, T::Hash, CredSchema, OptionQuery>; - - #[pallet::storage] - pub type Attestations = StorageDoubleMap< - _, - Blake2_128Concat, - AcquirerAddress, - Twox64Concat, - T::Hash, - CredAttestation, - OptionQuery, - >; - - #[pallet::event] - #[pallet::generate_deposit(pub (super) fn deposit_event)] - pub enum Event { - SchemaCreated { - schema_hash: T::Hash, - schema: CredSchema, - }, - AttestationCreated { - account_id: AcquirerAddress, - schema_hash: T::Hash, - attestation: CredAttestation, - }, - } - - // Errors inform users that something went wrong. - #[pallet::error] - pub enum Error { - SchemaNotFound, - InvalidFormat, - SchemaAlreadyExists, - } - - #[pallet::call] - impl Pallet { - #[pallet::call_index(0)] - #[pallet::weight(100_000)] - pub fn create_schema( - origin: OriginFor, - issuer_hash: T::Hash, - schema: CredSchema, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - - let bytes: Vec = schema - .iter() - .flat_map(|(vec, cred_type)| { - let mut bytes = vec.clone(); - bytes.extend_from_slice(&cred_type.encode()); - bytes - }) - .collect(); - - let schema_hash = ::Hashing::hash(&bytes); - - let schema_option = Schemas::::get(schema_hash); - if let Some(_) = schema_option { - // Revert the transaction with an error indicating that the schema already exists - return Err(Error::::SchemaAlreadyExists.into()); - } - - let issuer = - Issuers::::get(issuer_hash).ok_or(pallet_issuers::Error::::IssuerNotFound)?; - ensure!(issuer.controllers.contains(&who), pallet_issuers::Error::::NotAuthorized); - - Schemas::::insert(schema_hash, schema.clone()); - - Self::deposit_event(Event::SchemaCreated { schema_hash, schema }); - - Ok(()) - } - - #[pallet::call_index(2)] - #[pallet::weight(100_000)] - pub fn attest( - origin: OriginFor, - issuer_hash: T::Hash, - schema_hash: T::Hash, - for_account: Vec, - attestation: CredAttestation, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - - let acquirer_address = Pallet::::parse_acquirer_address(for_account)?; - - let issuer = - Issuers::::get(issuer_hash).ok_or(pallet_issuers::Error::::IssuerNotFound)?; - ensure!(issuer.controllers.contains(&who), pallet_issuers::Error::::NotAuthorized); - - let schema = Schemas::::get(schema_hash).ok_or(Error::::SchemaNotFound)?; - - let attestation = Pallet::::validate_attestation(&schema, &attestation) - .ok_or(Error::::InvalidFormat)?; - - log::debug!(target: "algo", "Creds:{:?}", attestation); - - Attestations::::insert(acquirer_address.clone(), schema_hash, attestation.clone()); - - Self::deposit_event(Event::AttestationCreated { - account_id: acquirer_address, - schema_hash, - attestation, - }); - - Ok(()) - } - - // #[pallet::call_index(1)] - // #[pallet::weight(100_000)] - // pub fn edit_issuer( - // origin: OriginFor, - // hash: T::Hash, - // name: Option>, - // controllers: Option>, - // ) -> DispatchResult { - // let who = ensure_signed(origin)?; - // - // - // let mut issuer = Issuers::::get(hash) - // .ok_or(Error::::IssuerNotFound)?; - // - // - // ensure!(!issuer.controllers.contains(&who), Error::::NotAuthorized); - // - // if let Some(name) = name { - // issuer.name = name; - // } - // - // if let Some(controllers) = controllers { - // issuer.controllers = controllers; - // } - // - // Issuers::::insert(hash, issuer.clone()); - // Self::deposit_event(Event::IssuerUpdated { hash, issuer }); - // - // Ok(()) - // } - } - - impl Pallet { - pub fn validate_attestation( - schema: &CredSchema, - attestation: &CredAttestation, - ) -> Option { - if schema.len() != attestation.len() { - return None; - } - - let mut formatted = vec![vec![]; attestation.len()]; - - for (((_, cred_type), val), i) in - schema.iter().zip(attestation).zip(0..attestation.len()) - { - let SizeInBytes::Limited(expected_len) = cred_type.size_in_bytes(); - if val.is_empty() || val.len() > expected_len as usize { - return None; - } - formatted[i] = val.clone(); - if val.len() != expected_len as usize { - for _ in 0..(expected_len as usize - val.len()) { - formatted[i].push(0); - } - } - } - - Some(formatted) - } - - pub fn is_valid_ethereum_address(address: &[u8]) -> bool { - address.len() == 20 && H160::from_slice(address).to_fixed_bytes() == *address + use frame_support::{ + dispatch::Vec, + log, + pallet_prelude::{OptionQuery, *}, + sp_std::prelude::ToOwned, + }; + use frame_system::pallet_prelude::*; + use scale_info::prelude::{format, string::String, vec}; + use sp_core::{ + crypto::{AccountId32, Ss58Codec}, + sr25519::Public, + H160, H256, U256, + }; + use sp_runtime::traits::{Hash, Keccak256}; + + use ed25519_dalek::VerifyingKey; + use hex::ToHex; + use regex::Regex; + + use pallet_issuers::Issuers; + + #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] + #[scale_info(skip_type_params(T))] + pub enum CredType { + Char, + U8, + I8, + U16, + I16, + U32, + I32, + U64, + I64, + F32, + F64, + Hash, } - pub fn is_valid_solana_address(address: &[u8]) -> bool { - // Check if the address is exactly 32 bytes long - - let address_array: [u8; 32] = match address.try_into() { - Ok(arr) => arr, - Err(_) => return false, - }; - - let public_key = Public(address_array); - - // Attempt to encode the public key to Base58 - public_key.to_ss58check().len() == 44 - } - - // need to make this generic over the chain configurations - fn is_valid_substrate_address(address: &[u8]) -> bool { - // Check if the address is exactly 32 bytes long - let address_array: [u8; 32] = match address.try_into() { - Ok(arr) => arr, - Err(_) => return false, - }; - - // Create an AccountId32 from the address bytes - let account_id = AccountId32::new(address_array); - - // Encode the AccountId32 to SS58 and then try to decode it - // This checks if the address is valid in any SS58 format - match AccountId32::from_ss58check(&account_id.to_ss58check()) { - Ok(_) => true, - Err(_) => false, - } - } - - pub fn parse_acquirer_address(address: Vec) -> Result { - match address.len() { - 20 => { - if Pallet::::is_valid_ethereum_address(&address) { - Ok(AcquirerAddress::Ethereum(address.try_into().unwrap())) - } else { - Err(DispatchError::Other("Invalid Ethereum address format")) - } - }, - 32 => { - if Self::is_valid_solana_address(&address) { - Ok(AcquirerAddress::Solana(address.try_into().unwrap())) - } else { - Err(DispatchError::Other("Invalid Solana address format")) - } - }, - _ if address.len() == T::AccountId::max_encoded_len() => { - if Self::is_valid_substrate_address(&address) { - Ok(AcquirerAddress::Substrate(address.try_into().unwrap())) - } else { - Err(DispatchError::Other("Invalid Substrate address format")) - } - }, - _ => Err(DispatchError::Other("Invalid address length")) - } - } - } -} + #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] + #[scale_info(skip_type_params(T))] + pub enum AcquirerAddress { + Substrate(AccountId32), + Ethereum(H160), + Solana(String), + } -mod testt { - #[test] - pub fn test_a() { - let bytes = (1i64).to_be_bytes(); - println!("{bytes:#04X?}\n{bytes:?}"); - } + #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] + pub enum SizeInBytes { + Limited(u8), + } + + impl CredType { + pub fn size_in_bytes(&self) -> SizeInBytes { + match self { + CredType::Char => SizeInBytes::Limited(1), + CredType::U8 => SizeInBytes::Limited(1), + CredType::I8 => SizeInBytes::Limited(1), + CredType::U16 => SizeInBytes::Limited(2), + CredType::I16 => SizeInBytes::Limited(2), + CredType::U32 => SizeInBytes::Limited(4), + CredType::I32 => SizeInBytes::Limited(4), + CredType::U64 => SizeInBytes::Limited(8), + CredType::I64 => SizeInBytes::Limited(8), + CredType::F32 => SizeInBytes::Limited(4), + CredType::F64 => SizeInBytes::Limited(8), + CredType::Hash => SizeInBytes::Limited(32), + } + } + } + + pub type CredVal = (Vec, CredType); + pub type CredSchema = Vec; + pub type CredAttestation = Vec>; + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + pallet_issuers::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type Hashing: Hash; + } + + #[pallet::storage] + pub type Schemas = StorageMap<_, Blake2_128Concat, T::Hash, CredSchema, OptionQuery>; + + #[pallet::storage] + pub type Attestations = StorageDoubleMap< + _, + Blake2_128Concat, + AcquirerAddress, + Twox64Concat, + T::Hash, + CredAttestation, + OptionQuery, + >; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + SchemaCreated { + schema_hash: T::Hash, + schema: CredSchema, + }, + AttestationCreated { + account_id: AcquirerAddress, + schema_hash: T::Hash, + attestation: CredAttestation, + }, + } + + #[pallet::error] + pub enum Error { + SchemaNotFound, + InvalidFormat, + SchemaAlreadyExists, + InvalidAddress, + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(100_000)] + pub fn create_schema( + origin: OriginFor, + issuer_hash: T::Hash, + schema: CredSchema, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + let bytes: Vec = schema + .iter() + .flat_map(|(vec, cred_type)| { + let mut bytes = vec.clone(); + bytes.extend_from_slice(&cred_type.encode()); + bytes + }) + .collect(); + + let schema_hash = ::Hashing::hash(&bytes); + + ensure!( + !Schemas::::contains_key(schema_hash), + Error::::SchemaAlreadyExists + ); + + let issuer = Issuers::::get(issuer_hash) + .ok_or(pallet_issuers::Error::::IssuerNotFound)?; + ensure!( + issuer.controllers.contains(&who), + pallet_issuers::Error::::NotAuthorized + ); + + Schemas::::insert(schema_hash, schema.clone()); + + Self::deposit_event(Event::SchemaCreated { schema_hash, schema }); + + Ok(()) + } + + #[pallet::call_index(2)] + #[pallet::weight(100_000)] + pub fn attest( + origin: OriginFor, + issuer_hash: T::Hash, + schema_hash: T::Hash, + for_account: Vec, + attestation: CredAttestation, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + let acquirer_address = Self::parse_acquirer_address(for_account)?; + + let issuer = Issuers::::get(issuer_hash) + .ok_or(pallet_issuers::Error::::IssuerNotFound)?; + ensure!( + issuer.controllers.contains(&who), + pallet_issuers::Error::::NotAuthorized + ); + + let schema = Schemas::::get(schema_hash).ok_or(Error::::SchemaNotFound)?; + + let attestation = + Self::validate_attestation(&schema, &attestation).ok_or(Error::::InvalidFormat)?; + + log::debug!(target: "algo", "Creds:{:?}", attestation); + + Attestations::::insert(acquirer_address.clone(), schema_hash, attestation.clone()); + + Self::deposit_event(Event::AttestationCreated { + account_id: acquirer_address, + schema_hash, + attestation, + }); + + Ok(()) + } + } + + impl Pallet { + pub fn validate_attestation( + schema: &CredSchema, + attestation: &CredAttestation, + ) -> Option { + if schema.len() != attestation.len() { + return None; + } + + let mut formatted = vec![vec![]; attestation.len()]; + + for (((_, cred_type), val), i) in + schema.iter().zip(attestation).zip(0..attestation.len()) + { + let SizeInBytes::Limited(expected_len) = cred_type.size_in_bytes(); + if val.is_empty() || val.len() > expected_len as usize { + return None; + } + formatted[i] = val.clone(); + if val.len() != expected_len as usize { + formatted[i].resize(expected_len as usize, 0); + } + } + + Some(formatted) + } + + pub fn is_valid_solana_address(address: &H256) -> bool { + let address_bytes: &[u8] = address.as_ref(); + + if address_bytes.len() != 32 { + return false; + } + + let address_array: [u8; 32] = match address_bytes.try_into() { + Ok(arr) => arr, + Err(_) => return false, + }; + + log::info!("sol address, check passed a little bits by"); + + if VerifyingKey::from_bytes(&address_array).is_err() { + return false; + } + + if address.as_ref().iter().all(|&x| x == 0) { + return false; + } + + let default_pubkey = H256::from_slice(&[1; 32]); + if address == &default_pubkey { + return false; + } + + true + } + + fn to_hex_string(bytes: &[u8]) -> String { + bytes.iter().map(|b| format!("{:02x}", b)).collect() + } + + pub fn check_valid_substrate_address(address: &[u8]) -> Option { + let address_array: [u8; 32] = address.try_into().ok()?; + let account_id = AccountId32::new(address_array); + AccountId32::from_ss58check(&account_id.to_ss58check()).ok().map(|_| account_id) + } + + pub fn is_solana_address(input: Vec) -> Option { + let base58_str = core::str::from_utf8(&input).ok()?; + + if input.len() == 32 { + return Some(String::from(base58_str)); + } + + let mut decoded_output = [0u8; 64]; + match bs58::decode(base58_str).onto(&mut decoded_output) { + Ok(32) => Some(String::from(base58_str)), + Ok(decoded_length) => { + log::error!("Decoded length is not 32 bytes: {}", decoded_length); + None + } + Err(e) => { + log::error!("Failed to decode Base58: {:?}", e); + None + } + } + } + + pub fn parse_acquirer_address(address: Vec) -> Result { + if let Some(solana_address) = Self::is_solana_address(address.clone()) { + return Ok(AcquirerAddress::Solana(solana_address)); + } + + match address.len() { + 20 => { + let mut array = [0u8; 20]; + array.copy_from_slice(&address); + let wallet_address = H160::from(array); + Ok(AcquirerAddress::Ethereum(wallet_address)) + }, + _ if address.len() == T::AccountId::max_encoded_len() => { + Self::check_valid_substrate_address(&address) + .map(AcquirerAddress::Substrate) + .ok_or_else(|| DispatchError::Other("Invalid Substrate address format")) + }, + _ => Err(Error::::InvalidFormat.into()), + } + } + } }