mirror of
https://github.com/aljazceru/cdk.git
synced 2025-12-23 15:44:50 +01:00
feat: remove multimint support
This commit is contained in:
@@ -137,7 +137,7 @@ async fn receive_token(
|
|||||||
) -> Result<Amount> {
|
) -> Result<Amount> {
|
||||||
let token: Token = Token::from_str(token_str)?;
|
let token: Token = Token::from_str(token_str)?;
|
||||||
|
|
||||||
let mint_url = token.proofs().into_keys().next().expect("Mint in token");
|
let mint_url = token.mint_url()?;
|
||||||
|
|
||||||
let wallet_key = WalletKey::new(mint_url.clone(), token.unit().unwrap_or_default());
|
let wallet_key = WalletKey::new(mint_url.clone(), token.unit().unwrap_or_default());
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ impl Token {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Proofs in [`Token`]
|
/// Proofs in [`Token`]
|
||||||
pub fn proofs(&self) -> HashMap<MintUrl, Proofs> {
|
pub fn proofs(&self) -> Proofs {
|
||||||
match self {
|
match self {
|
||||||
Self::TokenV3(token) => token.proofs(),
|
Self::TokenV3(token) => token.proofs(),
|
||||||
Self::TokenV4(token) => token.proofs(),
|
Self::TokenV4(token) => token.proofs(),
|
||||||
@@ -92,11 +92,27 @@ impl Token {
|
|||||||
/// Unit
|
/// Unit
|
||||||
pub fn unit(&self) -> Option<CurrencyUnit> {
|
pub fn unit(&self) -> Option<CurrencyUnit> {
|
||||||
match self {
|
match self {
|
||||||
Self::TokenV3(token) => token.unit(),
|
Self::TokenV3(token) => *token.unit(),
|
||||||
Self::TokenV4(token) => Some(token.unit()),
|
Self::TokenV4(token) => Some(token.unit()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mint url
|
||||||
|
pub fn mint_url(&self) -> Result<MintUrl, Error> {
|
||||||
|
match self {
|
||||||
|
Self::TokenV3(token) => {
|
||||||
|
let mint_urls = token.mint_urls();
|
||||||
|
|
||||||
|
if mint_urls.len() != 1 {
|
||||||
|
return Err(Error::UnsupportedToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(mint_urls.first().expect("Length is checked above").clone())
|
||||||
|
}
|
||||||
|
Self::TokenV4(token) => Ok(token.mint_url.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// To v3 string
|
/// To v3 string
|
||||||
pub fn to_v3_string(&self) -> String {
|
pub fn to_v3_string(&self) -> String {
|
||||||
let v3_token = match self {
|
let v3_token = match self {
|
||||||
@@ -187,24 +203,17 @@ impl TokenV3 {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn proofs(&self) -> HashMap<MintUrl, Proofs> {
|
/// Proofs
|
||||||
let mut proofs: HashMap<MintUrl, Proofs> = HashMap::new();
|
pub fn proofs(&self) -> Proofs {
|
||||||
|
self.token
|
||||||
for token in self.token.clone() {
|
.iter()
|
||||||
let mint_url = token.mint;
|
.flat_map(|token| token.proofs.clone())
|
||||||
let mut mint_proofs = token.proofs;
|
.collect()
|
||||||
|
|
||||||
proofs
|
|
||||||
.entry(mint_url)
|
|
||||||
.and_modify(|p| p.append(&mut mint_proofs))
|
|
||||||
.or_insert(mint_proofs);
|
|
||||||
}
|
|
||||||
|
|
||||||
proofs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Value
|
||||||
#[inline]
|
#[inline]
|
||||||
fn value(&self) -> Result<Amount, Error> {
|
pub fn value(&self) -> Result<Amount, Error> {
|
||||||
Ok(Amount::try_sum(
|
Ok(Amount::try_sum(
|
||||||
self.token
|
self.token
|
||||||
.iter()
|
.iter()
|
||||||
@@ -213,14 +222,27 @@ impl TokenV3 {
|
|||||||
)?)
|
)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Memo
|
||||||
#[inline]
|
#[inline]
|
||||||
fn memo(&self) -> &Option<String> {
|
pub fn memo(&self) -> &Option<String> {
|
||||||
&self.memo
|
&self.memo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unit
|
||||||
#[inline]
|
#[inline]
|
||||||
fn unit(&self) -> Option<CurrencyUnit> {
|
pub fn unit(&self) -> &Option<CurrencyUnit> {
|
||||||
self.unit
|
&self.unit
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mint Url
|
||||||
|
pub fn mint_urls(&self) -> Vec<MintUrl> {
|
||||||
|
let mut mint_urls = Vec::new();
|
||||||
|
|
||||||
|
for token in self.token.iter() {
|
||||||
|
mint_urls.push(token.mint.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
mint_urls
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,13 +271,10 @@ impl fmt::Display for TokenV3 {
|
|||||||
|
|
||||||
impl From<TokenV4> for TokenV3 {
|
impl From<TokenV4> for TokenV3 {
|
||||||
fn from(token: TokenV4) -> Self {
|
fn from(token: TokenV4) -> Self {
|
||||||
let (mint_url, proofs) = token
|
let proofs = token.proofs();
|
||||||
.proofs()
|
|
||||||
.into_iter()
|
|
||||||
.next()
|
|
||||||
.expect("Token has no proofs");
|
|
||||||
TokenV3 {
|
TokenV3 {
|
||||||
token: vec![TokenV3Token::new(mint_url, proofs)],
|
token: vec![TokenV3Token::new(token.mint_url, proofs)],
|
||||||
memo: token.memo,
|
memo: token.memo,
|
||||||
unit: Some(token.unit),
|
unit: Some(token.unit),
|
||||||
}
|
}
|
||||||
@@ -281,28 +300,16 @@ pub struct TokenV4 {
|
|||||||
|
|
||||||
impl TokenV4 {
|
impl TokenV4 {
|
||||||
/// Proofs from token
|
/// Proofs from token
|
||||||
pub fn proofs(&self) -> HashMap<MintUrl, Proofs> {
|
pub fn proofs(&self) -> Proofs {
|
||||||
let mint_url = &self.mint_url;
|
self.token
|
||||||
let mut proofs: HashMap<MintUrl, Proofs> = HashMap::new();
|
.iter()
|
||||||
|
.flat_map(|token| token.proofs.iter().map(|p| p.into_proof(&token.keyset_id)))
|
||||||
for token in self.token.clone() {
|
.collect()
|
||||||
let mut mint_proofs = token
|
|
||||||
.proofs
|
|
||||||
.iter()
|
|
||||||
.map(|p| p.into_proof(&token.keyset_id))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
proofs
|
|
||||||
.entry(mint_url.clone())
|
|
||||||
.and_modify(|p| p.append(&mut mint_proofs))
|
|
||||||
.or_insert(mint_proofs);
|
|
||||||
}
|
|
||||||
|
|
||||||
proofs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Value
|
||||||
#[inline]
|
#[inline]
|
||||||
fn value(&self) -> Result<Amount, Error> {
|
pub fn value(&self) -> Result<Amount, Error> {
|
||||||
Ok(Amount::try_sum(
|
Ok(Amount::try_sum(
|
||||||
self.token
|
self.token
|
||||||
.iter()
|
.iter()
|
||||||
@@ -311,13 +318,15 @@ impl TokenV4 {
|
|||||||
)?)
|
)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Memo
|
||||||
#[inline]
|
#[inline]
|
||||||
fn memo(&self) -> &Option<String> {
|
pub fn memo(&self) -> &Option<String> {
|
||||||
&self.memo
|
&self.memo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unit
|
||||||
#[inline]
|
#[inline]
|
||||||
fn unit(&self) -> CurrencyUnit {
|
pub fn unit(&self) -> CurrencyUnit {
|
||||||
self.unit
|
self.unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -350,13 +359,15 @@ impl TryFrom<TokenV3> for TokenV4 {
|
|||||||
type Error = Error;
|
type Error = Error;
|
||||||
fn try_from(token: TokenV3) -> Result<Self, Self::Error> {
|
fn try_from(token: TokenV3) -> Result<Self, Self::Error> {
|
||||||
let proofs = token.proofs();
|
let proofs = token.proofs();
|
||||||
if proofs.len() != 1 {
|
let mint_urls = token.mint_urls();
|
||||||
|
|
||||||
|
if mint_urls.len() != 1 {
|
||||||
return Err(Error::UnsupportedToken);
|
return Err(Error::UnsupportedToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mint_url, mint_proofs) = proofs.iter().next().expect("No proofs");
|
let mint_url = mint_urls.first().expect("Len is checked");
|
||||||
|
|
||||||
let proofs = mint_proofs
|
let proofs = proofs
|
||||||
.iter()
|
.iter()
|
||||||
.fold(HashMap::new(), |mut acc, val| {
|
.fold(HashMap::new(), |mut acc, val| {
|
||||||
acc.entry(val.keyset_id)
|
acc.entry(val.keyset_id)
|
||||||
@@ -369,7 +380,7 @@ impl TryFrom<TokenV3> for TokenV4 {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(TokenV4 {
|
Ok(TokenV4 {
|
||||||
mint_url: mint_url.to_owned(),
|
mint_url: mint_url.clone(),
|
||||||
token: proofs,
|
token: proofs,
|
||||||
memo: token.memo,
|
memo: token.memo,
|
||||||
unit: token.unit.ok_or(Error::UnsupportedUnit)?,
|
unit: token.unit.ok_or(Error::UnsupportedUnit)?,
|
||||||
|
|||||||
@@ -393,87 +393,87 @@ impl Wallet {
|
|||||||
"Must set locktime".to_string(),
|
"Must set locktime".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if token.mint_url()? != self.mint_url {
|
||||||
|
return Err(Error::IncorrectWallet(format!(
|
||||||
|
"Should be {} not {}",
|
||||||
|
self.mint_url,
|
||||||
|
token.mint_url()?
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
for (mint_url, proofs) in &token.proofs() {
|
let proofs = token.proofs();
|
||||||
if mint_url != &self.mint_url {
|
for proof in proofs {
|
||||||
return Err(Error::IncorrectWallet(format!(
|
let secret: nut10::Secret = (&proof.secret).try_into()?;
|
||||||
"Should be {} not {}",
|
|
||||||
self.mint_url, mint_url
|
let proof_conditions: SpendingConditions = secret.try_into()?;
|
||||||
)));
|
|
||||||
|
if num_sigs.ne(&proof_conditions.num_sigs()) {
|
||||||
|
tracing::debug!(
|
||||||
|
"Spending condition requires: {:?} sigs proof secret specifies: {:?}",
|
||||||
|
num_sigs,
|
||||||
|
proof_conditions.num_sigs()
|
||||||
|
);
|
||||||
|
|
||||||
|
return Err(Error::P2PKConditionsNotMet(
|
||||||
|
"Num sigs did not match spending condition".to_string(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
for proof in proofs {
|
|
||||||
let secret: nut10::Secret = (&proof.secret).try_into()?;
|
|
||||||
|
|
||||||
let proof_conditions: SpendingConditions = secret.try_into()?;
|
let spending_condition_pubkeys = pubkeys.clone().unwrap_or_default();
|
||||||
|
let proof_pubkeys = proof_conditions.pubkeys().unwrap_or_default();
|
||||||
|
|
||||||
if num_sigs.ne(&proof_conditions.num_sigs()) {
|
// Check the Proof has the required pubkeys
|
||||||
tracing::debug!(
|
if proof_pubkeys.len().ne(&spending_condition_pubkeys.len())
|
||||||
"Spending condition requires: {:?} sigs proof secret specifies: {:?}",
|
|| !proof_pubkeys
|
||||||
num_sigs,
|
.iter()
|
||||||
proof_conditions.num_sigs()
|
.all(|pubkey| spending_condition_pubkeys.contains(pubkey))
|
||||||
);
|
{
|
||||||
|
tracing::debug!("Proof did not included Publickeys meeting condition");
|
||||||
|
tracing::debug!("{:?}", proof_pubkeys);
|
||||||
|
tracing::debug!("{:?}", spending_condition_pubkeys);
|
||||||
|
return Err(Error::P2PKConditionsNotMet(
|
||||||
|
"Pubkeys in proof not allowed by spending condition".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
return Err(Error::P2PKConditionsNotMet(
|
// If spending condition refund keys is allowed (Some(Empty Vec))
|
||||||
"Num sigs did not match spending condition".to_string(),
|
// If spending conition refund keys is allowed to restricted set of keys check
|
||||||
));
|
// it is one of them Check that proof locktime is > condition
|
||||||
}
|
// locktime
|
||||||
|
|
||||||
let spending_condition_pubkeys = pubkeys.clone().unwrap_or_default();
|
if let Some(proof_refund_keys) = proof_conditions.refund_keys() {
|
||||||
let proof_pubkeys = proof_conditions.pubkeys().unwrap_or_default();
|
let proof_locktime = proof_conditions
|
||||||
|
.locktime()
|
||||||
|
.ok_or(Error::LocktimeNotProvided)?;
|
||||||
|
|
||||||
// Check the Proof has the required pubkeys
|
if let (Some(condition_refund_keys), Some(condition_locktime)) =
|
||||||
if proof_pubkeys.len().ne(&spending_condition_pubkeys.len())
|
(&refund_keys, locktime)
|
||||||
|| !proof_pubkeys
|
|
||||||
.iter()
|
|
||||||
.all(|pubkey| spending_condition_pubkeys.contains(pubkey))
|
|
||||||
{
|
{
|
||||||
tracing::debug!("Proof did not included Publickeys meeting condition");
|
// Proof locktime must be greater then condition locktime to ensure it
|
||||||
tracing::debug!("{:?}", proof_pubkeys);
|
// cannot be claimed back
|
||||||
tracing::debug!("{:?}", spending_condition_pubkeys);
|
if proof_locktime.lt(&condition_locktime) {
|
||||||
return Err(Error::P2PKConditionsNotMet(
|
|
||||||
"Pubkeys in proof not allowed by spending condition".to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If spending condition refund keys is allowed (Some(Empty Vec))
|
|
||||||
// If spending conition refund keys is allowed to restricted set of keys check
|
|
||||||
// it is one of them Check that proof locktime is > condition
|
|
||||||
// locktime
|
|
||||||
|
|
||||||
if let Some(proof_refund_keys) = proof_conditions.refund_keys() {
|
|
||||||
let proof_locktime = proof_conditions
|
|
||||||
.locktime()
|
|
||||||
.ok_or(Error::LocktimeNotProvided)?;
|
|
||||||
|
|
||||||
if let (Some(condition_refund_keys), Some(condition_locktime)) =
|
|
||||||
(&refund_keys, locktime)
|
|
||||||
{
|
|
||||||
// Proof locktime must be greater then condition locktime to ensure it
|
|
||||||
// cannot be claimed back
|
|
||||||
if proof_locktime.lt(&condition_locktime) {
|
|
||||||
return Err(Error::P2PKConditionsNotMet(
|
|
||||||
"Proof locktime less then required".to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// A non empty condition refund key list is used as a restricted set of keys
|
|
||||||
// returns are allowed to An empty list means the
|
|
||||||
// proof can be refunded to anykey set in the secret
|
|
||||||
if !condition_refund_keys.is_empty()
|
|
||||||
&& !proof_refund_keys
|
|
||||||
.iter()
|
|
||||||
.all(|refund_key| condition_refund_keys.contains(refund_key))
|
|
||||||
{
|
|
||||||
return Err(Error::P2PKConditionsNotMet(
|
|
||||||
"Refund Key not allowed".to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Spending conditions does not allow refund keys
|
|
||||||
return Err(Error::P2PKConditionsNotMet(
|
return Err(Error::P2PKConditionsNotMet(
|
||||||
"Spending condition does not allow refund keys".to_string(),
|
"Proof locktime less then required".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A non empty condition refund key list is used as a restricted set of keys
|
||||||
|
// returns are allowed to An empty list means the
|
||||||
|
// proof can be refunded to anykey set in the secret
|
||||||
|
if !condition_refund_keys.is_empty()
|
||||||
|
&& !proof_refund_keys
|
||||||
|
.iter()
|
||||||
|
.all(|refund_key| condition_refund_keys.contains(refund_key))
|
||||||
|
{
|
||||||
|
return Err(Error::P2PKConditionsNotMet(
|
||||||
|
"Refund Key not allowed".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Spending conditions does not allow refund keys
|
||||||
|
return Err(Error::P2PKConditionsNotMet(
|
||||||
|
"Spending condition does not allow refund keys".to_string(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -486,31 +486,32 @@ impl Wallet {
|
|||||||
pub async fn verify_token_dleq(&self, token: &Token) -> Result<(), Error> {
|
pub async fn verify_token_dleq(&self, token: &Token) -> Result<(), Error> {
|
||||||
let mut keys_cache: HashMap<Id, Keys> = HashMap::new();
|
let mut keys_cache: HashMap<Id, Keys> = HashMap::new();
|
||||||
|
|
||||||
for (mint_url, proofs) in &token.proofs() {
|
// TODO: Get mint url
|
||||||
if mint_url != &self.mint_url {
|
// if mint_url != &self.mint_url {
|
||||||
return Err(Error::IncorrectWallet(format!(
|
// return Err(Error::IncorrectWallet(format!(
|
||||||
"Should be {} not {}",
|
// "Should be {} not {}",
|
||||||
self.mint_url, mint_url
|
// self.mint_url, mint_url
|
||||||
)));
|
// )));
|
||||||
}
|
// }
|
||||||
for proof in proofs {
|
|
||||||
let mint_pubkey = match keys_cache.get(&proof.keyset_id) {
|
|
||||||
Some(keys) => keys.amount_key(proof.amount),
|
|
||||||
None => {
|
|
||||||
let keys = self.get_keyset_keys(proof.keyset_id).await?;
|
|
||||||
|
|
||||||
let key = keys.amount_key(proof.amount);
|
let proofs = token.proofs();
|
||||||
keys_cache.insert(proof.keyset_id, keys);
|
for proof in proofs {
|
||||||
|
let mint_pubkey = match keys_cache.get(&proof.keyset_id) {
|
||||||
|
Some(keys) => keys.amount_key(proof.amount),
|
||||||
|
None => {
|
||||||
|
let keys = self.get_keyset_keys(proof.keyset_id).await?;
|
||||||
|
|
||||||
key
|
let key = keys.amount_key(proof.amount);
|
||||||
}
|
keys_cache.insert(proof.keyset_id, keys);
|
||||||
|
|
||||||
|
key
|
||||||
}
|
}
|
||||||
.ok_or(Error::AmountKey)?;
|
|
||||||
|
|
||||||
proof
|
|
||||||
.verify_dleq(mint_pubkey)
|
|
||||||
.map_err(|_| Error::CouldNotVerifyDleq)?;
|
|
||||||
}
|
}
|
||||||
|
.ok_or(Error::AmountKey)?;
|
||||||
|
|
||||||
|
proof
|
||||||
|
.verify_dleq(mint_pubkey)
|
||||||
|
.map_err(|_| Error::CouldNotVerifyDleq)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -237,36 +237,36 @@ impl MultiMintWallet {
|
|||||||
let token_data = Token::from_str(encoded_token)?;
|
let token_data = Token::from_str(encoded_token)?;
|
||||||
let unit = token_data.unit().unwrap_or_default();
|
let unit = token_data.unit().unwrap_or_default();
|
||||||
|
|
||||||
let mint_proofs = token_data.proofs();
|
let proofs = token_data.proofs();
|
||||||
|
|
||||||
let mut amount_received = Amount::ZERO;
|
let mut amount_received = Amount::ZERO;
|
||||||
|
|
||||||
let mut mint_errors = None;
|
let mut mint_errors = None;
|
||||||
|
|
||||||
|
let mint_url = token_data.mint_url()?;
|
||||||
|
|
||||||
// Check that all mints in tokes have wallets
|
// Check that all mints in tokes have wallets
|
||||||
for (mint_url, proofs) in mint_proofs {
|
let wallet_key = WalletKey::new(mint_url.clone(), unit);
|
||||||
let wallet_key = WalletKey::new(mint_url.clone(), unit);
|
if !self.has(&wallet_key).await {
|
||||||
if !self.has(&wallet_key).await {
|
return Err(Error::UnknownWallet(wallet_key.clone()));
|
||||||
return Err(Error::UnknownWallet(wallet_key.clone()));
|
}
|
||||||
|
|
||||||
|
let wallet_key = WalletKey::new(mint_url.clone(), unit);
|
||||||
|
let wallet = self
|
||||||
|
.get_wallet(&wallet_key)
|
||||||
|
.await
|
||||||
|
.ok_or(Error::UnknownWallet(wallet_key.clone()))?;
|
||||||
|
|
||||||
|
match wallet
|
||||||
|
.receive_proofs(proofs, SplitTarget::default(), p2pk_signing_keys, preimages)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(amount) => {
|
||||||
|
amount_received += amount;
|
||||||
}
|
}
|
||||||
|
Err(err) => {
|
||||||
let wallet_key = WalletKey::new(mint_url.clone(), unit);
|
tracing::error!("Could no receive proofs for mint: {}", err);
|
||||||
let wallet = self
|
mint_errors = Some(err);
|
||||||
.get_wallet(&wallet_key)
|
|
||||||
.await
|
|
||||||
.ok_or(Error::UnknownWallet(wallet_key.clone()))?;
|
|
||||||
|
|
||||||
match wallet
|
|
||||||
.receive_proofs(proofs, SplitTarget::default(), p2pk_signing_keys, preimages)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(amount) => {
|
|
||||||
amount_received += amount;
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
tracing::error!("Could no receive proofs for mint: {}", err);
|
|
||||||
mint_errors = Some(err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -207,9 +207,7 @@ impl Wallet {
|
|||||||
return Err(Error::MultiMintTokenNotSupported);
|
return Err(Error::MultiMintTokenNotSupported);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mint_url, proofs) = proofs.into_iter().next().expect("Token has proofs");
|
if self.mint_url != token_data.mint_url()? {
|
||||||
|
|
||||||
if self.mint_url != mint_url {
|
|
||||||
return Err(Error::IncorrectMint);
|
return Err(Error::IncorrectMint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user