Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add UMA invitation functions to the SDK. #18

Merged
merged 3 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
225 changes: 224 additions & 1 deletion lightspark/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ use crate::objects::invoice_type::InvoiceType;
use crate::objects::lightning_fee_estimate_output::LightningFeeEstimateOutput;
use crate::objects::outgoing_payment::OutgoingPayment;
use crate::objects::permission::Permission;
use crate::objects::region_code::RegionCode;
use crate::objects::risk_rating::RiskRating;
use crate::objects::uma_invitation::UmaInvitation;
use crate::objects::withdrawal_mode::WithdrawalMode;
use crate::objects::withdrawal_request::WithdrawalRequest;
use crate::objects::{account, invoice_data};
use crate::objects::{account, invoice_data, uma_invitation};
use crate::objects::{api_token, incoming_payment, outgoing_payment};
use crate::objects::{bitcoin_network, withdrawal_request};
use crate::objects::{fee_estimate, lightning_fee_estimate_output};
Expand Down Expand Up @@ -965,4 +967,225 @@ impl<K: OperationSigningKey> LightsparkClient<K> {
.map_err(Error::JsonError)?;
Ok(result)
}

/// Creates an UMA invitation. If you are part of the incentive program, you should use
/// `create_uma_invitation_with_incentives`.
pub async fn create_uma_invitation(&self, inviter_uma: &str) -> Result<UmaInvitation, Error> {
let operation = format!(
"mutation CreateUmaInvitation(
$inviter_uma: String!
) {{
create_uma_invitation(input: {{
inviter_uma: $inviter_uma
}}) {{
invitation {{
...UmaInvitationFragment
}}
}}
}}

{}
",
uma_invitation::FRAGMENT
);

let mut variables: HashMap<&str, Value> = HashMap::new();
variables.insert("inviter_uma", inviter_uma.into());

let value = serde_json::to_value(variables).map_err(Error::ConversionError)?;
let json = self
.requester
.execute_graphql(&operation, Some(value))
.await?;

let result = serde_json::from_value(json["create_uma_invitation"]["invitation"].clone())
.map_err(Error::JsonError)?;
Ok(result)
}

/// Creates an UMA invitation as part of the incentive program. If you are not part of the
/// incentive program, you should use `create_uma_invitation`.
pub async fn create_uma_invitation_with_incentives(
&self,
inviter_uma: &str,
inviter_phone_number_e164: &str,
inviter_region: RegionCode,
) -> Result<UmaInvitation, Error> {
let operation = format!(
"mutation CreateUmaInvitationWithIncentives(
$inviter_uma: String!
$inviter_phone_hash: String!
$inviter_region: RegionCode!
) {{
create_uma_invitation_with_incentives(input: {{
inviter_uma: $inviter_uma
inviter_phone_hash: $inviter_phone_hash
inviter_region: $inviter_region
}}) {{
invitation {{
...UmaInvitationFragment
}}
}}
}}

{}
",
uma_invitation::FRAGMENT
);

let mut variables: HashMap<&str, Value> = HashMap::new();
variables.insert("inviter_uma", inviter_uma.into());
let inviter_phone_hash = Self::hash_phone_number(inviter_phone_number_e164)?;
variables.insert("inviter_phone_hash", inviter_phone_hash.into());
variables.insert("inviter_region", inviter_region.into());

let value = serde_json::to_value(variables).map_err(Error::ConversionError)?;
let json = self
.requester
.execute_graphql(&operation, Some(value))
.await?;

let result = serde_json::from_value(
json["create_uma_invitation_with_incentives"]["invitation"].clone(),
)
.map_err(Error::JsonError)?;
Ok(result)
}

/// Claims an UMA invitation. If you are part of the incentive program, you should use
/// `claim_uma_invitation_with_incentives`.
pub async fn claim_uma_invitation(
&self,
invitation_code: &str,
invitee_uma: &str,
) -> Result<UmaInvitation, Error> {
let operation = format!(
"mutation ClaimUmaInvitation(
$invitation_code: String!
$invitee_uma: String!
) {{
claim_uma_invitation(input: {{
invitation_code: $invitation_code
invitee_uma: $invitee_uma
}}) {{
invitation {{
...UmaInvitationFragment
}}
}}
}}

{}
",
uma_invitation::FRAGMENT
);

let mut variables: HashMap<&str, Value> = HashMap::new();
variables.insert("invitation_code", invitation_code.into());
variables.insert("invitee_uma", invitee_uma.into());

let value = serde_json::to_value(variables).map_err(Error::ConversionError)?;
let json = self
.requester
.execute_graphql(&operation, Some(value))
.await?;

let result = serde_json::from_value(json["claim_uma_invitation"]["invitation"].clone())
.map_err(Error::JsonError)?;
Ok(result)
}

/// Claims an UMA invitation as part of the incentive program. If you are not part of the
/// incentive program, you should use `claim_uma_invitation`.
pub async fn claim_uma_invitation_with_incentives(
&self,
invitation_code: &str,
invitee_uma: &str,
invitee_phone_number_e164: &str,
invitee_region: RegionCode,
) -> Result<UmaInvitation, Error> {
let operation = format!(
"mutation ClaimUmaInvitation(
$invitation_code: String!
$invitee_uma: String!
$invitee_phone_hash: String!
$invitee_region: RegionCode!
) {{
claim_uma_invitation_with_incentives(input: {{
invitation_code: $invitation_code
invitee_uma: $invitee_uma
invitee_phone_hash: $invitee_phone_hash
invitee_region: $invitee_region
}}) {{
invitation {{
...UmaInvitationFragment
}}
}}
}}

{}
",
uma_invitation::FRAGMENT
);

let mut variables: HashMap<&str, Value> = HashMap::new();
variables.insert("invitation_code", invitation_code.into());
variables.insert("invitee_uma", invitee_uma.into());
let invitee_phone_hash = Self::hash_phone_number(invitee_phone_number_e164)?;
variables.insert("invitee_phone_hash", invitee_phone_hash.into());
variables.insert("invitee_region", invitee_region.into());

let value = serde_json::to_value(variables).map_err(Error::ConversionError)?;
let json = self
.requester
.execute_graphql(&operation, Some(value))
.await?;

let result = serde_json::from_value(
json["claim_uma_invitation_with_incentives"]["invitation"].clone(),
)
.map_err(Error::JsonError)?;
Ok(result)
}

/// Fetches a UMA invitation by its code.
pub async fn fetch_uma_invitation(
&self,
invitation_code: &str,
) -> Result<UmaInvitation, Error> {
let operation = format!(
"query FetchUmaInvitation(
$invitation_code: String!
) {{
uma_invitation_by_code(code: $invitation_code) {{
...UmaInvitationFragment
}}
}}
{}
",
uma_invitation::FRAGMENT
);

let mut variables: HashMap<&str, Value> = HashMap::new();
variables.insert("invitation_code", invitation_code.into());

let value = serde_json::to_value(variables).map_err(Error::ConversionError)?;
let json = self
.requester
.execute_graphql(&operation, Some(value))
.await?;

let result = serde_json::from_value(json["uma_invitation_by_code"].clone())
.map_err(Error::JsonError)?;
Ok(result)
}

fn hash_phone_number(phone_number_e164: &str) -> Result<String, Error> {
let e164_regex = regex::Regex::new(r"^\+[1-9]\d{1,14}$").unwrap();
if !e164_regex.is_match(phone_number_e164) {
return Err(Error::InvalidPhoneNumber);
}
let mut hasher = Sha256::new();
hasher.update(phone_number_e164.as_bytes());
Ok(hex::encode(hasher.finalize()))
}
}
2 changes: 2 additions & 0 deletions lightspark/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub enum Error {
WebhookSignatureError,
SigningKeyNotFound,
InvalidCurrencyConversion,
InvalidPhoneNumber,
}

impl fmt::Display for Error {
Expand All @@ -33,6 +34,7 @@ impl fmt::Display for Error {
}
Self::SigningKeyNotFound => write!(f, "Signing key not found"),
Self::InvalidCurrencyConversion => write!(f, "Invalid currency conversion"),
Self::InvalidPhoneNumber => write!(f, "Invalid phone number. Must be E.164 format."),
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion lightspark/src/objects/account_to_nodes_connection.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
use crate::objects::connection::Connection;
use serde::{Deserialize, Serialize};

use crate::objects::lightspark_node::LightsparkNodeEnum;
use crate::objects::page_info::PageInfo;
use serde::{Deserialize, Serialize};
use std::vec::Vec;

/// A connection between an account and the nodes it manages.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
use crate::objects::connection::Connection;
use crate::objects::payment_request::PaymentRequestEnum;
use serde::{Deserialize, Serialize};
use std::vec::Vec;

use crate::objects::page_info::PageInfo;
use crate::objects::payment_request::PaymentRequestEnum;
use std::vec::Vec;

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct AccountToPaymentRequestsConnection {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::objects::currency_amount::CurrencyAmount;
use crate::objects::page_info::PageInfo;
use crate::objects::transaction::TransactionEnum;
use serde::{Deserialize, Serialize};

use std::vec::Vec;

#[derive(Debug, Clone, Deserialize, Serialize)]
Expand Down
9 changes: 9 additions & 0 deletions lightspark/src/objects/claim_uma_invitation_input.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ClaimUmaInvitationInput {
pub invitation_code: String,

pub invitee_uma: String,
}
18 changes: 18 additions & 0 deletions lightspark/src/objects/claim_uma_invitation_output.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
use crate::types::entity_wrapper::EntityWrapper;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ClaimUmaInvitationOutput {
#[serde(rename = "claim_uma_invitation_output_invitation")]
pub invitation: EntityWrapper,
}

pub const FRAGMENT: &str = "
fragment ClaimUmaInvitationOutputFragment on ClaimUmaInvitationOutput {
__typename
claim_uma_invitation_output_invitation: invitation {
id
}
}
";
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
use crate::objects::region_code::RegionCode;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ClaimUmaInvitationWithIncentivesInput {
pub invitation_code: String,

pub invitee_uma: String,

pub invitee_phone_hash: String,

pub invitee_region: RegionCode,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
use crate::types::entity_wrapper::EntityWrapper;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ClaimUmaInvitationWithIncentivesOutput {
#[serde(rename = "claim_uma_invitation_with_incentives_output_invitation")]
pub invitation: EntityWrapper,
}

pub const FRAGMENT: &str = "
fragment ClaimUmaInvitationWithIncentivesOutputFragment on ClaimUmaInvitationWithIncentivesOutput {
__typename
claim_uma_invitation_with_incentives_output_invitation: invitation {
id
}
}
";
12 changes: 12 additions & 0 deletions lightspark/src/objects/create_invitation_with_incentives_input.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
use crate::objects::region_code::RegionCode;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct CreateInvitationWithIncentivesInput {
pub inviter_uma: String,

pub inviter_phone_hash: String,

pub inviter_region: RegionCode,
}
18 changes: 18 additions & 0 deletions lightspark/src/objects/create_invitation_with_incentives_output.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
use crate::types::entity_wrapper::EntityWrapper;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct CreateInvitationWithIncentivesOutput {
#[serde(rename = "create_invitation_with_incentives_output_invitation")]
pub invitation: EntityWrapper,
}

pub const FRAGMENT: &str = "
fragment CreateInvitationWithIncentivesOutputFragment on CreateInvitationWithIncentivesOutput {
__typename
create_invitation_with_incentives_output_invitation: invitation {
id
}
}
";
7 changes: 7 additions & 0 deletions lightspark/src/objects/create_uma_invitation_input.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright ©, 2023-present, Lightspark Group, Inc. - All Rights Reserved
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct CreateUmaInvitationInput {
pub inviter_uma: String,
}
Loading