USDC/USDT to Cash App
bridge_to_cash_appbridge_to_cash_appbridgeToCashAppbridgeToCashAppbridgeToCashAppbridgeToCashAppbridgeToCashAppBridgeToCashAppBridgeToCashApp lets someone holding USDC or USDT on an external chain pay a Cash App user. The payer deposits the stablecoin, and the cross-chain provider pays the recipient in Bitcoin over Lightning. See Cash App and USDC/USDT for what the two Cash App bridges share.
How it works
- Select a source route for the Cash App user.
- Call
bridge_to_cash_appbridge_to_cash_appbridgeToCashAppbridgeToCashAppbridgeToCashAppbridgeToCashAppbridgeToCashAppBridgeToCashAppBridgeToCashAppwith the recipient, the route, the USD amount and the payer's refund address. The SDK checks the recipient and gets a quote from the cross-chain provider. - Show the payer the returned
payment_requestpayment_requestpaymentRequestpaymentRequestpaymentRequestpaymentRequestpaymentRequestPaymentRequestPaymentRequest, and store thebridge_idbridge_idbridgeIdbridgeIdbridgeIdbridgeIdbridgeIdBridgeIdBridgeIdandstatus_tokenstatus_tokenstatusTokenstatusTokenstatusTokenstatusTokenstatusTokenStatusTokenStatusTokento track the bridge. Once their deposit lands, the provider pays the recipient.
// List the routes to the Cash App user and pick what the payer pays in,
// e.g. USDC on Base.
let recipient = "$alice".to_string();
let routes = client
.get_routes(GetBridgeRoutesRequest {
recipient: recipient.clone(),
})
.await?
.routes;
let route = routes
.into_iter()
.find(|r| r.source.asset == "USDC" && r.source.chain == "base")
.ok_or_else(|| anyhow::anyhow!("No route from USDC on Base"))?;
// Pay $10 of USDC to the Cash App user $alice. The amount is in USDC base
// units (6 decimals), so 10_000_000 = 10 USDC, about $10. The deposit is
// refunded to the payer's address if delivery fails.
let response = client
.bridge_to_cash_app(CreateBridgeRequest {
recipient,
route,
amount: 10_000_000,
refund_address: Some("<payer address>".to_string()),
fee_policy: None,
max_slippage_bps: None,
})
.await?;
// Show the payer what to pay. The recipient then receives Bitcoin.
let info = response.info;
info!("Pay with: {}", response.payment_request);
info!(
"Deposit {} to {}, recipient receives ~{} sats",
info.deposit_amount, info.deposit_address, info.expected_received_amount
);
// List the routes to the Cash App user and pick what the payer pays in,
// e.g. USDC on Base.
let recipient = "$alice"
let routes = try await client.getRoutes(
request: GetBridgeRoutesRequest(recipient: recipient)
).routes
guard
let route = routes.first(where: {
$0.source.asset == "USDC" && $0.source.chain == "base"
})
else {
throw NSError(domain: "CashApp", code: 2)
}
// Pay $10 of USDC to the Cash App user $alice. The amount is in USDC base
// units (6 decimals), so 10_000_000 = 10 USDC, about $10. The deposit is
// refunded to the payer's address if delivery fails.
let response = try await client.bridgeToCashApp(
request: CreateBridgeRequest(
recipient: recipient,
route: route,
amount: BInt(10_000_000),
refundAddress: "<payer address>",
feePolicy: nil,
maxSlippageBps: nil
))
// Show the payer what to pay. The recipient then receives Bitcoin.
let info = response.info
print("Pay with: \(response.paymentRequest)")
print(
"Deposit \(info.depositAmount) to \(info.depositAddress), "
+ "recipient receives ~\(info.expectedReceivedAmount) sats"
)
// List the routes to the Cash App user and pick what the payer pays in,
// e.g. USDC on Base.
val recipient = "\$alice"
val routes = client.getRoutes(GetBridgeRoutesRequest(recipient = recipient)).routes
val route = routes.find { it.source.asset == "USDC" && it.source.chain == "base" }
?: throw IllegalArgumentException("No route from USDC on Base")
// Pay $10 of USDC to the Cash App user $alice. The amount is in USDC base
// units (6 decimals), so 10_000_000 = 10 USDC, about $10. The deposit is
// refunded to the payer's address if delivery fails.
val response = client.bridgeToCashApp(
CreateBridgeRequest(
recipient = recipient,
route = route,
amount = BigInteger.fromLong(10_000_000L),
refundAddress = "<payer address>",
feePolicy = null,
maxSlippageBps = null,
)
)
// Show the payer what to pay. The recipient then receives Bitcoin.
val info = response.info
// Log.v("Breez", "Pay with: ${response.paymentRequest}")
// Log.v("Breez", "Deposit ${info.depositAmount} to ${info.depositAddress}, " +
// "recipient receives ~${info.expectedReceivedAmount} sats")
// List the routes to the Cash App user and pick what the payer pays in,
// e.g. USDC on Base.
var recipient = "$alice";
var routes = (await client.GetRoutes(
request: new GetBridgeRoutesRequest(recipient: recipient)
)).routes;
var route = routes.First(
r => r.source.asset == "USDC" && r.source.chain == "base"
);
// Pay $10 of USDC to the Cash App user $alice. The amount is in USDC base
// units (6 decimals), so 10_000_000 = 10 USDC, about $10. The deposit is
// refunded to the payer's address if delivery fails.
var request = new CreateBridgeRequest(
recipient: recipient,
route: route,
amount: new BigInteger(10_000_000),
refundAddress: "<payer address>",
feePolicy: null,
maxSlippageBps: null
);
var response = await client.BridgeToCashApp(request: request);
// Show the payer what to pay. The recipient then receives Bitcoin.
var info = response.info;
Console.WriteLine($"Pay with: {response.paymentRequest}");
Console.WriteLine(
$"Deposit {info.depositAmount} to {info.depositAddress}, "
+ $"recipient receives ~{info.expectedReceivedAmount} sats"
);
// List the routes to the Cash App user and pick what the payer pays in,
// e.g. USDC on Base.
const recipient = '$alice'
const { routes } = await client.getRoutes({ recipient })
const route = routes.find((r) => r.source.asset === 'USDC' && r.source.chain === 'base')
if (route === undefined) {
throw new Error('No route from USDC on Base')
}
// Pay $10 of USDC to the Cash App user $alice. The amount is in USDC base
// units (6 decimals), so 10_000_000 = 10 USDC, about $10. The deposit is
// refunded to the payer's address if delivery fails.
const response = await client.bridgeToCashApp({
recipient,
route,
amount: BigInt(10_000_000),
refundAddress: '<payer address>',
feePolicy: undefined,
maxSlippageBps: undefined
})
// Show the payer what to pay. The recipient then receives Bitcoin.
const info = response.info
console.log(`Pay with: ${response.paymentRequest}`)
console.log(
`Deposit ${info.depositAmount} to ${info.depositAddress}, ` +
`recipient receives ~${info.expectedReceivedAmount} sats`
)
// List the routes to the Cash App user and pick what the payer pays in,
// e.g. USDC on Base.
const recipient = '$alice'
const { routes } = await client.getRoutes({ recipient })
const route = routes.find((r) => r.source.asset === 'USDC' && r.source.chain === 'base')
if (route === undefined) {
throw new Error('No route from USDC on Base')
}
// Pay $10 of USDC to the Cash App user $alice. The amount is in USDC base
// units (6 decimals), so 10_000_000 = 10 USDC, about $10. The deposit is
// refunded to the payer's address if delivery fails.
const response = await client.bridgeToCashApp({
recipient,
route,
amount: BigInt(10_000_000),
refundAddress: '<payer address>',
feePolicy: undefined,
maxSlippageBps: undefined
})
// Show the payer what to pay. The recipient then receives Bitcoin.
const info = response.info
console.log(`Pay with: ${response.paymentRequest}`)
console.log(
`Deposit ${info.depositAmount} to ${info.depositAddress}, ` +
`recipient receives ~${info.expectedReceivedAmount} sats`
)
// List the routes to the Cash App user and pick what the payer pays in,
// e.g. USDC on Base.
String recipient = "\$alice";
final routesResponse = await client.getRoutes(
request: GetBridgeRoutesRequest(recipient: recipient),
);
BridgeRoutePair route = routesResponse.routes.firstWhere(
(r) => r.source.asset == "USDC" && r.source.chain == "base",
);
// Pay $10 of USDC to the Cash App user $alice. The amount is in USDC base
// units (6 decimals), so 10000000 = 10 USDC, about $10. The deposit is
// refunded to the payer's address if delivery fails.
final response = await client.bridgeToCashApp(
request: CreateBridgeRequest(
recipient: recipient,
route: route,
amount: BigInt.from(10000000),
refundAddress: "<payer address>",
feePolicy: null,
maxSlippageBps: null,
),
);
// Show the payer what to pay. The recipient then receives Bitcoin.
final info = response.info;
print("Pay with: ${response.paymentRequest}");
print(
"Deposit ${info.depositAmount} to ${info.depositAddress},"
" recipient receives ~${info.expectedReceivedAmount} sats",
);
try:
# List the routes to the Cash App user and pick what the payer pays in,
# e.g. USDC on Base.
recipient = "$alice"
routes_response = await client.get_routes(
request=GetBridgeRoutesRequest(recipient=recipient)
)
route = next(
(
r
for r in routes_response.routes
if r.source.asset == "USDC" and r.source.chain == "base"
),
None,
)
if route is None:
raise ValueError("No route from USDC on Base")
# Pay $10 of USDC to the Cash App user $alice. The amount is in USDC base
# units (6 decimals), so 10_000_000 = 10 USDC, about $10. The deposit is
# refunded to the payer's address if delivery fails.
request = CreateBridgeRequest(
recipient=recipient,
route=route,
amount=10_000_000,
refund_address="<payer address>",
fee_policy=None,
max_slippage_bps=None,
)
response = await client.bridge_to_cash_app(request=request)
# Show the payer what to pay. The recipient then receives Bitcoin.
info = response.info
logging.debug(f"Pay with: {response.payment_request}")
logging.debug(
f"Deposit {info.deposit_amount} to {info.deposit_address}, "
f"recipient receives ~{info.expected_received_amount} sats"
)
except Exception as error:
logging.error(error)
raise
// List the routes to the Cash App user and pick what the payer pays in,
// e.g. USDC on Base.
recipient := "$alice"
routesResponse, err := client.GetRoutes(breez_sdk_spark.GetBridgeRoutesRequest{
Recipient: recipient,
})
if err != nil {
return nil, err
}
routes := routesResponse.Routes
var route *breez_sdk_spark.BridgeRoutePair
for i := range routes {
if routes[i].Source.Asset == "USDC" && routes[i].Source.Chain == "base" {
route = &routes[i]
break
}
}
if route == nil {
return nil, errors.New("no route from USDC on Base")
}
// Pay $10 of USDC to the Cash App user $alice. The amount is in USDC base
// units (6 decimals), so 10_000_000 = 10 USDC, about $10. The deposit is
// refunded to the payer's address if delivery fails.
refundAddress := "<payer address>"
response, err := client.BridgeToCashApp(breez_sdk_spark.CreateBridgeRequest{
Recipient: recipient,
Route: *route,
Amount: new(big.Int).SetInt64(10_000_000),
RefundAddress: &refundAddress,
FeePolicy: nil,
MaxSlippageBps: nil,
})
if err != nil {
return nil, err
}
// Show the payer what to pay. The recipient then receives Bitcoin.
info := response.Info
log.Printf("Pay with: %s", response.PaymentRequest)
log.Printf(
"Deposit %v to %s, recipient receives ~%v sats",
info.DepositAmount, info.DepositAddress, info.ExpectedReceivedAmount,
)
Recipient
The recipientrecipientrecipientrecipientrecipientrecipientrecipientRecipientRecipient is a Cash App username, given as $alice, or the user's Cash App Lightning address, alice@cash.app. Both reach the same user, who is paid at that Lightning address. bridge_to_cash_appbridge_to_cash_appbridgeToCashAppbridgeToCashAppbridgeToCashAppbridgeToCashAppbridgeToCashAppBridgeToCashAppBridgeToCashApp also takes the bare alice, but get_routesget_routesgetRoutesgetRoutesgetRoutesgetRoutesgetRoutesGetRoutesGetRoutes needs the $.
get_routesget_routesgetRoutesgetRoutesgetRoutesgetRoutesgetRoutesGetRoutesGetRoutes looks the user up, so an unknown username fails before anything is quoted. bridge_to_cash_appbridge_to_cash_appbridgeToCashAppbridgeToCashAppbridgeToCashAppbridgeToCashAppbridgeToCashAppBridgeToCashAppBridgeToCashApp fails with SdkError::InvalidInputSdkError.INVALID_INPUTSdkError.invalidInputSdkError.InvalidInputSdkError.InvalidInputSdkError.InvalidInputSdkError.InvalidInputSdkErrorInvalidInputSdkError.InvalidInput for a recipient who isn't a Cash App user, or an amount outside what the recipient accepts.
Refund address
The refund_addressrefund_addressrefundAddressrefundAddressrefundAddressrefundAddressrefundAddressRefundAddressRefundAddress is the payer's own address on the source chain. If the recipient can't be paid, the provider refunds the deposit there. It must belong to the sourcesourcesourcesourcesourcesourcesourceSourceSource chain's family (e.g. an EVM 0x... address for USDC on Base).
Response fields
bridge_to_cash_appbridge_to_cash_appbridgeToCashAppbridgeToCashAppbridgeToCashAppbridgeToCashAppbridgeToCashAppBridgeToCashAppBridgeToCashApp returns a CreateBridgeResponseCreateBridgeResponseCreateBridgeResponseCreateBridgeResponseCreateBridgeResponseCreateBridgeResponseCreateBridgeResponseCreateBridgeResponseCreateBridgeResponse, described in Bridging USDC/USDT. Its payment_requestpayment_requestpaymentRequestpaymentRequestpaymentRequestpaymentRequestpaymentRequestPaymentRequestPaymentRequest is what the payer pays: an EIP-681 URI on EVM chains, otherwise the bare deposit address.
Limitations
- Delivery can still fail after funding. The provider looks the recipient up again when it pays. If the account was closed, its limit lowered, or slippage moved the amount across a limit since the quote, the payment fails and the deposit is refunded to
refund_addressrefund_addressrefundAddressrefundAddressrefundAddressrefundAddressrefundAddressRefundAddressRefundAddress. - Lightning delivery only. A completed bridge means the Lightning payment was delivered. Whether Cash App credits it as Bitcoin or converts it to dollars depends on the recipient's Cash App settings.