Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ exports[`Request should render a blank scene with loaded props 1`] = `
}
}
>
To buy, sell, and receive funds, please back up your account. Edge encrypted backups use a familiar username and password method that will safeguard your assets and help prevent loss of funds.
To buy, sell, and receive funds, please create a full account. Edge full accounts require no personal information and use a familiar username and password method that will safeguard your assets and help prevent loss of funds.

Never share your username and password, and store your credentials securely!
</EdgeText>
Expand Down
23 changes: 18 additions & 5 deletions src/actions/ScanActions.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { gt } from 'biggystring'
import { asMaybeInsufficientFundsError, EdgeAccount, EdgeCurrencyWallet, EdgeParsedUri, EdgeSpendInfo, EdgeTokenId } from 'edge-core-js'
import * as React from 'react'
import { sprintf } from 'sprintf-js'
Expand All @@ -9,9 +10,10 @@ import { WalletListModal, WalletListResult } from '../components/modals/WalletLi
import { Airship, showError, showWarning } from '../components/services/AirshipInstance'
import { getSpecialCurrencyInfo } from '../constants/WalletAndCurrencyConstants'
import { lstrings } from '../locales/strings'
import { convertCurrency } from '../selectors/WalletSelectors'
import { config } from '../theme/appConfig'
import { RequestAddressLink } from '../types/DeepLinkTypes'
import { Dispatch, ThunkAction } from '../types/reduxTypes'
import { Dispatch, RootState, ThunkAction } from '../types/reduxTypes'
import { NavigationBase } from '../types/routerTypes'
import { getCurrencyCode, getWalletTokenId } from '../util/CurrencyInfoHelpers'
import { parseDeepLink } from '../util/DeepLinkParser'
Expand Down Expand Up @@ -203,7 +205,7 @@ export function handleWalletUris(

if (parsedUri.privateKeys != null && parsedUri.privateKeys.length > 0) {
// PRIVATE KEY URI
return await privateKeyModalActivated(account, navigation, wallet, parsedUri.privateKeys)
return await privateKeyModalActivated(state, account, navigation, wallet, parsedUri.privateKeys)
}

// PUBLIC ADDRESS URI
Expand Down Expand Up @@ -239,7 +241,13 @@ export function handleWalletUris(
}
}

async function privateKeyModalActivated(account: EdgeAccount, navigation: NavigationBase, wallet: EdgeCurrencyWallet, privateKeys: string[]): Promise<void> {
async function privateKeyModalActivated(
state: RootState,
account: EdgeAccount,
navigation: NavigationBase,
wallet: EdgeCurrencyWallet,
privateKeys: string[]
): Promise<void> {
const message = sprintf(lstrings.private_key_modal_sweep_from_private_key_message, config.appName)

await Airship.show<'confirm' | 'cancel' | undefined>(bridge => (
Expand All @@ -257,7 +265,7 @@ async function privateKeyModalActivated(account: EdgeAccount, navigation: Naviga
const memoryWalletPromise = account.makeMemoryWallet(wallet.type, { keys })
navigation.navigate('sweepPrivateKeyProcessing', { memoryWalletPromise, receivingWallet: wallet })
} catch (e) {
await sweepPrivateKeys(account, navigation, wallet, privateKeys)
await sweepPrivateKeys(state, account, navigation, wallet, privateKeys)
}
return true
}
Expand All @@ -269,7 +277,7 @@ async function privateKeyModalActivated(account: EdgeAccount, navigation: Naviga
))
}

async function sweepPrivateKeys(account: EdgeAccount, navigation: NavigationBase, wallet: EdgeCurrencyWallet, privateKeys: string[]) {
async function sweepPrivateKeys(state: RootState, account: EdgeAccount, navigation: NavigationBase, wallet: EdgeCurrencyWallet, privateKeys: string[]) {
if (checkAndShowLightBackupModal(account, navigation)) return

try {
Expand All @@ -278,6 +286,11 @@ async function sweepPrivateKeys(account: EdgeAccount, navigation: NavigationBase
privateKeys,
spendTargets: []
})
// Check for a $50 maximum sweep for light accounts
const sweepAmountFiat = convertCurrency(state, wallet.currencyInfo.currencyCode, 'USD', unsignedTx.nativeAmount)
if (gt(sweepAmountFiat, 50) && checkAndShowLightBackupModal(account, navigation)) return

// Continue with sweep if above requirements met
const signedTx = await wallet.signTx(unsignedTx)
await wallet.broadcastTx(signedTx)

Expand Down
62 changes: 40 additions & 22 deletions src/components/scenes/GettingStartedScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import uspImage1 from '../../assets/images/gettingStarted/usp1.png'
import uspImage2 from '../../assets/images/gettingStarted/usp2.png'
import uspImage3 from '../../assets/images/gettingStarted/usp3.png'
import { SCROLL_INDICATOR_INSET_FIX } from '../../constants/constantSettings'
import { ExperimentConfig } from '../../experimentConfig'
import { ExperimentConfig, UspSigninCtaType } from '../../experimentConfig'
import { useHandler } from '../../hooks/useHandler'
import { lstrings } from '../../locales/strings'
import { useDispatch, useSelector } from '../../types/reactRedux'
Expand Down Expand Up @@ -87,7 +87,6 @@ export const GettingStartedScene = (props: Props) => {
const { experimentConfig } = route.params
const context = useSelector(state => state.core.context)
const hasLocalUsers = context.localUsers.length > 0
const lightAccounts = experimentConfig.createAccountType === 'light' && !hasLocalUsers

// An extra index is added to account for the extra initial usp slide OR to
// allow the SwipeOffsetDetector extra room for the user to swipe beyond to
Expand All @@ -98,15 +97,16 @@ export const GettingStartedScene = (props: Props) => {
// Route helpers
const visitPasswordScene = (): void =>
navigation.replace('login', {
loginUiInitialRoute: lightAccounts ? 'login-password-light' : 'login-password',
loginUiInitialRoute: 'login-password',
experimentConfig
})

const visitNewAccountScene = (): void =>
// Android needs replace instead of navigate or the loginUiInitialRoute
// doesn't work...
navigation.replace('login', {
loginUiInitialRoute: lightAccounts ? 'new-light-account' : 'new-account',
// Only create light accounts if no other accounts exist
loginUiInitialRoute: hasLocalUsers ? 'new-account' : 'new-light-account',
experimentConfig
})

Expand Down Expand Up @@ -156,6 +156,37 @@ export const GettingStartedScene = (props: Props) => {
}
)

const footerButtons =
experimentConfig.uspSigninCta === 'alreadyHaveAccount' ? (
<>
<ButtonsView
layout="column"
primary={{
label: lstrings.account_get_started,
onPress: handlePressSignUp
}}
/>
<TertiaryTouchable onPress={handlePressSignIn}>
<TertiaryText>
{/* eslint-disable-next-line react-native/no-raw-text */}
{`${lstrings.getting_started_already_have_an_account} `}
<TappableText>{lstrings.getting_started_sign_in}</TappableText>
</TertiaryText>
</TertiaryTouchable>
</>
) : (
<ButtonsView
primary={{
label: lstrings.account_get_started,
onPress: handlePressSignUp
}}
secondary={{
label: lstrings.getting_started_sign_in,
onPress: handlePressSignIn
}}
/>
)

return (
<SceneWrapper hasHeader={false}>
<SkipButton swipeOffset={swipeOffset}>
Expand Down Expand Up @@ -204,7 +235,7 @@ export const GettingStartedScene = (props: Props) => {
))}
</Pagination>
<SectionCoverAnimated swipeOffset={swipeOffset}>
<Sections swipeOffset={swipeOffset}>
<Sections swipeOffset={swipeOffset} uspSigninCta={experimentConfig.uspSigninCta}>
{sections.map((section, index) => {
return (
<Section key={section.key} swipeOffset={swipeOffset} itemIndex={index + 1}>
Expand All @@ -217,20 +248,7 @@ export const GettingStartedScene = (props: Props) => {
)
})}
</Sections>
<ButtonsView
layout="column"
primary={{
label: lstrings.account_get_started,
onPress: handlePressSignUp
}}
/>
<TertiaryTouchable onPress={handlePressSignIn}>
<TertiaryText>
{/* eslint-disable-next-line react-native/no-raw-text */}
{`${lstrings.getting_started_already_have_an_account} `}
<TappableText>{lstrings.getting_started_sign_in}</TappableText>
</TertiaryText>
</TertiaryTouchable>
{footerButtons}
</SectionCoverAnimated>
</Container>
</SwipeOffsetDetector>
Expand Down Expand Up @@ -422,11 +440,11 @@ const SectionCoverAnimated = styled(Animated.View)<{ swipeOffset: SharedValue<nu
]
})

const Sections = styled(Animated.View)<{ swipeOffset: SharedValue<number> }>(theme => props => {
const { swipeOffset } = props
const Sections = styled(Animated.View)<{ swipeOffset: SharedValue<number>; uspSigninCta: UspSigninCtaType }>(theme => props => {
const { swipeOffset, uspSigninCta } = props
return [
{
paddingBottom: theme.rem(1)
paddingBottom: uspSigninCta === 'alreadyHaveAccount' ? theme.rem(1) : theme.rem(-0.5)
},
useAnimatedStyle(() => {
const flexGrow = interpolate(swipeOffset.value, [0, 1], [0, 1.5])
Expand Down
16 changes: 7 additions & 9 deletions src/experimentConfig.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,31 @@
import { asMaybe, asObject, asValue, Cleaner } from 'cleaners'
import { makeReactNativeDisklet } from 'disklet'
import { CreateAccountType } from 'edge-login-ui-rn'

import { LOCAL_EXPERIMENT_CONFIG } from './constants/constantSettings'
import { ENV } from './env'
import { isMaestro } from './util/maestro'

export type BackupTextType = 'original' | 'backup' | 'secure' | 'create'
export type UspSigninCtaType = 'alreadyHaveAccount' | 'signIn'

// Persistent experiment config for A/B testing. Values initialized in this
// config persist throughout the liftetime of the app install.
export interface ExperimentConfig {
createAccountType: CreateAccountType
signupCaptcha: 'withCaptcha' | 'withoutCaptcha'
uspSigninCta: UspSigninCtaType
}

// Defined default "unchanged" values before experimentation.
export const DEFAULT_EXPERIMENT_CONFIG: ExperimentConfig = {
createAccountType: 'full',
signupCaptcha: 'withoutCaptcha'
signupCaptcha: 'withoutCaptcha',
uspSigninCta: 'alreadyHaveAccount'
}

const experimentConfigDisklet = makeReactNativeDisklet()

// The probability of an experiment config feature being set for a given key
const experimentDistribution = {
createAccountType: [50, 50],
signupCaptcha: [50, 50],
backupText: [25, 25, 25, 25]
uspSigninCta: [50, 50]
}

/**
Expand Down Expand Up @@ -67,8 +65,8 @@ const generateExperimentConfigVal = <T>(key: keyof typeof experimentDistribution
}

const asExperimentConfig: Cleaner<ExperimentConfig> = asObject({
createAccountType: asMaybe(asValue('full', 'light'), generateExperimentConfigVal('createAccountType', ['full', 'light'])),
signupCaptcha: asMaybe(asValue('withoutCaptcha', 'withCaptcha'), generateExperimentConfigVal('signupCaptcha', ['withoutCaptcha', 'withCaptcha']))
signupCaptcha: asMaybe(asValue('withoutCaptcha', 'withCaptcha'), generateExperimentConfigVal('signupCaptcha', ['withoutCaptcha', 'withCaptcha'])),
uspSigninCta: asMaybe(asValue('alreadyHaveAccount', 'signIn'), generateExperimentConfigVal('uspSigninCta', ['alreadyHaveAccount', 'signIn']))
})

/**
Expand Down
12 changes: 6 additions & 6 deletions src/locales/en_US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1447,7 +1447,7 @@ const strings = {
fiat_plugin_sell_failed_try_again: 'Sell order failed. Please try again.',
fiat_plugin_sell_failed_to_send_try_again: 'Failed to send funds for sell transaction. Please try again.',
fiat_plugin_cannot_continue_camera_permission: 'Cannot continue. Camera permission needed for ID verifications',
fiat_plugin_purchase_limit_error: 'Please back up your account to increase the purchase limit',
fiat_plugin_purchase_limit_error: 'Please create a full account to increase the purchase limit',
fiat_plugin_max_buy_quote_error: 'Provider cannot create max buy quote',
fiat_plugin_max_sell_quote_error: 'Provider cannot create max sell quote',
fiat_plugin_max_sell_quote_error_1s: 'Cannot create max sell quote for %1$s',
Expand Down Expand Up @@ -1525,21 +1525,21 @@ const strings = {
backup_account: 'Back Up Account',
backup_delete_confirm_message:
'Are you sure you want to delete this account without backing up first? You will NOT be able to recover wallets and transactions for this account!',
backup_info_message: 'Create a username and password to securely encrypt and back up your account',
backup_dismiss_button: 'Continue Without a Backup',
backup_info_message: 'Create a username and password to create a full account and secure your funds. No personal information is required',
backup_dismiss_button: 'Continue with Guest Account',
backup_warning_message: 'Without a backup, you risk losing your funds!',
backup_web3_handle_warning_message: 'Without a backup, you risk losing your web3 handle!',
tap_to_learn_more: 'Tap to learn more.',
backup_for_transfer_message:
'To buy, sell, and receive funds, please back up your account. Edge encrypted backups use a familiar username and password method that will safeguard your assets and help prevent loss of funds.\n\nNever share your username and password, and store your credentials securely!',
'To buy, sell, and receive funds, please create a full account. Edge full accounts require no personal information and use a familiar username and password method that will safeguard your assets and help prevent loss of funds.\n\nNever share your username and password, and store your credentials securely!',

guest_account: 'Guest Account',
tap_to_create_username_password: 'Tap to create a username and password',

// Backup Message Variants
backup_title: 'Back Up Your Account',
backup_title: 'Create Full Account',
backup_message: 'Create a username and password to continue.',
backup_message_subtext: 'Backing up your account ensures you can safely recover your funds in the event that you lose access to your device.',
backup_message_subtext: 'Creating a full account ensures you can safely recover your funds in the event that you lose access to your device.',

no_access_disclaimer_1s: '%1$s has zero access to user funds and does not see or store any private keys or personal information.',

Expand Down
12 changes: 6 additions & 6 deletions src/locales/strings/enUS.json
Original file line number Diff line number Diff line change
Expand Up @@ -1272,7 +1272,7 @@
"fiat_plugin_sell_failed_try_again": "Sell order failed. Please try again.",
"fiat_plugin_sell_failed_to_send_try_again": "Failed to send funds for sell transaction. Please try again.",
"fiat_plugin_cannot_continue_camera_permission": "Cannot continue. Camera permission needed for ID verifications",
"fiat_plugin_purchase_limit_error": "Please back up your account to increase the purchase limit",
"fiat_plugin_purchase_limit_error": "Please create a full account to increase the purchase limit",
"fiat_plugin_max_buy_quote_error": "Provider cannot create max buy quote",
"fiat_plugin_max_sell_quote_error": "Provider cannot create max sell quote",
"fiat_plugin_max_sell_quote_error_1s": "Cannot create max sell quote for %1$s",
Expand Down Expand Up @@ -1330,17 +1330,17 @@
"sepa_transfer_prompt_s": "Your order %1$s has been submitted!\n\nPlease save the order details below for your records and instruct your bank to make the payment with the information in the Payment Details section.",
"backup_account": "Back Up Account",
"backup_delete_confirm_message": "Are you sure you want to delete this account without backing up first? You will NOT be able to recover wallets and transactions for this account!",
"backup_info_message": "Create a username and password to securely encrypt and back up your account",
"backup_dismiss_button": "Continue Without a Backup",
"backup_info_message": "Create a username and password to create a full account and secure your funds. No personal information is required",
"backup_dismiss_button": "Continue with Guest Account",
"backup_warning_message": "Without a backup, you risk losing your funds!",
"backup_web3_handle_warning_message": "Without a backup, you risk losing your web3 handle!",
"tap_to_learn_more": "Tap to learn more.",
"backup_for_transfer_message": "To buy, sell, and receive funds, please back up your account. Edge encrypted backups use a familiar username and password method that will safeguard your assets and help prevent loss of funds.\n\nNever share your username and password, and store your credentials securely!",
"backup_for_transfer_message": "To buy, sell, and receive funds, please create a full account. Edge full accounts require no personal information and use a familiar username and password method that will safeguard your assets and help prevent loss of funds.\n\nNever share your username and password, and store your credentials securely!",
"guest_account": "Guest Account",
"tap_to_create_username_password": "Tap to create a username and password",
"backup_title": "Back Up Your Account",
"backup_title": "Create Full Account",
"backup_message": "Create a username and password to continue.",
"backup_message_subtext": "Backing up your account ensures you can safely recover your funds in the event that you lose access to your device.",
"backup_message_subtext": "Creating a full account ensures you can safely recover your funds in the event that you lose access to your device.",
"no_access_disclaimer_1s": "%1$s has zero access to user funds and does not see or store any private keys or personal information.",
"learn_more": "Learn More",
"dismiss": "Dismiss",
Expand Down