Skip to content

Commit ffd20a3

Browse files
committed
Added BitsOfGold and LibertyX ramp plugins.
1 parent 39363b3 commit ffd20a3

16 files changed

+461
-43
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Unreleased (develop)
44

5+
- added: BitsOfGold and LibertyX ramp plugins.
56
- fixed: Fixed broken `logEvent` tracking calls by adding the needed `dispatch`.
67
- removed: Remove change quote tracking.
78

src/components/scenes/RampCreateScene.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useFocusEffect } from '@react-navigation/native'
22
import { useQuery } from '@tanstack/react-query'
3-
import { div, gt, mul, round, toBns } from 'biggystring'
3+
import { div, eq, gt, mul, round, toBns } from 'biggystring'
44
import type {
55
EdgeCurrencyWallet,
66
EdgeDenomination,
@@ -375,7 +375,10 @@ export const RampCreateScene: React.FC<Props> = (props: Props) => {
375375
const maxQuoteForMaxFlow = React.useMemo(() => {
376376
if (!('max' in exchangeAmount) || allQuotes.length === 0) return null
377377

378-
const picked = allQuotes.reduce((a, b): RampQuote => {
378+
const quotesWithAmounts = allQuotes.filter(rampQuoteHasAmounts)
379+
if (quotesWithAmounts.length === 0) return null
380+
381+
const picked = quotesWithAmounts.reduce((a, b): RampQuote => {
379382
const aAmount = lastUsedInput === 'crypto' ? a.cryptoAmount : a.fiatAmount
380383
const bAmount = lastUsedInput === 'crypto' ? b.cryptoAmount : b.fiatAmount
381384
return gt(bAmount, aAmount) ? b : a
@@ -385,8 +388,7 @@ export const RampCreateScene: React.FC<Props> = (props: Props) => {
385388

386389
// Calculate exchange rate from best quote
387390
const quoteExchangeRate = React.useMemo(() => {
388-
if (bestQuote?.cryptoAmount == null || bestQuote.fiatAmount == null)
389-
return 0
391+
if (bestQuote == null || !rampQuoteHasAmounts(bestQuote)) return 0
390392

391393
try {
392394
const cryptoAmount = parseFloat(bestQuote.cryptoAmount)
@@ -606,6 +608,7 @@ export const RampCreateScene: React.FC<Props> = (props: Props) => {
606608
if (isLightAccount) {
607609
// This should have loaded by now
608610
if (fiatUsdRate == null || bestQuote == null) return
611+
if (!rampQuoteHasAmounts(bestQuote)) return
609612
const maximumFiatAmount = getRoundedFiatEquivalent('50', fiatUsdRate)
610613
if (gt(bestQuote.fiatAmount, maximumFiatAmount)) {
611614
showToast(
@@ -1130,3 +1133,6 @@ async function getMaxSpendExchangeAmount(
11301133
)(maxSpendNativeAmount)
11311134
return maxSpendExchangeAmount
11321135
}
1136+
1137+
const rampQuoteHasAmounts = (quote: RampQuote): boolean =>
1138+
!eq(quote.fiatAmount, '0') || !eq(quote.cryptoAmount, '0')

src/components/scenes/RampSelectOptionScene.tsx

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { eq } from 'biggystring'
12
import * as React from 'react'
23
import { ActivityIndicator, Image, View } from 'react-native'
34
import { sprintf } from 'sprintf-js'
@@ -216,6 +217,9 @@ export const RampSelectOptionScene: React.FC<Props> = (props: Props) => {
216217
)
217218
}
218219

220+
const quoteHasAmounts = (quote: RampQuote): boolean =>
221+
!eq(quote.fiatAmount, '0') || !eq(quote.cryptoAmount, '0')
222+
219223
const QuoteResult: React.FC<{
220224
providerQuotes: RampQuote[]
221225
onPress: (quote: RampQuote) => Promise<void>
@@ -242,21 +246,27 @@ const QuoteResult: React.FC<{
242246

243247
// Create items array for the CardListModal
244248
const items = providerQuotes.map(quote => {
245-
// Format the quote amount display for each provider
246249
const fiatCurrencyCode = quote.fiatCurrencyCode.replace('iso:', '')
247250
const cryptoCurrencyCode = quote.displayCurrencyCode
248-
const formattedFiatAmount = formatNumber(quote.fiatAmount, { toFixed: 2 })
249251

250-
// Show fiat → crypto for buy, crypto → fiat for sell
251-
const body =
252-
quote.direction === 'buy'
253-
? `${formattedFiatAmount} ${fiatCurrencyCode}${quote.cryptoAmount} ${cryptoCurrencyCode}`
254-
: `${quote.cryptoAmount} ${cryptoCurrencyCode}${formattedFiatAmount} ${fiatCurrencyCode}`
252+
const body = quoteHasAmounts(quote)
253+
? quote.direction === 'buy'
254+
? `${formatNumber(quote.fiatAmount, {
255+
toFixed: 2
256+
})} ${fiatCurrencyCode}${
257+
quote.cryptoAmount
258+
} ${cryptoCurrencyCode}`
259+
: `${quote.cryptoAmount} ${cryptoCurrencyCode}${formatNumber(
260+
quote.fiatAmount,
261+
{ toFixed: 2 }
262+
)} ${fiatCurrencyCode}`
263+
: quote.specialQuoteRateMessage ??
264+
lstrings.failed_to_calculate_quote_rate
255265

256266
return {
257267
key: quote.pluginId,
258268
title: quote.pluginDisplayName,
259-
icon: quote.partnerIcon, // Already full path
269+
icon: quote.partnerIcon,
260270
body
261271
}
262272
})
@@ -285,16 +295,20 @@ const QuoteResult: React.FC<{
285295
}
286296

287297
// Check if the currently selected quote is the best rate
298+
const hasSelectedAmounts = quoteHasAmounts(providerQuote)
299+
288300
const isBestOption =
301+
hasSelectedAmounts &&
289302
bestQuoteOverall != null &&
303+
quoteHasAmounts(bestQuoteOverall) &&
290304
providerQuote.pluginId === bestQuoteOverall.pluginId &&
291305
providerQuote.paymentType === bestQuoteOverall.paymentType &&
292306
providerQuote.fiatAmount === bestQuoteOverall.fiatAmount
293307

294308
const fiatCurrencyCode = providerQuote.fiatCurrencyCode.replace('iso:', '')
295-
const formattedSelectedFiatAmount = formatNumber(providerQuote.fiatAmount, {
296-
toFixed: 2
297-
})
309+
const formattedSelectedFiatAmount = hasSelectedAmounts
310+
? formatNumber(providerQuote.fiatAmount, { toFixed: 2 })
311+
: ''
298312

299313
// Get the icon for the payment type
300314
const paymentTypeIcon = getPaymentTypeIcon(providerQuote.paymentType, theme)
@@ -333,12 +347,17 @@ const QuoteResult: React.FC<{
333347
<PaymentOptionCard
334348
title={titleComponent}
335349
icon={icon}
336-
totalAmount={sprintf(
337-
lstrings.string_total_amount_s,
338-
providerQuote.direction === 'buy'
339-
? `${formattedSelectedFiatAmount} ${fiatCurrencyCode}${providerQuote.cryptoAmount} ${providerQuote.displayCurrencyCode}`
340-
: `${providerQuote.cryptoAmount} ${providerQuote.displayCurrencyCode}${formattedSelectedFiatAmount} ${fiatCurrencyCode}`
341-
)}
350+
totalAmount={
351+
hasSelectedAmounts
352+
? sprintf(
353+
lstrings.string_total_amount_s,
354+
providerQuote.direction === 'buy'
355+
? `${formattedSelectedFiatAmount} ${fiatCurrencyCode}${providerQuote.cryptoAmount} ${providerQuote.displayCurrencyCode}`
356+
: `${providerQuote.cryptoAmount} ${providerQuote.displayCurrencyCode}${formattedSelectedFiatAmount} ${fiatCurrencyCode}`
357+
)
358+
: providerQuote.specialQuoteRateMessage ??
359+
lstrings.tap_to_view_quote_amount_and_rate
360+
}
342361
settlementTime={formatSettlementTime(providerQuote.settlementRange)}
343362
partner={{
344363
displayName: providerQuote.pluginDisplayName,

src/envConfig.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import {
1111
} from 'cleaners'
1212

1313
import { asInitOptions as asBanxaInitOptions } from './plugins/ramps/banxa/banxaRampTypes'
14+
import { asInitOptions as asBitsofgoldInitOptions } from './plugins/ramps/bitsofgold/bitsofgoldRampTypes'
1415
import { asInitOptions as asInfiniteInitOptions } from './plugins/ramps/infinite/infiniteRampTypes'
16+
import { asInitOptions as asLibertyxInitOptions } from './plugins/ramps/libertyx/libertyxRampTypes'
1517
import { asInitOptions as asMoonpayInitOptions } from './plugins/ramps/moonpay/moonpayRampTypes'
1618
import { asInitOptions as asPaybisInitOptions } from './plugins/ramps/paybis/paybisRampTypes'
1719
import { asInitOptions as asRevolutInitOptions } from './plugins/ramps/revolut/revolutRampTypes'
@@ -149,6 +151,8 @@ export const asEnvConfig = asObject({
149151
RAMP_PLUGIN_INITS: asOptional(
150152
asObject<Record<string, unknown>>({
151153
banxa: asOptional(asBanxaInitOptions),
154+
bitsofgold: asOptional(asBitsofgoldInitOptions),
155+
libertyx: asOptional(asLibertyxInitOptions),
152156
moonpay: asOptional(asMoonpayInitOptions),
153157
infinite: asOptional(asInfiniteInitOptions),
154158
paybis: asOptional(asPaybisInitOptions),
@@ -157,6 +161,8 @@ export const asEnvConfig = asObject({
157161
}).withRest,
158162
() => ({
159163
banxa: undefined,
164+
bitsofgold: undefined,
165+
libertyx: undefined,
160166
moonpay: undefined,
161167
infinite: undefined,
162168
paybis: undefined,

src/hooks/useRampQuotes.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useQuery } from '@tanstack/react-query'
2+
import { eq } from 'biggystring'
23
import * as React from 'react'
34
import { Platform } from 'react-native'
45

@@ -108,12 +109,18 @@ export const useRampQuotes = ({
108109

109110
// Sort by best rate (lowest fiat amount for same crypto amount)
110111
return platformFilteredQuotes.sort((a, b) => {
112+
const hasAmountA = quoteHasAmounts(a)
113+
const hasAmountB = quoteHasAmounts(b)
114+
115+
if (hasAmountA && !hasAmountB) return -1
116+
if (!hasAmountA && hasAmountB) return 1
117+
if (!hasAmountA && !hasAmountB) return 0
118+
111119
const cryptoAmountA = parseFloat(a.cryptoAmount)
112120
const cryptoAmountB = parseFloat(b.cryptoAmount)
113121

114122
// Guard against division by zero
115123
if (cryptoAmountA === 0 || cryptoAmountB === 0) {
116-
// If either crypto amount is zero, sort that quote to the end
117124
if (cryptoAmountA === 0 && cryptoAmountB === 0) return 0
118125
if (cryptoAmountA === 0) return 1
119126
return -1
@@ -150,3 +157,6 @@ export const useRampQuotes = ({
150157
errors
151158
}
152159
}
160+
161+
const quoteHasAmounts = (quote: RampQuote): boolean =>
162+
!eq(quote.fiatAmount, '0') || !eq(quote.cryptoAmount, '0')

src/locales/en_US.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,8 @@ const strings = {
11361136
user_closed_modal_no_wallet: 'User closed modal. No wallet was selected',
11371137
plugin_powered_by_space: 'Powered by ',
11381138
tap_to_change_provider: 'Tap to Change Provider',
1139+
tap_to_view_quote_amount_and_rate: 'Tap to view quote amounts and rates',
1140+
failed_to_calculate_quote_rate: 'Failed to calculate quote rate',
11391141
send_from_wallet: 'Send from %s',
11401142
send_to_wallet: 'Receive to %s',
11411143
exchange_slow: 'Locating a swap is taking longer than usual.\nPlease wait...',

src/locales/strings/enUS.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,8 @@
901901
"user_closed_modal_no_wallet": "User closed modal. No wallet was selected",
902902
"plugin_powered_by_space": "Powered by ",
903903
"tap_to_change_provider": "Tap to Change Provider",
904+
"tap_to_view_quote_amount_and_rate": "Tap to view quote amounts and rates",
905+
"failed_to_calculate_quote_rate": "Failed to calculate quote rate",
904906
"send_from_wallet": "Send from %s",
905907
"send_to_wallet": "Receive to %s",
906908
"exchange_slow": "Locating a swap is taking longer than usual.\nPlease wait...",

src/plugins/ramps/allRampPlugins.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { banxaRampPlugin } from './banxa/banxaRampPlugin'
2+
import { bitsofgoldRampPlugin } from './bitsofgold/bitsofgoldRampPlugin'
23
import { infiniteRampPlugin } from './infinite/infiniteRampPlugin'
4+
import { libertyxRampPlugin } from './libertyx/libertyxRampPlugin'
35
import { moonpayRampPlugin } from './moonpay/moonpayRampPlugin'
46
import { paybisRampPlugin } from './paybis/paybisRampPlugin'
57
import type { RampPluginFactory } from './rampPluginTypes'
@@ -8,7 +10,9 @@ import { simplexRampPlugin } from './simplex/simplexRampPlugin'
810

911
export const pluginFactories: Record<string, RampPluginFactory> = {
1012
banxa: banxaRampPlugin,
13+
bitsofgold: bitsofgoldRampPlugin,
1114
infinite: infiniteRampPlugin,
15+
libertyx: libertyxRampPlugin,
1216
moonpay: moonpayRampPlugin,
1317
paybis: paybisRampPlugin,
1418
revolut: revolutRampPlugin,
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { guiPlugins } from '../../../constants/plugins/GuiPlugins'
2+
import type { RampPluginFactory, SettlementRange } from '../rampPluginTypes'
3+
import { createExternalRampPlugin } from '../utils/createExternalRampPlugin'
4+
import { asInitOptions } from './bitsofgoldRampTypes'
5+
6+
const SETTLEMENT_ONE_TO_FORTY_EIGHT_HOURS: SettlementRange = {
7+
min: { value: 1, unit: 'hours' },
8+
max: { value: 48, unit: 'hours' }
9+
}
10+
11+
export const bitsofgoldRampPlugin: RampPluginFactory = config => {
12+
const initOptions = asInitOptions(config.initOptions)
13+
14+
return createExternalRampPlugin(
15+
'bitsofgold',
16+
{
17+
guiPlugin: guiPlugins.bitsofgold,
18+
partnerIcon: initOptions.partnerIcon,
19+
buy: {
20+
paymentTypes: ['wire'],
21+
countries: ['IL'],
22+
fiatCurrencyCodes: ['ILS'],
23+
cryptoAssets: [
24+
{ pluginId: 'bitcoin', tokenId: null },
25+
{ pluginId: 'ethereum', tokenId: null }
26+
],
27+
settlementRange: SETTLEMENT_ONE_TO_FORTY_EIGHT_HOURS,
28+
deepPath: '/order/buy',
29+
deepQuery: {
30+
order_id: 'null',
31+
page: '0'
32+
}
33+
},
34+
sell: {
35+
paymentTypes: ['wire'],
36+
countries: ['IL'],
37+
fiatCurrencyCodes: ['ILS'],
38+
cryptoAssets: [
39+
{ pluginId: 'bitcoin', tokenId: null },
40+
{ pluginId: 'ethereum', tokenId: null }
41+
],
42+
settlementRange: SETTLEMENT_ONE_TO_FORTY_EIGHT_HOURS,
43+
deepPath: '/order/sell',
44+
deepQuery: {
45+
order_id: 'null',
46+
page: '0',
47+
utm_source: 'Edge',
48+
utm_medium: 'mobile_app',
49+
utm_campaign: 'co',
50+
etag: 'true'
51+
}
52+
}
53+
},
54+
config
55+
)
56+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { asObject, asOptional, asString } from 'cleaners'
2+
3+
export interface InitOptions {
4+
readonly partnerIcon: string
5+
}
6+
7+
export const asInitOptions = asObject<InitOptions>({
8+
partnerIcon: asOptional(
9+
asString,
10+
`https://content.edge.app/bits-of-gold-logo.png`
11+
)
12+
}).withRest

0 commit comments

Comments
 (0)