Skip to content

Commit

Permalink
Add AnchorOutput and AnchorAddress
Browse files Browse the repository at this point in the history
  • Loading branch information
thibault-martinez committed Oct 3, 2023
1 parent 9b39040 commit 1b58ea9
Show file tree
Hide file tree
Showing 14 changed files with 1,117 additions and 4 deletions.
3 changes: 3 additions & 0 deletions cli/src/command/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,9 @@ async fn print_address(account: &Account, address: &Bip44Address) -> Result<(),
Output::Delegation(_) => {
// TODO do we want to log them?
}
Output::Anchor(_) => {
// TODO do we want to log them?
}
}
let unlock_conditions = output_data
.output
Expand Down
1 change: 1 addition & 0 deletions sdk/src/client/api/block_builder/input_selection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ impl InputSelection {
AccountTransition::State,
))),
Address::Nft(nft_address) => Ok(Some(Requirement::Nft(*nft_address.nft_id()))),
Address::Anchor(_) => todo!(),
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ impl InputSelection {
Err(e) => Err(e),
}
}
Address::Anchor(_) => todo!(),
}
}
}
1 change: 1 addition & 0 deletions sdk/src/client/secret/ledger_nano.rs
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@ fn merge_unlocks(
merged_unlocks.push(Unlock::Reference(ReferenceUnlock::new(*block_index as u16)?));
}
Address::Nft(_nft) => merged_unlocks.push(Unlock::Nft(NftUnlock::new(*block_index as u16)?)),
Address::Anchor(_) => todo!(),
},
None => {
// We can only sign ed25519 addresses and block_indexes needs to contain the account or nft
Expand Down
1 change: 1 addition & 0 deletions sdk/src/client/secret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,7 @@ where
blocks.push(Unlock::Reference(ReferenceUnlock::new(*block_index as u16)?));
}
Address::Nft(_nft) => blocks.push(Unlock::Nft(NftUnlock::new(*block_index as u16)?)),
Address::Anchor(_) => todo!(),
},
None => {
// We can only sign ed25519 addresses and block_indexes needs to contain the account or nft
Expand Down
1 change: 1 addition & 0 deletions sdk/src/client/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub fn bech32_to_hex(bech32: impl ConvertTo<Bech32Address>) -> Result<String> {
Address::Ed25519(ed) => ed.to_string(),
Address::Account(account) => account.to_string(),
Address::Nft(nft) => nft.to_string(),
Address::Anchor(anchor) => anchor.to_string(),
})
}

Expand Down
91 changes: 91 additions & 0 deletions sdk/src/types/block/address/anchor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright 2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use core::str::FromStr;

use derive_more::{AsRef, Deref, From};

use crate::types::block::{output::AnchorId, Error};

/// An anchor address.
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, From, AsRef, Deref, packable::Packable)]
#[as_ref(forward)]
pub struct AnchorAddress(AnchorId);

impl AnchorAddress {
/// The [`Address`](crate::types::block::address::Address) kind of an [`AnchorAddress`].
/// TODO
pub const KIND: u8 = 255;
/// The length of an [`AnchorAddress`].
pub const LENGTH: usize = AnchorId::LENGTH;

/// Creates a new [`AnchorAddress`].
#[inline(always)]
pub fn new(id: AnchorId) -> Self {
Self::from(id)
}

/// Returns the [`AnchorId`] of an [`AnchorAddress`].
#[inline(always)]
pub fn anchor_id(&self) -> &AnchorId {
&self.0
}

/// Consumes an [`AnchorAddress`] and returns its [`AnchorId`].
#[inline(always)]
pub fn into_anchor_id(self) -> AnchorId {
self.0
}
}

impl FromStr for AnchorAddress {
type Err = Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self::new(AnchorId::from_str(s)?))
}
}

impl core::fmt::Display for AnchorAddress {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.0)
}
}

impl core::fmt::Debug for AnchorAddress {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "AnchorAddress({self})")
}
}

#[cfg(feature = "serde")]
mod dto {
use serde::{Deserialize, Serialize};

use super::*;

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct AnchorAddressDto {
#[serde(rename = "type")]
kind: u8,
anchor_id: AnchorId,
}

impl From<&AnchorAddress> for AnchorAddressDto {
fn from(value: &AnchorAddress) -> Self {
Self {
kind: AnchorAddress::KIND,
anchor_id: value.0,
}
}
}

impl From<AnchorAddressDto> for AnchorAddress {
fn from(value: AnchorAddressDto) -> Self {
Self(value.anchor_id)
}
}

impl_serde_typed_dto!(AnchorAddress, AnchorAddressDto, "anchor address");
}
22 changes: 22 additions & 0 deletions sdk/src/types/block/address/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

mod account;
mod anchor;
mod bech32;
mod ed25519;
mod nft;
Expand All @@ -10,6 +11,7 @@ use derive_more::From;

pub use self::{
account::AccountAddress,
anchor::AnchorAddress,
bech32::{Bech32Address, Hrp},
ed25519::Ed25519Address,
nft::NftAddress,
Expand Down Expand Up @@ -37,6 +39,9 @@ pub enum Address {
/// An NFT address.
#[packable(tag = NftAddress::KIND)]
Nft(NftAddress),
/// An anchor address.
#[packable(tag = AnchorAddress::KIND)]
Anchor(AnchorAddress),
}

impl core::fmt::Debug for Address {
Expand All @@ -45,6 +50,7 @@ impl core::fmt::Debug for Address {
Self::Ed25519(address) => address.fmt(f),
Self::Account(address) => address.fmt(f),
Self::Nft(address) => address.fmt(f),
Self::Anchor(address) => address.fmt(f),
}
}
}
Expand All @@ -56,6 +62,7 @@ impl Address {
Self::Ed25519(_) => Ed25519Address::KIND,
Self::Account(_) => AccountAddress::KIND,
Self::Nft(_) => NftAddress::KIND,
Self::Anchor(_) => AnchorAddress::KIND,
}
}

Expand Down Expand Up @@ -104,6 +111,21 @@ impl Address {
}
}

/// Checks whether the address is an [`AnchorAddress`].
pub fn is_anchor(&self) -> bool {
matches!(self, Self::Anchor(_))
}

/// Gets the address as an actual [`AnchorAddress`].
/// PANIC: do not call on a non-anchor address.
pub fn as_anchor(&self) -> &AnchorAddress {
if let Self::Anchor(address) = self {
address
} else {
panic!("as_anchor called on a non-anchor address");
}
}

/// Tries to create an [`Address`] from a bech32 encoded string.
pub fn try_from_bech32(address: impl AsRef<str>) -> Result<Self, Error> {
Bech32Address::try_from_str(address).map(|res| res.inner)
Expand Down
7 changes: 6 additions & 1 deletion sdk/src/types/block/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::types::block::{
output::{
feature::{BlockIssuerKeyCount, FeatureCount},
unlock_condition::UnlockConditionCount,
AccountId, ChainId, MetadataFeatureLength, NativeTokenCount, NftId, OutputIndex, StateMetadataLength,
AccountId, AnchorId, ChainId, MetadataFeatureLength, NativeTokenCount, NftId, OutputIndex, StateMetadataLength,
TagFeatureLength,
},
payload::{ContextInputCount, InputCount, OutputCount, TagLength, TaggedDataLength},
Expand Down Expand Up @@ -150,7 +150,9 @@ pub enum Error {
},
BlockIssuerKeysNotUniqueSorted,
RemainingBytesAfterBlock,
// TODO remove?
SelfControlledAccountOutput(AccountId),
SelfControlledAnchorOutput(AnchorId),
SelfDepositNft(NftId),
SignaturePublicKeyMismatch {
expected: String,
Expand Down Expand Up @@ -346,6 +348,9 @@ impl fmt::Display for Error {
Self::SelfControlledAccountOutput(account_id) => {
write!(f, "self controlled account output, account ID {account_id}")
}
Self::SelfControlledAnchorOutput(anchor_id) => {
write!(f, "self controlled anchor output, anchor ID {anchor_id}")
}
Self::SelfDepositNft(nft_id) => {
write!(f, "self deposit nft output, NFT ID {nft_id}")
}
Expand Down
Loading

0 comments on commit 1b58ea9

Please sign in to comment.