From ef8751261af85b542214a8f318a2ad5607a090ad Mon Sep 17 00:00:00 2001 From: Jeeyong Um Date: Sun, 27 Oct 2024 05:55:48 +0900 Subject: [PATCH] feat: Add Solana address type --- Cargo.toml | 2 + primitives/solana/Cargo.toml | 31 ++++++++++ primitives/solana/src/lib.rs | 113 +++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 primitives/solana/Cargo.toml create mode 100644 primitives/solana/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 5e85f335..76df7b25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ members = [ "primitives/cosmos", "primitives/ethereum", "primitives/runtime", + "primitives/solana", "runtime/common", "vendor/composable/composable-support", "vendor/composable/vm", @@ -53,6 +54,7 @@ np-babel = { path = "primitives/babel", default-features = false } np-cosmos = { path = "primitives/cosmos", default-features = false } np-ethereum = { path = "primitives/ethereum", default-features = false } np-runtime = { path = "primitives/runtime", default-features = false } +np-solana = { path = "primitives/solana", default-features = false } pallet-cosmos = { path = "frame/cosmos", default-features = false } pallet-cosmos-types = { path = "frame/cosmos/types", default-features = false } pallet-cosmos-x-auth = { path = "frame/cosmos/x/auth", default-features = false } diff --git a/primitives/solana/Cargo.toml b/primitives/solana/Cargo.toml new file mode 100644 index 00000000..edb67694 --- /dev/null +++ b/primitives/solana/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "np-solana" +version = "0.4.0" +authors = ["Haderech Pte. Ltd."] +edition = "2021" +license = "Apache-2.0" +repository = "https://github.com/noirhq/noir.git" +publish = false + +[dependencies] +bs58 = { version = "0.5.1", default-features = false, optional = true } +buidl = { version = "0.1.1", default-features = false, features = ["derive"] } +parity-scale-codec = { version = "3.6", default-features = false, features = ["derive"] } +scale-info = { version = "2.11", default-features = false, features = ["derive"] } +serde = { version = "1.0", default-features = false, optional = true } +sp-core = { git = "https://github.com/paritytech/polkadot-sdk", branch = "stable2409", default-features = false } + +[features] +default = ["std"] +std = [ + "bs58?/std", + "buidl/std", + "parity-scale-codec/std", + "scale-info/std", + "serde/std", + "sp-core/std", +] +serde = [ + "dep:serde", + "bs58/alloc", +] diff --git a/primitives/solana/src/lib.rs b/primitives/solana/src/lib.rs new file mode 100644 index 00000000..d1a8d803 --- /dev/null +++ b/primitives/solana/src/lib.rs @@ -0,0 +1,113 @@ +// This file is part of Noir. + +// Copyright (c) Haderech Pte. Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Noir primitive types for Solana compatibility. + +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + +#[cfg(feature = "serde")] +use alloc::string::String; +use buidl::FixedBytes; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +use sp_core::{ed25519, H256}; + +/// Solana address. +#[derive(FixedBytes)] +#[buidl(substrate(Core, Codec, TypeInfo))] +pub struct Address([u8; 32]); + +impl From for Address { + fn from(h: H256) -> Self { + Self(h.0) + } +} + +impl From
for H256 { + fn from(v: Address) -> Self { + Self(v.0) + } +} + +impl From for Address { + fn from(key: ed25519::Public) -> Self { + Address(key.0) + } +} + +#[cfg(feature = "serde")] +impl core::fmt::Display for Address { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{}", bs58::encode(&self.0).into_string()) + } +} + +#[cfg(feature = "serde")] +impl core::str::FromStr for Address { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + Ok(Address(bs58::decode(s.as_bytes()).into_array_const().map_err(|_| "invalid address")?)) + } +} + +impl core::fmt::Debug for Address { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{}", sp_core::hexdisplay::HexDisplay::from(&self.0)) + } +} + +#[cfg(feature = "serde")] +impl Serialize for Address { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use alloc::string::ToString; + serializer.serialize_str(&self.to_string()) + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for Address { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + use core::str::FromStr; + let s = String::deserialize(deserializer)?; + Address::from_str(&s).map_err(serde::de::Error::custom) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sp_core::{ed25519, Pair}; + + fn dev_public() -> ed25519::Public { + ed25519::Pair::from_string("//Alice", None).unwrap().public() + } + + #[test] + fn display_solana_address() { + let alice = "ADFCNGW3av5BR6Jm5mvjEfdTGqcsfFQWPEvkB47AHHcq"; + assert_eq!(Address::from(dev_public()).to_string(), alice); + } +}