Purge nym-name-service-common
This commit is contained in:
@@ -1,20 +0,0 @@
|
||||
[package]
|
||||
name = "nym-name-service-common"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
cosmwasm-schema = { workspace = true }
|
||||
cosmwasm-std = { workspace = true }
|
||||
cw2 = { workspace = true, optional = true }
|
||||
cw-controllers = { workspace = true }
|
||||
cw-utils = { workspace = true }
|
||||
nym-contracts-common = { path = "../contracts-common", version = "0.5.0" }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[features]
|
||||
schema = ["cw2"]
|
||||
@@ -1,83 +0,0 @@
|
||||
use cosmwasm_std::{Addr, StdError};
|
||||
use cw_controllers::AdminError;
|
||||
use nym_contracts_common::signing::verifier::ApiVerifierError;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{Address, NameId, NymName};
|
||||
|
||||
#[derive(Error, Debug, PartialEq)]
|
||||
pub enum NameServiceError {
|
||||
#[error("{0}")]
|
||||
Std(#[from] StdError),
|
||||
|
||||
#[error("{0}")]
|
||||
AdminError(#[from] AdminError),
|
||||
|
||||
#[error("name id entry not found: {name_id}")]
|
||||
NotFound { name_id: NameId },
|
||||
|
||||
#[error("name entry not found: {name}")]
|
||||
NameNotFound { name: NymName },
|
||||
|
||||
#[error("{sender} is not registrator of name")]
|
||||
Unauthorized { sender: Addr },
|
||||
|
||||
#[error("deposit required to register a name")]
|
||||
DepositRequired { source: cw_utils::PaymentError },
|
||||
|
||||
#[error("insufficiant deposit: {funds}, required: {deposit_required}")]
|
||||
InsufficientDeposit {
|
||||
funds: cosmwasm_std::Uint128,
|
||||
deposit_required: cosmwasm_std::Uint128,
|
||||
},
|
||||
|
||||
#[error("deposit too large: {funds}, required: {deposit_required}")]
|
||||
TooLargeDeposit {
|
||||
funds: cosmwasm_std::Uint128,
|
||||
deposit_required: cosmwasm_std::Uint128,
|
||||
},
|
||||
|
||||
#[error("reached the max number of names ({max_names}) for owner {owner}")]
|
||||
ReachedMaxNamesForOwner { max_names: u32, owner: Addr },
|
||||
|
||||
#[error("reached the max number of names ({max_names}) for address {0}", address.to_string())]
|
||||
ReachedMaxNamesForAddress { max_names: u32, address: Address },
|
||||
|
||||
#[error("failed to parse {value} into a valid SemVer version: {error_message}")]
|
||||
SemVerFailure {
|
||||
value: String,
|
||||
error_message: String,
|
||||
},
|
||||
|
||||
#[error("failed to recover ed25519 public key from its base58 representation: {0}")]
|
||||
MalformedEd25519IdentityKey(String),
|
||||
|
||||
#[error("failed to recover ed25519 signature from its base58 representation: {0}")]
|
||||
MalformedEd25519Signature(String),
|
||||
|
||||
#[error("provided ed25519 signature did not verify correctly")]
|
||||
InvalidEd25519Signature,
|
||||
|
||||
#[error("failed to verify message signature: {source}")]
|
||||
SignatureVerificationFailure {
|
||||
#[from]
|
||||
source: ApiVerifierError,
|
||||
},
|
||||
|
||||
#[error("duplicate entries detected for name: {name}")]
|
||||
DuplicateNames { name: NymName },
|
||||
|
||||
#[error("name already registered: {name}")]
|
||||
NameAlreadyRegistered { name: NymName },
|
||||
|
||||
#[error("invalid nym address format: {0}")]
|
||||
InvalidNymAddress(String),
|
||||
|
||||
#[error("client identity in nym address does not match the provided identity key")]
|
||||
IdentityKeyMismatch {
|
||||
address: Address,
|
||||
identity_key: String,
|
||||
},
|
||||
}
|
||||
|
||||
pub type Result<T, E = NameServiceError> = std::result::Result<T, E>;
|
||||
@@ -1,66 +0,0 @@
|
||||
use cosmwasm_std::{Coin, Event};
|
||||
|
||||
use crate::RegisteredName;
|
||||
|
||||
pub enum NameEventType {
|
||||
Register,
|
||||
DeleteId,
|
||||
DeleteName,
|
||||
UpdateDepositRequired,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for NameEventType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
NameEventType::Register => write!(f, "register"),
|
||||
NameEventType::DeleteId => write!(f, "delete_id"),
|
||||
NameEventType::DeleteName => write!(f, "delete_name"),
|
||||
NameEventType::UpdateDepositRequired => write!(f, "update_deposit_required"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NameEventType> for String {
|
||||
fn from(event_type: NameEventType) -> Self {
|
||||
event_type.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub const ACTION: &str = "action";
|
||||
|
||||
pub const NAME_ID: &str = "name_id";
|
||||
pub const NAME: &str = "name";
|
||||
pub const OWNER: &str = "owner";
|
||||
|
||||
pub const DEPOSIT_REQUIRED: &str = "deposit_required";
|
||||
|
||||
pub fn new_register_event(name: RegisteredName) -> Event {
|
||||
Event::new(NameEventType::Register)
|
||||
.add_attribute(ACTION, NameEventType::Register)
|
||||
.add_attribute(NAME_ID, name.id.to_string())
|
||||
.add_attribute(NAME, name.name.name.to_string())
|
||||
.add_attribute(name.name.address.event_tag(), name.name.address.to_string())
|
||||
.add_attribute(OWNER, name.owner.to_string())
|
||||
}
|
||||
|
||||
pub fn new_delete_id_event(name: RegisteredName) -> Event {
|
||||
Event::new(NameEventType::DeleteId)
|
||||
.add_attribute(ACTION, NameEventType::DeleteId)
|
||||
.add_attribute(NAME_ID, name.id.to_string())
|
||||
.add_attribute(NAME, name.name.name.to_string())
|
||||
.add_attribute(name.name.address.event_tag(), name.name.address.to_string())
|
||||
}
|
||||
|
||||
pub fn new_delete_name_event(name: RegisteredName) -> Event {
|
||||
Event::new(NameEventType::DeleteId)
|
||||
.add_attribute(ACTION, NameEventType::DeleteName)
|
||||
.add_attribute(NAME_ID, name.id.to_string())
|
||||
.add_attribute(NAME, name.name.name.to_string())
|
||||
.add_attribute(name.name.address.event_tag(), name.name.address.to_string())
|
||||
}
|
||||
|
||||
pub fn new_update_deposit_required_event(deposit_required: Coin) -> Event {
|
||||
Event::new(NameEventType::UpdateDepositRequired)
|
||||
.add_attribute(ACTION, NameEventType::UpdateDepositRequired)
|
||||
.add_attribute(DEPOSIT_REQUIRED, deposit_required.to_string())
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
pub mod error;
|
||||
pub mod events;
|
||||
pub mod msg;
|
||||
pub mod response;
|
||||
pub mod signing_types;
|
||||
pub mod types;
|
||||
|
||||
// Re-export all types at the top-level
|
||||
pub use types::*;
|
||||
|
||||
pub use cosmwasm_std::{Addr, Coin, Decimal, Fraction};
|
||||
@@ -1,123 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{Address, NameDetails, NameId, NymName};
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::Coin;
|
||||
use nym_contracts_common::signing::MessageSignature;
|
||||
|
||||
#[cfg(feature = "schema")]
|
||||
use crate::{
|
||||
response::{ConfigResponse, NamesListResponse, PagedNamesListResponse},
|
||||
types::RegisteredName,
|
||||
};
|
||||
#[cfg(feature = "schema")]
|
||||
use cosmwasm_schema::QueryResponses;
|
||||
#[cfg(feature = "schema")]
|
||||
use nym_contracts_common::{signing::Nonce, ContractBuildInformation};
|
||||
|
||||
#[cw_serde]
|
||||
pub struct InstantiateMsg {
|
||||
pub deposit_required: Coin,
|
||||
}
|
||||
|
||||
impl InstantiateMsg {
|
||||
pub fn new(deposit_required: Coin) -> Self {
|
||||
Self { deposit_required }
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct MigrateMsg {}
|
||||
|
||||
#[cw_serde]
|
||||
pub enum ExecuteMsg {
|
||||
/// Announcing a name pointing to a nym-address
|
||||
Register {
|
||||
name: NameDetails,
|
||||
owner_signature: MessageSignature,
|
||||
},
|
||||
|
||||
/// Delete a name entry by id
|
||||
DeleteId { name_id: NameId },
|
||||
|
||||
/// Delete a name entry by name
|
||||
DeleteName { name: NymName },
|
||||
|
||||
/// Change the deposit required for announcing a name
|
||||
UpdateDepositRequired { deposit_required: Coin },
|
||||
}
|
||||
|
||||
impl ExecuteMsg {
|
||||
pub fn delete_id(name_id: NameId) -> Self {
|
||||
ExecuteMsg::DeleteId { name_id }
|
||||
}
|
||||
|
||||
pub fn default_memo(&self) -> String {
|
||||
match self {
|
||||
ExecuteMsg::Register {
|
||||
name,
|
||||
owner_signature: _,
|
||||
} => {
|
||||
format!("registering {} as name: {}", name.address, name.name)
|
||||
}
|
||||
ExecuteMsg::DeleteId { name_id } => {
|
||||
format!("deleting name with id {name_id}")
|
||||
}
|
||||
ExecuteMsg::DeleteName { name } => {
|
||||
format!("deleting name: {name}")
|
||||
}
|
||||
ExecuteMsg::UpdateDepositRequired { deposit_required } => {
|
||||
format!("updating the deposit required to {deposit_required}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
#[cfg_attr(feature = "schema", derive(QueryResponses))]
|
||||
pub enum QueryMsg {
|
||||
/// Query the name by it's assigned id
|
||||
#[cfg_attr(feature = "schema", returns(RegisteredName))]
|
||||
NameId { name_id: NameId },
|
||||
|
||||
/// Query the names by the registrator
|
||||
#[cfg_attr(feature = "schema", returns(NamesListResponse))]
|
||||
ByOwner { owner: String },
|
||||
|
||||
#[cfg_attr(feature = "schema", returns(RegisteredName))]
|
||||
ByName { name: NymName },
|
||||
|
||||
#[cfg_attr(feature = "schema", returns(NamesListResponse))]
|
||||
ByAddress { address: Address },
|
||||
|
||||
#[cfg_attr(feature = "schema", returns(PagedNamesListResponse))]
|
||||
All {
|
||||
limit: Option<u32>,
|
||||
start_after: Option<NameId>,
|
||||
},
|
||||
|
||||
#[cfg_attr(feature = "schema", returns(Nonce))]
|
||||
SigningNonce { address: String },
|
||||
|
||||
#[cfg_attr(feature = "schema", returns(ConfigResponse))]
|
||||
Config {},
|
||||
|
||||
/// Gets build information of this contract, such as the commit hash used for the build or rustc version.
|
||||
#[cfg_attr(feature = "schema", returns(ContractBuildInformation))]
|
||||
GetContractVersion {},
|
||||
|
||||
/// Gets the stored contract version information that's required by the CW2 spec interface for migrations.
|
||||
#[serde(rename = "get_cw2_contract_version")]
|
||||
#[cfg_attr(feature = "schema", returns(cw2::ContractVersion))]
|
||||
GetCW2ContractVersion {},
|
||||
}
|
||||
|
||||
impl QueryMsg {
|
||||
pub fn all() -> QueryMsg {
|
||||
QueryMsg::All {
|
||||
limit: None,
|
||||
start_after: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{NameId, RegisteredName};
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::Coin;
|
||||
|
||||
#[cw_serde]
|
||||
pub struct NamesListResponse {
|
||||
pub names: Vec<RegisteredName>,
|
||||
}
|
||||
|
||||
impl NamesListResponse {
|
||||
pub fn new(names: Vec<RegisteredName>) -> NamesListResponse {
|
||||
NamesListResponse { names }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[RegisteredName]> for NamesListResponse {
|
||||
fn from(names: &[RegisteredName]) -> Self {
|
||||
NamesListResponse {
|
||||
names: names.to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct PagedNamesListResponse {
|
||||
pub names: Vec<RegisteredName>,
|
||||
pub per_page: usize,
|
||||
|
||||
/// Field indicating paging information for the following queries if the caller wishes to get further entries.
|
||||
pub start_next_after: Option<NameId>,
|
||||
}
|
||||
|
||||
impl PagedNamesListResponse {
|
||||
pub fn new(
|
||||
names: Vec<RegisteredName>,
|
||||
per_page: usize,
|
||||
start_next_after: Option<NameId>,
|
||||
) -> PagedNamesListResponse {
|
||||
PagedNamesListResponse {
|
||||
names,
|
||||
per_page,
|
||||
start_next_after,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct ConfigResponse {
|
||||
pub deposit_required: Coin,
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
use cosmwasm_std::{Addr, Coin};
|
||||
use nym_contracts_common::signing::{
|
||||
ContractMessageContent, MessageType, Nonce, SignableMessage, SigningPurpose,
|
||||
};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::NameDetails;
|
||||
|
||||
pub type SignableNameRegisterMsg = SignableMessage<ContractMessageContent<NameRegister>>;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct NameRegister {
|
||||
name: NameDetails,
|
||||
}
|
||||
|
||||
impl SigningPurpose for NameRegister {
|
||||
fn message_type() -> MessageType {
|
||||
MessageType::new("name-register")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn construct_name_register_sign_payload(
|
||||
nonce: Nonce,
|
||||
sender: Addr,
|
||||
deposit: Coin,
|
||||
name: NameDetails,
|
||||
) -> SignableNameRegisterMsg {
|
||||
let payload = NameRegister { name };
|
||||
let proxy = None;
|
||||
let content = ContractMessageContent::new(sender, proxy, vec![deposit], payload);
|
||||
SignableMessage::new(nonce, content)
|
||||
}
|
||||
@@ -1,252 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::{Addr, Coin};
|
||||
use nym_contracts_common::IdentityKey;
|
||||
use std::{
|
||||
fmt::{Display, Formatter},
|
||||
str::FromStr,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::error::{NameServiceError, Result};
|
||||
|
||||
/// The directory of names are indexed by [`NameId`].
|
||||
pub type NameId = u32;
|
||||
|
||||
#[cw_serde]
|
||||
pub struct RegisteredName {
|
||||
/// Unique id assigned to the registerd name.
|
||||
pub id: NameId,
|
||||
|
||||
/// The registerd name details.
|
||||
pub name: NameDetails,
|
||||
|
||||
/// name owner.
|
||||
pub owner: Addr,
|
||||
|
||||
/// Block height at which the name was added.
|
||||
pub block_height: u64,
|
||||
|
||||
/// The deposit used to announce the name.
|
||||
pub deposit: Coin,
|
||||
}
|
||||
|
||||
impl RegisteredName {
|
||||
// Shortcut for getting the actual name
|
||||
pub fn entry(&self) -> &NymName {
|
||||
&self.name.name
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct NameDetails {
|
||||
/// The name pointing to the nym address
|
||||
pub name: NymName,
|
||||
|
||||
/// The address of the name alias.
|
||||
pub address: Address,
|
||||
|
||||
/// The identity key of the registered name.
|
||||
pub identity_key: IdentityKey,
|
||||
}
|
||||
|
||||
/// String representation of a nym address, which is of the form
|
||||
/// client_id.client_enc@gateway_id.
|
||||
/// NOTE: entirely unvalidated.
|
||||
#[cw_serde]
|
||||
pub enum Address {
|
||||
NymAddress(NymAddressInner),
|
||||
// Possible extension:
|
||||
//Gateway(String)
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct NymAddressInner {
|
||||
client_id: String,
|
||||
client_enc: String,
|
||||
gateway_id: String,
|
||||
}
|
||||
|
||||
// ADDRESS . ENCRYPTION @ GATEWAY_ID
|
||||
impl std::fmt::Display for NymAddressInner {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}.{}@{}",
|
||||
self.client_id, self.client_enc, self.gateway_id
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Address {
|
||||
/// Create a new nym address.
|
||||
pub fn new(address: &str) -> Result<Self> {
|
||||
parse_nym_address(address)
|
||||
.map(Self::NymAddress)
|
||||
.ok_or_else(|| NameServiceError::InvalidNymAddress(address.to_string()))
|
||||
}
|
||||
|
||||
pub fn client_id(&self) -> &str {
|
||||
match self {
|
||||
Address::NymAddress(address) => &address.client_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn client_enc(&self) -> &str {
|
||||
match self {
|
||||
Address::NymAddress(address) => &address.client_enc,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gateway_id(&self) -> &str {
|
||||
match self {
|
||||
Address::NymAddress(address) => &address.gateway_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn event_tag(&self) -> &str {
|
||||
match self {
|
||||
Address::NymAddress(_) => "nym_address",
|
||||
//Address::Gateway(_) => "gatway_address",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Address {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Address::NymAddress(address) => write!(f, "{}", address),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A valid nym address is of the form client_id.client_enc@gateway_id
|
||||
fn parse_nym_address(address: &str) -> Option<NymAddressInner> {
|
||||
let parts: Vec<&str> = address.split('@').collect();
|
||||
if parts.len() != 2 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let client_part = parts[0];
|
||||
let gateway_part = parts[1];
|
||||
|
||||
// The client part consists of two parts separated by a dot
|
||||
let client_parts: Vec<&str> = client_part.split('.').collect();
|
||||
if client_parts.len() != 2 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Check that the gateway part does not contain any dots
|
||||
if gateway_part.contains('.') {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(NymAddressInner {
|
||||
client_id: client_parts[0].to_string(),
|
||||
client_enc: client_parts[1].to_string(),
|
||||
gateway_id: gateway_part.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Name stored and pointing a to a nym-address
|
||||
#[cw_serde]
|
||||
pub struct NymName(String);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum NymNameError {
|
||||
#[error("invalid name")]
|
||||
InvalidName,
|
||||
}
|
||||
|
||||
/// Defines what names are allowed
|
||||
fn is_valid_name_char(c: char) -> bool {
|
||||
// Normal lowercase letters
|
||||
(c.is_alphabetic() && c.is_lowercase())
|
||||
// or numbers
|
||||
|| c.is_numeric()
|
||||
// special case hyphen or underscore
|
||||
|| c == '-' || c == '_'
|
||||
}
|
||||
|
||||
impl NymName {
|
||||
pub fn new(name: &str) -> Result<NymName, NymNameError> {
|
||||
// We are a bit restrictive in which names we allow, to start out with. Consider relaxing
|
||||
// this in the future.
|
||||
if !name.chars().all(is_valid_name_char) {
|
||||
return Err(NymNameError::InvalidName);
|
||||
}
|
||||
Ok(Self(name.to_string()))
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for NymName {
|
||||
type Err = NymNameError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Self::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for NymName {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::NymName;
|
||||
|
||||
#[test]
|
||||
fn parse_nym_name() {
|
||||
// Test some valid cases
|
||||
assert!(NymName::new("foo").is_ok());
|
||||
assert!(NymName::new("foo-bar").is_ok());
|
||||
assert!(NymName::new("foo-bar-123").is_ok());
|
||||
assert!(NymName::new("foo_bar").is_ok());
|
||||
assert!(NymName::new("foo_bar_123").is_ok());
|
||||
|
||||
// And now test all some invalid ones
|
||||
assert!(NymName::new("Foo").is_err());
|
||||
assert!(NymName::new("foo bar").is_err());
|
||||
assert!(NymName::new("foo!bar").is_err());
|
||||
assert!(NymName::new("foo#bar").is_err());
|
||||
assert!(NymName::new("foo$bar").is_err());
|
||||
assert!(NymName::new("foo%bar").is_err());
|
||||
assert!(NymName::new("foo&bar").is_err());
|
||||
assert!(NymName::new("foo'bar").is_err());
|
||||
assert!(NymName::new("foo(bar").is_err());
|
||||
assert!(NymName::new("foo)bar").is_err());
|
||||
assert!(NymName::new("foo*bar").is_err());
|
||||
assert!(NymName::new("foo+bar").is_err());
|
||||
assert!(NymName::new("foo,bar").is_err());
|
||||
assert!(NymName::new("foo.bar").is_err());
|
||||
assert!(NymName::new("foo.bar").is_err());
|
||||
assert!(NymName::new("foo/bar").is_err());
|
||||
assert!(NymName::new("foo/bar").is_err());
|
||||
assert!(NymName::new("foo:bar").is_err());
|
||||
assert!(NymName::new("foo;bar").is_err());
|
||||
assert!(NymName::new("foo<bar").is_err());
|
||||
assert!(NymName::new("foo=bar").is_err());
|
||||
assert!(NymName::new("foo>bar").is_err());
|
||||
assert!(NymName::new("foo?bar").is_err());
|
||||
assert!(NymName::new("foo@bar").is_err());
|
||||
assert!(NymName::new("fooBar").is_err());
|
||||
assert!(NymName::new("foo[bar").is_err());
|
||||
assert!(NymName::new("foo\"bar").is_err());
|
||||
assert!(NymName::new("foo\\bar").is_err());
|
||||
assert!(NymName::new("foo]bar").is_err());
|
||||
assert!(NymName::new("foo^bar").is_err());
|
||||
assert!(NymName::new("foo`bar").is_err());
|
||||
assert!(NymName::new("foo{bar").is_err());
|
||||
assert!(NymName::new("foo|bar").is_err());
|
||||
assert!(NymName::new("foo}bar").is_err());
|
||||
assert!(NymName::new("foo~bar").is_err());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user