Get Started
Handcash Connect
Business Wallet
Wallet API
Use Cases and Examples
Miscellaneous
On Ramps
How to Get Money into Your Users Wallets
There are several ways for users to deposit money into their new accounts:
- Other BSV Wallets using
account.getDepositInfo()
- Paymail
- Base58 Address
- Credit Card
- Other Cryptocurrencies
While Paymail and address deposits are straightforward, this guide will cover how to add a widget for Credit Card and Cryptocurrency deposits. Both methods will use the base58Address
provided in a user’s deposit info, and the widget will conveniently pass it into the services to create a seamless user experience.
A full example can be found here.
Cryptocurrency Deposit
To support cryptocurrency deposits, you can use LetsExchange. You will need an affiliate ID, or you may use the HandCash affiliate ID: ZOTVxWxEZxW6dcfS
.
Credit Card Top-Ups
To support credit card top-ups, you can use Guardarian. You will need a public API token, or you can use the HandCash one: 797beecc-7f37-4f4f-9904-9bb77c38eb88
.
Here is a widget that handles both fiat and cryptocurrency top-ups using the shadcn component library:
'use client';
import {
AlertDialogCancel,
AlertDialogContent,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from '@/components/ui/alert-dialog';
import {
IconCreditCard,
IconCurrencyBitcoin,
IconSwitchHorizontal,
IconX,
} from '@tabler/icons-react';
import { AlertDialog } from '@radix-ui/react-alert-dialog';
import React from 'react';
import InputTextField from '@/components/ui/InputTextField';
import { Button } from '@/components/ui/button';
import { cn } from "@/lib/utils";
import { useWallet } from '@/app/context/WalletContext';
type Props = {
trigger: React.ReactNode;
depositAddress: string;
};
type LetsExchangeQueryParams = {
affiliate_id: string;
is_iframe: boolean;
};
type GuardarianQueryParams = {
partner_api_token: string;
type: string;
theme: string;
default_from_amount: number;
default_fiat_currency: string;
default_crypto_currency: string;
crypto_currencies_list: string;
default_side: string;
side_toggle_disabled: boolean;
calc_background: string;
body_background: string;
button_background: string;
create_nav_behaviour: string;
without_box_shadow: boolean;
};
const NEXT_PUBLIC_NEXT_EXCHANGE_AFFILIATE_ID = process.env.NEXT_PUBLIC_NEXT_EXCHANGE_AFFILIATE_ID as string;
const NEXT_PUBLIC_GUARDARIAN_API_TOKEN = process.env.NEXT_PUBLIC_GUARDARIAN_API_TOKEN as string;
function serializeQueryParams<T extends Record<string, any>>(params: T): string {
return Object.entries(params)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join('&');
}
export default function TopUpDialog({ trigger, depositAddress }: Props) {
const [selectedTopUpMethod, setSelectedTopUpMethod] = React.useState<string | undefined>();
const { refreshBalances } = useWallet();
const guardarianQueryParams: GuardarianQueryParams = {
partner_api_token: NEXT_PUBLIC_GUARDARIAN_API_TOKEN,
type: 'narrow',
theme: 'blue',
default_from_amount: 50,
default_fiat_currency: 'USD',
default_crypto_currency: 'BSV',
crypto_currencies_list: '%5B%7B%22ticker%22%3A%22BSV%22%2C%22network%22%3A%22BSV%22%7D%5D',
default_side: 'buy_crypto',
side_toggle_disabled: true,
calc_background: 'hex_040404',
body_background: 'hex_040404',
button_background: 'hex_57ff97',
create_nav_behaviour: 'new_tab',
without_box_shadow: true,
};
const letsExchangeQueryParams: LetsExchangeQueryParams = {
affiliate_id: NEXT_PUBLIC_NEXT_EXCHANGE_AFFILIATE_ID,
is_iframe: true,
};
const onOpenChange = (open: boolean) => {
refreshBalances();
setTimeout(() => setSelectedTopUpMethod(undefined), 500);
};
return (
<AlertDialog onOpenChange={onOpenChange}>
<AlertDialogTrigger asChild>{trigger}</AlertDialogTrigger>
<AlertDialogContent className="w-full max-w-[500px] rounded-xl">
<AlertDialogHeader className="flex flex-row justify-between items-center">
<AlertDialogTitle>Top-up your wallet</AlertDialogTitle>
<AlertDialogCancel className="p-1 w-5 h-5 !mt-0 rounded-full bg-white/10">
<IconX />
</AlertDialogCancel>
</AlertDialogHeader>
{!selectedTopUpMethod && (
<div className="flex flex-col gap-y-0.5">
<Button
onClick={() => {
setSelectedTopUpMethod('fiat');
}}
variant="ghost"
className={cn(
'h-14 flex items-center justify-start w-full px-3 py-3 md:px-3 md:py-3 mb-1 hover:cursor-pointer hover:bg-white/15 duration-200 transition backdrop-blur-md rounded-md border border-white/20',
)}
>
<IconCreditCard className="mr-4 h-6 w-6 text-primary" />
<div className="flex flex-col items-start">
<p className="text-foreground">Buy with Credit Card</p>
<p className="text-muted-foreground text-xs">Visa, Mastercard, Google Pay, Apple Pay</p>
</div>
</Button>
<Button
onClick={() => {
setSelectedTopUpMethod('crypto');
}}
variant="ghost"
className={cn(
'h-14 flex items-center justify-start w-full px-3 py-3 md:px-3 md:py-3 mb-1 hover:cursor-pointer hover:bg-white/15 duration-200 transition backdrop-blur-md rounded-md border border-white/20',
)}
>
<IconCurrencyBitcoin className="mr-4 h-6 w-6 text-primary" />
<div className="flex flex-col items-start">
<p className="text-foreground">Deposit Crypto</p>
<p className="text-muted-foreground text-xs">Select from over 4,880 cryptocurrencies</p>
</div>
</Button>
<a href="https://ramps.handcash.io" target="_blank" rel="noopener noreferrer">
<Button
variant="ghost"
className={cn(
'h-14 flex items-center justify-start w-full px-3 py-3 md:px-3 md:py-3 mb-1 hover:cursor-pointer hover:bg-white/15 duration-200 transition backdrop-blur-md rounded-md border border-white/20',
)}
>
<IconSwitchHorizontal className="mr-4 h-6 w-6 text-primary" />
<div className="flex flex-col items-start">
<p className="text-foreground">Other options</p>
<p className="text-muted-foreground text-xs">Buy, Sell & Swap crypto</p>
</div>
</Button>
</a>
</div>
)}
{selectedTopUpMethod === 'crypto' && (
<div>
<div className="mb-4">
<p className="flex items-center text-sm text-center text-white/80">Your BSV receiving address</p>
<InputTextField className="rounded-xl" value={depositAddress} readOnly isMonotype isCopyContent />
</div>
<div className="lets-widget rounded-xl" id="lets_widget_ZOTVxWxEZxW6dcfS" style={{ maxWidth: '480px', height: '512px' }}>
<iframe
src={`https://letsexchange.io/v2/widget?${serializeQueryParams(letsExchangeQueryParams)}`}
width="100%"
height="100%"
frameBorder="0"
allow="clipboard-read; clipboard-write"
></iframe>
</div>
</div>
)}
{selectedTopUpMethod === 'fiat' && (
<div>
<div className="mb-0">
<p className="flex items-center text-sm text-center text-white/80">Your BSV receiving address</p>
<InputTextField className="rounded-xl" value={depositAddress} readOnly isMonotype isCopyContent />
</div>
<div className="lets-widget rounded-xl" id="lets_widget_ZOTVxWxEZxW6dcfS" style={{ maxWidth: '480px', height: '300px' }}>
<iframe
src={`https://guardarian.com/calculator/v1?${serializeQueryParams(guardarianQueryParams)}`}
width="100%"
height="100%"
frameBorder="0"
allow="clipboard-read; clipboard-write"
></iframe>
</div>
</div>
)}
</AlertDialogContent>
</AlertDialog>
);
}