Including an answer to the big question: How to prevent double spending?
In our previous article, we explained the criteria for determining if your wallet would be best served by a debit card or a prepaid card. As mentioned, the smooth user experience offered by crypto debit cards comes with some additional technical issues; below, we detail how Kulipa handles them based on account characteristics, security keys, risk management, and more.
When a wallet comes to Kulipa to ask about deploying our crypto debit cards to their users, the conversation quickly turns to some relatively technical points. On our side, we want to know more about the wallet’s current goals, as issuing a debit card is a resource intensive endeavor. On their side, they need to know exactly how Kulipa manages the various flows of authorization, clearing, fund transfer and more.
Those are good questions, and we’re happy to go over the details for each particular situation. Here, though, we’d like to explain how the flow of funds works for debit cards, depending on the various characteristics a wallet can have.
First up: The double spending issue
Debit cards for self-custodial wallets are quite new. Instead of the classical prepaid card model, a debit card transmits funds directly from the user’s self-custodial wallet to the merchant’s bank. This means we at Kulipa have around 5-6 seconds to:
- Receive the authorization request that begins when the card is being used,
- Check if there are enough funds in the user’s wallet,
- Say yes or no to Visa/Mastercard.
After that, there’s another thing we have to do before the payment is cleared and the funds are settled:
- Somehow ensure the user doesn’t move the funds before we send them to the merchant.
Step 4 is known as the double spending issue. As we saw in our previous article on payment networks, clearing and settlement happen quite some time after the payment authorization is granted (ranging from 24-72 hours, depending on what day of the week it is).
Thus the transaction can be approved quickly, but the funds only leave the user’s account when it’s time for Kulipa to settle the payment with the card network. Double spending would occur if, in the meantime, the user had placed another transaction before the settlement that depleted the account to the point where there are no longer enough funds available for the transaction.
We clearly need to prevent that, and how it happens depends on the wallet infrastructure. What does that mean? Wallets can generally be characterized as:
- Account abstraction (AA), often referred to as smart wallets. These are managed by smart contracts and are therefore programmable. This means that we can have some special rights over the user’s funds, including freezing them. Argent, Avocado, and Trust Wallet SWIFT are examples of this kind of wallet.
- Externally-owned accounts (EOA), including MPC wallets, which are a bit more tricky. As their infrastructure is hard-coded into protocols, they have limited functionalities and need different safeguards to prevent double spending. Some examples here are Metamask, Trust classic, and Coinbase wallet.
Let’s see how we implement debit cards into each of these, starting with Account Abstraction.
Account Abstraction Wallet: The Flow of Funds
Let’s use the example of Argent, one of the wallets using Kulipa’s crypto debit cards. It’s a very instructive one, showing how we can use the specific characteristics of AA wallets to fit within the existing debit card system.
TLDR for the model
The full flow of funds, from authorization to clearing and settlement, looks like this:
Authorization
- The user enters their key via Argent’s app to execute a transaction with a merchant (i.e., they try to pay for something).
- Our issuer processor receives the transaction request from the card network and sends it to Kulipa.
- Kulipa checks the user’s account balance with Argent. If sufficient funds are available, we send a transaction approval to both Argent and the card network.
- Argent places a hold on the funds using their cosigner key (more details on that below); The card network sends an approval message to the merchant’s point of sale machine.
- Kulipa updates the user’s account balance on the backend (a process that also works when funds are added to the wallet using an on-chain transaction).
Clearing & settlement
- At the end of each day, the card network sends the clearing file to Kulipa.
- Kulipa uses its session key to send USDC from the user’s wallet to an offramp account that is owned by Mastercard, Visa, or another EMI, depending on the region.
- Funds are offramped into a settlement account before being sent along traditional payment rails to the merchant’s bank account.
Argent’s specificities
Argent uses a cosigner model, meaning that both the user and Argent need to validate a transaction with their respective keys in order for it to be validated on-chain. Cosigning is important because it avoids double spending using an enforced hold of the funds being used for a debit card transaction. This then enables the funds to only truly move at the end of the day, when Kulipa has received the clearing file from the card network.
While the user has a key generated when they create their wallet, and Argent has its own key that lets them cosign transactions, Kulipa needs to become part of this flow as well. This happens thanks to session keys, which Argent has been developing for quite some time.
Session keys allow Kulipa to hold its own key, generated when the user orders their debit card. This key gives Kulipa very specific rights to the user’s funds held in Argent: Kulipa can only touch USDC, and the funds are offramped.
Externally-owned accounts
Issuing a debit card for EOA wallets works a bit differently since these wallets can’t enforce smart policies on users’ funds like those seen with account abstraction wallets. As such, Kulipa can’t block a third-party transaction after authorizing a payment, nor can we wait for the clearing file to arrive before collecting the funds.
Therefore, in order to solve the double spending problem, there’s an additional account added to the flow of funds: an escrow account, where the funds are placed directly after authorization takes place.
Authorization
- The user uses their card to execute a transaction with a merchant (i.e., they try to pay for something).
- The issuer processor sends Kulipa a request for authorization.
- Kulipa attempts to move the funds to the escrow account.
- If the transaction is validated by the blockchain, that means there were enough funds and we can say “Yes” to the card network.
- If the transaction fails, there aren't enough funds and we say “No”.
- Kulipa updates the user’s account balance on the backend (a process that also works when funds are added to the wallet using an on-chain transaction).
Clearing and settlement
- At the end of each day, the card network sends the clearing file to Kulipa.
- Kulipa sends the funds from the escrow account to an offramp account that is owned by Mastercard, Visa, or another EMI, depending on the region.
- Funds are offramped into a settlement account before being sent along traditional payment rails to the merchant’s bank account.
And that’s it for this product deep dive! Stay tuned for next week’s article, and in the meantime, feel free to follow us on X or stop by our brand new website for more information.