Powered by Coinflow
Payments · Documentation
Operational

Settlement to Stellar Contracts

This page is for advanced / cryptocurrency-native companies. If that’s not you, head back to the Quickstart for the standard flows.

Overview

On-chain merchants with custom Soroban contract logic can choose to settle directly to a smart contract on the Stellar network. Coinflow requires these merchants to pass a transaction to our system as a base64-encoded XDR string. The following section explains how merchants can construct and submit a transaction compatible with their Soroban contracts.

How It Works

When a customer makes a purchase on Stellar, Coinflow’s checkout contract executes a mint_and_redeem call that:

  1. Approves USDC — The Coinflow checkout contract approves a USDC allowance to your merchant contract based on the purchase subtotal
  2. Invokes your contract — Coinflow calls your merchant contract’s function with the parameters you specified in the transaction
  3. Your contract transfers USDC — Your merchant contract uses transfer_from to move USDC from the Coinflow contract to your treasury

This means your merchant contract receives a USDC allowance and is responsible for pulling the funds using the Soroban token transfer_from function.

Stellar checkout does not support Credits settlement or partial purchases where the customer contributes their own USDC alongside a credit card payment.

Specifying the Transaction

Pass your Soroban contract invocation as a base64-encoded XDR string in the stellarTransaction field. Coinflow will automatically extract the contract address, function name, and arguments from your transaction.

Step 1: Generate TypeScript Bindings

Use the Stellar CLI to generate TypeScript bindings for your Soroban contract:

# Use --network mainnet for production
stellar contract bindings typescript \
  --network testnet \
  --contract-id YOUR_CONTRACT_ID \
  --output-dir ./your-contract-client

This generates a typed TypeScript client you can use to build transactions.

Step 2: Build the Transaction

Use the generated client to build a transaction that invokes your contract function:

import {YourContractClient} from './your-contract-client';

const client = new YourContractClient({
  contractId: 'YOUR_CONTRACT_ID',
  networkPassphrase: 'Test SDF Network ; September 2015', // Mainnet: 'Public Global Stellar Network ; September 2015'
  rpcUrl: 'https://soroban-testnet.stellar.org',          // Mainnet: use your Soroban RPC provider
  publicKey: sourceAccountPublicKey,
});

const tx = await client.your_purchase_function({
  usdc: 'CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA', // Stellar USDC contract
  payer: 'CA6F7DX4RBZLENHGLPPTGQA4CRNNH3U6QJ3KD7HQLN46YENHTWJRZUOH', // Coinflow checkout contract
  recipient: customerWalletAddress,
});

Step 3: Convert to Base64 XDR

Convert the assembled transaction to a base64-encoded XDR string:

const stellarTransaction = tx.toXDR();
// Returns: "AAAAAgAAAABh...(base64 XDR string)..."

Step 4: Pass to Coinflow

Pass the XDR string as stellarTransaction in your checkout request:

// React SDK
<CoinflowPurchase
  wallet={stellarWallet}
  merchantId="your-merchant-id"
  env="sandbox"
  blockchain="stellar"
  transaction={stellarTransaction}
  subtotal={{ cents: 500, currency: 'USD' }}
/>

Or via the API:

{
  "subtotal": { "cents": 500, "currency": "USD" },
  "blockchain": "stellar",
  "stellarTransaction": "AAAAAgAAAABh...(base64 XDR)..."
}

Merchant Contract Requirements

Your Soroban smart contract function should follow this pattern:

  1. Accept payer (the Coinflow checkout contract address) and recipient (the customer’s wallet) as parameters
  2. Use the Soroban token client’s transfer_from to pull USDC from the Coinflow contract
  3. Deliver the purchased item to the recipient

Example: NFT Purchase Contract (Rust)

use soroban_sdk::{contract, contractimpl, token, Address, Env};

#[contract]
pub struct MerchantContract;

#[contractimpl]
impl MerchantContract {
    pub fn purchase_item(
        e: &Env,
        usdc: Address,          // USDC token contract address
        payer: Address,         // Coinflow checkout contract (pays USDC)
        recipient: Address,     // Customer wallet (receives the item)
    ) -> u32 {
        let price = Self::get_price(e);

        // Pull USDC from Coinflow contract to your treasury
        let usdc_client = token::Client::new(e, &usdc);
        usdc_client.transfer_from(
            &e.current_contract_address(), // spender: your contract
            &payer,                        // from: Coinflow contract
            &Self::get_treasury(e),        // to: your treasury
            &price,                        // amount: item price
        );

        // Deliver the item to the customer
        Self::mint_item(e, &recipient)
    }
}

The payer parameter should always be the Coinflow checkout contract address. Coinflow approves your contract to spend USDC on its behalf before invoking your function.

Environment Checkout Contract Address
Sandbox CA6F7DX4RBZLENHGLPPTGQA4CRNNH3U6QJ3KD7HQLN46YENHTWJRZUOH
Production CDUVNW53LTEPPA6SWEGMAV2KJT4YCRECSLRB7XG3KEN3B62YK6HBKG7S

Gas-Only Purchases

If your contract charges $0 USDC for the purchase (e.g., free mints, promotional items), Coinflow will only pay the Stellar gas fees to execute the transaction on your contract. Your contract function does not need to handle any USDC transfer logic in this case.

pub fn purchase_free_item(
    e: &Env,
    recipient: Address,     // Customer wallet (receives the item)
) -> u32 {
    // No USDC handling needed - just deliver the item
    Self::mint_item(e, &recipient)
}

For gas-only purchases, pass subtotal: { cents: 0 } in your checkout request. The customer is only charged for the gas fees.

Gas Fee Handling

Coinflow automatically simulates your Stellar transaction to estimate gas fees. These fees are added to the customer’s total purchase price. The merchant does not need to handle gas fees or fund any wallets with XLM.

Whitelisting Your Contract

Before your contract can receive settlement, it must be whitelisted by Coinflow. Submit your contract address through the Coinflow Merchant Dashboard.

Your contract must be whitelisted on both sandbox and production environments separately. Start with sandbox for testing.

For more details on the whitelisting process, see How to Whitelist Your Contract.