From d618848bc753407106ebbf62df2d73836ff1e480 Mon Sep 17 00:00:00 2001 From: Paul Puey Date: Fri, 20 Sep 2024 10:34:45 -0700 Subject: [PATCH 1/4] Use requestId as orderId `invoice` is not available at the point of a buy order so we can't use it as the orderId. --- src/plugins/gui/providers/paybisProvider.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/gui/providers/paybisProvider.ts b/src/plugins/gui/providers/paybisProvider.ts index 0f922584f37..08cbaacd9a9 100644 --- a/src/plugins/gui/providers/paybisProvider.ts +++ b/src/plugins/gui/providers/paybisProvider.ts @@ -195,7 +195,7 @@ const asQuote = asObject({ const asPaymentDetails = asObject({ assetId: asString, - invoice: asString, + // invoice: asString, blockchain: asString, network: asString, depositAddress: asString, @@ -609,7 +609,7 @@ export const paybisProvider: FiatProviderFactory = { inPayment = true try { const payDetails = await paybisFetch({ method: 'GET', url, path: `v2/request/${requestId}/payment-details`, apiKey, promoCode }) - const { assetId, amount, currencyCode: pbCurrencyCode, invoice, network, depositAddress, destinationTag } = asPaymentDetails(payDetails) + const { assetId, amount, currencyCode: pbCurrencyCode, network, depositAddress, destinationTag } = asPaymentDetails(payDetails) const { pluginId, tokenId } = PAYBIS_TO_EDGE_CURRENCY_MAP[assetId] console.log(`Creating Paybis payment`) @@ -626,7 +626,7 @@ export const paybisProvider: FiatProviderFactory = { } const savedAction: EdgeTxActionFiat = { actionType: 'fiat', - orderId: invoice, + orderId: requestId, orderUri: `${widgetUrl}?requestId=${requestId}`, isEstimate: true, fiatPlugin: { @@ -694,7 +694,7 @@ export const paybisProvider: FiatProviderFactory = { exchangeAmount: amount }), fiatProviderId: providerId, - orderId: invoice + orderId: requestId } }) From 5a5619d919513ffec7e163d55a9bbd71d9bc205b Mon Sep 17 00:00:00 2001 From: Paul Puey Date: Fri, 20 Sep 2024 16:48:52 -0700 Subject: [PATCH 2/4] Add support for deeplinking return.edge.app --- android/app/src/main/AndroidManifest.xml | 1 + ios/edge/edge.entitlements | 1 + src/__tests__/DeepLink.test.ts | 24 ++++++++++++++++++++++++ src/types/DeepLinkTypes.ts | 1 + src/util/DeepLinkParser.ts | 1 + 5 files changed, 28 insertions(+) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 9fb3d1d3f6b..93656b4e7c6 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -58,6 +58,7 @@ + diff --git a/ios/edge/edge.entitlements b/ios/edge/edge.entitlements index f8c6053cb6d..3ee27306f01 100644 --- a/ios/edge/edge.entitlements +++ b/ios/edge/edge.entitlements @@ -7,6 +7,7 @@ com.apple.developer.associated-domains applinks:dl.edge.app + applinks:return.edge.app applinks:deep.edge.app diff --git a/src/__tests__/DeepLink.test.ts b/src/__tests__/DeepLink.test.ts index f485a0694e9..336a2555b69 100644 --- a/src/__tests__/DeepLink.test.ts +++ b/src/__tests__/DeepLink.test.ts @@ -134,6 +134,10 @@ describe('parseDeepLink', function () { 'https://deep.edge.app/edge/1234567890a': { type: 'edgeLogin', lobbyId: '1234567890a' + }, + 'https://return.edge.app/edge/1234567890a': { + type: 'edgeLogin', + lobbyId: '1234567890a' } }) @@ -226,6 +230,26 @@ describe('parseDeepLink', function () { } }) }) + describe('fiatProvider', function () { + makeLinkTests({ + 'https://deep.edge.app/fiatprovider/buy/moonpay?param=alice': { + type: 'fiatProvider', + providerId: 'moonpay', + direction: 'buy', + path: '', + query: { param: 'alice' }, + uri: 'edge://fiatprovider/buy/moonpay?param=alice' + }, + 'https://return.edge.app/fiatprovider/buy/moonpay?param=alice': { + type: 'fiatProvider', + providerId: 'moonpay', + direction: 'buy', + path: '', + query: { param: 'alice' }, + uri: 'edge://fiatprovider/buy/moonpay?param=alice' + } + }) + }) describe('promotion', function () { makeLinkTests({ diff --git a/src/types/DeepLinkTypes.ts b/src/types/DeepLinkTypes.ts index 3c176687bdb..e0a00247609 100644 --- a/src/types/DeepLinkTypes.ts +++ b/src/types/DeepLinkTypes.ts @@ -5,6 +5,7 @@ * - edge:///... * - airbitz:///... * - https://deep.edge.app//... + * - https://dp.edge.app//... * * The `edge://` protocol supports the following link types: * diff --git a/src/util/DeepLinkParser.ts b/src/util/DeepLinkParser.ts index d88ee8aebaa..7d0162d8ba7 100644 --- a/src/util/DeepLinkParser.ts +++ b/src/util/DeepLinkParser.ts @@ -251,6 +251,7 @@ const prefixes: Array<[string, string]> = [ // Alternative schemes: ['https://deep.edge.app/', 'edge://'], + ['https://return.edge.app/', 'edge://'], ['airbitz://', 'edge://'], ['reqaddr://', 'edge://reqaddr'] ] From 417ed017c63580c3914e264c8a6d300420b72881 Mon Sep 17 00:00:00 2001 From: Paul Puey Date: Fri, 20 Sep 2024 16:57:09 -0700 Subject: [PATCH 3/4] Fix uri encoding --- src/plugins/gui/providers/paybisProvider.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/gui/providers/paybisProvider.ts b/src/plugins/gui/providers/paybisProvider.ts index 08cbaacd9a9..3ccb9d7645c 100644 --- a/src/plugins/gui/providers/paybisProvider.ts +++ b/src/plugins/gui/providers/paybisProvider.ts @@ -590,8 +590,8 @@ export const paybisProvider: FiatProviderFactory = { return } - const successReturnURL = encodeURI(RETURN_URL_SUCCESS) - const failureReturnURL = encodeURI(RETURN_URL_FAIL) + const successReturnURL = encodeURIComponent(RETURN_URL_SUCCESS) + const failureReturnURL = encodeURIComponent(RETURN_URL_FAIL) const webviewUrl = `${widgetUrl}?requestId=${requestId}&successReturnURL=${successReturnURL}&failureReturnURL=${failureReturnURL}${ott}${promoCodeParam}` console.log(`webviewUrl: ${webviewUrl}`) let inPayment = false From e489742d0ec1f63ca529624765aef8769a750214 Mon Sep 17 00:00:00 2001 From: Paul Puey Date: Fri, 20 Sep 2024 16:58:35 -0700 Subject: [PATCH 4/4] Add buy tracking for paybis --- CHANGELOG.md | 3 ++ src/locales/en_US.ts | 1 + src/locales/strings/enUS.json | 1 + src/plugins/gui/providers/paybisProvider.ts | 44 ++++++++++++++++++++- 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4017a8b9ec3..e4252ed1cce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,13 @@ - added: Re-enable Piratechain on iOS - added: Battery Saver warning message for Android - added: Buy conversion tracking for Moonpay +- added: Buy conversion tracking for Paybis +- added: Support for return.edge.app deeplinks - added: Error tracking for failure to report conversions to referral server - changed: Remove whitespaces from custom token contract address input - changed: Use unique ENV configs for thorchain and thorchainda swap plugins - fixed: Correctly tag `tokenApproval` `actionType` in `getTxActionDisplayInfo` +- fixed: URI encoding in Paybis return URIs - fixed: AddressTile2 touchable area states - fixed: Cases where it was possible to create duplicate custom tokens - fixed: Clear previous swap errors when new amounts are entered or swap assets are changed in `SwapCreateScene` diff --git a/src/locales/en_US.ts b/src/locales/en_US.ts index 624d7819143..2ab66a7804c 100644 --- a/src/locales/en_US.ts +++ b/src/locales/en_US.ts @@ -1450,6 +1450,7 @@ const strings = { fiat_plugin_buy_complete_message_s: 'Your buy order of %1$s %2$s with %3$s %4$s has been completed.', fiat_plugin_buy_complete_message_2_hour_s: 'Please allow up to %1$s hour for the funds to appear in your wallet.', fiat_plugin_buy_complete_message_2_hours_s: 'Please allow up to %1$s hours for the funds to appear in your wallet.', + fiat_plugin_buy_failed_try_again: 'Buy order failed. Please try again', fiat_plugin_sell_complete_title: 'Sell Order Complete', fiat_plugin_sell_complete_message_s: 'Your sell order of %1$s %2$s for %3$s %4$s has been completed.', fiat_plugin_sell_complete_message_2_hour_s: 'Please allow up to %1$s hour for the funds to appear in your account.', diff --git a/src/locales/strings/enUS.json b/src/locales/strings/enUS.json index 04b4c5be5a2..c0c4b14d681 100644 --- a/src/locales/strings/enUS.json +++ b/src/locales/strings/enUS.json @@ -1281,6 +1281,7 @@ "fiat_plugin_buy_complete_message_s": "Your buy order of %1$s %2$s with %3$s %4$s has been completed.", "fiat_plugin_buy_complete_message_2_hour_s": "Please allow up to %1$s hour for the funds to appear in your wallet.", "fiat_plugin_buy_complete_message_2_hours_s": "Please allow up to %1$s hours for the funds to appear in your wallet.", + "fiat_plugin_buy_failed_try_again": "Buy order failed. Please try again", "fiat_plugin_sell_complete_title": "Sell Order Complete", "fiat_plugin_sell_complete_message_s": "Your sell order of %1$s %2$s for %3$s %4$s has been completed.", "fiat_plugin_sell_complete_message_2_hour_s": "Please allow up to %1$s hour for the funds to appear in your account.", diff --git a/src/plugins/gui/providers/paybisProvider.ts b/src/plugins/gui/providers/paybisProvider.ts index 3ccb9d7645c..082cbb2fc19 100644 --- a/src/plugins/gui/providers/paybisProvider.ts +++ b/src/plugins/gui/providers/paybisProvider.ts @@ -1,6 +1,7 @@ import { eq, lte, mul, round } from 'biggystring' import { asArray, asBoolean, asDate, asMaybe, asObject, asOptional, asString, asValue } from 'cleaners' import { EdgeAssetAction, EdgeFetchOptions, EdgeSpendInfo, EdgeTxActionFiat, JsonObject } from 'edge-core-js' +import { sprintf } from 'sprintf-js' import URL from 'url-parse' import { SendScene2Params } from '../../../components/scenes/SendScene2' @@ -584,8 +585,49 @@ export const paybisProvider: FiatProviderFactory = { const promoCodeParam = promoCode != null ? `&promoCode=${promoCode}` : '' if (direction === 'buy') { + const successReturnURL = encodeURIComponent('https://return.edge.app/fiatprovider/buy/paybis?transactionStatus=success') + const failureReturnURL = encodeURIComponent('https://return.edge.app/fiatprovider/buy/paybis?transactionStatus=fail') await showUi.openExternalWebView({ - url: `${widgetUrl}?requestId=${requestId}${ott}${promoCodeParam}` + url: `${widgetUrl}?requestId=${requestId}${ott}${promoCodeParam}&successReturnURL=${successReturnURL}&failureReturnURL=${failureReturnURL}`, + providerId, + deeplinkHandler: async link => { + const { query, uri } = link + console.log('Paybis WebView launch buy success: ' + uri) + const { transactionStatus } = query + if (transactionStatus === 'success') { + await showUi.trackConversion('Buy_Success', { + conversionValues: { + conversionType: 'buy', + sourceFiatCurrencyCode: fiatCurrencyCode, + sourceFiatAmount: fiatAmount, + destAmount: new CryptoAmount({ + currencyConfig: coreWallet.currencyConfig, + currencyCode: displayCurrencyCode, + exchangeAmount: cryptoAmount + }), + fiatProviderId: providerId, + orderId: requestId + } + }) + const message = + sprintf(lstrings.fiat_plugin_buy_complete_message_s, cryptoAmount, displayCurrencyCode, fiatAmount, fiat, '1') + + '\n\n' + + sprintf(lstrings.fiat_plugin_buy_complete_message_2_hour_s, '1') + + '\n\n' + + lstrings.fiat_plugin_sell_complete_message_3 + await showUi.buttonModal({ + buttons: { + ok: { label: lstrings.string_ok, type: 'primary' } + }, + title: lstrings.fiat_plugin_buy_complete_title, + message + }) + } else if (transactionStatus === 'failure') { + await showUi.showToast(lstrings.fiat_plugin_buy_failed_try_again, NOT_SUCCESS_TOAST_HIDE_MS) + } else { + await showUi.showError(new Error(`Paybis: Invalid transactionStatus "${transactionStatus}".`)) + } + } }) return }