Skip to content
Open
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Unreleased (develop)

- fixed: Infinite buy transfer payload and confirmation error handling

## 4.46.0 (staging)

- added: Xgram swap exchange plugin support
Expand Down
11 changes: 10 additions & 1 deletion src/components/scenes/DevTestScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -366,8 +366,17 @@ export const DevTestScene: React.FC<Props> = props => {
navigation.navigate('rampBankRoutingDetails', {
bank: {
name: 'Test Bank',
beneficiaryName: 'Test Business',
address: {
addressLine1: '123 Main St',
city: 'New York',
state: 'NY',
postalCode: '10001',
country: 'US'
},
accountNumber: '1234567890',
routingNumber: '987654321'
routingNumber: '987654321',
depositMessage: 'REF-12345'
},
fiatCurrencyCode: 'USD',
fiatAmount: '1,000.00',
Expand Down
111 changes: 104 additions & 7 deletions src/components/scenes/RampBankRoutingDetailsScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,24 @@ import { SceneContainer } from '../layout/SceneContainer'
import { EdgeRow } from '../rows/EdgeRow'
import { showToast } from '../services/AirshipInstance'
import { cacheStyles, type Theme, useTheme } from '../services/ThemeContext'
import { EdgeText, Paragraph } from '../themed/EdgeText'
import { EdgeText } from '../themed/EdgeText'

export interface BankAddress {
addressLine1: string
city: string
state: string
postalCode: string
country: string
}

export interface BankInfo {
name: string
beneficiaryName: string
address?: BankAddress
addressLine?: string
accountNumber: string
routingNumber: string
depositMessage: string
}

export interface RampBankRoutingDetailsParams {
Expand All @@ -31,6 +43,24 @@ export interface RampBankRoutingDetailsParams {
onDone: () => void
}

/** Try to parse a single-line US address like "1800 North Pole St., Orlando, FL 32801" */
const parseAddressLine = (line: string): BankAddress | undefined => {
const parts = line.split(',').map(s => s.trim())
if (parts.length < 3) return undefined

const stateZip = parts[parts.length - 1]
const match = /^([A-Z]{2})\s+(\S+)$/.exec(stateZip)
if (match == null) return undefined

return {
addressLine1: parts.slice(0, -2).join(', '),
city: parts[parts.length - 2],
state: match[1],
postalCode: match[2],
country: 'US'
}
}

interface Props extends EdgeAppSceneProps<'rampBankRoutingDetails'> {}

export const RampBankRoutingDetailsScene: React.FC<Props> = props => {
Expand All @@ -40,6 +70,10 @@ export const RampBankRoutingDetailsScene: React.FC<Props> = props => {
const theme = useTheme()
const styles = getStyles(theme)

const resolvedAddress: BankAddress | undefined =
bank.address ??
(bank.addressLine != null ? parseAddressLine(bank.addressLine) : undefined)

const amountToSendText = `${fiatAmount} ${fiatCurrencyCode}`

const handleCopyAmount = useHandler(() => {
Expand All @@ -57,9 +91,9 @@ export const RampBankRoutingDetailsScene: React.FC<Props> = props => {
size={theme.rem(2.5)}
color={theme.primaryText}
/>
<Paragraph style={styles.instructionText}>
{lstrings.ramp_bank_routing_instructions}
</Paragraph>
<EdgeText numberOfLines={0} style={styles.instructionText}>
{lstrings.ramp_bank_routing_instructions_1}
</EdgeText>
</View>

<EdgeCard>
Expand Down Expand Up @@ -87,6 +121,13 @@ export const RampBankRoutingDetailsScene: React.FC<Props> = props => {
body={bank.name}
rightButtonType="copy"
/>
{bank.beneficiaryName !== '' && (
<EdgeRow
title={lstrings.ramp_business_name_label}
body={bank.beneficiaryName}
rightButtonType="copy"
/>
)}
<EdgeRow
title={lstrings.ramp_account_number_label}
body={bank.accountNumber}
Expand All @@ -97,11 +138,66 @@ export const RampBankRoutingDetailsScene: React.FC<Props> = props => {
body={bank.routingNumber}
rightButtonType="copy"
/>
{bank.depositMessage !== '' && (
<EdgeRow
title={lstrings.ramp_deposit_message_label}
body={bank.depositMessage}
rightButtonType="copy"
/>
)}
</EdgeCard>

{resolvedAddress != null ? (
<>
<SectionHeader leftTitle={lstrings.ramp_bank_address_label} />
<EdgeCard sections>
<EdgeRow
title={lstrings.ramp_address_line_label}
body={resolvedAddress.addressLine1}
rightButtonType="copy"
/>
<EdgeRow
title={lstrings.ramp_city_label}
body={resolvedAddress.city}
rightButtonType="copy"
/>
<EdgeRow
title={lstrings.ramp_state_label}
body={resolvedAddress.state}
rightButtonType="copy"
/>
<EdgeRow
title={lstrings.ramp_postal_code_label}
body={resolvedAddress.postalCode}
rightButtonType="copy"
/>
<EdgeRow
title={lstrings.ramp_country_label}
body={resolvedAddress.country}
rightButtonType="copy"
/>
</EdgeCard>
</>
) : bank.addressLine != null && bank.addressLine !== '' ? (
<>
<SectionHeader leftTitle={lstrings.ramp_bank_address_label} />
<EdgeCard sections>
<EdgeRow
title={lstrings.ramp_address_line_label}
body={bank.addressLine}
rightButtonType="copy"
/>
</EdgeCard>
</>
) : null}

<View style={styles.warningTextContainer}>
<EdgeText style={styles.warningText}>
{lstrings.ramp_bank_routing_warning}
<EdgeText
style={styles.warningText}
disableFontScaling
numberOfLines={0}
>
{lstrings.ramp_bank_routing_instructions_2}
</EdgeText>
</View>

Expand All @@ -127,7 +223,8 @@ const getStyles = cacheStyles((theme: Theme) => ({
color: theme.iconTappable
},
instructionText: {
flexShrink: 1
flexShrink: 1,
marginLeft: theme.rem(0.5)
},
cardContent: {
padding: theme.rem(0.5)
Expand Down
4 changes: 2 additions & 2 deletions src/components/scenes/RampConfirmationScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ export const RampConfirmationScene: React.FC<Props> = props => {
setIsConfirming(true)
try {
await onConfirm()
} catch (err) {
} catch (err: unknown) {
setError(err)
reset() // Reset the slider on error
} finally {
reset()
setIsConfirming(false)
}
})
Expand Down
16 changes: 12 additions & 4 deletions src/locales/en_US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2541,15 +2541,23 @@ const strings = {

// Ramp Bank Routing Details
ramp_bank_routing_title: 'Send Bank Transfer',
ramp_bank_routing_instructions:
'Please send the exact amount shown below to the following bank account.',
ramp_bank_routing_instructions_1:
'Please send the exact amount shown below to the following bank account using ACH transfer.',
ramp_bank_routing_instructions_2:
'Verify all details before sending. Be sure to include the reference/memo exactly as shown. Transfers must be completed within 7 days of the quote.',
ramp_send_amount_label: 'Amount to Send',
ramp_bank_details_section_title: 'Bank Details',
ramp_bank_name_label: 'Bank Name',
ramp_business_name_label: 'Business Name',
ramp_bank_address_label: 'Recipient Address',
ramp_address_line_label: 'Address',
ramp_city_label: 'City',
ramp_state_label: 'State',
ramp_postal_code_label: 'ZIP / Postal Code',
ramp_country_label: 'Country',
ramp_account_number_label: 'Account Number',
ramp_routing_number_label: 'Routing Number',
ramp_bank_routing_warning:
'Please ensure all details are correct before making the transfer.',
ramp_deposit_message_label: 'Reference / Memo',
// #endregion

unknown_error_message: 'An unknown error occurred.'
Expand Down
12 changes: 10 additions & 2 deletions src/locales/strings/enUS.json
Original file line number Diff line number Diff line change
Expand Up @@ -1984,12 +1984,20 @@
"ramp_routing_number_error_length_1s": "Routing number must be exactly %1$s digits",
"string_submit": "Submit",
"ramp_bank_routing_title": "Send Bank Transfer",
"ramp_bank_routing_instructions": "Please send the exact amount shown below to the following bank account.",
"ramp_bank_routing_instructions_1": "Please send the exact amount shown below to the following bank account using ACH transfer.",
"ramp_bank_routing_instructions_2": "Verify all details before sending. Be sure to include the reference/memo exactly as shown. Transfers must be completed within 7 days of the quote.",
"ramp_send_amount_label": "Amount to Send",
"ramp_bank_details_section_title": "Bank Details",
"ramp_bank_name_label": "Bank Name",
"ramp_business_name_label": "Business Name",
"ramp_bank_address_label": "Recipient Address",
"ramp_address_line_label": "Address",
"ramp_city_label": "City",
"ramp_state_label": "State",
"ramp_postal_code_label": "ZIP / Postal Code",
"ramp_country_label": "Country",
"ramp_account_number_label": "Account Number",
"ramp_routing_number_label": "Routing Number",
"ramp_bank_routing_warning": "Please ensure all details are correct before making the transfer.",
"ramp_deposit_message_label": "Reference / Memo",
"unknown_error_message": "An unknown error occurred."
}
71 changes: 51 additions & 20 deletions src/plugins/ramps/infinite/infiniteApiTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,26 @@ export const asInfiniteTransferResponse = asJSON(
sourceDepositInstructions: asOptional(
asObject({
amount: asNumber,
depositMessage: asOptional(asString, null),
bankAccountNumber: asOptional(asString, null),
bankRoutingNumber: asOptional(asString, null),
bankBeneficiaryName: asOptional(asString, null),
bankName: asOptional(asString, null),
bankAddress: asOptional(
asObject({
addressLine1: asString,
city: asString,
state: asString,
postalCode: asString,
country: asString
}),
null
),
bankAddressLine: asOptional(asString, null),
toAddress: asOptional(asString, null)
// UNUSED fields:
// network: asString,
// currency: asString,
// depositMessage: asOptional(asString, null),
// bankBeneficiaryName: asOptional(asString, null),
// fromAddress: asOptional(asString, null)
})
)
Expand Down Expand Up @@ -360,6 +371,41 @@ export type InfiniteQuoteResponse = ReturnType<typeof asInfiniteQuoteResponse>
export type InfiniteTransferResponse = ReturnType<
typeof asInfiniteTransferResponse
>
export interface InfiniteOnrampTransferRequest {
type: 'ONRAMP'
amount: number
source: {
currency: string
}
destination: {
currency: string
network: string
toAddress: string
}
clientReferenceId?: string
developerFee?: string
}

export interface InfiniteOfframpTransferRequest {
type: 'OFFRAMP'
amount: number
source: {
currency: string
network: string
fromAddress: string
}
destination: {
currency: string
network: string
accountId: string
}
clientReferenceId?: string
developerFee?: string
}

export type InfiniteTransferRequest =
| InfiniteOnrampTransferRequest
| InfiniteOfframpTransferRequest
export type InfiniteCustomerRequest = ReturnType<
typeof asInfiniteCustomerRequest
>
Expand Down Expand Up @@ -443,24 +489,9 @@ export interface InfiniteApi {
}) => Promise<InfiniteQuoteResponse>

// Transfer methods
createTransfer: (params: {
type: InfiniteQuoteFlow
amount: number
source: {
currency: string
network: string
accountId?: string
fromAddress?: string
}
destination: {
currency: string
network: string
accountId?: string
toAddress?: string
}
clientReferenceId?: string
developerFee?: string
}) => Promise<InfiniteTransferResponse>
createTransfer: (
params: InfiniteTransferRequest
) => Promise<InfiniteTransferResponse>

getTransferStatus: (transferId: string) => Promise<InfiniteTransferResponse>

Expand Down
1 change: 0 additions & 1 deletion src/plugins/ramps/infinite/infiniteRampPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,6 @@ export const infiniteRampPlugin: RampPluginFactory = (
freshQuote,
coreWallet,
bankAccountId: bankAccountResult.bankAccountId,
flow,
infiniteNetwork,
cleanFiatCode
}
Expand Down
8 changes: 7 additions & 1 deletion src/plugins/ramps/infinite/utils/navigationFlow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { NavigationBase } from '../../../../types/routerTypes'
export interface NavigationFlow {
navigate: NavigationBase['navigate']
goBack: () => void
popToTop: () => void
}

export const makeNavigationFlow = (
Expand All @@ -26,5 +27,10 @@ export const makeNavigationFlow = (
hasNavigated = false
}

return { navigate, goBack }
const popToTop = (): void => {
navigation.popToTop()
hasNavigated = false
}

return { navigate, goBack, popToTop }
}
Loading
Loading