Programmatic Deposit and Withdrawal
This guide is available on three different programming languages: Typescript, Kotlin and Flutter (Dart). You can change the shown version on each page via the buttons above.
The SEP-6 standard defines a way for anchors and wallets to interact on behalf of users. Wallets use this standard to facilitate exchanges between on-chain assets (such as stablecoins) and off-chain assets (such as fiat, or other network assets such as BTC).
Please note, this is for programmatic deposits and withdrawals. For hosted deposits and withdrawals, where the anchor interacts with wallets interactively using a popup, please see Hosted Deposit and Withdrawal.
Get Anchor Informationβ
Let's start with creating a sep6 object, which we'll use for all SEP-6 interactions:
- TypeScript
const sep6 = anchor.sep6();
First, let's get information about the anchor's support for SEP-6. This request doesn't require authentication, and will return generic info, such as supported currencies, and features supported by the anchor. You can get a full list of returned fields in the SEP-6 specification.
- TypeScript
const info = await sep6.info();
Start a depositβ
Before getting started, make sure you have connected to the anchor and received an authentication token, as described in the Stellar Authentication wallet guide. We will use authToken
in the examples below as the SEP-10 authentication token, obtained earlier.
To initiate an operation, we need to know an asset. You can hardcode this. Ensure it is one that is included in the info response above.
Before starting with the deposit flow, make sure that the user account has established a trustline for the asset you are working with.
Let's start with a basic deposit. We will use account
to represent our account's public key.
- TypeScript
const deposit = await sep6.deposit({
authToken,
params: {
asset_code,
account,
},
});
There are several kinds of responses, depending on if the anchor needs more information. All deposits and withdrawals will have these same response types:
1. Success responseβ
If the response is successful (HTTP 200), then the anchor is processing the deposit. If it needs additional information, it will communicate it when providing the transaction info.
2. Still processing, or deniedβ
If an HTTP 403 with data: customer_info_status
is returned, it means the action is still processing, or not accepted. In this case the more_info_url
field should have a link describing next steps.
An example response:
{
"type": "customer_info_status",
"status": "denied",
"more_info_url": "https://api.example.com/kycstatus?account=GACW7NONV43MZIFHCOKCQJAKSJSISSICFVUJ2C6EZIW5773OU3HD64VI"
}
3. Needs more KYC infoβ
Another common response is an HTTP 403, with the response: non_interactive_customer_info_needed
. In this case the anchor needs more KYC information via SEP-12.
An example response:
{
"type": "non_interactive_customer_info_needed",
"fields" : ["family_name", "given_name", "address", "tax_id"]
}
Let's show how a wallet can handle this situation. First, we get the deposit response object. If the response includes this error, then we can see which missing fields the anchor is requiring.
- TypeScript
if (deposit.type === "non_interactive_customer_info_needed") {
// handle displaying the missing fields to the user
console.log(deposit.fields);
}
The wallet will need to handle displaying to the user which fields are missing. And then to add those fields, we can use the sep12 class like so.
- TypeScript
const sep12 = await anchor.sep12(authToken);
// adding the missing kyc info (sample data)
await sep12.add({
sep9Info: {
family_name: "smith",
given_name: "john",
address: "123 street",
tax_id: "123",
},
});
Then, we can re-call the deposit method like before and it should be successful.
More information about sending KYC info using SEP-12 can be found in Providing KYC info.
Providing KYC infoβ
An anchor may respond to a deposit or withdrawal request saying they need additional KYC info. To faciliate this, SEP-6 supports adding a customer's KYC info via SEP-12. The user can send in the required info using the sep12 object like below.
Let's add some KYC info for our account using sample data. Binary data (eg. image data), needs to be sent in a separate field. The fields allowed to send to the anchor are described in SEP-9.
- TypeScript
const sep12 = await anchor.sep12(authToken);
await sep12.add({
sep9Info: {
first_name: "john",
last_name: "smith",
email_address: "[email protected]",
bank_number: "12345",
bank_account_number: "12345",
},
sep9BinaryInfo: {
photo_id_front: Buffer.from("./path/to/image/front"),
photo_id_back: Buffer.from("./path/to/image/back"),
},
});
Start a withdrawalβ
Starting a withdrawal is similar to deposit, and has the same response types as described earlier.
- TypeScript
const resp = await sep6.withdraw({
authToken,
params: {
asset_code: "SRT",
account: accountKp.publicKey,
type: "bank_account",
dest: "123",
dest_extra: "12345",
},
});
Get exchange infoβ
If the anchor supports SEP-38 quotes, it can support deposits that make a bridge between non-equivalent assets. For example, an anchor recieves BRL via bank transfer and in return sends USDC (of equivalent value minus fees) to the user on Stellar.
The sep6 exchange functions allow a user to start an exchange deposit or withdrawal with the anchor, and the anchor can communicate back next steps to the user.
First, let's start a deposit exchange with sample data. Assets are described using the SEP-38 scheme.
- TypeScript
const resp = await sep6.depositExchange({
authToken,
params: {
destination_asset:
"stellar:SRT:GCDNJUBQSX7AJWLJACMJ7I4BC3Z47BQUTMHEICZLE6MU4KQBRYG5JY6B",
source_asset: "iso4217:USD",
amount: "10",
},
});
The response follows the same types as all the deposits and withdrawals for SEP-6.
Now let's create a withdrawal exchange, which follows the same format as the deposit exchange. We also specify it's bank account withdrawal using the type
field.
- TypeScript
const resp = await sep6.withdrawExchange({
authToken,
params: {
destination_asset: "iso4217:USD",
source_asset:
"stellar:SRT:GCDNJUBQSX7AJWLJACMJ7I4BC3Z47BQUTMHEICZLE6MU4KQBRYG5JY6B",
amount: "10",
type: "bank_account",
},
});
The response follows the same types as all the deposits and withdrawals for SEP-6.
Getting Transaction Infoβ
On the typical flow, the wallet would get transaction data to notify users about status updates. This is done via the SEP-6 GET /transaction
and GET /transactions
endpoint.
Tracking Transactionβ
Let's look into how to use the sdk to track transaction status changes. We will use the Watcher
class for this purpose. First, let's initialize it and start tracking a transaction.
- TypeScript
const watcher = anchor.sep6().watcher();
const { stop, refresh } = watcher.watchOneTransaction({
authToken,
assetCode,
id: txId,
onSuccess,
onMessage,
onError,
});
Alternatively, we can track multiple transactions for the same asset.
- TypeScript
const watcher = anchor.sep6().watcher();
const { stop, refresh } = watcher.watchAllTransactions({
authToken,
assetCode,
onMessage,
onError,
});
Fetching Transactionβ
While Watcher
class offers powerful tracking capabilities, sometimes it's required to just fetch a transaction (or transactions) once. The Anchor
class allows you to fetch a transaction by ID, Stellar transaction ID, or external transaction ID:
- TypeScript
const transaction = await anchor
.sep6()
.getTransactionBy({ authToken, id: transactionId });
It's also possible to fetch transactions by the asset.
- TypeScript
const transactions = await anchor.sep6().getTransactionsForAsset({
authToken,
assetCode,
});