Skip to content

These new docs are in beta. Please submit bugs to GitHub issues.


Setup for Anchored Assets

So how do we make use of SEP-0024 to allow deposits and withdrawals of anchored assets? First let’s boot up our project:

View trustline boilerplate code on GitHub

Next, let’s think about our goals. What we’re trying to do is communicate with Anchors to get information about the assets they honor, and about the requirements and steps necessary to initiate a deposit or withdrawal on behalf of a user. When a user deposits with an Anchor — by sending dollars to their bank account via ACH, for example — the Anchor will credit their Stellar account with the equivalent amount of tokens. The user can then hold, transfer, or trade those tokens just like any other Stellar asset. When a user withdraws those tokens — generally by making a payment back to the Anchor’s Stellar account — the Anchor redeems them for cash in hand or money in the bank. If you’re still a little lost it will all hopefully become clear as we get coding.

This tutorial will consist of a few minor ./events/ updates and two new ./methods/. Let’s start with the updates first. We actually need to update the core wallet.ts component.

Update Wallet Component

TypeScript
import { Component, State, Prop } from "@stencil/core";
import { Server, ServerApi } from "stellar-sdk";

import componentWillLoad from "./events/componentWillLoad"; // UPDATE
import render from "./events/render"; // UPDATE

import createAccount from "./methods/createAccount";
import updateAccount from "./methods/updateAccount";
import depositAsset from "./methods/depositAsset"; // NEW
import withdrawAsset from "./methods/withdrawAsset"; // NEW
import trustAsset from "./methods/trustAsset";
import makePayment from "./methods/makePayment";
import copyAddress from "./methods/copyAddress";
import copySecret from "./methods/copySecret";
import signOut from "./methods/signOut";
import setPrompt from "./methods/setPrompt";

import { Prompter } from "@prompt/prompt";

interface StellarAccount {
  publicKey: string;
  keystore: string;
  state?: ServerApi.AccountRecord;
}

interface Loading {
  fund?: boolean;
  pay?: boolean;
  trust?: boolean;
  update?: boolean;
  deposit?: boolean; // NEW
  withdraw?: boolean; // NEW
}

@Component({
  tag: "stellar-wallet",
  styleUrl: "wallet.scss",
  shadow: true,
})
export class Wallet {
  @State() account: StellarAccount;
  @State() prompter: Prompter = { show: false };
  @State() loading: Loading = {};
  @State() error: any = null;

  @Prop() server: Server;
  @Prop() homeDomain: String; // NEW
  @Prop() toml: Object; // NEW

  // Component events
  componentWillLoad() {}
  render() {}

  // Stellar methods
  createAccount = createAccount;
  updateAccount = updateAccount;
  depositAsset = depositAsset; // NEW
  withdrawAsset = withdrawAsset; // NEW
  trustAsset = trustAsset;
  makePayment = makePayment;
  copyAddress = copyAddress;
  copySecret = copySecret;
  signOut = signOut;

  // Misc methods
  setPrompt = setPrompt;
}

Wallet.prototype.componentWillLoad = componentWillLoad;
Wallet.prototype.render = render;

You can see from the // NEW and // UPDATE comments what we are adding and updating. Nothing worth noting here other than near the bottom two new @Prop’s.

TypeScript
@Prop() homeDomain: String // NEW
@Prop() toml: Object // NEW

We’ll talk more about home domain’s and stellar.toml files in a moment, but take special note of these as they will play a critical roll in connecting tp the world outside of Stellar.

Add Deposit and Withdraw Buttons

Next let’s add a couple buttons for deposit and withdraw to the ./events/render.tsx.

TSX
import { h } from "@stencil/core";
import { has as loHas } from "lodash-es";

export default function render() {
  return [
    <stellar-prompt prompter={this.prompter} />,

    this.account ? (
      [
        <div class="account-key">
          <p>{this.account.publicKey}</p>
          <button
            class="small"
            type="button"
            onClick={(e) => this.copyAddress(e)}
          >
            Copy Address
          </button>
          <button
            class="small"
            type="button"
            onClick={(e) => this.copySecret(e)}
          >
            Copy Secret
          </button>
        </div>,

        <button
          class={this.loading.deposit ? "loading" : null}
          type="button"
          onClick={(e) => this.depositAsset(e)}
        >
          {this.loading.deposit ? <stellar-loader /> : null} Deposit Asset
        </button>,
        <button
          class={this.loading.withdraw ? "loading" : null}
          type="button"
          onClick={(e) => this.withdrawAsset(e)}
        >
          {this.loading.withdraw ? <stellar-loader /> : null} Withdraw Asset
        </button>,

        <button
          class={this.loading.trust ? "loading" : null}
          type="button"
          onClick={(e) => this.trustAsset(e)}
        >
          {this.loading.trust ? <stellar-loader /> : null} Trust Asset
        </button>,
        <button
          class={this.loading.pay ? "loading" : null}
          type="button"
          onClick={(e) => this.makePayment(e)}
        >
          {this.loading.pay ? <stellar-loader /> : null} Make Payment
        </button>,
      ]
    ) : (
      <button
        class={this.loading.fund ? "loading" : null}
        type="button"
        onClick={(e) => this.createAccount(e)}
      >
        {this.loading.fund ? <stellar-loader /> : null} Create Account
      </button>
    ),

    this.error ? (
      <pre class="error">{JSON.stringify(this.error, null, 2)}</pre>
    ) : null,

    loHas(this.account, "state") ? (
      <pre class="account-state">
        {JSON.stringify(this.account.state, null, 2)}
      </pre>
    ) : null,

    this.account
      ? [
          <button
            class={this.loading.update ? "loading" : null}
            type="button"
            onClick={(e) => this.updateAccount(e)}
          >
            {this.loading.update ? <stellar-loader /> : null} Update Account
          </button>,
          <button type="button" onClick={(e) => this.signOut(e)}>
            Sign Out
          </button>,
        ]
      : null,
  ];
}

This is the same as what we did in the previous tutorial except that we’re adding two buttons.

TSX
<button class={this.loading.deposit ? 'loading' : null} type="button" onClick={(e) => this.depositAsset(e)}>{this.loading.deposit ? <stellar-loader /> : null} Deposit Asset</button>,
<button class={this.loading.withdraw ? 'loading' : null} type="button" onClick={(e) => this.withdrawAsset(e)}>{this.loading.withdraw ? <stellar-loader /> : null} Withdraw Asset</button>,

“Deposit Asset” and “Withdraw Asset” connect to the this.depositAsset and this.withdrawAsset methods respectively. We’ll create those methods momentarily.

Before that though let’s make a change to the ./events/componentWillLoad.ts file.

Update Components

TypeScript
import { Server, StellarTomlResolver } from "stellar-sdk";
import { handleError } from "@services/error";
import { get } from "@services/storage";

export default async function componentWillLoad() {
  try {
    let keystore = await get("keyStore");

    this.error = null;
    this.server = new Server("https://horizon-testnet.stellar.org");
    this.homeDomain = "stellar-anchor-server.herokuapp.com";
    this.toml = await StellarTomlResolver.resolve(this.homeDomain);

    if (keystore) {
      keystore = atob(keystore);

      const { publicKey } = JSON.parse(atob(JSON.parse(keystore).adata));

      this.account = {
        publicKey,
        keystore,
      };

      this.updateAccount();
    }
  } catch (err) {
    this.error = handleError(err);
  }
}

Here, the only changes we’re making are to include of the StellarTomlResolver from the stellar-sdk package and to set the values for this.homeDomain and this.toml.

TypeScript
this.homeDomain = "stellar-anchor-server.herokuapp.com";
this.toml = await StellarTomlResolver.resolve(this.homeDomain);

About stellar.toml Files

You know what, let’s just go ahead and cover stellar.toml files. A stellar.toml file is a static resource that organizations building on Stellar publish on their home domain at https://{homeDomain}/.well-known/stellar.toml. By linking their home domain to a Stellar account using a set_options operation, they create a verifiable connection from that account to the information published there. To find out everything you’d ever want to know about stellar.toml files, check out [SEP-1], which is the complete stellar.toml specification.

Stellar.toml files contain all sorts of information about an organization, the assets they offer, and the integrations they support. Wallets can look at an account, find the home domain, and crawl a stellar.toml to find out pretty much everything they need to know about an Anchor, and that’s exactly what the Stellar SDK StellarTomlResolver.resolve method does: it pulls in a stellar.toml and parses it.

Let’s look at some concrete examples: here’s StellarX.com’s stellar.toml file.

TOML
FEDERATION_SERVER="https://federation.stellarx.com/federation"

ACCOUNTS=[
"GDM4UWTGHCWSTM7Z46PNF4BLH35GS6IUZYBWNNI4VU5KVIHYSIVQ55Y6"
]

[DOCUMENTATION]
ORG_NAME="Diamond Ltd."
ORG_DBA="StellarX"
ORG_URL="https://www.stellarx.com"
ORG_LOGO="https://www.stellarx.com/emailAssets/stellarx.png"
ORG_DESCRIPTION="The first full-featured trading app for Stellar's universal marketplace"
ORG_PHYSICAL_ADDRESS="Hamilton, Bermuda"
ORG_OFFICIAL_EMAIL="[email protected]"

And here’s [AnchorUSD]’s3.

TOML
# ----- AnchorUSD Stellar Anchor <www.anchorusd.com> -----

NETWORK_PASSPHRASE="Public Global Stellar Network ; September 2015"

ACCOUNTS=["GDUKMGUGDZQK6YHYA5Z6AY2G4XDSZPSZ3SW5UN3ARVMO6QSRDWP5YLEX", "GASWJWFRYE55KC7MGANZMMRBK5NPXT3HMPDQ6SEXZN6ZPWYXVVYBFRTE"]
TRANSFER_SERVER="https://api.anchorusd.com/transfer/"
WEB_AUTH_ENDPOINT="https://api.anchorusd.com/api/webauth"

[DOCUMENTATION]
ORG_NAME="AnchorCoin LLC"
ORG_DBA="AnchorUSD"
ORG_URL="https://www.anchorusd.com"
ORG_LOGO="https://www.anchorusd.com/assets/images/logo/logo.png"
ORG_DESCRIPTION="AnchorUSD develops a stable cryptocurrency backed one-for-one to the US dollar."
ORG_TWITTER="AnchorUSD"
ORG_OFFICIAL_EMAIL="[email protected]"

[[PRINCIPALS]]
name="Jim Berkley-Danz"
email="[email protected]"
twitter="jimdanz"
github="jimdanz"

[[CURRENCIES]]
code="USD"
issuer="GDUKMGUGDZQK6YHYA5Z6AY2G4XDSZPSZ3SW5UN3ARVMO6QSRDWP5YLEX"
display_decimals=2
anchor_asset_type="fiat"
anchor_asset="USD"
name="US Dollar"
desc="Cryptocurrency backed one-for-one to the US dollar.  All dollar deposits are held in an audited, US-domiciled escrow account for the exclusive benefit of AnchorUSD token holders."
image="https://www.anchorusd.com/img/usdx.png"

You can see the data provided by these companies that identifies who they are, what they do, and what services they provide. In this tutorial, we’re interested in the [[CURRENCIES]] they issue as that’s what we’re trying to get ahold of. We’re also looking for the TRANSFER_SERVER keyword, which indicates that an Anchor supports SEP-24, and the WEB_AUTH_ENDPOINT, which allows a wallet to set up an authenticated user session. Any time you find these three fields, and you’ve found an Anchor you can interoperate with.

Once we’ve found an Anchor that supports deposit and withdrawal, we can begin the process of connecting with them from our wallet. This tutorial builds on the testnet, so from we’ll be use an SDF testing anchor server located at stellar-anchor-server.herokuapp.com You can view the TOML file for this entity here.

Last updated Sep. 23, 2020

Page Outline