use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize)]
pub struct Wallet {
pub id: String,
pub address: String,
pub chain_type: String,
#[serde(default)]
pub policy_ids: Vec<String>,
#[serde(default)]
pub additional_signers: Vec<WalletSigner>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct WalletSigner {
pub signer_id: String,
#[serde(default)]
pub override_policy_ids: Vec<String>,
}
#[derive(Debug, Deserialize)]
pub struct WalletsResponse {
pub data: Vec<Wallet>,
}
#[derive(Debug, Deserialize)]
pub struct SignTransactionResponse {
#[serde(default)]
pub method: String,
pub data: SignTransactionData,
}
#[derive(Debug, Deserialize)]
pub struct SignTransactionData {
pub signed_transaction: String,
#[serde(default)]
pub encoding: String,
}
#[derive(Debug, Serialize)]
pub struct CreatePolicyRequest {
pub version: String,
pub name: String,
pub chain_type: String,
pub rules: Vec<PolicyRule>,
}
#[derive(Debug, Clone, Serialize)]
pub struct PolicyRule {
pub name: String,
pub method: String,
pub conditions: Vec<PolicyCondition>,
pub action: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct PolicyCondition {
pub field_source: String,
pub field: String,
pub operator: String,
pub value: serde_json::Value,
}
#[derive(Debug, Deserialize)]
pub struct CreatePolicyResponse {
pub id: String,
}
#[derive(Debug, Deserialize, Default)]
#[serde(default)]
pub struct GetPolicyResponse {
pub id: String,
pub name: String,
pub rules: Vec<PolicyRuleResponse>,
}
#[derive(Debug, Deserialize, Default)]
#[serde(default)]
pub struct PolicyRuleResponse {
pub id: String,
pub name: String,
pub method: String,
pub conditions: Vec<PolicyConditionResponse>,
pub action: String,
}
#[derive(Debug, Deserialize, Default)]
#[serde(default)]
pub struct PolicyConditionResponse {
pub field_source: String,
pub field: String,
pub operator: String,
pub value: serde_json::Value,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct PrivyClaims {
pub aud: String,
pub exp: u64,
pub iss: String,
pub sub: String,
pub sid: String,
pub iat: u64,
#[serde(default)]
pub linked_accounts: Option<String>,
#[serde(default)]
pub custom_metadata: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum LinkedAccount {
Email {
address: String,
},
Wallet {
address: String,
#[serde(default)]
chain_type: Option<String>,
},
Phone {
#[serde(rename = "phoneNumber")]
phone_number: String,
},
Google {
email: String,
#[serde(default)]
name: Option<String>,
},
Apple {
email: String,
},
#[serde(other)]
Unknown,
}
impl PrivyClaims {
pub fn get_email(&self) -> Option<String> {
let accounts_json = self.linked_accounts.as_ref()?;
let accounts: Vec<LinkedAccount> = serde_json::from_str(accounts_json).ok()?;
accounts.into_iter().find_map(|acc| match acc {
LinkedAccount::Email { address } => Some(address),
LinkedAccount::Google { email, .. } => Some(email),
LinkedAccount::Apple { email } => Some(email),
_ => None,
})
}
pub fn get_all_emails(&self) -> Vec<String> {
let Some(accounts_json) = self.linked_accounts.as_ref() else {
return Vec::new();
};
let Ok(accounts) = serde_json::from_str::<Vec<LinkedAccount>>(accounts_json) else {
return Vec::new();
};
accounts
.into_iter()
.filter_map(|acc| match acc {
LinkedAccount::Email { address } => Some(address),
LinkedAccount::Google { email, .. } => Some(email),
LinkedAccount::Apple { email } => Some(email),
_ => None,
})
.collect()
}
pub fn get_wallet_addresses(&self) -> Vec<String> {
let Some(accounts_json) = self.linked_accounts.as_ref() else {
return Vec::new();
};
let Ok(accounts) = serde_json::from_str::<Vec<LinkedAccount>>(accounts_json) else {
return Vec::new();
};
accounts
.into_iter()
.filter_map(|acc| match acc {
LinkedAccount::Wallet { address, .. } => Some(address),
_ => None,
})
.collect()
}
}