From c6d1c3fc9dd8b92922760d363e5793d76657f46d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Granh=C3=A3o?= <32176319+danielgranhao@users.noreply.github.com> Date: Tue, 3 Dec 2024 12:10:07 +0000 Subject: [PATCH] Implement fiat topup setup (#118) * Implement fiat topup setup * Add referral code parameter * Rename `FiatTopupInfo` to `FiatTopupSetupInfo` * Add `source_iban` param to `complete_topup_setup` * Update schema --- crow/src/lib.rs | 107 ++++++++++++++++--- graphql/schemas/operations.graphql | 28 +++++ graphql/schemas/schema_wallet_read.graphql | 113 +++++++-------------- graphql/src/schema.rs | 16 +++ 4 files changed, 171 insertions(+), 93 deletions(-) diff --git a/crow/src/lib.rs b/crow/src/lib.rs index 71a478d..b245389 100644 --- a/crow/src/lib.rs +++ b/crow/src/lib.rs @@ -1,8 +1,9 @@ use graphql::perro::{ensure, permanent_failure}; use graphql::schema::list_uncompleted_topups::{topup_status_enum, ListUncompletedTopupsTopup}; use graphql::schema::{ - hide_topup, list_uncompleted_topups, register_notification_token, register_topup, HideTopup, - ListUncompletedTopups, RegisterNotificationToken, RegisterTopup, + complete_topup_setup, hide_topup, list_uncompleted_topups, register_notification_token, + start_topup_setup, CompleteTopupSetup, HideTopup, ListUncompletedTopups, + RegisterNotificationToken, StartTopupSetup, }; use graphql::{build_client, parse_from_rfc3339, post_blocking, ExchangeRate}; use honeybadger::Auth; @@ -10,6 +11,7 @@ use std::sync::Arc; use std::time::SystemTime; use graphql::perro::runtime_error; +use graphql::schema::complete_topup_setup::CompleteTopupSetupCompleteTopupSetup; pub use isocountry::CountryCode; pub use isolanguage_1::LanguageCode; @@ -63,6 +65,58 @@ pub struct TopupInfo { pub error: Option, } +pub struct FiatTopupSetupChallenge { + pub id: String, + pub challenge: String, +} + +/// Information about a fiat top-up registration +#[derive(Debug, Clone, PartialEq)] +pub struct FiatTopupSetupInfo { + pub order_id: String, + /// The user should transfer fiat from this IBAN + pub debitor_iban: String, + /// This reference should be included in the fiat transfer reference + pub creditor_reference: String, + /// The user should transfer fiat to this IBAN + pub creditor_iban: String, + pub creditor_bank_name: String, + pub creditor_bank_street: String, + pub creditor_bank_postal_code: String, + pub creditor_bank_town: String, + pub creditor_bank_country: String, + pub creditor_bank_bic: String, + pub creditor_name: String, + pub creditor_street: String, + pub creditor_postal_code: String, + pub creditor_town: String, + pub creditor_country: String, + pub currency: String, +} + +impl From for FiatTopupSetupInfo { + fn from(value: CompleteTopupSetupCompleteTopupSetup) -> Self { + Self { + order_id: value.id, + debitor_iban: value.debitor_iban, + creditor_reference: value.creditor_reference, + creditor_iban: value.creditor_iban, + creditor_bank_name: value.creditor_bank_name, + creditor_bank_street: value.creditor_bank_street, + creditor_bank_postal_code: value.creditor_bank_postal_code, + creditor_bank_town: value.creditor_bank_town, + creditor_bank_country: value.creditor_bank_country, + creditor_bank_bic: value.creditor_bank_bic, + creditor_name: value.creditor_name, + creditor_street: value.creditor_street, + creditor_postal_code: value.creditor_postal_code, + creditor_town: value.creditor_town, + creditor_country: value.creditor_country, + currency: value.currency, + } + } +} + pub struct OfferManager { backend_url: String, auth: Arc, @@ -73,28 +127,49 @@ impl OfferManager { Self { backend_url, auth } } - pub fn register_topup( + pub fn start_topup_setup( &self, - order_id: String, + node_pubkey: String, + provider: String, + source_iban: String, + user_currency: String, email: Option, referral_code: Option, - ) -> graphql::Result<()> { - let variables = register_topup::Variables { - order_id, + ) -> graphql::Result { + let variables = start_topup_setup::Variables { email, + node_pubkey, + provider, referral_code, + source_iban, + user_currency, }; let access_token = self.auth.query_token()?; let client = build_client(Some(&access_token))?; - let data = post_blocking::(&client, &self.backend_url, variables)?; - ensure!( - matches!( - data.register_topup, - Some(register_topup::RegisterTopupRegisterTopup { .. }) - ), - permanent_failure("Backend rejected topup registration") - ); - Ok(()) + let data = post_blocking::(&client, &self.backend_url, variables)?; + + Ok(FiatTopupSetupChallenge { + id: data.start_topup_setup.id, + challenge: data.start_topup_setup.challenge, + }) + } + + pub fn complete_topup_setup( + &self, + id: String, + signed_challenge: String, + source_iban: String, + ) -> graphql::Result { + let variables = complete_topup_setup::Variables { + id, + signed_challenge, + source_iban, + }; + let access_token = self.auth.query_token()?; + let client = build_client(Some(&access_token))?; + let data = post_blocking::(&client, &self.backend_url, variables)?; + + Ok(data.complete_topup_setup.into()) } pub fn register_notification_token( diff --git a/graphql/schemas/operations.graphql b/graphql/schemas/operations.graphql index 0746d73..0e77f0b 100644 --- a/graphql/schemas/operations.graphql +++ b/graphql/schemas/operations.graphql @@ -190,3 +190,31 @@ mutation DisableLightningAddresses($addresses: [String!]!) { mutation EnableLightningAddresses($addresses: [String!]!) { enable_lightning_addresses(addresses: $addresses) } + +mutation StartTopupSetup($email: String, $node_pubkey: String!, $provider: String!, $referralCode: String, $source_iban: String!, $user_currency: String!) { + start_topup_setup(email: $email, node_pubkey: $node_pubkey, provider: $provider, referralCode: $referralCode, source_iban: $source_iban, user_currency: $user_currency) { + id + challenge + } +} + +mutation CompleteTopupSetup($id: String!, $signedChallenge: String!, $sourceIban: String!) { + complete_topup_setup(id: $id, signed_challenge: $signedChallenge, source_iban: $sourceIban) { + id + debitorIban + creditorReference + creditorIban + creditorBankName + creditorBankStreet + creditorBankPostalCode + creditorBankTown + creditorBankCountry + creditorBankBic + creditorName + creditorStreet + creditorPostalCode + creditorTown + creditorCountry + currency + } +} diff --git a/graphql/schemas/schema_wallet_read.graphql b/graphql/schemas/schema_wallet_read.graphql index a47fa4f..a744c20 100644 --- a/graphql/schemas/schema_wallet_read.graphql +++ b/graphql/schemas/schema_wallet_read.graphql @@ -58,6 +58,25 @@ enum ChallengeSignatureType { SECP256K1 } +type CompleteTopupSetupResponse { + creditorBankBic: String! + creditorBankCountry: String! + creditorBankName: String! + creditorBankPostalCode: String! + creditorBankStreet: String! + creditorBankTown: String! + creditorCountry: String! + creditorIban: String! + creditorName: String! + creditorPostalCode: String! + creditorReference: String! + creditorStreet: String! + creditorTown: String! + currency: String! + debitorIban: String! + id: String! +} + type CreateBackupResponse { schemaName: String schemaVersion: String @@ -199,6 +218,11 @@ type SessionPermit { walletPubKeyId: String } +type StartTopupSetupResponse { + challenge: String! + id: String! +} + """ Boolean expression to compare columns of type "String". All fields are combined with logical 'AND'. """ @@ -316,7 +340,7 @@ unique or primary key constraints on table "accepted_terms_conditions" """ enum accepted_terms_conditions_constraint { """ - unique or primary key constraint on columns "id", "service" + unique or primary key constraint on columns "service", "id" """ accepted_terms_conditions_pkey } @@ -521,26 +545,6 @@ enum country_select_column { name } -""" -Streaming cursor of the table "country" -""" -input country_stream_cursor_input { - """Stream column input with initial value""" - initial_value: country_stream_cursor_value_input! - - """cursor ordering""" - ordering: cursor_ordering -} - -"""Initial value of the column from where the streaming should start""" -input country_stream_cursor_value_input { - callingCode: String - countryCode: String - currencyCode: bpchar - currencyName: String - name: String -} - """ columns and relationships of "currency" """ @@ -697,6 +701,7 @@ type mutation_root { accept_terms_conditions_v2(args: AcceptTermsConditionsV2Input): AcceptTermsConditionsV2Response accept_wallet_acl_by_pk(pk_columns: AcceptWalletPkRequestInput!): WalletAcl assign_lightning_address: LightningAddressResponse + complete_topup_setup(id: String!, signed_challenge: String!, source_iban: String!): CompleteTopupSetupResponse! create_backup(encryptedBackup: String!, schemaName: String!, schemaVersion: String!): CreateBackupResponse disable_lightning_addresses(addresses: [String!]!): Void enable_lightning_addresses(addresses: [String!]!): Void @@ -728,13 +733,14 @@ type mutation_root { refresh_session(refreshToken: String!): TokenContainer refresh_session_v2(refreshToken: String!): SessionPermit register_notification_token(language: String!, notificationToken: String!): Token - register_topup(email: String, orderId: String!): RegisterTopupResponse + register_topup(email: String, orderId: String!, referralCode: String): RegisterTopupResponse report_payment_telemetry(events: PaymentTelemetryEventsInput, telemetryId: String!): ReportPaymentTelemetryResponse request_phone_number_verification(encryptedNumber: String!, number: String!): Void start_prepared_session(challenge: String!, challengeSignature: String!, challengeSignatureType: ChallengeSignatureType, preparedPermissionToken: String!): TokenContainer start_prepared_session_v2(challenge: String!, challengeSignature: String!, challengeSignatureType: ChallengeSignatureType, preparedPermissionToken: String!): SessionPermit start_session(authPubKey: String!, challenge: String!, challengeSignature: String!, challengeSignatureType: ChallengeSignatureType, signedAuthPubKey: String!, walletPubKey: String!): TokenContainer start_session_v2(authPubKey: String!, challenge: String!, challengeSignature: String!, challengeSignatureType: ChallengeSignatureType, signedAuthPubKey: String!, walletPubKey: String!): SessionPermit + start_topup_setup(email: String, node_pubkey: String!, provider: String!, referralCode: String, source_iban: String!, user_currency: String!): StartTopupSetupResponse! submit_lnurl_pay_invoice(id: String!, invoice: String): Void verify_phone_number(number: String!, otp: String!): Void } @@ -801,9 +807,7 @@ type query_root { backup_service_version: String consumer_service_version: String - """ - fetch data from the table: "country" - """ + """Get information about all countries supported by lipa""" country( """distinct select on columns""" distinct_on: [country_select_column!] @@ -821,12 +825,10 @@ type query_root { where: country_bool_exp ): [country!]! - """fetch data from the table: "country" using primary key columns""" + """Get information about a specific country supported by lipa""" country_by_pk(countryCode: String!): country - """ - fetch data from the table: "currency" - """ + """Get exchange rates for all currencies supported by lipa""" currency( """distinct select on columns""" distinct_on: [currency_select_column!] @@ -844,7 +846,7 @@ type query_root { where: currency_bool_exp ): [currency!]! - """fetch data from the table: "currency" using primary key columns""" + """Get exchange rate for a specific currency supported by lipa""" currency_by_pk( """ISO 4217""" currencyCode: String! @@ -878,9 +880,7 @@ type query_root { prepare_wallet_session(challenge: String!, ownerPubKeyId: String!, signature: String!): String sms_service_version: String - """ - fetch data from the table: "token" - """ + """TEST COMMENT""" token( """distinct select on columns""" distinct_on: [token_select_column!] @@ -1001,46 +1001,7 @@ type subscription_root { where: accepted_terms_conditions_bool_exp ): [accepted_terms_conditions!]! - """ - fetch data from the table: "country" - """ - country( - """distinct select on columns""" - distinct_on: [country_select_column!] - - """limit the number of rows returned""" - limit: Int - - """skip the first n rows. Use only with order_by""" - offset: Int - - """sort the rows by one or more columns""" - order_by: [country_order_by!] - - """filter the rows returned""" - where: country_bool_exp - ): [country!]! - - """fetch data from the table: "country" using primary key columns""" - country_by_pk(countryCode: String!): country - - """ - fetch data from the table in a streaming manner: "country" - """ - country_stream( - """maximum number of rows returned in a single batch""" - batch_size: Int! - - """cursor to stream the results returned by the query""" - cursor: [country_stream_cursor_input]! - - """filter the rows returned""" - where: country_bool_exp - ): [country!]! - - """ - fetch data from the table: "currency" - """ + """Get exchange rates for all currencies supported by lipa""" currency( """distinct select on columns""" distinct_on: [currency_select_column!] @@ -1058,7 +1019,7 @@ type subscription_root { where: currency_bool_exp ): [currency!]! - """fetch data from the table: "currency" using primary key columns""" + """Get exchange rate for a specific currency supported by lipa""" currency_by_pk( """ISO 4217""" currencyCode: String! @@ -1112,9 +1073,7 @@ type subscription_root { where: lightning_address_bool_exp ): [lightning_address!]! - """ - fetch data from the table: "token" - """ + """TEST COMMENT""" token( """distinct select on columns""" distinct_on: [token_select_column!] diff --git a/graphql/src/schema.rs b/graphql/src/schema.rs index 014206d..1a88b3c 100644 --- a/graphql/src/schema.rs +++ b/graphql/src/schema.rs @@ -230,3 +230,19 @@ pub struct DisableLightningAddresses; response_derives = "Debug" )] pub struct EnableLightningAddresses; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "schemas/schema_wallet_read.graphql", + query_path = "schemas/operations.graphql", + response_derives = "Debug" +)] +pub struct StartTopupSetup; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "schemas/schema_wallet_read.graphql", + query_path = "schemas/operations.graphql", + response_derives = "Debug" +)] +pub struct CompleteTopupSetup;