Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion app/contexts/BreezContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,17 @@ import { WalletCurrency } from "@app/graphql/generated"
import { usePersistentStateContext } from "@app/store/persistent-state"
import { Alert, Platform } from "react-native"
import { v4 as uuidv4 } from "uuid"
import { initializeBreezSDK, getInfo, handleSparkMigration } from "@app/utils/breez-sdk"
import {
initializeBreezSDK,
getInfo,
handleSparkMigration,
registerLightningAddress,
getLightningAddress,
checkLightningAddressAvailable,
} from "@app/utils/breez-sdk"
import { useAppConfig } from "@app/hooks/use-app-config"
import { useAddressScreenQuery } from "@app/graphql/generated"
import { useIsAuthed } from "@app/graphql/is-authed-context"
import SparkMigrationModal from "@app/components/spark-migration-modal"

type BtcWallet = {
Expand Down Expand Up @@ -34,6 +44,12 @@ type Props = {

export const BreezProvider = ({ children }: Props) => {
const { persistentState, updateState } = usePersistentStateContext()
const { appConfig } = useAppConfig()
const isAuthed = useIsAuthed()
const { data: meData } = useAddressScreenQuery({
fetchPolicy: "cache-first",
skip: !isAuthed,
})
const [loading, setLoading] = useState(false)
const [btcWallet, setBtcWallet] = useState<BtcWallet>({
id: "",
Expand Down Expand Up @@ -111,6 +127,27 @@ export const BreezProvider = ({ children }: Props) => {
}
}

const ensureLightningAddress = async () => {
const username = meData?.me?.username
if (!username) return

try {
const existing = await getLightningAddress()
console.log("BREEZ LIGHTNING ADDRESS: ", existing)
if (existing) return

// Register with username as the Lightning address
const lightningAddress = username + uuidv4()
const res = await registerLightningAddress(
lightningAddress,
`Pay to ${username}@${appConfig.galoyInstance.lnAddressHostname}`,
)
console.log("BREEZ LIGHTNING ADDRESS RES: ", res)
} catch (err) {
console.warn("Failed to register Lightning address:", err)
}
}

const getBreezInfo = async () => {
if (initializingRef.current) return
initializingRef.current = true
Expand All @@ -120,6 +157,9 @@ export const BreezProvider = ({ children }: Props) => {
await updateBalance()
setLoading(false)

// Register Lightning address
await ensureLightningAddress()

// Trigger migration after Spark SDK is ready
if (!persistentState.sparkMigrationCompleted) {
await onMigrate()
Expand Down
2 changes: 2 additions & 0 deletions app/screens/import-wallet-screen/ImportWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { useI18nContext } from "@app/i18n/i18n-react"
import { useCreateAccount } from "@app/hooks/useCreateAccount"
import { Text, useTheme, useThemeMode } from "@rneui/themed"
import { usePersistentStateContext } from "@app/store/persistent-state"
import { useAppConfig } from "@app/hooks/use-app-config"

// utils
import { disconnectToSDK, initializeBreezSDK } from "@app/utils/breez-sdk"
Expand All @@ -31,6 +32,7 @@ const ImportWallet: React.FC<Props> = ({ navigation, route }) => {
const { mode } = useThemeMode()
const { LL } = useI18nContext()
const { updateState } = usePersistentStateContext()
const { appConfig } = useAppConfig()
const { createDeviceAccountAndLogin } = useCreateAccount()

const inputRef = useRef<TextInput[]>([])
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import React from "react"
import { Linking, TouchableWithoutFeedback, View, TouchableOpacity, ScrollView } from "react-native"
import {
Linking,
TouchableWithoutFeedback,
View,
TouchableOpacity,
ScrollView,
} from "react-native"
import { makeStyles, Text, useTheme, Card } from "@rneui/themed"
import { StackScreenProps } from "@react-navigation/stack"
import Icon from "react-native-vector-icons/Ionicons"
Expand Down Expand Up @@ -167,8 +173,8 @@ export const BreezTransactionDetailScreen: React.FC<Props> = ({ route }) => {
if (details) {
if (details.tag === PaymentDetails_Tags.Lightning) {
description = details.inner.description ?? undefined
paymentHash = details.inner.paymentHash
preimage = details.inner.preimage ?? undefined
paymentHash = details.inner.htlcDetails.paymentHash
preimage = details.inner.htlcDetails.preimage ?? undefined
invoice = details.inner.invoice
destinationPubkey = details.inner.destinationPubkey
} else if (details.tag === PaymentDetails_Tags.Spark) {
Expand Down
1 change: 1 addition & 0 deletions app/types/declaration.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ declare module "@env" {
export const GREENLIGHT_PARTNER_KEY: string
export const GOOGLE_PLACE_API_KEY: string
export const MIGRATION_FEE_LNURL_W: string
export const BREEZ_LNURL_DOMAIN: string
}
16 changes: 9 additions & 7 deletions app/types/transactions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import type { Payment } from "@breeztech/breez-sdk-spark-react-native"
import { PaymentDetails_Tags } from "@breeztech/breez-sdk-spark-react-native"
import {
PaymentDetails_Tags,
PaymentType,
PaymentStatus,
} from "@breeztech/breez-sdk-spark-react-native"
import type { TransactionFragment } from "@app/graphql/generated"

// ============================================================================
Expand Down Expand Up @@ -87,8 +91,7 @@ export const getTransactionAmount = (tx: UnifiedTransaction): number => {
*/
export const isReceiveTransaction = (tx: UnifiedTransaction): boolean => {
if (isBreezTransaction(tx)) {
// PaymentType.Receive = 1
return tx.payment.paymentType === 1
return tx.payment.paymentType === PaymentType.Receive
}
return tx.transaction.direction === "RECEIVE"
}
Expand All @@ -100,13 +103,12 @@ export const getTransactionStatus = (
tx: UnifiedTransaction,
): "SUCCESS" | "PENDING" | "FAILURE" => {
if (isBreezTransaction(tx)) {
// PaymentStatus: Completed = 0, Pending = 1, Failed = 2
switch (tx.payment.status) {
case 0:
case PaymentStatus.Completed:
return "SUCCESS"
case 1:
case PaymentStatus.Pending:
return "PENDING"
case 2:
case PaymentStatus.Failed:
return "FAILURE"
default:
return "PENDING"
Expand Down
45 changes: 43 additions & 2 deletions app/utils/breez-sdk/spark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ import type {
RecommendedFees,
SendPaymentMethod,
LnurlPayResponse,
LightningAddressInfo,
Payment,
Logger,
LogEntry,
} from "@breeztech/breez-sdk-spark-react-native"
import { API_KEY } from "@env"
import { API_KEY, BREEZ_LNURL_DOMAIN } from "@env"
import { appendLog, initLogBuffer } from "./log-buffer"

// Constants
Expand Down Expand Up @@ -67,7 +68,7 @@ export const initializeBreezSDK = async (): Promise<boolean> => {

breezSDKInitializing = (async () => {
try {
await retry(connectToSDK, 5000, 3)
await retry(() => connectToSDK(), 5000, 3)
breezSDKInitialized = true
return true
} catch (error: unknown) {
Expand Down Expand Up @@ -120,6 +121,7 @@ const connectToSDK = async (): Promise<void> => {

const config = defaultConfig(Network.Mainnet)
config.apiKey = API_KEY
config.lnurlDomain = BREEZ_LNURL_DOMAIN
config.maxDepositClaimFee = new MaxFee.NetworkRecommended({
leewaySatPerVbyte: BigInt(1),
})
Expand Down Expand Up @@ -238,6 +240,7 @@ export const fetchBreezFee = async (
amount: BigInt(amountSats),
tokenIdentifier: undefined,
conversionOptions: undefined,
feePolicy: undefined,
})
const fee = extractFeeFromPaymentMethod(prepareResponse.paymentMethod)
return { fee: Number(fee), err: null }
Expand All @@ -249,6 +252,7 @@ export const fetchBreezFee = async (
amount: BigInt(amountSats),
tokenIdentifier: undefined,
conversionOptions: undefined,
feePolicy: undefined,
})
const fee = extractFeeFromPaymentMethod(
prepareResponse.paymentMethod,
Expand All @@ -266,6 +270,8 @@ export const fetchBreezFee = async (
payRequest: parsed.inner[0].payRequest,
comment: undefined,
validateSuccessActionUrl: undefined,
conversionOptions: undefined,
feePolicy: undefined,
})

return { fee: Number(prepareResponse.feeSats), err: null }
Expand Down Expand Up @@ -296,6 +302,7 @@ export const receivePaymentBreez = async (
description: description || "",
amountSats: BigInt(amountSats || 0),
expirySecs: undefined,
paymentHash: undefined,
}),
})

Expand Down Expand Up @@ -332,6 +339,7 @@ export const payLightningBreez = async (
amount: BigInt(amountSats),
tokenIdentifier: undefined,
conversionOptions: undefined,
feePolicy: undefined,
})

const options = new SendPaymentOptions.Bolt11Invoice({
Expand Down Expand Up @@ -368,6 +376,7 @@ export const payOnchainBreez = async (
amount: BigInt(amountSats),
tokenIdentifier: undefined,
conversionOptions: undefined,
feePolicy: undefined,
})

const confirmationSpeed =
Expand Down Expand Up @@ -411,6 +420,8 @@ export const payLnurlBreez = async (
payRequest: input.inner[0].payRequest,
comment: memo,
validateSuccessActionUrl: true,
conversionOptions: undefined,
feePolicy: undefined,
})

const response = await sdk.lnurlPay({
Expand Down Expand Up @@ -473,6 +484,8 @@ export const onRedeem = async (
payRequest: input.inner[0].payRequest,
comment: memo,
validateSuccessActionUrl: true,
conversionOptions: undefined,
feePolicy: undefined,
})

const response = await sdk.lnurlPay({
Expand Down Expand Up @@ -612,3 +625,31 @@ export const refundDeposit = async (
return { success: false, error: message }
}
}

// Lightning Address (LNURL-Pay)
export const checkLightningAddressAvailable = async (
username: string,
): Promise<boolean> => {
const sdk = getSDKInstance()
return sdk.checkLightningAddressAvailable({ username })
}

export const registerLightningAddress = async (
username: string,
description?: string,
): Promise<LightningAddressInfo> => {
const sdk = getSDKInstance()
return sdk.registerLightningAddress({ username, description })
}

export const getLightningAddress = async (): Promise<
LightningAddressInfo | undefined
> => {
const sdk = getSDKInstance()
return sdk.getLightningAddress()
}

export const deleteLightningAddress = async (): Promise<void> => {
const sdk = getSDKInstance()
await sdk.deleteLightningAddress()
}
4 changes: 2 additions & 2 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ PODS:
- breez_sdk_liquidFFI (0.11.13)
- BreezSDKLiquid (0.11.13):
- breez_sdk_liquidFFI (= 0.11.13)
- breeztech-breez-sdk-spark-react-native (0.7.14):
- breeztech-breez-sdk-spark-react-native (0.12.2-dev1):
- DoubleConversion
- glog
- hermes-engine
Expand Down Expand Up @@ -2996,7 +2996,7 @@ SPEC CHECKSUMS:
breez_sdk_liquid: 5c229f9ab3bcf6b648bbf2d512f6fe1eee96d121
breez_sdk_liquidFFI: f05fadc0611126ade76d1fe6761ed8b020aabefb
BreezSDKLiquid: ee6bf5a57f1b2533dc3c14c24c9773496f17b756
breeztech-breez-sdk-spark-react-native: 0af390a27a5f95bc838cddbecead825b671f60b2
breeztech-breez-sdk-spark-react-native: de3a2235712440ee9fa2aa92a04c6838312c8343
BVLinearGradient: 880f91a7854faff2df62518f0281afb1c60d49a3
DoubleConversion: f16ae600a246532c4020132d54af21d0ddb2a385
fast_float: 06eeec4fe712a76acc9376682e4808b05ce978b6
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"dependencies": {
"@apollo/client": "3.9.0-alpha.5",
"@bitcoinerlab/secp256k1": "^1.0.5",
"@breeztech/breez-sdk-spark-react-native": "^0.7.14",
"@breeztech/breez-sdk-spark-react-native": "^0.12.2-dev1",
"@breeztech/react-native-breez-sdk-liquid": "^0.11.13",
"@flash/client": "git+https://github.com/lnflash/flash-client.git",
"@formatjs/intl-getcanonicallocales": "^2.3.0",
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1901,10 +1901,10 @@
"@noble/hashes" "^1.1.5"
"@noble/secp256k1" "^1.7.1"

"@breeztech/breez-sdk-spark-react-native@^0.7.14":
version "0.7.14"
resolved "https://registry.yarnpkg.com/@breeztech/breez-sdk-spark-react-native/-/breez-sdk-spark-react-native-0.7.14.tgz#b8914719e67620aa6b85178d7a903d7efcaedbac"
integrity sha512-xHhcwD0/aDQAGg6mJM1K1Wepp3bmf3SnuK7tIC2jSX7VA308lB92u6ag3vIQMvAtz6mZptu+8Le+br9sr2u4/w==
"@breeztech/breez-sdk-spark-react-native@^0.12.2-dev1":
version "0.12.2-dev1"
resolved "https://registry.yarnpkg.com/@breeztech/breez-sdk-spark-react-native/-/breez-sdk-spark-react-native-0.12.2-dev1.tgz#7d84efaf69307d9b94270b10b1ad68228d077cc6"
integrity sha512-B3xls7j4/7GIwOJR3FPParNtjIQPBj3RTuelTDq2CCY+idStrJww37vdNyxp1yo6FnjkhIhdCPIjH7+PTAi1Yw==
dependencies:
uniffi-bindgen-react-native "^0.28.3-5"

Expand Down