Require chain ID field in payment options of ethereum type
This commit is contained in:
parent
690a03946e
commit
c5c3911de6
7 changed files with 65 additions and 17 deletions
|
@ -0,0 +1,9 @@
|
|||
UPDATE actor_profile
|
||||
SET payment_options = (
|
||||
-- remove all payment options except links
|
||||
SELECT COALESCE (
|
||||
jsonb_agg(opt) FILTER (WHERE opt ->> 'payment_type' = '1'),
|
||||
'[]'
|
||||
)
|
||||
FROM jsonb_array_elements(actor_profile.payment_options) AS opt
|
||||
);
|
|
@ -68,8 +68,9 @@ pub fn attach_payment_option(
|
|||
payment_option: PaymentOption,
|
||||
) -> ActorAttachment {
|
||||
match payment_option {
|
||||
// Local actors can't have payment links
|
||||
PaymentOption::Link(_) => unimplemented!(),
|
||||
PaymentOption::EthereumSubscription => {
|
||||
PaymentOption::EthereumSubscription(_) => {
|
||||
let name = "EthereumSubscription".to_string();
|
||||
let subscription_page_url =
|
||||
get_subscription_page_url(instance_url, user_id);
|
||||
|
@ -132,6 +133,7 @@ pub fn parse_extra_field(
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::utils::caip2::ChainId;
|
||||
use crate::utils::id::new_uuid;
|
||||
use super::*;
|
||||
|
||||
|
@ -155,7 +157,8 @@ mod tests {
|
|||
#[test]
|
||||
fn test_payment_option() {
|
||||
let user_id = new_uuid();
|
||||
let payment_option = PaymentOption::EthereumSubscription;
|
||||
let payment_option =
|
||||
PaymentOption::ethereum_subscription(ChainId::ethereum_mainnet());
|
||||
let subscription_page_url =
|
||||
format!("https://example.com/profile/{}/subscription", user_id);
|
||||
let attachment = attach_payment_option(
|
||||
|
|
|
@ -12,9 +12,9 @@ pub async fn apply_migrations(db_client: &mut Client) {
|
|||
|
||||
for migration in migration_report.applied_migrations() {
|
||||
log::info!(
|
||||
"Migration Applied - Name: {}, Version: {}",
|
||||
migration.name(),
|
||||
"migration applied: version {} ({})",
|
||||
migration.version(),
|
||||
migration.name(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ impl Account {
|
|||
.map(|option| {
|
||||
match option {
|
||||
PaymentOption::Link(link) => link.href,
|
||||
PaymentOption::EthereumSubscription => {
|
||||
PaymentOption::EthereumSubscription(_) => {
|
||||
get_subscription_page_url(instance_url, &profile.id)
|
||||
},
|
||||
}
|
||||
|
|
|
@ -63,6 +63,9 @@ pub async fn subscriptions_enabled(
|
|||
let mut maybe_payment_option = None;
|
||||
match subscription_settings.into_inner() {
|
||||
SubscriptionSettings::Ethereum => {
|
||||
let ethereum_config = config.blockchain.as_ref()
|
||||
.and_then(|conf| conf.ethereum_config())
|
||||
.ok_or(HttpError::NotSupported)?;
|
||||
let contract_set = maybe_blockchain.as_ref().as_ref()
|
||||
.ok_or(HttpError::NotSupported)?;
|
||||
let wallet_address = current_user
|
||||
|
@ -78,7 +81,9 @@ pub async fn subscriptions_enabled(
|
|||
if !is_registered {
|
||||
return Err(ValidationError("recipient is not registered").into());
|
||||
};
|
||||
maybe_payment_option = Some(PaymentOption::EthereumSubscription);
|
||||
maybe_payment_option = Some(PaymentOption::ethereum_subscription(
|
||||
ethereum_config.chain_id.clone(),
|
||||
));
|
||||
};
|
||||
},
|
||||
SubscriptionSettings::Monero { } => {
|
||||
|
|
|
@ -15,6 +15,7 @@ use crate::activitypub::identifiers::local_actor_id;
|
|||
use crate::database::json_macro::{json_from_sql, json_to_sql};
|
||||
use crate::errors::{ConversionError, ValidationError};
|
||||
use crate::ethereum::identity::DidPkh;
|
||||
use crate::utils::caip2::ChainId;
|
||||
use super::validators::{
|
||||
validate_username,
|
||||
validate_display_name,
|
||||
|
@ -76,17 +77,26 @@ pub struct PaymentLink {
|
|||
pub href: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct EthereumSubscription {
|
||||
chain_id: ChainId,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PaymentOption {
|
||||
Link(PaymentLink),
|
||||
EthereumSubscription,
|
||||
EthereumSubscription(EthereumSubscription),
|
||||
}
|
||||
|
||||
impl PaymentOption {
|
||||
pub fn ethereum_subscription(chain_id: ChainId) -> Self {
|
||||
Self::EthereumSubscription(EthereumSubscription { chain_id })
|
||||
}
|
||||
|
||||
fn payment_type(&self) -> PaymentType {
|
||||
match self {
|
||||
Self::Link(_) => PaymentType::Link,
|
||||
Self::EthereumSubscription => PaymentType::EthereumSubscription,
|
||||
Self::EthereumSubscription(_) => PaymentType::EthereumSubscription,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +119,11 @@ impl<'de> Deserialize<'de> for PaymentOption {
|
|||
.map_err(DeserializerError::custom)?;
|
||||
Self::Link(link)
|
||||
},
|
||||
PaymentType::EthereumSubscription => Self::EthereumSubscription,
|
||||
PaymentType::EthereumSubscription => {
|
||||
let payment_info = EthereumSubscription::deserialize(value)
|
||||
.map_err(DeserializerError::custom)?;
|
||||
Self::EthereumSubscription(payment_info)
|
||||
},
|
||||
};
|
||||
Ok(payment_option)
|
||||
}
|
||||
|
@ -125,7 +139,9 @@ impl Serialize for PaymentOption {
|
|||
|
||||
match self {
|
||||
Self::Link(link) => link.serialize(FlatMapSerializer(&mut map))?,
|
||||
Self::EthereumSubscription => (),
|
||||
Self::EthereumSubscription(payment_info) => {
|
||||
payment_info.serialize(FlatMapSerializer(&mut map))?
|
||||
},
|
||||
};
|
||||
map.end()
|
||||
}
|
||||
|
@ -384,14 +400,15 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_payment_option_ethereum_subscription_serialization() {
|
||||
let json_data = r#"{"payment_type":2,"name":null,"href":null}"#;
|
||||
let json_data = r#"{"payment_type":2,"chain_id":"eip155:1","name":null}"#;
|
||||
let payment_option: PaymentOption = serde_json::from_str(json_data).unwrap();
|
||||
assert!(matches!(
|
||||
payment_option,
|
||||
PaymentOption::EthereumSubscription,
|
||||
));
|
||||
let payment_info = match payment_option {
|
||||
PaymentOption::EthereumSubscription(ref payment_info) => payment_info,
|
||||
_ => panic!("wrong option"),
|
||||
};
|
||||
assert_eq!(payment_info.chain_id, ChainId::ethereum_mainnet());
|
||||
let serialized = serde_json::to_string(&payment_option).unwrap();
|
||||
assert_eq!(serialized, r#"{"payment_type":2}"#);
|
||||
assert_eq!(serialized, r#"{"payment_type":2,"chain_id":"eip155:1"}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -2,7 +2,13 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize, Deserializer, de::Error as DeserializerError};
|
||||
use serde::{
|
||||
Deserialize,
|
||||
Deserializer,
|
||||
Serialize,
|
||||
Serializer,
|
||||
de::Error as DeserializerError,
|
||||
};
|
||||
|
||||
const CAIP2_RE: &str = r"(?P<namespace>[-a-z0-9]{3,8}):(?P<reference>[-a-zA-Z0-9]{1,32})";
|
||||
const CAIP2_ETHEREUM_NAMESPACE: &str = "eip155";
|
||||
|
@ -47,6 +53,14 @@ impl ToString for ChainId {
|
|||
}
|
||||
}
|
||||
|
||||
impl Serialize for ChainId {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer
|
||||
{
|
||||
serializer.serialize_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ChainId {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: Deserializer<'de>
|
||||
|
|
Loading…
Reference in a new issue