From f967f680d6962dce710b2cd6729b2d9a2aa507df Mon Sep 17 00:00:00 2001 From: eshanvaid Date: Wed, 2 Aug 2023 10:24:44 +0530 Subject: [PATCH 1/5] feat: list transactions --- src/app/operations/user.rs | 19 + src/cli/commands.rs | 13 + src/cli/runner.rs | 10 + src/client/gql/queries/transactions.gql | 59 + src/client/gql/schema.gql | 2066 ++++++++++++----------- src/client/queries.rs | 17 + src/client/requests/me.rs | 39 +- 7 files changed, 1272 insertions(+), 951 deletions(-) create mode 100644 src/client/gql/queries/transactions.gql diff --git a/src/app/operations/user.rs b/src/app/operations/user.rs index 8b1368d..0fb78cf 100644 --- a/src/app/operations/user.rs +++ b/src/app/operations/user.rs @@ -18,6 +18,25 @@ impl App { Ok(()) } + pub async fn list_transactions( + &self, + after: Option, + before: Option, + last: Option, + first: Option, + wallet_ids: Option>>, + ) -> anyhow::Result<()> { + let result = self + .client + .list_transactions(after, before, last, first, wallet_ids) + .await + .context("Error occurred while fetching transactions")?; + + println!("{:?}", result); + + Ok(()) + } + pub async fn set_username(&self, username: String) -> anyhow::Result<()> { self.client .set_username(username) diff --git a/src/cli/commands.rs b/src/cli/commands.rs index 4cec041..e757db1 100644 --- a/src/cli/commands.rs +++ b/src/cli/commands.rs @@ -32,6 +32,19 @@ pub enum Command { Logout, /// Execute Me query Me, + // Lists all transactions of user + Transactions { + #[clap(short, long)] + after: Option, + #[clap(short, long)] + before: Option, + #[clap(short, long)] + last: Option, + #[clap(short, long)] + first: Option, + #[clap(long, use_value_delimiter = true)] + wallet_ids: Option>>, + }, /// Get WalletId for an account DefaultWallet { #[clap(value_parser)] diff --git a/src/cli/runner.rs b/src/cli/runner.rs index 5c240a4..9c852c1 100644 --- a/src/cli/runner.rs +++ b/src/cli/runner.rs @@ -20,6 +20,16 @@ pub async fn run() -> anyhow::Result<()> { Command::Me => { app.me().await?; } + Command::Transactions { + after, + before, + last, + first, + wallet_ids, + } => { + app.list_transactions(after, before, last, first, wallet_ids) + .await?; + } Command::DefaultWallet { username } => { app.default_wallet(username).await?; } diff --git a/src/client/gql/queries/transactions.gql b/src/client/gql/queries/transactions.gql new file mode 100644 index 0000000..7aab65c --- /dev/null +++ b/src/client/gql/queries/transactions.gql @@ -0,0 +1,59 @@ +query Transactions($after: String, $before: String, $first: Int, $last: Int, $walletIds: [WalletId]) { + me { + defaultAccount { + __typename + transactions(after: $after, before: $before, first: $first, last: $last, walletIds: $walletIds) { + edges { + cursor + node { + createdAt + direction + id + initiationVia { + __typename + ... on InitiationViaIntraLedger { + counterPartyUsername + counterPartyWalletId + } + ... on InitiationViaLn { + paymentHash + } + ... on InitiationViaOnChain { + address + } + } + memo + settlementAmount + settlementCurrency + settlementDisplayAmount + settlementDisplayCurrency + settlementDisplayFee + settlementFee + settlementPrice { + base + currencyUnit + formattedAmount + offset + } + settlementVia { + __typename + ... on SettlementViaIntraLedger { + counterPartyUsername + counterPartyWalletId + } + ... on SettlementViaLn { + preImage + paymentSecret + } + ... on SettlementViaOnChain { + transactionHash + vout + } + } + status + } + } + } + } + } +} \ No newline at end of file diff --git a/src/client/gql/schema.gql b/src/client/gql/schema.gql index 865cdb4..bf002dc 100644 --- a/src/client/gql/schema.gql +++ b/src/client/gql/schema.gql @@ -1,1293 +1,1459 @@ -type GraphQLApplicationError implements Error { - message: String! - path: [String] - code: String -} - -interface Error { - message: String! - path: [String] - code: String -} - -type ConsumerAccount implements Account { - id: ID! - wallets: [Wallet!]! +interface Account { + csvTransactions(walletIds: [WalletId!]!): String! defaultWalletId: WalletId! displayCurrency: DisplayCurrency! + id: ID! level: AccountLevel! - realtimePrice: RealtimePrice! - - # return CSV stream, base64 encoded, of the list of transactions in the wallet - csvTransactions(walletIds: [WalletId!]!): String! limits: AccountLimits! - - # List the quiz questions of the consumer account - quiz: [Quiz!]! - - # A list of all transactions associated with walletIds optionally passed. + realtimePrice: RealtimePrice! transactions( - # Returns the items in the list that come after the specified cursor. + """Returns the items in the list that come after the specified cursor.""" after: String - # Returns the first n items from the list. - first: Int - - # Returns the items in the list that come before the specified cursor. + """Returns the items in the list that come before the specified cursor.""" before: String - # Returns the last n items from the list. + """Returns the first n items from the list.""" + first: Int + + """Returns the last n items from the list.""" last: Int walletIds: [WalletId] ): TransactionConnection + wallets: [Wallet!]! } -interface Account { - id: ID! - wallets: [Wallet!]! - defaultWalletId: WalletId! - displayCurrency: DisplayCurrency! - level: AccountLevel! - realtimePrice: RealtimePrice! - csvTransactions(walletIds: [WalletId!]!): String! - limits: AccountLimits! - transactions( - # Returns the items in the list that come after the specified cursor. - after: String +type AccountDeletePayload { + errors: [Error!]! + success: Boolean! +} - # Returns the first n items from the list. - first: Int +enum AccountLevel { + ONE + TWO + ZERO +} - # Returns the items in the list that come before the specified cursor. - before: String +interface AccountLimit { + """The rolling time interval in seconds that the limits would apply for.""" + interval: Seconds - # Returns the last n items from the list. - last: Int - walletIds: [WalletId] - ): TransactionConnection + """ + The amount of cents remaining below the limit for the current 24 hour period. + """ + remainingLimit: CentAmount + + """The current maximum limit for a given 24 hour period.""" + totalLimit: CentAmount! } -# A generic wallet which stores value in one of our supported currencies. -interface Wallet { - id: ID! +type AccountLimits { + """ + Limits for converting between currencies among a account's own wallets. + """ + convert: [AccountLimit!]! + + """Limits for sending to other internal accounts.""" + internalSend: [AccountLimit!]! + + """Limits for withdrawing to external onchain or lightning destinations.""" + withdrawal: [AccountLimit!]! +} + +input AccountUpdateDefaultWalletIdInput { + walletId: WalletId! +} + +type AccountUpdateDefaultWalletIdPayload { + account: ConsumerAccount + errors: [Error!]! +} + +input AccountUpdateDisplayCurrencyInput { + currency: DisplayCurrency! +} + +type AccountUpdateDisplayCurrencyPayload { + account: ConsumerAccount + errors: [Error!]! +} + +"""An Opaque Bearer token""" +scalar AuthToken + +type AuthTokenPayload { + authToken: AuthToken + errors: [Error!]! + totpRequired: Boolean +} + +""" +A wallet belonging to an account which contains a BTC balance and a list of transactions. +""" +type BTCWallet implements Wallet { accountId: ID! - walletCurrency: WalletCurrency! + + """A balance stored in BTC.""" balance: SignedAmount! + id: ID! + + """An unconfirmed incoming onchain balance.""" pendingIncomingBalance: SignedAmount! - # Transactions are ordered anti-chronologically, - # ie: the newest transaction will be first + """A list of BTC transactions associated with this wallet.""" transactions( - # Returns the items in the list that come after the specified cursor. + """Returns the items in the list that come after the specified cursor.""" after: String - # Returns the first n items from the list. - first: Int - - # Returns the items in the list that come before the specified cursor. + """Returns the items in the list that come before the specified cursor.""" before: String - # Returns the last n items from the list. + """Returns the first n items from the list.""" + first: Int + + """Returns the last n items from the list.""" last: Int ): TransactionConnection - - # Transactions are ordered anti-chronologically, - # ie: the newest transaction will be first transactionsByAddress( - # Returns the items in the list that come after the specified cursor. - after: String + """Returns the items that include this address.""" + address: OnChainAddress! - # Returns the first n items from the list. - first: Int + """Returns the items in the list that come after the specified cursor.""" + after: String - # Returns the items in the list that come before the specified cursor. + """Returns the items in the list that come before the specified cursor.""" before: String - # Returns the last n items from the list. - last: Int + """Returns the first n items from the list.""" + first: Int - # Returns the items that include this address. - address: OnChainAddress! + """Returns the last n items from the list.""" + last: Int ): TransactionConnection + walletCurrency: WalletCurrency! } -enum WalletCurrency { - BTC - USD +type BuildInformation { + buildTime: Timestamp + commitHash: String + helmRevision: Int } -# An amount (of a currency) that can be negative (e.g. in a transaction) -scalar SignedAmount - -# A connection to a list of items. -type TransactionConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - - # A list of edges. - edges: [TransactionEdge!] +type CaptchaCreateChallengePayload { + errors: [Error!]! + result: CaptchaCreateChallengeResult } -# Information about pagination in a connection. -type PageInfo { - # When paginating forwards, are there more items? - hasNextPage: Boolean! - - # When paginating backwards, are there more items? - hasPreviousPage: Boolean! - - # When paginating backwards, the cursor to continue. - startCursor: String +type CaptchaCreateChallengeResult { + challengeCode: String! + failbackMode: Boolean! + id: String! + newCaptcha: Boolean! +} - # When paginating forwards, the cursor to continue. - endCursor: String +input CaptchaRequestAuthCodeInput { + challengeCode: String! + channel: PhoneCodeChannelType + phone: Phone! + secCode: String! + validationCode: String! } -# An edge in a connection. -type TransactionEdge { - # The item at the end of the edge - node: Transaction! +"""(Positive) Cent amount (1/100 of a dollar)""" +scalar CentAmount - # A cursor for use in pagination - cursor: String! +type CentAmountPayload { + amount: CentAmount + errors: [Error!]! } -# Give details about an individual transaction. -# Galoy have a smart routing system which is automatically -# settling intraledger when both the payer and payee use the same wallet -# therefore it's possible the transactions is being initiated onchain -# or with lightning but settled intraledger. -type Transaction { +type ConsumerAccount implements Account { + """ + return CSV stream, base64 encoded, of the list of transactions in the wallet + """ + csvTransactions(walletIds: [WalletId!]!): String! + defaultWalletId: WalletId! + displayCurrency: DisplayCurrency! id: ID! + level: AccountLevel! + limits: AccountLimits! - # From which protocol the payment has been initiated. - initiationVia: InitiationVia! + """List the quiz questions of the consumer account""" + quiz: [Quiz!]! + realtimePrice: RealtimePrice! - # To which protocol the payment has settled on. - settlementVia: SettlementVia! + """ + A list of all transactions associated with walletIds optionally passed. + """ + transactions( + """Returns the items in the list that come after the specified cursor.""" + after: String - # Amount of the settlement currency sent or received. - settlementAmount: SignedAmount! - settlementFee: SignedAmount! + """Returns the items in the list that come before the specified cursor.""" + before: String - # Price in WALLETCURRENCY/SETTLEMENTUNIT at time of settlement. - settlementPrice: PriceOfOneSettlementMinorUnitInDisplayMinorUnit! + """Returns the first n items from the list.""" + first: Int - # Wallet currency for transaction. - settlementCurrency: WalletCurrency! - settlementDisplayAmount: SignedDisplayMajorAmount! - settlementDisplayFee: SignedDisplayMajorAmount! - settlementDisplayCurrency: DisplayCurrency! - direction: TxDirection! - status: TxStatus! - memo: Memo - createdAt: Timestamp! + """Returns the last n items from the list.""" + last: Int + walletIds: [WalletId] + ): TransactionConnection + wallets: [Wallet!]! } -union InitiationVia = - InitiationViaIntraLedger - | InitiationViaLn - | InitiationViaOnChain +""" +An alias name that a user can set for a wallet (with which they have transactions) +""" +scalar ContactAlias -type InitiationViaIntraLedger { - counterPartyWalletId: WalletId - counterPartyUsername: Username +type Coordinates { + latitude: Float! + longitude: Float! } -# Unique identifier of a wallet -scalar WalletId - -# Unique identifier of a user -scalar Username - -type InitiationViaLn { - paymentHash: PaymentHash! +type Country { + id: CountryCode! + supportedAuthChannels: [PhoneCodeChannelType!]! } -scalar PaymentHash +"""A CCA2 country code (ex US, FR, etc)""" +scalar CountryCode -type InitiationViaOnChain { - address: OnChainAddress! +type Currency { + flag: String! + fractionDigits: Int! + id: ID! + name: String! + symbol: String! } -# An address for an on-chain bitcoin destination -scalar OnChainAddress +type DepositFeesInformation { + minBankFee: String! -union SettlementVia = - SettlementViaIntraLedger - | SettlementViaLn - | SettlementViaOnChain + """below this amount minBankFee will be charged""" + minBankFeeThreshold: String! -type SettlementViaIntraLedger { - counterPartyWalletId: WalletId + """ratio to charge as basis points above minBankFeeThreshold amount""" + ratio: String! +} - # Settlement destination: Could be null if the payee does not have a username - counterPartyUsername: Username +input DeviceNotificationTokenCreateInput { + deviceToken: String! } -type SettlementViaLn { - paymentSecret: LnPaymentSecret - @deprecated( - reason: "Shifting property to 'preImage' to improve granularity of the LnPaymentSecret type" - ) - preImage: LnPaymentPreImage +"""Display currency of an account""" +scalar DisplayCurrency + +type Email { + address: EmailAddress + verified: Boolean } -scalar LnPaymentSecret +"""Email address""" +scalar EmailAddress -scalar LnPaymentPreImage +""" +An id to be passed between registrationInitiate and registrationValidate for confirming email +""" +scalar EmailRegistrationId -type SettlementViaOnChain { - transactionHash: OnChainTxHash - vout: Int +interface Error { + code: String + message: String! + path: [String] } -scalar OnChainTxHash +enum ExchangeCurrencyUnit { + BTCSAT + USDCENT +} -# Price of 1 sat or 1 usd cent in base/offset. To calculate, use: `base / 10^offset` -type PriceOfOneSettlementMinorUnitInDisplayMinorUnit implements PriceInterface { - base: SafeInt! - offset: Int! - currencyUnit: String! @deprecated(reason: "Deprecated due to type renaming") - formattedAmount: String! - @deprecated(reason: "Deprecated please use `base / 10^offset`") +"""Feedback shared with our user""" +scalar Feedback + +input FeedbackSubmitInput { + feedback: Feedback! } -interface PriceInterface { - base: SafeInt! - offset: Int! - currencyUnit: String! @deprecated(reason: "Deprecated due to type renaming") +type FeesInformation { + deposit: DepositFeesInformation! } -# Non-fractional signed whole numeric value between -(2^53) + 1 and 2^53 - 1 -scalar SafeInt +""" +Provides global settings for the application which might have an impact for the user. +""" +type Globals { + buildInformation: BuildInformation! + feesInformation: FeesInformation! -# A string amount (of a currency) that can be negative (e.g. in a transaction) -scalar SignedDisplayMajorAmount + """ + The domain name for lightning addresses accepted by this Galoy instance + """ + lightningAddressDomain: String! + lightningAddressDomainAliases: [String!]! -# Display currency of an account -scalar DisplayCurrency + """ + Which network (mainnet, testnet, regtest, signet) this instance is running on. + """ + network: Network! -enum TxDirection { - SEND - RECEIVE + """ + A list of public keys for the running lightning nodes. + This can be used to know if an invoice belongs to one of our nodes. + """ + nodesIds: [String!]! + + """A list of countries and their supported auth channels""" + supportedCountries: [Country!]! } -enum TxStatus { +type GraphQLApplicationError implements Error { + code: String + message: String! + path: [String] +} + +"""Hex-encoded string of 32 bytes""" +scalar Hex32Bytes + +union InitiationVia = InitiationViaIntraLedger | InitiationViaLn | InitiationViaOnChain + +type InitiationViaIntraLedger { + counterPartyUsername: Username + counterPartyWalletId: WalletId +} + +type InitiationViaLn { + paymentHash: PaymentHash! +} + +type InitiationViaOnChain { + address: OnChainAddress! +} + +input IntraLedgerPaymentSendInput { + """Amount in satoshis.""" + amount: SatAmount! + + """Optional memo to be attached to the payment.""" + memo: Memo + recipientWalletId: WalletId! + + """The wallet ID of the sender.""" + walletId: WalletId! +} + +type IntraLedgerUpdate { + amount: SatAmount! + displayCurrencyPerSat: Float! + txNotificationType: TxNotificationType! + usdPerSat: Float! @deprecated(reason: "updated over displayCurrencyPerSat") + walletId: WalletId! +} + +input IntraLedgerUsdPaymentSendInput { + """Amount in cents.""" + amount: CentAmount! + + """Optional memo to be attached to the payment.""" + memo: Memo + recipientWalletId: WalletId! + + """The wallet ID of the sender.""" + walletId: WalletId! +} + +enum InvoicePaymentStatus { + EXPIRED + PAID PENDING - SUCCESS - FAILURE } -# Text field in a lightning payment transaction -scalar Memo +scalar Language -# Timestamp field, serialized as Unix time (the number of seconds since the Unix epoch) -scalar Timestamp +type LnInvoice { + paymentHash: PaymentHash! + paymentRequest: LnPaymentRequest! + paymentSecret: LnPaymentSecret! + satoshis: SatAmount +} -enum AccountLevel { - ZERO - ONE - TWO +input LnInvoiceCreateInput { + """Amount in satoshis.""" + amount: SatAmount! + + """Optional invoice expiration time in minutes.""" + expiresIn: Minutes + + """Optional memo for the lightning invoice.""" + memo: Memo + + """Wallet ID for a BTC wallet belonging to the current account.""" + walletId: WalletId! } -type RealtimePrice { - id: ID! +input LnInvoiceCreateOnBehalfOfRecipientInput { + """Amount in satoshis.""" + amount: SatAmount! + descriptionHash: Hex32Bytes - # Unix timestamp (number of seconds elapsed since January 1, 1970 00:00:00 UTC) - timestamp: Timestamp! - denominatorCurrency: DisplayCurrency! - btcSatPrice: PriceOfOneSatInMinorUnit! - usdCentPrice: PriceOfOneUsdCentInMinorUnit! + """Optional invoice expiration time in minutes.""" + expiresIn: Minutes + + """Optional memo for the lightning invoice.""" + memo: Memo + + """Wallet ID for a BTC wallet which belongs to any account.""" + recipientWalletId: WalletId! } -# Price of 1 sat in base/offset. To calculate, use: `base / 10^offset` -type PriceOfOneSatInMinorUnit implements PriceInterface { - base: SafeInt! - offset: Int! - currencyUnit: String! @deprecated(reason: "Deprecated due to type renaming") +input LnInvoiceFeeProbeInput { + paymentRequest: LnPaymentRequest! + walletId: WalletId! } -# Price of 1 usd cent in base/offset. To calculate, use: `base / 10^offset` -type PriceOfOneUsdCentInMinorUnit implements PriceInterface { - base: SafeInt! - offset: Int! - currencyUnit: String! @deprecated(reason: "Deprecated due to type renaming") +type LnInvoicePayload { + errors: [Error!]! + invoice: LnInvoice } -type AccountLimits { - # Limits for withdrawing to external onchain or lightning destinations. - withdrawal: [AccountLimit!]! +input LnInvoicePaymentInput { + """Optional memo to associate with the lightning invoice.""" + memo: Memo - # Limits for sending to other internal accounts. - internalSend: [AccountLimit!]! + """Payment request representing the invoice which is being paid.""" + paymentRequest: LnPaymentRequest! - # Limits for converting between currencies among a account's own wallets. - convert: [AccountLimit!]! + """ + Wallet ID with sufficient balance to cover amount of invoice. Must belong to the account of the current user. + """ + walletId: WalletId! } -interface AccountLimit { - # The current maximum limit for a given 24 hour period. - totalLimit: CentAmount! +input LnInvoicePaymentStatusInput { + paymentRequest: LnPaymentRequest! +} - # The amount of cents remaining below the limit for the current 24 hour period. - remainingLimit: CentAmount +type LnInvoicePaymentStatusPayload { + errors: [Error!]! + status: InvoicePaymentStatus +} - # The rolling time interval in seconds that the limits would apply for. - interval: Seconds +type LnNoAmountInvoice { + paymentHash: PaymentHash! + paymentRequest: LnPaymentRequest! + paymentSecret: LnPaymentSecret! } -# (Positive) Cent amount (1/100 of a dollar) -scalar CentAmount +input LnNoAmountInvoiceCreateInput { + """Optional invoice expiration time in minutes.""" + expiresIn: Minutes -# (Positive) amount of seconds -scalar Seconds + """Optional memo for the lightning invoice.""" + memo: Memo -type Quiz { - id: ID! + """ + ID for either a USD or BTC wallet belonging to the account of the current user. + """ + walletId: WalletId! +} + +input LnNoAmountInvoiceCreateOnBehalfOfRecipientInput { + """Optional invoice expiration time in minutes.""" + expiresIn: Minutes - # The reward in Satoshis for the quiz question + """Optional memo for the lightning invoice.""" + memo: Memo + + """ + ID for either a USD or BTC wallet which belongs to the account of any user. + """ + recipientWalletId: WalletId! +} + +input LnNoAmountInvoiceFeeProbeInput { amount: SatAmount! - completed: Boolean! + paymentRequest: LnPaymentRequest! + walletId: WalletId! } -# (Positive) Satoshi amount -scalar SatAmount +type LnNoAmountInvoicePayload { + errors: [Error!]! + invoice: LnNoAmountInvoice +} -# A wallet belonging to an account which contains a BTC balance and a list of transactions. -type BTCWallet implements Wallet { - id: ID! - accountId: ID! - walletCurrency: WalletCurrency! +input LnNoAmountInvoicePaymentInput { + """Amount to pay in satoshis.""" + amount: SatAmount! - # A balance stored in BTC. - balance: SignedAmount! + """Optional memo to associate with the lightning invoice.""" + memo: Memo - # An unconfirmed incoming onchain balance. - pendingIncomingBalance: SignedAmount! + """Payment request representing the invoice which is being paid.""" + paymentRequest: LnPaymentRequest! - # A list of BTC transactions associated with this wallet. - transactions( - # Returns the items in the list that come after the specified cursor. - after: String + """ + Wallet ID with sufficient balance to cover amount defined in mutation request. Must belong to the account of the current user. + """ + walletId: WalletId! +} - # Returns the first n items from the list. - first: Int +input LnNoAmountUsdInvoiceFeeProbeInput { + amount: CentAmount! + paymentRequest: LnPaymentRequest! + walletId: WalletId! +} - # Returns the items in the list that come before the specified cursor. - before: String +input LnNoAmountUsdInvoicePaymentInput { + """Amount to pay in USD cents.""" + amount: CentAmount! - # Returns the last n items from the list. - last: Int - ): TransactionConnection - transactionsByAddress( - # Returns the items in the list that come after the specified cursor. - after: String + """Optional memo to associate with the lightning invoice.""" + memo: Memo - # Returns the first n items from the list. - first: Int + """Payment request representing the invoice which is being paid.""" + paymentRequest: LnPaymentRequest! - # Returns the items in the list that come before the specified cursor. - before: String + """ + Wallet ID with sufficient balance to cover amount defined in mutation request. Must belong to the account of the current user. + """ + walletId: WalletId! +} + +scalar LnPaymentPreImage + +"""BOLT11 lightning invoice payment request with the amount included""" +scalar LnPaymentRequest + +scalar LnPaymentSecret + +type LnUpdate { + paymentHash: PaymentHash! + status: InvoicePaymentStatus! + walletId: WalletId! +} + +input LnUsdInvoiceCreateInput { + """Amount in USD cents.""" + amount: CentAmount! + + """Optional invoice expiration time in minutes.""" + expiresIn: Minutes + + """Optional memo for the lightning invoice.""" + memo: Memo + + """Wallet ID for a USD wallet belonging to the current user.""" + walletId: WalletId! +} + +input LnUsdInvoiceCreateOnBehalfOfRecipientInput { + """Amount in USD cents.""" + amount: CentAmount! + descriptionHash: Hex32Bytes + + """Optional invoice expiration time in minutes.""" + expiresIn: Minutes + + """ + Optional memo for the lightning invoice. Acts as a note to the recipient. + """ + memo: Memo + + """Wallet ID for a USD wallet which belongs to the account of any user.""" + recipientWalletId: WalletId! +} + +input LnUsdInvoiceFeeProbeInput { + paymentRequest: LnPaymentRequest! + walletId: WalletId! +} + +type MapInfo { + coordinates: Coordinates! + title: String! +} + +type MapMarker { + mapInfo: MapInfo! + username: Username +} + +"""Text field in a lightning payment transaction""" +scalar Memo + +"""(Positive) amount of minutes""" +scalar Minutes + +type MobileVersions { + currentSupported: Int! + minSupported: Int! + platform: String! +} + +type Mutation { + accountDelete: AccountDeletePayload! + accountUpdateDefaultWalletId(input: AccountUpdateDefaultWalletIdInput!): AccountUpdateDefaultWalletIdPayload! + accountUpdateDisplayCurrency(input: AccountUpdateDisplayCurrencyInput!): AccountUpdateDisplayCurrencyPayload! + captchaCreateChallenge: CaptchaCreateChallengePayload! + captchaRequestAuthCode(input: CaptchaRequestAuthCodeInput!): SuccessPayload! + deviceNotificationTokenCreate(input: DeviceNotificationTokenCreateInput!): SuccessPayload! + feedbackSubmit(input: FeedbackSubmitInput!): SuccessPayload! + + """ + Actions a payment which is internal to the ledger e.g. it does + not use onchain/lightning. Returns payment status (success, + failed, pending, already_paid). + """ + intraLedgerPaymentSend(input: IntraLedgerPaymentSendInput!): PaymentSendPayload! + + """ + Actions a payment which is internal to the ledger e.g. it does + not use onchain/lightning. Returns payment status (success, + failed, pending, already_paid). + """ + intraLedgerUsdPaymentSend(input: IntraLedgerUsdPaymentSendInput!): PaymentSendPayload! + + """ + Returns a lightning invoice for an associated wallet. + When invoice is paid the value will be credited to a BTC wallet. + Expires after 'expiresIn' or 24 hours. + """ + lnInvoiceCreate(input: LnInvoiceCreateInput!): LnInvoicePayload! + + """ + Returns a lightning invoice for an associated wallet. + When invoice is paid the value will be credited to a BTC wallet. + Expires after 'expiresIn' or 24 hours. + """ + lnInvoiceCreateOnBehalfOfRecipient(input: LnInvoiceCreateOnBehalfOfRecipientInput!): LnInvoicePayload! + lnInvoiceFeeProbe(input: LnInvoiceFeeProbeInput!): SatAmountPayload! + + """ + Pay a lightning invoice using a balance from a wallet which is owned by the account of the current user. + Provided wallet can be USD or BTC and must have sufficient balance to cover amount in lightning invoice. + Returns payment status (success, failed, pending, already_paid). + """ + lnInvoicePaymentSend(input: LnInvoicePaymentInput!): PaymentSendPayload! + + """ + Returns a lightning invoice for an associated wallet. + Can be used to receive any supported currency value (currently USD or BTC). + Expires after 'expiresIn' or 24 hours for BTC invoices or 5 minutes for USD invoices. + """ + lnNoAmountInvoiceCreate(input: LnNoAmountInvoiceCreateInput!): LnNoAmountInvoicePayload! + + """ + Returns a lightning invoice for an associated wallet. + Can be used to receive any supported currency value (currently USD or BTC). + Expires after 'expiresIn' or 24 hours for BTC invoices or 5 minutes for USD invoices. + """ + lnNoAmountInvoiceCreateOnBehalfOfRecipient(input: LnNoAmountInvoiceCreateOnBehalfOfRecipientInput!): LnNoAmountInvoicePayload! + lnNoAmountInvoiceFeeProbe(input: LnNoAmountInvoiceFeeProbeInput!): SatAmountPayload! + + """ + Pay a lightning invoice using a balance from a wallet which is owned by the account of the current user. + Provided wallet must be BTC and must have sufficient balance to cover amount specified in mutation request. + Returns payment status (success, failed, pending, already_paid). + """ + lnNoAmountInvoicePaymentSend(input: LnNoAmountInvoicePaymentInput!): PaymentSendPayload! + lnNoAmountUsdInvoiceFeeProbe(input: LnNoAmountUsdInvoiceFeeProbeInput!): CentAmountPayload! + + """ + Pay a lightning invoice using a balance from a wallet which is owned by the account of the current user. + Provided wallet must be USD and have sufficient balance to cover amount specified in mutation request. + Returns payment status (success, failed, pending, already_paid). + """ + lnNoAmountUsdInvoicePaymentSend(input: LnNoAmountUsdInvoicePaymentInput!): PaymentSendPayload! + + """ + Returns a lightning invoice denominated in satoshis for an associated wallet. + When invoice is paid the equivalent value at invoice creation will be credited to a USD wallet. + Expires after 'expiresIn' or 5 minutes (short expiry time because there is a USD/BTC exchange rate + associated with the amount). + """ + lnUsdInvoiceCreate(input: LnUsdInvoiceCreateInput!): LnInvoicePayload! + + """ + Returns a lightning invoice denominated in satoshis for an associated wallet. + When invoice is paid the equivalent value at invoice creation will be credited to a USD wallet. + Expires after 'expiresIn' or 5 minutes (short expiry time because there is a USD/BTC exchange rate + associated with the amount). + """ + lnUsdInvoiceCreateOnBehalfOfRecipient(input: LnUsdInvoiceCreateOnBehalfOfRecipientInput!): LnInvoicePayload! + lnUsdInvoiceFeeProbe(input: LnUsdInvoiceFeeProbeInput!): SatAmountPayload! + onChainAddressCreate(input: OnChainAddressCreateInput!): OnChainAddressPayload! + onChainAddressCurrent(input: OnChainAddressCurrentInput!): OnChainAddressPayload! + onChainPaymentSend(input: OnChainPaymentSendInput!): PaymentSendPayload! + onChainPaymentSendAll(input: OnChainPaymentSendAllInput!): PaymentSendPayload! + onChainUsdPaymentSend(input: OnChainUsdPaymentSendInput!): PaymentSendPayload! + onChainUsdPaymentSendAsBtcDenominated(input: OnChainUsdPaymentSendAsBtcDenominatedInput!): PaymentSendPayload! + quizCompleted(input: QuizCompletedInput!): QuizCompletedPayload! + userContactUpdateAlias(input: UserContactUpdateAliasInput!): UserContactUpdateAliasPayload! @deprecated(reason: "will be moved to AccountContact") + userEmailDelete: UserEmailDeletePayload! + userEmailRegistrationInitiate(input: UserEmailRegistrationInitiateInput!): UserEmailRegistrationInitiatePayload! + userEmailRegistrationValidate(input: UserEmailRegistrationValidateInput!): UserEmailRegistrationValidatePayload! + userLogin(input: UserLoginInput!): AuthTokenPayload! + userLoginUpgrade(input: UserLoginUpgradeInput!): UpgradePayload! + userLogout(input: UserLogoutInput!): SuccessPayload! + userPhoneDelete: UserPhoneDeletePayload! + userPhoneRegistrationInitiate(input: UserPhoneRegistrationInitiateInput!): SuccessPayload! + userPhoneRegistrationValidate(input: UserPhoneRegistrationValidateInput!): UserPhoneRegistrationValidatePayload! + userQuizQuestionUpdateCompleted(input: UserQuizQuestionUpdateCompletedInput!): UserQuizQuestionUpdateCompletedPayload! @deprecated(reason: "Use QuizCompletedMutation instead") + userRequestAuthCode(input: UserRequestAuthCodeInput!): SuccessPayload! + userTotpDelete(input: UserTotpDeleteInput!): UserTotpDeletePayload! + userTotpRegistrationInitiate(input: UserTotpRegistrationInitiateInput!): UserTotpRegistrationInitiatePayload! + userTotpRegistrationValidate(input: UserTotpRegistrationValidateInput!): UserTotpRegistrationValidatePayload! + userUpdateLanguage(input: UserUpdateLanguageInput!): UserUpdateLanguagePayload! + userUpdateUsername(input: UserUpdateUsernameInput!): UserUpdateUsernamePayload! @deprecated(reason: "Username will be moved to @Handle in Accounts. Also SetUsername naming should be used instead of UpdateUsername to reflect the idempotency of Handles") +} + +type MyUpdatesPayload { + errors: [Error!]! + me: User + update: UserUpdate +} + +enum Network { + mainnet + regtest + signet + testnet +} + +"""An address for an on-chain bitcoin destination""" +scalar OnChainAddress - # Returns the last n items from the list. - last: Int +input OnChainAddressCreateInput { + walletId: WalletId! +} - # Returns the items that include this address. - address: OnChainAddress! - ): TransactionConnection +input OnChainAddressCurrentInput { + walletId: WalletId! } -# A wallet belonging to an account which contains a USD balance and a list of transactions. -type UsdWallet implements Wallet { - id: ID! - accountId: ID! - walletCurrency: WalletCurrency! - balance: SignedAmount! +type OnChainAddressPayload { + address: OnChainAddress + errors: [Error!]! +} - # An unconfirmed incoming onchain balance. - pendingIncomingBalance: SignedAmount! - transactions( - # Returns the items in the list that come after the specified cursor. - after: String +input OnChainPaymentSendAllInput { + address: OnChainAddress! + memo: Memo + speed: PayoutSpeed = FAST + targetConfirmations: TargetConfirmations = 0 @deprecated(reason: "Ignored - will be replaced") + walletId: WalletId! +} - # Returns the first n items from the list. - first: Int +input OnChainPaymentSendInput { + address: OnChainAddress! + amount: SatAmount! + memo: Memo + speed: PayoutSpeed = FAST + targetConfirmations: TargetConfirmations = 0 @deprecated(reason: "Ignored - will be replaced") + walletId: WalletId! +} - # Returns the items in the list that come before the specified cursor. - before: String +type OnChainTxFee { + amount: SatAmount! + targetConfirmations: TargetConfirmations! @deprecated(reason: "Ignored - will be removed") +} - # Returns the last n items from the list. - last: Int - ): TransactionConnection - transactionsByAddress( - # Returns the items in the list that come after the specified cursor. - after: String +scalar OnChainTxHash - # Returns the first n items from the list. - first: Int +type OnChainUpdate { + amount: SatAmount! + displayCurrencyPerSat: Float! + txHash: OnChainTxHash! + txNotificationType: TxNotificationType! + usdPerSat: Float! @deprecated(reason: "updated over displayCurrencyPerSat") + walletId: WalletId! +} - # Returns the items in the list that come before the specified cursor. - before: String +input OnChainUsdPaymentSendAsBtcDenominatedInput { + address: OnChainAddress! + amount: SatAmount! + memo: Memo + speed: PayoutSpeed = FAST + targetConfirmations: TargetConfirmations = 0 @deprecated(reason: "Ignored - will be replaced") + walletId: WalletId! +} - # Returns the last n items from the list. - last: Int +input OnChainUsdPaymentSendInput { + address: OnChainAddress! + amount: CentAmount! + memo: Memo + speed: PayoutSpeed = FAST + targetConfirmations: TargetConfirmations = 0 @deprecated(reason: "Ignored - will be replaced") + walletId: WalletId! +} - # Returns the items that include this address. - address: OnChainAddress! - ): TransactionConnection +type OnChainUsdTxFee { + amount: CentAmount! + targetConfirmations: TargetConfirmations! @deprecated(reason: "Ignored - will be removed") } type OneDayAccountLimit implements AccountLimit { - # The current maximum limit for a given 24 hour period. - totalLimit: CentAmount! + """ + The rolling time interval value in seconds for the current 24 hour period. + """ + interval: Seconds - # The amount of cents remaining below the limit for the current 24 hour period. + """ + The amount of cents remaining below the limit for the current 24 hour period. + """ remainingLimit: CentAmount - # The rolling time interval value in seconds for the current 24 hour period. - interval: Seconds + """The current maximum limit for a given 24 hour period.""" + totalLimit: CentAmount! } -type Query { - globals: Globals - usernameAvailable(username: Username!): Boolean - userDefaultWalletId(username: Username!): WalletId! - @deprecated(reason: "will be migrated to AccountDefaultWalletId") - accountDefaultWallet( - username: Username! - walletCurrency: WalletCurrency - ): PublicWallet! - businessMapMarkers: [MapMarker] - currencyList: [Currency!]! - mobileVersions: [MobileVersions] - quizQuestions: [QuizQuestion] - @deprecated( - reason: "TODO: remove. we don't need a non authenticated version of this query. the users can only do the query while authenticated" - ) - btcPrice(currency: DisplayCurrency! = "USD"): Price - @deprecated(reason: "Deprecated in favor of realtimePrice") - - # Returns 1 Sat and 1 Usd Cent price for the given currency - realtimePrice(currency: DisplayCurrency = "USD"): RealtimePrice! - btcPriceList(range: PriceGraphRange!): [PricePoint] - lnInvoicePaymentStatus( - input: LnInvoicePaymentStatusInput! - ): LnInvoicePaymentStatusPayload! - me: User - onChainTxFee( - walletId: WalletId! - address: OnChainAddress! - amount: SatAmount! - speed: PayoutSpeed = FAST - ): OnChainTxFee! - onChainUsdTxFee( - walletId: WalletId! - address: OnChainAddress! - amount: CentAmount! - speed: PayoutSpeed = FAST - ): OnChainUsdTxFee! - onChainUsdTxFeeAsBtcDenominated( - walletId: WalletId! - address: OnChainAddress! - amount: SatAmount! - speed: PayoutSpeed = FAST - ): OnChainUsdTxFee! -} +"""An authentication code valid for a single use""" +scalar OneTimeAuthCode -# Provides global settings for the application which might have an impact for the user. -type Globals { - # A list of public keys for the running lightning nodes. - # This can be used to know if an invoice belongs to one of our nodes. - nodesIds: [String!]! +"""Information about pagination in a connection.""" +type PageInfo { + """When paginating forwards, the cursor to continue.""" + endCursor: String - # Which network (mainnet, testnet, regtest, signet) this instance is running on. - network: Network! - buildInformation: BuildInformation! + """When paginating forwards, are there more items?""" + hasNextPage: Boolean! - # The domain name for lightning addresses accepted by this Galoy instance - lightningAddressDomain: String! + """When paginating backwards, are there more items?""" + hasPreviousPage: Boolean! - # A list of countries and their supported auth channels - supportedCountries: [Country!]! - lightningAddressDomainAliases: [String!]! + """When paginating backwards, the cursor to continue.""" + startCursor: String } -enum Network { - mainnet - testnet - signet - regtest +scalar PaymentHash + +type PaymentSendPayload { + errors: [Error!]! + status: PaymentSendResult } -type BuildInformation { - commitHash: String - buildTime: Timestamp - helmRevision: Int +enum PaymentSendResult { + ALREADY_PAID + FAILURE + PENDING + SUCCESS } -type Country { - id: CountryCode! - supportedAuthChannels: [PhoneCodeChannelType!]! +enum PayoutSpeed { + FAST } -# A CCA2 country code (ex US, FR, etc) -scalar CountryCode +"""Phone number which includes country code""" +scalar Phone enum PhoneCodeChannelType { SMS WHATSAPP } -# A public view of a generic wallet which stores value in one of our supported currencies. -type PublicWallet { - id: ID! - walletCurrency: WalletCurrency! -} - -type MapMarker { - username: Username - mapInfo: MapInfo! +""" +Price amount expressed in base/offset. To calculate, use: `base / 10^offset` +""" +type Price { + base: SafeInt! + currencyUnit: String! + formattedAmount: String! + offset: Int! } -type MapInfo { - title: String! - coordinates: Coordinates! +"""The range for the X axis in the BTC price graph""" +enum PriceGraphRange { + FIVE_YEARS + ONE_DAY + ONE_MONTH + ONE_WEEK + ONE_YEAR } -type Coordinates { - longitude: Float! - latitude: Float! +input PriceInput { + amount: SatAmount! + amountCurrencyUnit: ExchangeCurrencyUnit! + priceCurrencyUnit: ExchangeCurrencyUnit! } -type Currency { - id: ID! - symbol: String! - name: String! - flag: String! - fractionDigits: Int! +interface PriceInterface { + base: SafeInt! + currencyUnit: String! @deprecated(reason: "Deprecated due to type renaming") + offset: Int! } -type MobileVersions { - platform: String! - currentSupported: Int! - minSupported: Int! +"""Price of 1 sat in base/offset. To calculate, use: `base / 10^offset`""" +type PriceOfOneSatInMinorUnit implements PriceInterface { + base: SafeInt! + currencyUnit: String! @deprecated(reason: "Deprecated due to type renaming") + offset: Int! } -type QuizQuestion { - id: ID! - - # The earn reward in Satoshis for the quiz question - earnAmount: SatAmount! +""" +Price of 1 sat or 1 usd cent in base/offset. To calculate, use: `base / 10^offset` +""" +type PriceOfOneSettlementMinorUnitInDisplayMinorUnit implements PriceInterface { + base: SafeInt! + currencyUnit: String! @deprecated(reason: "Deprecated due to type renaming") + formattedAmount: String! @deprecated(reason: "Deprecated please use `base / 10^offset`") + offset: Int! } -# Price amount expressed in base/offset. To calculate, use: `base / 10^offset` -type Price { +""" +Price of 1 usd cent in base/offset. To calculate, use: `base / 10^offset` +""" +type PriceOfOneUsdCentInMinorUnit implements PriceInterface { base: SafeInt! + currencyUnit: String! @deprecated(reason: "Deprecated due to type renaming") offset: Int! - currencyUnit: String! - formattedAmount: String! +} + +type PricePayload { + errors: [Error!]! + price: Price } type PricePoint { - # Unix timestamp (number of seconds elapsed since January 1, 1970 00:00:00 UTC) - timestamp: Timestamp! price: Price! -} -# The range for the X axis in the BTC price graph -enum PriceGraphRange { - ONE_DAY - ONE_WEEK - ONE_MONTH - ONE_YEAR - FIVE_YEARS + """ + Unix timestamp (number of seconds elapsed since January 1, 1970 00:00:00 UTC) + """ + timestamp: Timestamp! } -type LnInvoicePaymentStatusPayload { - errors: [Error!]! - status: InvoicePaymentStatus +""" +A public view of a generic wallet which stores value in one of our supported currencies. +""" +type PublicWallet { + id: ID! + walletCurrency: WalletCurrency! } -enum InvoicePaymentStatus { - PENDING - PAID - EXPIRED -} +type Query { + accountDefaultWallet(username: Username!, walletCurrency: WalletCurrency): PublicWallet! + btcPrice(currency: DisplayCurrency! = "USD"): Price @deprecated(reason: "Deprecated in favor of realtimePrice") + btcPriceList(range: PriceGraphRange!): [PricePoint] + businessMapMarkers: [MapMarker] + currencyList: [Currency!]! + globals: Globals + lnInvoicePaymentStatus(input: LnInvoicePaymentStatusInput!): LnInvoicePaymentStatusPayload! + me: User + mobileVersions: [MobileVersions] + onChainTxFee(address: OnChainAddress!, amount: SatAmount!, speed: PayoutSpeed = FAST, targetConfirmations: TargetConfirmations = 0 @deprecated(reason: "Ignored - will be replaced"), walletId: WalletId!): OnChainTxFee! + onChainUsdTxFee(address: OnChainAddress!, amount: CentAmount!, speed: PayoutSpeed = FAST, targetConfirmations: TargetConfirmations = 0 @deprecated(reason: "Ignored - will be replaced"), walletId: WalletId!): OnChainUsdTxFee! + onChainUsdTxFeeAsBtcDenominated(address: OnChainAddress!, amount: SatAmount!, speed: PayoutSpeed = FAST, targetConfirmations: TargetConfirmations = 0 @deprecated(reason: "Ignored - will be replaced"), walletId: WalletId!): OnChainUsdTxFee! + quizQuestions: [QuizQuestion] @deprecated(reason: "TODO: remove. we don't need a non authenticated version of this query. the users can only do the query while authenticated") -input LnInvoicePaymentStatusInput { - paymentRequest: LnPaymentRequest! + """Returns 1 Sat and 1 Usd Cent price for the given currency""" + realtimePrice(currency: DisplayCurrency = "USD"): RealtimePrice! + userDefaultWalletId(username: Username!): WalletId! @deprecated(reason: "will be migrated to AccountDefaultWalletId") + usernameAvailable(username: Username!): Boolean } -# BOLT11 lightning invoice payment request with the amount included -scalar LnPaymentRequest - -type User { +type Quiz { + """The reward in Satoshis for the quiz question""" + amount: SatAmount! + completed: Boolean! id: ID! +} - # Phone number with international calling code. - phone: Phone - - # Optional immutable user friendly identifier. - username: Username - @deprecated(reason: "will be moved to @Handle in Account and Wallet") - - # Preferred language for user. - # When value is 'default' the intent is to use preferred language from OS settings. - language: Language! - - # List the quiz questions the user may have completed. - quizQuestions: [UserQuizQuestion!]! - @deprecated(reason: "use Quiz from Account instead") +input QuizCompletedInput { + id: ID! +} - # Get full list of contacts. - # Can include the transactions associated with each contact. - contacts: [UserContact!]! @deprecated(reason: "will be moved to account") +type QuizCompletedPayload { + errors: [Error!]! + quiz: Quiz +} - # Get single contact details. - # Can include the transactions associated with the contact. - contactByUsername(username: Username!): UserContact! - @deprecated(reason: "will be moved to Accounts") - createdAt: Timestamp! - defaultAccount: Account! +type QuizQuestion { + """The earn reward in Satoshis for the quiz question""" + earnAmount: SatAmount! + id: ID! } -# Phone number which includes country code -scalar Phone +type RealtimePrice { + btcSatPrice: PriceOfOneSatInMinorUnit! + denominatorCurrency: DisplayCurrency! + id: ID! -scalar Language + """ + Unix timestamp (number of seconds elapsed since January 1, 1970 00:00:00 UTC) + """ + timestamp: Timestamp! + usdCentPrice: PriceOfOneUsdCentInMinorUnit! +} -type UserQuizQuestion { - question: QuizQuestion! - completed: Boolean! +input RealtimePriceInput { + currency: DisplayCurrency = "USD" } -type UserContact { - id: Username! +type RealtimePricePayload { + errors: [Error!]! + realtimePrice: RealtimePrice +} - # Actual identifier of the contact. - username: Username! +""" +Non-fractional signed whole numeric value between -(2^53) + 1 and 2^53 - 1 +""" +scalar SafeInt - # Alias the user can set for this contact. - # Only the user can see the alias attached to their contact. - alias: ContactAlias - transactionsCount: Int! +"""(Positive) Satoshi amount""" +scalar SatAmount - # Paginated list of transactions sent to/from this contact. - transactions( - # Returns the items in the list that come after the specified cursor. - after: String +type SatAmountPayload { + amount: SatAmount + errors: [Error!]! +} - # Returns the first n items from the list. - first: Int +"""(Positive) amount of seconds""" +scalar Seconds - # Returns the items in the list that come before the specified cursor. - before: String +union SettlementVia = SettlementViaIntraLedger | SettlementViaLn | SettlementViaOnChain - # Returns the last n items from the list. - last: Int - ): TransactionConnection +type SettlementViaIntraLedger { + """ + Settlement destination: Could be null if the payee does not have a username + """ + counterPartyUsername: Username + counterPartyWalletId: WalletId } -# An alias name that a user can set for a wallet (with which they have transactions) -scalar ContactAlias +type SettlementViaLn { + paymentSecret: LnPaymentSecret @deprecated(reason: "Shifting property to 'preImage' to improve granularity of the LnPaymentSecret type") + preImage: LnPaymentPreImage +} -type OnChainTxFee { - amount: SatAmount! - targetConfirmations: TargetConfirmations! - @deprecated(reason: "Ignored - will be removed") +type SettlementViaOnChain { + transactionHash: OnChainTxHash + vout: Int } -# (Positive) Number of blocks in which the transaction is expected to be confirmed -scalar TargetConfirmations +"""An amount (of a currency) that can be negative (e.g. in a transaction)""" +scalar SignedAmount -enum PayoutSpeed { - FAST +""" +A string amount (of a currency) that can be negative (e.g. in a transaction) +""" +scalar SignedDisplayMajorAmount + +type Subscription { + lnInvoicePaymentStatus(input: LnInvoicePaymentStatusInput!): LnInvoicePaymentStatusPayload! + myUpdates: MyUpdatesPayload! + price(input: PriceInput!): PricePayload! + + """Returns the price of 1 satoshi""" + realtimePrice(input: RealtimePriceInput!): RealtimePricePayload! } -type OnChainUsdTxFee { - amount: CentAmount! - targetConfirmations: TargetConfirmations! - @deprecated(reason: "Ignored - will be removed") +type SuccessPayload { + errors: [Error!]! + success: Boolean } -type Mutation { - userRequestAuthCode(input: UserRequestAuthCodeInput!): SuccessPayload! - userLogin(input: UserLoginInput!): AuthTokenPayload! - userLogout(input: UserLogoutInput!): AuthTokenPayload! - captchaCreateChallenge: CaptchaCreateChallengePayload! - captchaRequestAuthCode(input: CaptchaRequestAuthCodeInput!): SuccessPayload! +""" +(Positive) Number of blocks in which the transaction is expected to be confirmed +""" +scalar TargetConfirmations - # Returns a lightning invoice for an associated wallet. - # When invoice is paid the value will be credited to a BTC wallet. - # Expires after 24 hours. - lnInvoiceCreateOnBehalfOfRecipient( - input: LnInvoiceCreateOnBehalfOfRecipientInput! - ): LnInvoicePayload! - - # Returns a lightning invoice denominated in satoshis for an associated wallet. - # When invoice is paid the equivalent value at invoice creation will be credited to a USD wallet. - # Expires after 5 minutes (short expiry time because there is a USD/BTC exchange rate - # associated with the amount). - lnUsdInvoiceCreateOnBehalfOfRecipient( - input: LnUsdInvoiceCreateOnBehalfOfRecipientInput! - ): LnInvoicePayload! - - # Returns a lightning invoice for an associated wallet. - # Can be used to receive any supported currency value (currently USD or BTC). - # Expires after 24 hours. - lnNoAmountInvoiceCreateOnBehalfOfRecipient( - input: LnNoAmountInvoiceCreateOnBehalfOfRecipientInput! - ): LnNoAmountInvoicePayload! - userLoginUpgrade(input: UserLoginUpgradeInput!): UpgradePayload! - userQuizQuestionUpdateCompleted( - input: UserQuizQuestionUpdateCompletedInput! - ): UserQuizQuestionUpdateCompletedPayload! - @deprecated(reason: "Use QuizCompletedMutation instead") - quizCompleted(input: QuizCompletedInput!): QuizCompletedPayload! - deviceNotificationTokenCreate( - input: DeviceNotificationTokenCreateInput! - ): SuccessPayload! - userUpdateLanguage( - input: UserUpdateLanguageInput! - ): UserUpdateLanguagePayload! - userUpdateUsername( - input: UserUpdateUsernameInput! - ): UserUpdateUsernamePayload! - userContactUpdateAlias( - input: UserContactUpdateAliasInput! - ): UserContactUpdateAliasPayload! - @deprecated(reason: "will be moved to AccountContact") - accountUpdateDefaultWalletId( - input: AccountUpdateDefaultWalletIdInput! - ): AccountUpdateDefaultWalletIdPayload! - accountUpdateDisplayCurrency( - input: AccountUpdateDisplayCurrencyInput! - ): AccountUpdateDisplayCurrencyPayload! - accountDelete: AccountDeletePayload! +""" +Timestamp field, serialized as Unix time (the number of seconds since the Unix epoch) +""" +scalar Timestamp - # Actions a payment which is internal to the ledger e.g. it does - # not use onchain/lightning. Returns payment status (success, - # failed, pending, already_paid). - intraLedgerPaymentSend( - input: IntraLedgerPaymentSendInput! - ): PaymentSendPayload! - - # Actions a payment which is internal to the ledger e.g. it does - # not use onchain/lightning. Returns payment status (success, - # failed, pending, already_paid). - intraLedgerUsdPaymentSend( - input: IntraLedgerUsdPaymentSendInput! - ): PaymentSendPayload! - lnInvoiceFeeProbe(input: LnInvoiceFeeProbeInput!): SatAmountPayload! - lnUsdInvoiceFeeProbe(input: LnUsdInvoiceFeeProbeInput!): SatAmountPayload! - lnNoAmountInvoiceFeeProbe( - input: LnNoAmountInvoiceFeeProbeInput! - ): SatAmountPayload! - lnNoAmountUsdInvoiceFeeProbe( - input: LnNoAmountUsdInvoiceFeeProbeInput! - ): CentAmountPayload! - - # Returns a lightning invoice for an associated wallet. - # When invoice is paid the value will be credited to a BTC wallet. - # Expires after 24 hours. - lnInvoiceCreate(input: LnInvoiceCreateInput!): LnInvoicePayload! +"""A time-based one-time password""" +scalar TotpCode - # Returns a lightning invoice denominated in satoshis for an associated wallet. - # When invoice is paid the equivalent value at invoice creation will be credited to a USD wallet. - # Expires after 5 minutes (short expiry time because there is a USD/BTC exchange rate - # associated with the amount). - lnUsdInvoiceCreate(input: LnUsdInvoiceCreateInput!): LnInvoicePayload! +"""An id to be passed between set and verify for confirming totp""" +scalar TotpRegistrationId - # Returns a lightning invoice for an associated wallet. - # Can be used to receive any supported currency value (currently USD or BTC). - # Expires after 24 hours. - lnNoAmountInvoiceCreate( - input: LnNoAmountInvoiceCreateInput! - ): LnNoAmountInvoicePayload! +"""A secret to generate time-based one-time password""" +scalar TotpSecret - # Pay a lightning invoice using a balance from a wallet which is owned by the account of the current user. - # Provided wallet can be USD or BTC and must have sufficient balance to cover amount in lightning invoice. - # Returns payment status (success, failed, pending, already_paid). - lnInvoicePaymentSend(input: LnInvoicePaymentInput!): PaymentSendPayload! +""" +Give details about an individual transaction. +Galoy have a smart routing system which is automatically +settling intraledger when both the payer and payee use the same wallet +therefore it's possible the transactions is being initiated onchain +or with lightning but settled intraledger. +""" +type Transaction { + createdAt: Timestamp! + direction: TxDirection! + id: ID! - # Pay a lightning invoice using a balance from a wallet which is owned by the account of the current user. - # Provided wallet must be BTC and must have sufficient balance to cover amount specified in mutation request. - # Returns payment status (success, failed, pending, already_paid). - lnNoAmountInvoicePaymentSend( - input: LnNoAmountInvoicePaymentInput! - ): PaymentSendPayload! - - # Pay a lightning invoice using a balance from a wallet which is owned by the account of the current user. - # Provided wallet must be USD and have sufficient balance to cover amount specified in mutation request. - # Returns payment status (success, failed, pending, already_paid). - lnNoAmountUsdInvoicePaymentSend( - input: LnNoAmountUsdInvoicePaymentInput! - ): PaymentSendPayload! - onChainAddressCreate( - input: OnChainAddressCreateInput! - ): OnChainAddressPayload! - onChainAddressCurrent( - input: OnChainAddressCurrentInput! - ): OnChainAddressPayload! - onChainPaymentSend(input: OnChainPaymentSendInput!): PaymentSendPayload! - onChainUsdPaymentSend(input: OnChainUsdPaymentSendInput!): PaymentSendPayload! - onChainUsdPaymentSendAsBtcDenominated( - input: OnChainUsdPaymentSendAsBtcDenominatedInput! - ): PaymentSendPayload! - onChainPaymentSendAll(input: OnChainPaymentSendAllInput!): PaymentSendPayload! -} + """From which protocol the payment has been initiated.""" + initiationVia: InitiationVia! + memo: Memo -type SuccessPayload { - errors: [Error!]! - success: Boolean -} + """Amount of the settlement currency sent or received.""" + settlementAmount: SignedAmount! -input UserRequestAuthCodeInput { - phone: Phone! - channel: PhoneCodeChannelType -} + """Wallet currency for transaction.""" + settlementCurrency: WalletCurrency! + settlementDisplayAmount: SignedDisplayMajorAmount! + settlementDisplayCurrency: DisplayCurrency! + settlementDisplayFee: SignedDisplayMajorAmount! + settlementFee: SignedAmount! -type AuthTokenPayload { - errors: [Error!]! - authToken: AuthToken + """Price in WALLETCURRENCY/SETTLEMENTUNIT at time of settlement.""" + settlementPrice: PriceOfOneSettlementMinorUnitInDisplayMinorUnit! + + """To which protocol the payment has settled on.""" + settlementVia: SettlementVia! + status: TxStatus! } -# An Opaque Bearer token -scalar AuthToken +"""A connection to a list of items.""" +type TransactionConnection { + """A list of edges.""" + edges: [TransactionEdge!] -input UserLoginInput { - phone: Phone! - code: OneTimeAuthCode! + """Information to aid in pagination.""" + pageInfo: PageInfo! } -# An authentication code valid for a single use -scalar OneTimeAuthCode +"""An edge in a connection.""" +type TransactionEdge { + """A cursor for use in pagination""" + cursor: String! -input UserLogoutInput { - authToken: AuthToken! + """The item at the end of the edge""" + node: Transaction! } -type CaptchaCreateChallengePayload { - errors: [Error!]! - result: CaptchaCreateChallengeResult +enum TxDirection { + RECEIVE + SEND } -type CaptchaCreateChallengeResult { - id: String! - challengeCode: String! - newCaptcha: Boolean! - failbackMode: Boolean! +enum TxNotificationType { + IntraLedgerPayment + IntraLedgerReceipt + LnInvoicePaid + OnchainPayment + OnchainReceipt + OnchainReceiptPending } -input CaptchaRequestAuthCodeInput { - phone: Phone! - challengeCode: String! - validationCode: String! - secCode: String! - channel: PhoneCodeChannelType +enum TxStatus { + FAILURE + PENDING + SUCCESS } -type LnInvoicePayload { +type UpgradePayload { + authToken: AuthToken errors: [Error!]! - invoice: LnInvoice + success: Boolean! } -type LnInvoice { - paymentRequest: LnPaymentRequest! - paymentHash: PaymentHash! - paymentSecret: LnPaymentSecret! - satoshis: SatAmount -} +""" +A wallet belonging to an account which contains a USD balance and a list of transactions. +""" +type UsdWallet implements Wallet { + accountId: ID! + balance: SignedAmount! + id: ID! -input LnInvoiceCreateOnBehalfOfRecipientInput { - # Wallet ID for a BTC wallet which belongs to any account. - recipientWalletId: WalletId! + """An unconfirmed incoming onchain balance.""" + pendingIncomingBalance: SignedAmount! + transactions( + """Returns the items in the list that come after the specified cursor.""" + after: String - # Amount in satoshis. - amount: SatAmount! + """Returns the items in the list that come before the specified cursor.""" + before: String - # Optional memo for the lightning invoice. - memo: Memo - descriptionHash: Hex32Bytes -} + """Returns the first n items from the list.""" + first: Int -# Hex-encoded string of 32 bytes -scalar Hex32Bytes + """Returns the last n items from the list.""" + last: Int + ): TransactionConnection + transactionsByAddress( + """Returns the items that include this address.""" + address: OnChainAddress! -input LnUsdInvoiceCreateOnBehalfOfRecipientInput { - # Wallet ID for a USD wallet which belongs to the account of any user. - recipientWalletId: WalletId! + """Returns the items in the list that come after the specified cursor.""" + after: String - # Amount in USD cents. - amount: CentAmount! + """Returns the items in the list that come before the specified cursor.""" + before: String - # Optional memo for the lightning invoice. Acts as a note to the recipient. - memo: Memo - descriptionHash: Hex32Bytes -} + """Returns the first n items from the list.""" + first: Int -type LnNoAmountInvoicePayload { - errors: [Error!]! - invoice: LnNoAmountInvoice + """Returns the last n items from the list.""" + last: Int + ): TransactionConnection + walletCurrency: WalletCurrency! } -type LnNoAmountInvoice { - paymentRequest: LnPaymentRequest! - paymentHash: PaymentHash! - paymentSecret: LnPaymentSecret! -} +type User { + """ + Get single contact details. + Can include the transactions associated with the contact. + """ + contactByUsername(username: Username!): UserContact! @deprecated(reason: "will be moved to Accounts") + + """ + Get full list of contacts. + Can include the transactions associated with each contact. + """ + contacts: [UserContact!]! @deprecated(reason: "will be moved to account") + createdAt: Timestamp! + defaultAccount: Account! -input LnNoAmountInvoiceCreateOnBehalfOfRecipientInput { - # ID for either a USD or BTC wallet which belongs to the account of any user. - recipientWalletId: WalletId! + """Email address""" + email: Email + id: ID! - # Optional memo for the lightning invoice. - memo: Memo -} + """ + Preferred language for user. + When value is 'default' the intent is to use preferred language from OS settings. + """ + language: Language! -type UpgradePayload { - errors: [Error!]! - success: Boolean! - authToken: AuthToken -} + """Phone number with international calling code.""" + phone: Phone -input UserLoginUpgradeInput { - phone: Phone! - code: OneTimeAuthCode! -} + """List the quiz questions the user may have completed.""" + quizQuestions: [UserQuizQuestion!]! @deprecated(reason: "use Quiz from Account instead") -type UserQuizQuestionUpdateCompletedPayload { - errors: [Error!]! - userQuizQuestion: UserQuizQuestion -} + """Whether TOTP is enabled for this user.""" + totpEnabled: Boolean! -input UserQuizQuestionUpdateCompletedInput { - id: ID! + """Optional immutable user friendly identifier.""" + username: Username @deprecated(reason: "will be moved to @Handle in Account and Wallet") } -type QuizCompletedPayload { - errors: [Error!]! - quiz: Quiz -} +type UserContact { + """ + Alias the user can set for this contact. + Only the user can see the alias attached to their contact. + """ + alias: ContactAlias + id: Username! -input QuizCompletedInput { - id: ID! -} + """Paginated list of transactions sent to/from this contact.""" + transactions( + """Returns the items in the list that come after the specified cursor.""" + after: String -input DeviceNotificationTokenCreateInput { - deviceToken: String! -} + """Returns the items in the list that come before the specified cursor.""" + before: String -type UserUpdateLanguagePayload { - errors: [Error!]! - user: User -} + """Returns the first n items from the list.""" + first: Int -input UserUpdateLanguageInput { - language: Language! -} + """Returns the last n items from the list.""" + last: Int + ): TransactionConnection + transactionsCount: Int! -type UserUpdateUsernamePayload { - errors: [Error!]! - user: User + """Actual identifier of the contact.""" + username: Username! } -input UserUpdateUsernameInput { +input UserContactUpdateAliasInput { + alias: ContactAlias! username: Username! } type UserContactUpdateAliasPayload { - errors: [Error!]! contact: UserContact + errors: [Error!]! } -input UserContactUpdateAliasInput { - username: Username! - alias: ContactAlias! -} - -type AccountUpdateDefaultWalletIdPayload { +type UserEmailDeletePayload { errors: [Error!]! - account: ConsumerAccount + me: User } -input AccountUpdateDefaultWalletIdInput { - walletId: WalletId! +input UserEmailRegistrationInitiateInput { + email: EmailAddress! } -type AccountUpdateDisplayCurrencyPayload { +type UserEmailRegistrationInitiatePayload { + emailRegistrationId: EmailRegistrationId errors: [Error!]! - account: ConsumerAccount + me: User } -input AccountUpdateDisplayCurrencyInput { - currency: DisplayCurrency! +input UserEmailRegistrationValidateInput { + code: OneTimeAuthCode! + emailRegistrationId: EmailRegistrationId! } -type AccountDeletePayload { +type UserEmailRegistrationValidatePayload { errors: [Error!]! - success: Boolean! + me: User } -type PaymentSendPayload { - errors: [Error!]! - status: PaymentSendResult +input UserLoginInput { + code: OneTimeAuthCode! + phone: Phone! } -enum PaymentSendResult { - SUCCESS - FAILURE - PENDING - ALREADY_PAID +input UserLoginUpgradeInput { + code: OneTimeAuthCode! + phone: Phone! } -input IntraLedgerPaymentSendInput { - # The wallet ID of the sender. - walletId: WalletId! - recipientWalletId: WalletId! - - # Amount in satoshis. - amount: SatAmount! - - # Optional memo to be attached to the payment. - memo: Memo +input UserLogoutInput { + authToken: AuthToken! } -input IntraLedgerUsdPaymentSendInput { - # The wallet ID of the sender. - walletId: WalletId! - recipientWalletId: WalletId! - - # Amount in cents. - amount: CentAmount! - - # Optional memo to be attached to the payment. - memo: Memo -} +"""Unique identifier of a user""" +scalar Username -type SatAmountPayload { +type UserPhoneDeletePayload { errors: [Error!]! - amount: SatAmount -} - -input LnInvoiceFeeProbeInput { - walletId: WalletId! - paymentRequest: LnPaymentRequest! + me: User } -input LnUsdInvoiceFeeProbeInput { - walletId: WalletId! - paymentRequest: LnPaymentRequest! +input UserPhoneRegistrationInitiateInput { + channel: PhoneCodeChannelType + phone: Phone! } -input LnNoAmountInvoiceFeeProbeInput { - walletId: WalletId! - paymentRequest: LnPaymentRequest! - amount: SatAmount! +input UserPhoneRegistrationValidateInput { + code: OneTimeAuthCode! + phone: Phone! } -type CentAmountPayload { +type UserPhoneRegistrationValidatePayload { errors: [Error!]! - amount: CentAmount + me: User } -input LnNoAmountUsdInvoiceFeeProbeInput { - walletId: WalletId! - paymentRequest: LnPaymentRequest! - amount: CentAmount! +type UserQuizQuestion { + completed: Boolean! + question: QuizQuestion! } -input LnInvoiceCreateInput { - # Wallet ID for a BTC wallet belonging to the current account. - walletId: WalletId! - - # Amount in satoshis. - amount: SatAmount! - - # Optional memo for the lightning invoice. - memo: Memo +input UserQuizQuestionUpdateCompletedInput { + id: ID! } -input LnUsdInvoiceCreateInput { - # Wallet ID for a USD wallet belonging to the current user. - walletId: WalletId! - - # Amount in USD cents. - amount: CentAmount! - - # Optional memo for the lightning invoice. - memo: Memo +type UserQuizQuestionUpdateCompletedPayload { + errors: [Error!]! + userQuizQuestion: UserQuizQuestion } -input LnNoAmountInvoiceCreateInput { - # ID for either a USD or BTC wallet belonging to the account of the current user. - walletId: WalletId! - - # Optional memo for the lightning invoice. - memo: Memo +input UserRequestAuthCodeInput { + channel: PhoneCodeChannelType + phone: Phone! } -input LnInvoicePaymentInput { - # Wallet ID with sufficient balance to cover amount of invoice. Must belong to the account of the current user. - walletId: WalletId! - - # Payment request representing the invoice which is being paid. - paymentRequest: LnPaymentRequest! - - # Optional memo to associate with the lightning invoice. - memo: Memo +input UserTotpDeleteInput { + authToken: AuthToken! } -input LnNoAmountInvoicePaymentInput { - # Wallet ID with sufficient balance to cover amount defined in mutation request. Must belong to the account of the current user. - walletId: WalletId! - - # Payment request representing the invoice which is being paid. - paymentRequest: LnPaymentRequest! - - # Amount to pay in satoshis. - amount: SatAmount! - - # Optional memo to associate with the lightning invoice. - memo: Memo +type UserTotpDeletePayload { + errors: [Error!]! + me: User } -input LnNoAmountUsdInvoicePaymentInput { - # Wallet ID with sufficient balance to cover amount defined in mutation request. Must belong to the account of the current user. - walletId: WalletId! - - # Payment request representing the invoice which is being paid. - paymentRequest: LnPaymentRequest! - - # Amount to pay in USD cents. - amount: CentAmount! - - # Optional memo to associate with the lightning invoice. - memo: Memo +input UserTotpRegistrationInitiateInput { + authToken: AuthToken! } -type OnChainAddressPayload { +type UserTotpRegistrationInitiatePayload { errors: [Error!]! - address: OnChainAddress -} - -input OnChainAddressCreateInput { - walletId: WalletId! + totpRegistrationId: TotpRegistrationId + totpSecret: TotpSecret } -input OnChainAddressCurrentInput { - walletId: WalletId! +input UserTotpRegistrationValidateInput { + authToken: AuthToken! + totpCode: TotpCode! + totpRegistrationId: TotpRegistrationId! } -input OnChainPaymentSendInput { - walletId: WalletId! - address: OnChainAddress! - amount: SatAmount! - speed: PayoutSpeed = FAST - memo: Memo +type UserTotpRegistrationValidatePayload { + errors: [Error!]! + me: User } -input OnChainUsdPaymentSendInput { - walletId: WalletId! - address: OnChainAddress! - amount: CentAmount! - speed: PayoutSpeed = FAST - memo: Memo -} +union UserUpdate = IntraLedgerUpdate | LnUpdate | OnChainUpdate | Price | RealtimePrice -input OnChainUsdPaymentSendAsBtcDenominatedInput { - walletId: WalletId! - address: OnChainAddress! - amount: SatAmount! - speed: PayoutSpeed = FAST - memo: Memo +input UserUpdateLanguageInput { + language: Language! } -input OnChainPaymentSendAllInput { - walletId: WalletId! - address: OnChainAddress! - speed: PayoutSpeed = FAST - memo: Memo +type UserUpdateLanguagePayload { + errors: [Error!]! + user: User } -type Subscription { - myUpdates: MyUpdatesPayload! - price(input: PriceInput!): PricePayload! - - # Returns the price of 1 satoshi - realtimePrice(input: RealtimePriceInput!): RealtimePricePayload! - lnInvoicePaymentStatus( - input: LnInvoicePaymentStatusInput! - ): LnInvoicePaymentStatusPayload! +input UserUpdateUsernameInput { + username: Username! } -type MyUpdatesPayload { +type UserUpdateUsernamePayload { errors: [Error!]! - update: UserUpdate - me: User + user: User } -union UserUpdate = - RealtimePrice - | Price - | LnUpdate - | OnChainUpdate - | IntraLedgerUpdate +""" +A generic wallet which stores value in one of our supported currencies. +""" +interface Wallet { + accountId: ID! + balance: SignedAmount! + id: ID! + pendingIncomingBalance: SignedAmount! -type LnUpdate { - paymentHash: PaymentHash! - status: InvoicePaymentStatus! - walletId: WalletId! -} + """ + Transactions are ordered anti-chronologically, + ie: the newest transaction will be first + """ + transactions( + """Returns the items in the list that come after the specified cursor.""" + after: String -type OnChainUpdate { - txNotificationType: TxNotificationType! - txHash: OnChainTxHash! - amount: SatAmount! - displayCurrencyPerSat: Float! - usdPerSat: Float! @deprecated(reason: "updated over displayCurrencyPerSat") - walletId: WalletId! -} + """Returns the items in the list that come before the specified cursor.""" + before: String -enum TxNotificationType { - OnchainReceipt - OnchainReceiptPending - OnchainPayment - LnInvoicePaid - IntraLedgerReceipt - IntraLedgerPayment -} + """Returns the first n items from the list.""" + first: Int -type IntraLedgerUpdate { - txNotificationType: TxNotificationType! - amount: SatAmount! - displayCurrencyPerSat: Float! - usdPerSat: Float! @deprecated(reason: "updated over displayCurrencyPerSat") - walletId: WalletId! -} + """Returns the last n items from the list.""" + last: Int + ): TransactionConnection -type PricePayload { - errors: [Error!]! - price: Price -} + """ + Transactions are ordered anti-chronologically, + ie: the newest transaction will be first + """ + transactionsByAddress( + """Returns the items that include this address.""" + address: OnChainAddress! -input PriceInput { - amount: SatAmount! - amountCurrencyUnit: ExchangeCurrencyUnit! - priceCurrencyUnit: ExchangeCurrencyUnit! -} + """Returns the items in the list that come after the specified cursor.""" + after: String -enum ExchangeCurrencyUnit { - BTCSAT - USDCENT -} + """Returns the items in the list that come before the specified cursor.""" + before: String -type RealtimePricePayload { - errors: [Error!]! - realtimePrice: RealtimePrice + """Returns the first n items from the list.""" + first: Int + + """Returns the last n items from the list.""" + last: Int + ): TransactionConnection + walletCurrency: WalletCurrency! } -input RealtimePriceInput { - currency: DisplayCurrency = "USD" +enum WalletCurrency { + BTC + USD } + +"""Unique identifier of a wallet""" +scalar WalletId diff --git a/src/client/queries.rs b/src/client/queries.rs index 70a090c..2ec78a5 100644 --- a/src/client/queries.rs +++ b/src/client/queries.rs @@ -13,6 +13,14 @@ type SatAmount = Decimal; type CentAmount = Decimal; type Memo = String; type OnChainAddress = String; +type PaymentHash = String; +type LnPaymentSecret = String; +type LnPaymentPreImage = String; +type OnChainTxHash = String; +type SignedDisplayMajorAmount = String; +type DisplayCurrency = String; +type SafeInt = Decimal; +type Timestamp = Decimal; #[derive(GraphQLQuery)] #[graphql( @@ -101,6 +109,15 @@ pub use self::captcha_request_auth_code::CaptchaRequestAuthCodeInput; pub struct QueryMe; pub use self::query_me::QueryMeMe; +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "src/client/gql/schema.gql", + query_path = "src/client/gql/queries/transactions.gql", + response_derives = "Debug, Serialize, PartialEq" +)] +pub(super) struct Transactions; +pub use self::transactions::TransactionsMeDefaultAccountTransactionsEdges; + #[derive(GraphQLQuery)] #[graphql( schema_path = "src/client/gql/schema.gql", diff --git a/src/client/requests/me.rs b/src/client/requests/me.rs index 27999f3..b9f10a8 100644 --- a/src/client/requests/me.rs +++ b/src/client/requests/me.rs @@ -1,6 +1,9 @@ use crate::client::{ errors::{api_error::ApiError, me_error::MeError, ClientError}, - queries::{query_me, QueryMe, QueryMeMe}, + queries::{ + query_me, transactions, QueryMe, QueryMeMe, Transactions, + TransactionsMeDefaultAccountTransactionsEdges, + }, GaloyClient, }; use graphql_client::reqwest::post_graphql; @@ -17,4 +20,38 @@ impl GaloyClient { let me = response_data.me.ok_or(MeError::FailedToUnwrapMe)?; Ok(me) } + + pub async fn list_transactions( + &self, + after: Option, + before: Option, + last: Option, + first: Option, + wallet_ids: Option>>, + ) -> Result>, ClientError> { + let variables = transactions::Variables { + after, + before, + first, + last, + wallet_ids, + }; + + let response_body = + post_graphql::(&self.graphql_client, &self.api, variables) + .await + .map_err(|err| ApiError::IssueGettingResponse(anyhow::Error::new(err)))?; + + println!("{:?}", response_body); + + let response_data = response_body.data.ok_or(ApiError::IssueParsingResponse)?; + let transactions = response_data + .me + .ok_or(MeError::FailedToUnwrapMe)? + .default_account + .transactions + .ok_or(ApiError::IssueParsingResponse)? //change this error + .edges; + Ok(transactions) + } } From 0699a78ca5e57e00647b03299d69c2a5a2690926 Mon Sep 17 00:00:00 2001 From: eshanvaid Date: Thu, 3 Aug 2023 02:19:39 +0530 Subject: [PATCH 2/5] fix: filter the transactions in app layer --- src/app/operations/user.rs | 30 ++++++++++++++++++++----- src/cli/commands.rs | 14 ++++++------ src/cli/runner.rs | 9 ++++---- src/client/errors/me_error.rs | 2 ++ src/client/gql/queries/transactions.gql | 4 ++-- src/client/requests/me.rs | 24 ++++++++------------ 6 files changed, 49 insertions(+), 34 deletions(-) diff --git a/src/app/operations/user.rs b/src/app/operations/user.rs index 0fb78cf..46c5b5a 100644 --- a/src/app/operations/user.rs +++ b/src/app/operations/user.rs @@ -20,20 +20,40 @@ impl App { pub async fn list_transactions( &self, - after: Option, - before: Option, + // after: Option, + // before: Option, last: Option, first: Option, - wallet_ids: Option>>, + // wallet_ids: Option>>, ) -> anyhow::Result<()> { let result = self .client - .list_transactions(after, before, last, first, wallet_ids) + .list_transactions() .await .context("Error occurred while fetching transactions")?; - println!("{:?}", result); + if let Some(transactions) = result { + let selected_transactions: Vec<_> = if let Some(first) = first { + transactions + .iter() + .take(first.try_into().unwrap()) + .collect() + } else if let Some(last) = last { + let total_transactions = transactions.len(); + transactions + .iter() + .skip(total_transactions.saturating_sub(last.try_into().unwrap())) + .collect() + } else { + transactions.iter().collect() + }; + println!( + "{}", + serde_json::to_string_pretty(&selected_transactions) + .context("Failed to serialize JSON")? + ); + } Ok(()) } diff --git a/src/cli/commands.rs b/src/cli/commands.rs index e757db1..93af608 100644 --- a/src/cli/commands.rs +++ b/src/cli/commands.rs @@ -34,16 +34,16 @@ pub enum Command { Me, // Lists all transactions of user Transactions { - #[clap(short, long)] - after: Option, - #[clap(short, long)] - before: Option, - #[clap(short, long)] + // #[clap(short, long)] + // after: Option, + // #[clap(short, long)] + // before: Option, + #[clap(short, long, conflicts_with("first"))] last: Option, #[clap(short, long)] first: Option, - #[clap(long, use_value_delimiter = true)] - wallet_ids: Option>>, + // #[clap(long, use_value_delimiter = true)] + // wallet_ids: Option>>, }, /// Get WalletId for an account DefaultWallet { diff --git a/src/cli/runner.rs b/src/cli/runner.rs index 9c852c1..6ed3fb6 100644 --- a/src/cli/runner.rs +++ b/src/cli/runner.rs @@ -21,14 +21,13 @@ pub async fn run() -> anyhow::Result<()> { app.me().await?; } Command::Transactions { - after, - before, + // after, + // before, last, first, - wallet_ids, + // wallet_ids, } => { - app.list_transactions(after, before, last, first, wallet_ids) - .await?; + app.list_transactions(last, first).await?; } Command::DefaultWallet { username } => { app.default_wallet(username).await?; diff --git a/src/client/errors/me_error.rs b/src/client/errors/me_error.rs index d3440bd..d7670d7 100644 --- a/src/client/errors/me_error.rs +++ b/src/client/errors/me_error.rs @@ -4,4 +4,6 @@ use thiserror::Error; pub enum MeError { #[error("Failed to unwrap .me")] FailedToUnwrapMe, + #[error("Failed to unwrap transactions")] + FailedToUnwrapTransactions, } diff --git a/src/client/gql/queries/transactions.gql b/src/client/gql/queries/transactions.gql index 7aab65c..b9e41e4 100644 --- a/src/client/gql/queries/transactions.gql +++ b/src/client/gql/queries/transactions.gql @@ -1,8 +1,8 @@ -query Transactions($after: String, $before: String, $first: Int, $last: Int, $walletIds: [WalletId]) { +query Transactions { me { defaultAccount { __typename - transactions(after: $after, before: $before, first: $first, last: $last, walletIds: $walletIds) { + transactions { edges { cursor node { diff --git a/src/client/requests/me.rs b/src/client/requests/me.rs index b9f10a8..86176f1 100644 --- a/src/client/requests/me.rs +++ b/src/client/requests/me.rs @@ -23,34 +23,28 @@ impl GaloyClient { pub async fn list_transactions( &self, - after: Option, - before: Option, - last: Option, - first: Option, - wallet_ids: Option>>, + //TODO: Add pagination from BE + + // after: Option, + // before: Option, + // last: Option, + // first: Option, + // wallet_ids: Option>>, ) -> Result>, ClientError> { - let variables = transactions::Variables { - after, - before, - first, - last, - wallet_ids, - }; + let variables = transactions::Variables; let response_body = post_graphql::(&self.graphql_client, &self.api, variables) .await .map_err(|err| ApiError::IssueGettingResponse(anyhow::Error::new(err)))?; - println!("{:?}", response_body); - let response_data = response_body.data.ok_or(ApiError::IssueParsingResponse)?; let transactions = response_data .me .ok_or(MeError::FailedToUnwrapMe)? .default_account .transactions - .ok_or(ApiError::IssueParsingResponse)? //change this error + .ok_or(MeError::FailedToUnwrapTransactions)? .edges; Ok(transactions) } From 522edf6ce3d9dd220ef88d8a489e350112169eaa Mon Sep 17 00:00:00 2001 From: eshanvaid Date: Fri, 4 Aug 2023 00:25:08 +0530 Subject: [PATCH 3/5] feat: default to last 5 --- src/cli/commands.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/commands.rs b/src/cli/commands.rs index 93af608..9a720bf 100644 --- a/src/cli/commands.rs +++ b/src/cli/commands.rs @@ -38,7 +38,7 @@ pub enum Command { // after: Option, // #[clap(short, long)] // before: Option, - #[clap(short, long, conflicts_with("first"))] + #[clap(short, long, default_value("5"), conflicts_with("first"))] last: Option, #[clap(short, long)] first: Option, From 291000564d71d3d2e3850a2944c671d27d479aa8 Mon Sep 17 00:00:00 2001 From: eshanvaid Date: Fri, 4 Aug 2023 00:28:14 +0530 Subject: [PATCH 4/5] fix: reverse transactions --- src/app/operations/user.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/app/operations/user.rs b/src/app/operations/user.rs index 46c5b5a..4629656 100644 --- a/src/app/operations/user.rs +++ b/src/app/operations/user.rs @@ -34,16 +34,13 @@ impl App { if let Some(transactions) = result { let selected_transactions: Vec<_> = if let Some(first) = first { - transactions - .iter() - .take(first.try_into().unwrap()) - .collect() - } else if let Some(last) = last { let total_transactions = transactions.len(); transactions .iter() - .skip(total_transactions.saturating_sub(last.try_into().unwrap())) + .skip(total_transactions.saturating_sub(first.try_into().unwrap())) .collect() + } else if let Some(last) = last { + transactions.iter().take(last.try_into().unwrap()).collect() } else { transactions.iter().collect() }; From af18cfa881cabb8cb95aece90cf0ab3172aad5a1 Mon Sep 17 00:00:00 2001 From: eshanvaid Date: Fri, 4 Aug 2023 00:33:33 +0530 Subject: [PATCH 5/5] feat: add --all flag --- src/app/operations/user.rs | 5 ++++- src/cli/commands.rs | 2 ++ src/cli/runner.rs | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/app/operations/user.rs b/src/app/operations/user.rs index 4629656..fdb2a39 100644 --- a/src/app/operations/user.rs +++ b/src/app/operations/user.rs @@ -25,6 +25,7 @@ impl App { last: Option, first: Option, // wallet_ids: Option>>, + all: bool, ) -> anyhow::Result<()> { let result = self .client @@ -33,7 +34,9 @@ impl App { .context("Error occurred while fetching transactions")?; if let Some(transactions) = result { - let selected_transactions: Vec<_> = if let Some(first) = first { + let selected_transactions: Vec<_> = if all { + transactions.iter().collect() + } else if let Some(first) = first { let total_transactions = transactions.len(); transactions .iter() diff --git a/src/cli/commands.rs b/src/cli/commands.rs index 9a720bf..fcada88 100644 --- a/src/cli/commands.rs +++ b/src/cli/commands.rs @@ -44,6 +44,8 @@ pub enum Command { first: Option, // #[clap(long, use_value_delimiter = true)] // wallet_ids: Option>>, + #[clap(long, conflicts_with_all(["first", "last"]))] + all: bool, }, /// Get WalletId for an account DefaultWallet { diff --git a/src/cli/runner.rs b/src/cli/runner.rs index 6ed3fb6..5fe7419 100644 --- a/src/cli/runner.rs +++ b/src/cli/runner.rs @@ -26,8 +26,9 @@ pub async fn run() -> anyhow::Result<()> { last, first, // wallet_ids, + all, } => { - app.list_transactions(last, first).await?; + app.list_transactions(last, first, all).await?; } Command::DefaultWallet { username } => { app.default_wallet(username).await?;