๐Ÿš€
Stellar Kickstart
  • ๐Ÿ•๏ธWelcome to the SCF Kickstart Week
    • ๐Ÿ’ฐFunding Overview
    • โœ๏ธDear changemakers, visionaries, and problem solvers
    • โ„น๏ธTL;DR: How to Maximize Your SCF Kickstart Week Experience
  • ๐Ÿ“šFundamentals of Integrating with Stellar
    • ๐Ÿš€Stellar For
    • ๐Ÿ—๏ธBuilding with Stellar
    • ๐Ÿ”งTools
    • ๐Ÿ‘ทResources
      • Fundamental Concepts
        • โญIntroduction to the Stellar network
        • โ›“๏ธIntroduction to blockchain technology
        • ๐Ÿ’ตIntroduction to payments in Stellar
        • ๐Ÿง‘Accounts
      • Core Features & Mechanisms
        • ๐Ÿ”Assets: Powering Digital Value Exchange
        • Assets Issuance: Manage digital assets effortlessly on Stellar
        • ๐Ÿ’ธTransactions: At Stellar Core
        • ๐Ÿ‘ฎโ€โ™‚๏ธSignatures in Stellar: Who, how much and to what is authorized
      • Payments & Transactions
        • ๐Ÿ’ฐPayments: Simplifying Transactions with Stellar
        • โ›“๏ธPath Payments: Convert Assets at Minimal Cost
        • โ›ฝFee-Bump: How to pay for other people's transactions
      • Developer & Integration Tools
        • ๐Ÿ‘ฉโ€๐Ÿ”ฌStellar Laboratory: Stellar at hand for everyone
        • ๐ŸšชFaucet: Easy Access to Free Blockchain Assets
        • ๐ŸงฐStellar Wallets Kit: A kit to handle all Stellar Wallets at once with a simple API
        • โœ๏ธSimple Signer: A wallet aggregator and transaction signer
      • Advanced Development & Testing
        • ๐ŸงชHow to Create Integration Tests Using GitHub Actions and Stellar's Docker Image
  • ๐ŸŽจDesign Sprint
    • ๐ŸŒ…Introduction
    • 1๏ธโƒฃDay 1 - Validate your problem and define your MVP's Scope
    • 2๏ธโƒฃDay 2 - Build a prototype to validate with real users
    • 3๏ธโƒฃDay 3 - Define the technical architecture
    • 4๏ธโƒฃDay 4: Develop your Go To Market Strategy & Pitch Deck
    • 5๏ธโƒฃDay 5: Compile all the information
    • ๐Ÿ‘€Sample Completed Design Sprint
Powered by GitBook
On this page
  • Keypair
  • Minimum balance
  • Subentries
  • Trustlines
  • Account data structure
  • How to Delete Accounts (Merge Account Operation)
  1. ๐Ÿ“šFundamentals of Integrating with Stellar
  2. ๐Ÿ‘ทResources
  3. Fundamental Concepts

๐Ÿง‘Accounts

Dive in the Account data structure

PreviousIntroduction to payments in StellarNextCore Features & Mechanisms

Last updated 3 months ago

Accounts are one of the most important data structures on the Stellar blockchain. They hold asset balances, sign transactions and issue assets. Lets dive into its core concepts.

Keypair

Every account has a public key and a private key (also known as a secret key). The public key is the account identifier and can be shared freely without any issues. However, the secret key must never be exposed, as it is used to sign transactions. If the secret key is compromised, you lose control of the account.

Here's an example of public and secret keys for a typical account:

Public Key	GCE25NEKUTN7QB6TALFWG2XMYA3IYDXUOMIQPJD6C6US6HXFYKMITU2L
Secret Key	SBX4DY6EBHP5EYKUAUY2RFNUXXL4E46YZCCDRLMHGEY24DPZ7CGUUMIX

They are two 56-character strings made up of uppercase letters and numbers. The public key always starts with a "G" and the secret key with an "S". Together, the public and secret keys make up what is known as a KeyPair.

In this simple example we see how to create an account:

import { Server, TransactionBuilder, Operation, Keypair } from "stellar-sdk";

const networkPassphrase = "Test SDF Network ; September 2015";
const server = new Server("https://horizon-testnet.stellar.org");

const sourceSecretKey = process.env.SOURCE_SECRET_KEY ?? "";
const sourceKeypair = Keypair.fromSecret(sourceSecretKey);

const keyPair = Keypair.random();
const createAccountOperation = Operation.createAccount({
  destination: keyPair.publicKey(),
  startingBalance: "10",
});

const sourceAccount = await server.loadAccount(sourceKeypair.publicKey());

const transaction = new TransactionBuilder(sourceAccount, {
  fee: "100",
  networkPassphrase,
})
  .addOperation(createAccountOperation)
  .setTimeout(30)
  .build();

transaction.sign(sourceKeypair);
const transactionResult = await server.submitTransaction(transaction);

if (transactionResult.successful)
  console.log("New account public key: ", keyPair.publicKey());

The key code in the example is represented by these lines:

const keyPair = Keypair.random();
const createAccountOperation = Operation.createAccount({
  destination: keyPair.publicKey(),
  startingBalance: "10",
});

Using Keypair.random(), we generate a valid Keypair. Then, we pass the public key from this Keypair to Operation.createAccount(), along with the initial balance of the account in lumens.

Minimum balance

To exist on the network, an account must have a minimum balance of XLM, which is twice the base reserve:

Minimum balance = 2 * Base reserve.

The base reserve is simply a unit used to calculate the minimum balance of an account. Currently, it is set to 0.5 XLM. Therefore, an account must have at least 1 XLM at all times to operate on the network.

Subentries

However, a single XLM might not be enough, because the minimum balance increases by a base reserve as we add subentries, such as:

  • Trustlines

  • Offers

  • Additional signers

  • Data entries

Trustlines

Any asset other than XLM requires explicit acceptance for an account to hold a balance of that asset. This acceptance is established through trustlines and involves operations that must be sent in a transaction and recorded in the ledger.

We use the changeTrust method of the Operation class to set the trustline of an account:

const assetIssuer = "GCE25NEKUTN7QB6TALFWG2XMYA3IYDXUOMIQPJD6C6US6HXFYKMITU2L";
const testAsset = new Asset("TEST", assetIssuer);

const changeTrustOperation = Operation.changeTrust({
  asset: testAsset,
});

In addition to allowing an account to accept payments of an asset, the trustline also sets limits for the amount of that asset that can be held in the account.

Note: if no limit is set, the maximum possible amount is allowed, which is (2^63 - 1)/10^7, or 922,337,203.6854775807. If set to 0, the trustline for that asset is removed.

Account data structure

These are some of the properties you can find in the Account data structure:

"id": "GDNYNR4ZV6DAXEBC5VPVRZTPTP4H3SFOGHD5BIVM3EG5H4E25QD6GDON",
  "account_id": "GDNYNR4ZV6DAXEBC5VPVRZTPTP4H3SFOGHD5BIVM3EG5H4E25QD6GDON",
  "sequence": "11414906381271040",
  "thresholds": {
    "low_threshold": 0,
    "med_threshold": 0,
    "high_threshold": 0
  },
    "flags": {
    "auth_required": false,
    "auth_revocable": false,
    "auth_immutable": false,
    "auth_clawback_enabled": false
  },
  "balances": [
    {
      "balance": "1.0000000",
      "limit": "922337203685.4775807",
      "buying_liabilities": "0.0000000",
      "selling_liabilities": "0.0000000",
      "last_modified_ledger": 2911582,
      "is_authorized": true,
      "is_authorized_to_maintain_liabilities": true,
      "asset_type": "credit_alphanum4",
      "asset_code": "USDC",
      "asset_issuer": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
    },
    {
      "balance": "0.0000000",
      "limit": "922337203685.4775807",
      "buying_liabilities": "0.0000000",
      "selling_liabilities": "0.0000000",
      "last_modified_ledger": 2511582,
      "is_authorized": true,
      "is_authorized_to_maintain_liabilities": true,
      "asset_type": "credit_alphanum4",
      "asset_code": "EUR",
      "asset_issuer": "GBMXE6NZOVAUDGZD3VKZKRHFGEUYMRQ27NZYU6PPV4A2BUVWGO7SXDQW"
    },
    {
      "balance": "10.0000000",
      "buying_liabilities": "0.0000000",
      "selling_liabilities": "0.0000000",
      "asset_type": "native"
    }
  ],
  "signers": [
    {
      "weight": 1,
      "key": "GDNYNR4ZV6DAXEBC5VPVRZTPTP4H3SFOGHD5BIVM3EG5H4E25QD6GDON",
      "type": "ed25519_public_key"
    }
  ],
  "num_sponsoring": 0,
  "num_sponsored": 0,

Id and Account Id: These are the public key of the account

Sequence number: Since all transactions sent to the network have a source account, the sequence number is used to identify and verify the order of transactions. You cannot send two transactions to the network with the same sequence number. Once a transaction is sent to the network, the sequence number of the source account increments by one, regardless of whether the transaction was accepted or rejected. When working with the SDK, you won't need to manually increment the sequence number because it does this automatically for you.

Thresholds: are defined as access levels for an operation. Each operation falls into a threshold category based on its impact or potential disruption.

For example:

  • Low Threshold: Operations like bump sequence (which modifies the sequence number) or claiming a claimable balance fall into this category.

  • Medium Threshold: Operations such as payments, change trust (which involves adding, removing, or modifying trustlines), creating claimable balances, and creating offers are categorized under this threshold.

  • High Threshold: Operations like account merge and set options (where the weight of the signature is modified or signers are added to an account, among other things) are classified here.

These thresholds are represented as numbers between 0 and 255, are set arbitrarily and representing the minimum sum of signature weights required to perform these operations.

Asset Balances: The asset balances are represented by an array containing each asset's balance for which the account has a trustline. This array includes attributes such as the amount of the asset the account holds, the maximum limit it can possess, and asset information like the code and the issuing account.

It's important to note that it is entirely possible to have a balance of 0 for an asset that is not XLM.

Signers: Before transactions are submitted to the network, they must be signed by all accounts involved in its operations, as well as by the source account of the transaction, which pays the fee for the submission to the network.

For example:

  • If the transaction includes a payment operation from Account A to Account B, Account A must sign the transaction.

  • If Account B does not have a trustline for the asset sent by Account A and we include an operation to add that trustline, then Account B must also sign the transaction. Account B does not need to sign if it already has a trustline for the asset being sent, such as lumens.

In the signers section, the accounts that can sign for the account in question and their weights are listed. In our case, the only signer for the account is itself with a weight of one. As we discussed in the thresholds section, all thresholds are set to 0, so this account can sign all operations that affect it.

Sponsoring: The last attributes we'll look at relate to the concept of Sponsored Reserves, which allow one account to cover the base reserve requirement of another account. For example, instead of an account needing to reserve XLM to create a trustline, these XLM can be held in another account (the sponsoring account). In our code example, the account is not sponsoring any other accounts, nor is it being sponsored by any other accounts.

  "num_sponsoring": 0,
  "num_sponsored": 0,

How to Delete Accounts (Merge Account Operation)

Finally, let's look at how to delete accounts. This process affects not only the account to be deleted but also another account, as the account to be deleted must merge with another account.

Before diving into the code, lets see it graphically for clarity:

Let's assume we have Account A, which we need to delete, and it has a balance of 5 lumens.

To delete it, we need another account, which in this case is Account B, with a balance of 20 lumens.

After successfully executing the deletion operation, Account A no longer exists in the ledger, and Account B now has a balance of 25 lumens.

Now let's see it in code.

import { Server, TransactionBuilder, Operation, Keypair } from "stellar-sdk";

const networkPassphrase = "Test SDF Network ; September 2015";
const server = new Server("https://horizon-testnet.stellar.org");

const accountASecretKey = process.env.ACCOUNT_A_SECRET_KEY ?? "";
const accountAKeypair = Keypair.fromSecret(accountASecretKey);

const accountBSecretKey = process.env.ACCOUNT_B_SECRET_KEY ?? "";
const accountBKeypair = Keypair.fromSecret(accountBSecretKey);

const mergeAccountOperation = Operation.accountMerge({
  destination: accountBKeypair.publicKey(),
  source: accountAKeypair.publicKey(),
});

const accountB = await server.loadAccount(accountBKeypair.publicKey());

const transaction = new TransactionBuilder(accountB, {
  fee: "100",
  networkPassphrase,
})
  .addOperation(mergeAccountOperation)
  .setTimeout(30)
  .build();

transaction.sign(accountBKeypair);
transaction.sign(accountAKeypair);

const transactionResult = await server.submitTransaction(transaction);
console.log(transactionResult);

Note: If an account has subentries (such as trustlines, signers, etc.), it cannot be merged until all these subentries are removed.