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
40 changes: 34 additions & 6 deletions samples/frontend/src/steps/CreateQuote.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,31 @@ interface Props {

const SOURCE_CURRENCIES = ['USD', 'USDC'] as const

// Currencies that fund over a crypto network and therefore require `cryptoNetwork`.
const CRYPTO_SOURCE_CURRENCIES = ['USDC']
// Networks a stablecoin funding source can deposit on.
const CRYPTO_NETWORKS = ['BASE', 'ETHEREUM', 'POLYGON', 'SOLANA']

export default function CreateQuote({ customerId, externalAccountId, destCurrency, onComplete, disabled }: Props) {
const [body, setBody] = useState('')
const [response, setResponse] = useState<string | null>(null)
const [error, setError] = useState<string | null>(null)
const [loading, setLoading] = useState(false)
const [sourceCurrency, setSourceCurrency] = useState<string>(SOURCE_CURRENCIES[0])
const [cryptoNetwork, setCryptoNetwork] = useState<string>(CRYPTO_NETWORKS[0])

const isCryptoSource = CRYPTO_SOURCE_CURRENCIES.includes(sourceCurrency)

useEffect(() => {
const source: Record<string, unknown> = {
sourceType: "REALTIME_FUNDING",
currency: sourceCurrency,
customerId: customerId ?? "<customer-id>"
}
// cryptoNetwork is required when funding from a crypto currency (e.g. USDC).
if (isCryptoSource) source.cryptoNetwork = cryptoNetwork
setBody(JSON.stringify({
source: {
sourceType: "REALTIME_FUNDING",
currency: sourceCurrency,
customerId: customerId ?? "<customer-id>"
},
source,
destination: {
destinationType: "ACCOUNT",
accountId: externalAccountId ?? "<external-account-id>"
Expand All @@ -35,7 +46,7 @@ export default function CreateQuote({ customerId, externalAccountId, destCurrenc
lockedCurrencySide: "SENDING",
purposeOfPayment: "GIFT"
}, null, 2))
}, [customerId, externalAccountId, sourceCurrency, destCurrency])
}, [customerId, externalAccountId, sourceCurrency, destCurrency, isCryptoSource, cryptoNetwork])

const submit = async () => {
setLoading(true)
Expand Down Expand Up @@ -72,6 +83,23 @@ export default function CreateQuote({ customerId, externalAccountId, destCurrenc
))}
</select>
</div>
{isCryptoSource && (
<div className="mb-3">
<label htmlFor="crypto-network" className="block text-sm font-medium text-gray-300 mb-1">Funding Network</label>
<select
id="crypto-network"
value={cryptoNetwork}
onChange={(e) => setCryptoNetwork(e.target.value)}
disabled={disabled || loading}
className="w-full px-3 py-2 bg-gray-800 border border-gray-700 rounded text-sm text-gray-100 focus:outline-none focus:border-blue-500"
>
{CRYPTO_NETWORKS.map((n) => (
<option key={n} value={n}>{n}</option>
))}
</select>
<p className="text-xs text-gray-500 mt-1">Required when funding from a crypto currency — the network the customer deposits {sourceCurrency} on.</p>
</div>
)}
<JsonEditor value={body} onChange={setBody} disabled={disabled || loading} />
<button
onClick={submit}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ private fun buildQuoteSource(sourceNode: JsonNode): QuoteSourceOneOf {
.currency(sourceNode.get("currency").asText())
.apply {
sourceNode.optText("customerId")?.let { customerId(it) }
// Required when funding from a crypto currency (e.g. USDC): selects the
// network the customer deposits on so the right deposit address is issued.
sourceNode.optText("cryptoNetwork")?.let { cryptoNetwork(it) }
}
.build()
return QuoteSourceOneOf.ofRealtimeFundingQuoteSource(realtimeSource)
Expand Down
Loading