Add branta (#845)
* adding translations * adding branta * implemtn branta with pollyfill * improve pollyfill * change function name
This commit is contained in:
@@ -16,6 +16,7 @@ export default function InvoiceInfo({
|
||||
darkModeType,
|
||||
isSplitPayment,
|
||||
splitRecipients = [],
|
||||
isUsingBranta,
|
||||
}) {
|
||||
const formmateedSparkPaymentInfo = formatSparkPaymentAddress(
|
||||
paymentInfo,
|
||||
@@ -40,7 +41,30 @@ export default function InvoiceInfo({
|
||||
]}
|
||||
disabled={isSplitPayment}
|
||||
>
|
||||
{isSplitPayment ? (
|
||||
{isUsingBranta ? (
|
||||
<View style={styles.contactRow}>
|
||||
<View
|
||||
style={[
|
||||
styles.profileImage,
|
||||
{
|
||||
backgroundColor: backgroundColor,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<ContactProfileImage
|
||||
updated={undefined}
|
||||
uri={paymentInfo?.brantaMerchantLogo}
|
||||
darkModeType={darkModeType}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
<ThemeText
|
||||
styles={styles.addressText}
|
||||
CustomNumberOfLines={1}
|
||||
content={paymentInfo?.brantaMerchantName || ''}
|
||||
/>
|
||||
</View>
|
||||
) : isSplitPayment ? (
|
||||
<ProfileImageRow
|
||||
avatarSize={40}
|
||||
contacts={splitContacts}
|
||||
|
||||
@@ -21,6 +21,9 @@ import { getCachedProfileImage } from '../../../../../functions/cachedImage';
|
||||
import { getPayLinkDoc, addDataToCollection } from '../../../../../../db';
|
||||
import { receiveSparkLightningPayment } from '../../../../../functions/spark';
|
||||
import { isBlitzLNURLAddress } from '../../../../../functions/lnurl';
|
||||
import { handleBrantaVerification } from '../../../../../functions/branta/index';
|
||||
import { Image as ExpoImage } from 'expo-image';
|
||||
|
||||
export default async function decodeSendAddress(props) {
|
||||
let {
|
||||
btcAdress,
|
||||
@@ -212,33 +215,6 @@ export default async function decodeSendAddress(props) {
|
||||
}
|
||||
}
|
||||
|
||||
// handle bip21 qrs
|
||||
// if (
|
||||
// btcAdress.toLowerCase().startsWith('lightning') ||
|
||||
// btcAdress.toLowerCase().startsWith('bitcoin')
|
||||
// ) {
|
||||
// console.log(btcAdress);
|
||||
// const decodedAddress = decodeBip21Address(
|
||||
// btcAdress,
|
||||
// btcAdress.toLowerCase().startsWith('lightning')
|
||||
// ? 'lightning'
|
||||
// : 'bitcoin',
|
||||
// );
|
||||
|
||||
// console.log(decodedAddress);
|
||||
// const lightningInvoice = btcAdress.toLowerCase().startsWith('lightning')
|
||||
// ? decodedAddress.address.toUpperCase()
|
||||
// : decodedAddress.options.lightning?.toUpperCase();
|
||||
|
||||
// console.log(lightningInvoice);
|
||||
// if (lightningInvoice)
|
||||
// btcAdress = await hanndleLNURLAddress(lightningInvoice);
|
||||
// }
|
||||
|
||||
// if (btcAdress.toLowerCase().startsWith('lnurl')) {
|
||||
// btcAdress = await hanndleLNURLAddress(btcAdress);
|
||||
// }
|
||||
|
||||
console.log(btcAdress, 'bitcoin address');
|
||||
|
||||
let input;
|
||||
@@ -256,37 +232,74 @@ export default async function decodeSendAddress(props) {
|
||||
}
|
||||
|
||||
let processedPaymentInfo;
|
||||
let brantaVerification;
|
||||
try {
|
||||
processedPaymentInfo = await processInputType(input, {
|
||||
fiatStats,
|
||||
liquidNodeInformation,
|
||||
masterInfoObject,
|
||||
navigate,
|
||||
// maxZeroConf,
|
||||
comingFromAccept,
|
||||
enteredPaymentInfo,
|
||||
setPaymentInfo,
|
||||
// webViewRef,
|
||||
setLoadingMessage,
|
||||
paymentInfo,
|
||||
fromPage,
|
||||
seletctedToken,
|
||||
currentWalletMnemoinc,
|
||||
t,
|
||||
sendWebViewRequest,
|
||||
contactInfo,
|
||||
sparkInformation,
|
||||
globalContactsInformation,
|
||||
accountMnemoinc,
|
||||
usablePaymentMethod,
|
||||
bitcoinBalance,
|
||||
dollarBalanceSat,
|
||||
convertedSendAmount,
|
||||
poolInfoRef,
|
||||
swapLimits,
|
||||
// usd_multiplier_coefiicent,
|
||||
min_usd_swap_amount,
|
||||
});
|
||||
let shouldRunBrantaVerification = false;
|
||||
if (input.type === InputTypes.BOLT11) shouldRunBrantaVerification = true;
|
||||
if (input.type === InputTypes.BITCOIN_ADDRESS) {
|
||||
try {
|
||||
const url = new URL(btcAdress);
|
||||
shouldRunBrantaVerification =
|
||||
url.searchParams.has('branta_id') &&
|
||||
url.searchParams.has('branta_secret');
|
||||
} catch {
|
||||
shouldRunBrantaVerification = false;
|
||||
}
|
||||
}
|
||||
|
||||
const brantaVerificationPromise = shouldRunBrantaVerification
|
||||
? Promise.race([
|
||||
handleBrantaVerification(btcAdress),
|
||||
new Promise(resolve => setTimeout(() => resolve(null), 2000)),
|
||||
])
|
||||
: Promise.resolve(null);
|
||||
|
||||
if (shouldRunBrantaVerification) {
|
||||
brantaVerificationPromise.then(brantaResult => {
|
||||
if (brantaResult && brantaResult.length) {
|
||||
const [details] = brantaResult;
|
||||
if (details.platformLogoUrl) {
|
||||
ExpoImage.prefetch(details.platformLogoUrl).catch(err =>
|
||||
console.log('Error prefetching branta merchant logo', err),
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[processedPaymentInfo, brantaVerification] = await Promise.all([
|
||||
processInputType(input, {
|
||||
fiatStats,
|
||||
liquidNodeInformation,
|
||||
masterInfoObject,
|
||||
navigate,
|
||||
// maxZeroConf,
|
||||
comingFromAccept,
|
||||
enteredPaymentInfo,
|
||||
setPaymentInfo,
|
||||
// webViewRef,
|
||||
setLoadingMessage,
|
||||
paymentInfo,
|
||||
fromPage,
|
||||
seletctedToken,
|
||||
currentWalletMnemoinc,
|
||||
t,
|
||||
sendWebViewRequest,
|
||||
contactInfo,
|
||||
sparkInformation,
|
||||
globalContactsInformation,
|
||||
accountMnemoinc,
|
||||
usablePaymentMethod,
|
||||
bitcoinBalance,
|
||||
dollarBalanceSat,
|
||||
convertedSendAmount,
|
||||
poolInfoRef,
|
||||
swapLimits,
|
||||
// usd_multiplier_coefiicent,
|
||||
min_usd_swap_amount,
|
||||
}),
|
||||
brantaVerificationPromise,
|
||||
]);
|
||||
} catch (err) {
|
||||
return goBackFunction(
|
||||
err.message ||
|
||||
@@ -301,6 +314,23 @@ export default async function decodeSendAddress(props) {
|
||||
};
|
||||
}
|
||||
|
||||
if (brantaVerification && brantaVerification.length) {
|
||||
const [details] = brantaVerification;
|
||||
const isHttpsUrl = val =>
|
||||
typeof val === 'string' && val.startsWith('https://');
|
||||
processedPaymentInfo = {
|
||||
...processedPaymentInfo,
|
||||
isUsingBranta: true,
|
||||
brantaMerchantName: details.platform,
|
||||
brantaMerchantLogo: isHttpsUrl(details.platformLogoUrl)
|
||||
? details.platformLogoUrl
|
||||
: undefined,
|
||||
verificationURL: isHttpsUrl(details.verifyUrl)
|
||||
? details.verifyUrl
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
if (processedPaymentInfo) {
|
||||
// const isLRC20 =
|
||||
// seletctedToken?.tokenMetadata?.tokenTicker !== undefined &&
|
||||
|
||||
@@ -193,6 +193,7 @@ export default function SendPaymentScreen(props) {
|
||||
const isBitcoinPayment = paymentInfo?.paymentNetwork === 'Bitcoin';
|
||||
const isSparkPayment = paymentInfo?.paymentNetwork === 'spark';
|
||||
const isLNURLPayment = paymentInfo?.type === InputTypes.LNURL_PAY;
|
||||
const isUsingBranta = paymentInfo?.isUsingBranta;
|
||||
|
||||
const enabledLRC20 = showTokensInformation;
|
||||
const defaultToken = enabledLRC20
|
||||
@@ -1320,6 +1321,13 @@ export default function SendPaymentScreen(props) {
|
||||
};
|
||||
}, [isAmountFocused, bottomPadding]);
|
||||
|
||||
const handleBrandaVerificationUrl = useCallback(() => {
|
||||
navigate.navigate('CustomWebView', {
|
||||
headerText: 'Branta',
|
||||
webViewURL: paymentInfo?.verificationURL,
|
||||
});
|
||||
}, [paymentInfo?.verificationURL, navigate, t]);
|
||||
|
||||
const sendingAsset =
|
||||
selectedLRC20Asset === 'Bitcoin'
|
||||
? !isLightningPayment &&
|
||||
@@ -1348,7 +1356,13 @@ export default function SendPaymentScreen(props) {
|
||||
return (
|
||||
<CustomKeyboardAvoidingView globalThemeViewStyles={memorizedKeyboardStyle}>
|
||||
<View style={styles.replacementContainer}>
|
||||
<CustomSettingsTopBar label={t('constants.send')} />
|
||||
<CustomSettingsTopBar
|
||||
label={t('constants.send')}
|
||||
showLeftImage={isUsingBranta}
|
||||
iconNew="BadgeCheck"
|
||||
leftImageStyles={{ height: 25 }}
|
||||
leftImageFunction={handleBrandaVerificationUrl}
|
||||
/>
|
||||
<ScrollView contentContainerStyle={styles.balanceScrollContainer}>
|
||||
{/* Amount display */}
|
||||
{uiState !== 'SWAP_RATES_CHANGED' && (
|
||||
@@ -1428,6 +1442,7 @@ export default function SendPaymentScreen(props) {
|
||||
}
|
||||
theme={theme}
|
||||
darkModeType={darkModeType}
|
||||
isUsingBranta={isUsingBranta}
|
||||
/>
|
||||
)}
|
||||
{uiState === 'CHOOSE_METHOD' && (
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { BrantaServerBaseUrl, V2BrantaClient } from '@branta-ops/branta';
|
||||
|
||||
const brantaClient = new V2BrantaClient({
|
||||
baseUrl: BrantaServerBaseUrl.Production,
|
||||
privacy: 'strict',
|
||||
});
|
||||
|
||||
export async function handleBrantaVerification(qrCode) {
|
||||
try {
|
||||
const brantaResponse = await brantaClient.getPaymentsByQRCode(qrCode ?? '');
|
||||
return brantaResponse;
|
||||
} catch (err) {
|
||||
console.log('Error retriving branta verification', err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1170,7 +1170,8 @@
|
||||
"swapRatesChangedTitle": "Wechselkurs aktualisiert",
|
||||
"swapRatesChangedBody": "Der Wechselkurs für diesen Tausch hat sich während Ihrer Überprüfung geändert. Bitte geben Sie den Betrag erneut ein, um fortzufahren.",
|
||||
"swapRatesChangedButton": "Betrag erneut eingeben",
|
||||
"feeEstimateError": "Gebühr konnte nicht geschätzt werden, bitte versuchen Sie es erneut"
|
||||
"feeEstimateError": "Gebühr konnte nicht geschätzt werden, bitte versuchen Sie es erneut",
|
||||
"brantaVerification": "Diese Zahlung wurde von Branta verifiziert"
|
||||
},
|
||||
"selectPaymentMethod": {
|
||||
"header": "Bitte wählen Sie aus, wie Sie Ihre Zahlung senden möchten (BTC oder USD)."
|
||||
|
||||
@@ -1170,7 +1170,8 @@
|
||||
"swapRatesChangedTitle": "Swap Rate Updated",
|
||||
"swapRatesChangedBody": "The exchange rate for this swap changed while you were reviewing. Please re-enter your amount to continue.",
|
||||
"swapRatesChangedButton": "Re-enter Amount",
|
||||
"feeEstimateError": "Unable to estimate fee, please try again"
|
||||
"feeEstimateError": "Unable to estimate fee, please try again",
|
||||
"brantaVerification": "This payment has been verified by Branta"
|
||||
},
|
||||
"selectPaymentMethod": {
|
||||
"header": "How do you want to fund your payment?"
|
||||
|
||||
@@ -1170,7 +1170,8 @@
|
||||
"swapRatesChangedTitle": "Tipo de cambio actualizado",
|
||||
"swapRatesChangedBody": "El tipo de cambio para este intercambio cambió mientras lo estabas revisando. Vuelve a ingresar el monto para continuar.",
|
||||
"swapRatesChangedButton": "Volver a ingresar el monto",
|
||||
"feeEstimateError": "No se pudo estimar la comisión, inténtalo de nuevo"
|
||||
"feeEstimateError": "No se pudo estimar la comisión, inténtalo de nuevo",
|
||||
"brantaVerification": "Este pago ha sido verificado por Branta"
|
||||
},
|
||||
"selectPaymentMethod": {
|
||||
"header": "Selecciona cómo deseas financiar tu pago."
|
||||
|
||||
@@ -1170,7 +1170,8 @@
|
||||
"swapRatesChangedTitle": "Taux de change mis à jour",
|
||||
"swapRatesChangedBody": "Le taux de change pour cet échange a changé pendant votre vérification. Veuillez saisir à nouveau le montant pour continuer.",
|
||||
"swapRatesChangedButton": "Ressaisir le montant",
|
||||
"feeEstimateError": "Impossible d’estimer les frais, veuillez réessayer"
|
||||
"feeEstimateError": "Impossible d’estimer les frais, veuillez réessayer",
|
||||
"brantaVerification": "Ce paiement a été vérifié par Branta"
|
||||
},
|
||||
"selectPaymentMethod": {
|
||||
"header": "Veuillez sélectionner comment vous souhaitez financer votre paiement."
|
||||
|
||||
@@ -1170,7 +1170,8 @@
|
||||
"swapRatesChangedTitle": "Tasso di cambio aggiornato",
|
||||
"swapRatesChangedBody": "Il tasso di cambio per questo scambio è cambiato durante la revisione. Inserisci nuovamente l’importo per continuare.",
|
||||
"swapRatesChangedButton": "Reinserisci importo",
|
||||
"feeEstimateError": "Impossibile stimare la commissione, riprova"
|
||||
"feeEstimateError": "Impossibile stimare la commissione, riprova",
|
||||
"brantaVerification": "Questo pagamento è stato verificato da Branta"
|
||||
},
|
||||
"selectPaymentMethod": {
|
||||
"header": "Seleziona come desideri finanziare il pagamento."
|
||||
|
||||
@@ -1170,7 +1170,8 @@
|
||||
"swapRatesChangedTitle": "Cotação atualizada",
|
||||
"swapRatesChangedBody": "A cotação para esta troca mudou enquanto você estava revisando. Insira o valor novamente para continuar.",
|
||||
"swapRatesChangedButton": "Inserir valor novamente",
|
||||
"feeEstimateError": "Não foi possível estimar a taxa, tente novamente"
|
||||
"feeEstimateError": "Não foi possível estimar a taxa, tente novamente",
|
||||
"brantaVerification": "Este pagamento foi verificado pela Branta"
|
||||
},
|
||||
"selectPaymentMethod": {
|
||||
"header": "Escolha o saldo para realizar esse pagamento"
|
||||
|
||||
@@ -1171,7 +1171,8 @@
|
||||
"swapRatesChangedTitle": "Курс обмена обновлён",
|
||||
"swapRatesChangedBody": "Курс обмена для этой операции изменился во время проверки. Пожалуйста, введите сумму заново, чтобы продолжить.",
|
||||
"swapRatesChangedButton": "Ввести сумму снова",
|
||||
"feeEstimateError": "Не удалось оценить комиссию, попробуйте снова"
|
||||
"feeEstimateError": "Не удалось оценить комиссию, попробуйте снова",
|
||||
"brantaVerification": "Этот платёж был подтверждён Branta"
|
||||
},
|
||||
"selectPaymentMethod": {
|
||||
"header": "Выберите источник средств."
|
||||
|
||||
@@ -1170,7 +1170,8 @@
|
||||
"swapRatesChangedTitle": "Växelkurs uppdaterad",
|
||||
"swapRatesChangedBody": "Växelkursen för denna växling ändrades medan du granskade den. Ange beloppet igen för att fortsätta.",
|
||||
"swapRatesChangedButton": "Ange belopp igen",
|
||||
"feeEstimateError": "Kunde inte uppskatta avgiften, försök igen"
|
||||
"feeEstimateError": "Kunde inte uppskatta avgiften, försök igen",
|
||||
"brantaVerification": "Denna betalning har verifierats av Branta"
|
||||
},
|
||||
"selectPaymentMethod": {
|
||||
"header": "Välj hur du vill finansiera din betalning."
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@azure/core-asynciterator-polyfill": "^1.0.2",
|
||||
"@branta-ops/branta": "2.0.0",
|
||||
"@breeztech/react-native-breez-sdk-liquid": "^0.11.9",
|
||||
"@buildonspark/spark-sdk": "^0.8.0",
|
||||
"@craftzdog/react-native-buffer": "^6.1.0",
|
||||
|
||||
+24
-1
@@ -5,10 +5,33 @@ import 'react-native-gesture-handler';
|
||||
import '@azure/core-asynciterator-polyfill';
|
||||
//neeed for encription + spark
|
||||
import 'react-native-quick-base64';
|
||||
|
||||
import { Buffer } from '@craftzdog/react-native-buffer';
|
||||
import { pbkdf2Sync, createHash } from 'react-native-quick-crypto';
|
||||
import QuickCrypto, {
|
||||
pbkdf2Sync,
|
||||
createHash,
|
||||
subtle,
|
||||
} from 'react-native-quick-crypto';
|
||||
global.Buffer = Buffer;
|
||||
|
||||
// Polyfill Web Crypto API for packages that rely on crypto.subtle (e.g. @branta-ops/branta)
|
||||
// react-native-get-random-values (imported above) already provides crypto.getRandomValues
|
||||
// need for @branta-ops/branta
|
||||
global.crypto = QuickCrypto;
|
||||
global.crypto.subtle = subtle;
|
||||
global.crypto.randomUUID =
|
||||
global.crypto.randomUUID ||
|
||||
function () {
|
||||
const bytes = new Uint8Array(16);
|
||||
global.crypto.getRandomValues(bytes);
|
||||
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
||||
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
||||
const hex = Array.from(bytes, b => b.toString(16).padStart(2, '0'));
|
||||
return `${hex.slice(0, 4).join('')}-${hex.slice(4, 6).join('')}-${hex
|
||||
.slice(6, 8)
|
||||
.join('')}-${hex.slice(8, 10).join('')}-${hex.slice(10).join('')}`;
|
||||
};
|
||||
|
||||
// import 'text-encoding-polyfill';
|
||||
import 'text-encoding'; // needed for spark
|
||||
|
||||
|
||||
@@ -1776,6 +1776,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@branta-ops/branta@npm:2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "@branta-ops/branta@npm:2.0.0"
|
||||
checksum: 6966c87c85ee8547541849aa5b5499c8927b5808f79ab4f96f3ad38c0ff21f1162f381c1f4c196adf4ee6b9378e09463e0c2fe81a03d4c58f724ae4a0adce4e0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@breeztech/react-native-breez-sdk-liquid@npm:^0.11.9":
|
||||
version: 0.11.9
|
||||
resolution: "@breeztech/react-native-breez-sdk-liquid@npm:0.11.9"
|
||||
@@ -4912,6 +4919,7 @@ __metadata:
|
||||
"@babel/plugin-transform-class-static-block": ^7.28.3
|
||||
"@babel/preset-env": ^7.28.3
|
||||
"@babel/runtime": ^7.25.0
|
||||
"@branta-ops/branta": 2.0.0
|
||||
"@breeztech/react-native-breez-sdk-liquid": ^0.11.9
|
||||
"@buildonspark/spark-sdk": ^0.8.0
|
||||
"@craftzdog/react-native-buffer": ^6.1.0
|
||||
|
||||
Reference in New Issue
Block a user