Skip to content

Commit

Permalink
feat: Add Solana address type (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
conr2d authored Oct 28, 2024
1 parent 96aca0c commit 6ca529e
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ members = [
"primitives/ethereum",
"primitives/nostr",
"primitives/runtime",
"primitives/solana",
"runtime/common",
"vendor/composable/composable-support",
"vendor/composable/vm",
Expand Down Expand Up @@ -55,6 +56,7 @@ np-cosmos = { path = "primitives/cosmos", default-features = false }
np-ethereum = { path = "primitives/ethereum", default-features = false }
np-nostr = { path = "primitives/nostr", 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 }
Expand Down
31 changes: 31 additions & 0 deletions primitives/solana/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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",
]
113 changes: 113 additions & 0 deletions primitives/solana/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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<H256> for Address {
fn from(h: H256) -> Self {
Self(h.0)
}
}

impl From<Address> for H256 {
fn from(v: Address) -> Self {
Self(v.0)
}
}

impl From<ed25519::Public> 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<Self, Self::Err> {
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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<D>(deserializer: D) -> Result<Address, D::Error>
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);
}
}

0 comments on commit 6ca529e

Please sign in to comment.