diff --git a/README.md b/README.md index 97ef465..ac3efa0 100644 --- a/README.md +++ b/README.md @@ -25,4 +25,4 @@ important analytics data about payments to the backend. This data is pseudonymiz ## Pigeon Pigeons excel in orientation and have a remarkable ability to navigate addresses. -The library allows to register Lightning addresses and processing incoming payments sent to a Lightning address. +The library allows to register Lightning addresses and phone numbers as well as processing incoming payments sent to an address or number. diff --git a/graphql/schemas/operations.graphql b/graphql/schemas/operations.graphql index 6b4df05..64fca0b 100644 --- a/graphql/schemas/operations.graphql +++ b/graphql/schemas/operations.graphql @@ -48,12 +48,12 @@ mutation AcceptTermsAndConditions($serviceProvider: String!, $version: Int!) { } query GetTermsAndConditionsStatus($serviceProvider: ServiceProviderEnum!) { - get_terms_conditions_status(args: {service_provider: $serviceProvider}) { - serviceProvider - acceptedTerms - acceptDate - version - } + get_terms_conditions_status(args: {service_provider: $serviceProvider}) { + serviceProvider + acceptedTerms + acceptDate + version + } } # Employee @@ -130,7 +130,7 @@ query ListUncompletedTopups { query MigrationBalance($nodePubKey: String) { migration_balance(nodePubKey: $nodePubKey) { - balanceAmountSat + balanceAmountSat } } @@ -160,11 +160,25 @@ mutation ReportPaymentTelemetry($telemetryId: String!, $events: PaymentTelemetry mutation AssignLightningAddress { assign_lightning_address { - address - assignedAt + address + assignedAt } } mutation SubmitLnurlPayInvoice($id: String!, $invoice: String!) { submit_lnurl_pay_invoice(id: $id, invoice: $invoice) } + +mutation RequestPhoneNumberVerification($number: String!) { + request_phone_number_verification(number: $number) +} + +mutation VerifyPhoneNumber($number: String!, $otp: String!) { + verify_phone_number(number: $number, otp: $otp) +} + +query VerifiedPhoneNumber { + verified_phone_number { + phoneNumber + } +} diff --git a/graphql/schemas/schema_wallet_read.graphql b/graphql/schemas/schema_wallet_read.graphql index 3146dad..5543101 100644 --- a/graphql/schemas/schema_wallet_read.graphql +++ b/graphql/schemas/schema_wallet_read.graphql @@ -721,6 +721,16 @@ type mutation_root { recover_backup(schemaName: String!): RecoverBackupResponse refresh_session(refreshToken: String!): TokenContainer refresh_session_v2(refreshToken: String!): SessionPermit + """ + Allows registering even if a previous registration is verified or pending verification. + """ + request_phone_number_verification(number: String!): Void + + """ + If a distinct phone number was previously registered, expire it in case this + new one gets verified. + """ + verify_phone_number(number: String!, otp: String!): Void register_notification_token(language: String!, notificationToken: String!): Token register_topup(email: String, orderId: String!): RegisterTopupResponse report_payment_telemetry(events: PaymentTelemetryEventsInput, telemetryId: String!): ReportPaymentTelemetryResponse @@ -816,6 +826,12 @@ type query_root { """fetch data from the table: "country" using primary key columns""" country_by_pk(countryCode: String!): country + """ + Returns the PhoneNumberResponse corresponding to the VERIFIED registration. + If there's no VERIFIED registration, it returns null. + """ + verified_phone_number: PhoneNumberResponse + """ fetch data from the table: "currency" """ @@ -940,6 +956,10 @@ type query_root { wallet_acl_by_pk(id: uuid!): wallet_acl } +type PhoneNumberResponse { + phoneNumber: String! +} + enum service_enum { LIPA_WALLET POCKET_EXCHANGE diff --git a/graphql/src/schema.rs b/graphql/src/schema.rs index 0d6b6a2..945a808 100644 --- a/graphql/src/schema.rs +++ b/graphql/src/schema.rs @@ -190,3 +190,27 @@ pub struct AssignLightningAddress; response_derives = "Debug" )] pub struct SubmitLnurlPayInvoice; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "schemas/schema_wallet_read.graphql", + query_path = "schemas/operations.graphql", + response_derives = "Debug" +)] +pub struct RequestPhoneNumberVerification; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "schemas/schema_wallet_read.graphql", + query_path = "schemas/operations.graphql", + response_derives = "Debug" +)] +pub struct VerifyPhoneNumber; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "schemas/schema_wallet_read.graphql", + query_path = "schemas/operations.graphql", + response_derives = "Debug" +)] +pub struct VerifiedPhoneNumber; diff --git a/pigeon/src/lib.rs b/pigeon/src/lib.rs index b4329c0..803b1b4 100644 --- a/pigeon/src/lib.rs +++ b/pigeon/src/lib.rs @@ -1,8 +1,13 @@ use graphql::perro::OptionToError; +use graphql::schema::VerifiedPhoneNumber; use graphql::schema::{ assign_lightning_address, submit_lnurl_pay_invoice, AssignLightningAddress, SubmitLnurlPayInvoice, }; +use graphql::schema::{ + request_phone_number_verification, verified_phone_number, verify_phone_number, + RequestPhoneNumberVerification, VerifyPhoneNumber, +}; use graphql::{build_async_client, post}; use honeybadger::asynchronous::Auth; @@ -38,3 +43,48 @@ pub async fn submit_lnurl_pay_invoice( .await?; Ok(()) } + +pub async fn request_phone_number_verification( + backend_url: &str, + auth: &Auth, + number: String, +) -> graphql::Result<()> { + let token = auth.query_token().await?; + let client = build_async_client(Some(&token))?; + let _data = post::( + &client, + backend_url, + request_phone_number_verification::Variables { number }, + ) + .await?; + Ok(()) +} + +pub async fn verify_phone_number( + backend_url: &str, + auth: &Auth, + number: String, + otp: String, +) -> graphql::Result<()> { + let token = auth.query_token().await?; + let client = build_async_client(Some(&token))?; + let _data = post::( + &client, + backend_url, + verify_phone_number::Variables { number, otp }, + ) + .await?; + Ok(()) +} + +pub async fn query_verified_phone_number( + backend_url: &str, + auth: &Auth, +) -> graphql::Result> { + let token = auth.query_token().await?; + let client = build_async_client(Some(&token))?; + let data = + post::(&client, backend_url, verified_phone_number::Variables {}) + .await?; + Ok(data.verified_phone_number.map(|n| n.phone_number)) +} diff --git a/pigeon/tests/integration_tests.rs b/pigeon/tests/integration_tests.rs index 9415c99..1c848b2 100644 --- a/pigeon/tests/integration_tests.rs +++ b/pigeon/tests/integration_tests.rs @@ -2,7 +2,7 @@ use bitcoin::Network; use honeybadger::asynchronous::Auth; use honeybadger::secrets::{derive_keys, generate_keypair, generate_mnemonic}; use honeybadger::AuthLevel; -use pigeon::assign_lightning_address; +use pigeon::{assign_lightning_address, submit_lnurl_pay_invoice}; use simplelog::TestLogger; use std::env; use std::sync::Once; @@ -33,6 +33,19 @@ async fn test_assigning_lightning_address() { assert_ne!(address, address_for_another_user); } +#[tokio::test] +async fn test_submit_lnurl_pay_invoice() { + let (backend_url, auth) = build_client(); + submit_lnurl_pay_invoice( + &backend_url, + &auth, + "5fab1a65-3486-4dfd-bba8-dad2c1a1b98e".to_string(), + "invoice".to_string(), + ) + .await + .unwrap(); +} + fn build_client() -> (String, Auth) { println!("Generating keys ..."); let mnemonic = generate_mnemonic();