├── 1-launch.md ├── 2-payments.md ├── 3-assets.md ├── 4-multisig.md ├── 5-dex.md ├── 6-debugging.md ├── LICENSE └── README.md /1-launch.md: -------------------------------------------------------------------------------- 1 | [Front](https://github.com/0xfe/hacking-stellar/blob/master/README.md) - 2 | [Chapter 1](https://github.com/0xfe/hacking-stellar/blob/master/1-launch.md) - 3 | [Chapter 2](https://github.com/0xfe/hacking-stellar/blob/master/2-payments.md) - 4 | [Chapter 3](https://github.com/0xfe/hacking-stellar/blob/master/3-assets.md) - 5 | [Chapter 4](https://github.com/0xfe/hacking-stellar/blob/master/4-multisig.md) - 6 | [Chapter 5](https://github.com/0xfe/hacking-stellar/blob/master/5-dex.md) - 7 | [Chapter 6](https://github.com/0xfe/hacking-stellar/blob/master/6-debugging.md) 8 | 9 | # Chapter 1. The Basics 10 | 11 | ## What is Stellar? 12 | 13 | Stellar is a decentralized payment network. In a nutshell, it lets multiple parties send *unforgeable* digital tokens to each other. These tokens could represent any kind of value, like Dollars and Euros, or even kittens and hugs. 14 | 15 | Anyone can create and distribute tokens on the Stellar platform. It's dead simple. 16 | 17 | For example, I could create five tokens for a new currency called `AXE`, one for each of my guitars, with the note: *“the bearer of this token is entitled to one of Mo’s guitars.”* I could then sell the tokens to third parties, who could in turn resell them. 18 | 19 | Since I’m generally regarded as a trustworthy individual, the current token owners would be comfortable holding these tokens -- they know they could redeem them for real guitars any time. 20 | 21 | 22 | ## On Trust 23 | 24 | The magic of Stellar is that it’s *trustless*. Because it’s built on a decentralized ledger (commonly also known as a blockchain), there isn’t a single entity that has overreaching control over it. The platform is run by individuals and organizations all over the world, each contributing some compute, storage, and network capacity. 25 | 26 | No single person owns it, and this makes Stellar very difficult for governments, organizations, or rogue entities to compromise. 27 | 28 | Obviously, you still need to trust the issuers of the tokens, just like you’d have to trust me to redeem the guitars. Or just like you trust a government that issues real currencies. 29 | 30 | With decentralized ledgers however, you have fewer things to trust. For example, when a currency is issued on the Stellar network, you can verify that the supply is consistent with what the issuer claims, or you can move funds quickly and reliably without going through a trusted third-party. 31 | 32 | ***Thought exercise:*** *Think about how you would buy, say, an expensive guitar, today from a distant seller without a trusted third-party.* 33 | 34 | As always, the devil’s in the details, so let’s start exploring by getting our hands dirty. 35 | 36 | ## Hacking Stellar 37 | 38 | To start experimenting, let’s use [Lumen](http://github.com/0xfe/lumen), which is a commandline client for the Stellar platform. Lumen is a really handy tool for working with Stellar, and especially useful while debugging complex Stellar applications. 39 | 40 | You can download the latest release of Lumen for your operating system [here](https://github.com/0xfe/lumen/releases). 41 | 42 | After downloading Lumen, move it to your search path, and configure it to use the test network. We're not playing with real money for now. 43 | 44 | ```sh 45 | sudo mv lumen.macos /usr/local/bin/lumen 46 | lumen set config:network test 47 | ``` 48 | 49 | ### Create an account 50 | A user must have an account to transact on the network. To create an account, you first need to generate a key pair -- these are the keys to your vault. 51 | 52 | A key pair consists of two 28-byte strings. One of them is your public “*address*”, the other your private “*seed*”. Think of one as your username, and the other as your password. Your seed is a secret -- protect it. 53 | 54 | Let’s create a new key pair for Bob with Lumen. 55 | 56 | ```sh 57 | $ lumen account new bob 58 | # Output: 59 | # GDTNQMX5RJ34CWU2XGPJOYHKWSATVALZZ3VCVQOQUXDO7CMHCLH6HDST SAEEOOLWEQDA6H3S5US3IFQ6TE377AR7OS7WUEKJNKVU437FM4KHKJNQ 60 | ``` 61 | 62 | You’ll see that Lumen spit out two strings. The one starting with `G` is Bob’s address, the one starting with `S` is his seed. Lumen stored this key pair in your home directory (`$HOME/.lumen_data.json`) and associated it with the name `bob`. 63 | 64 | You can always lookup Bob’s address or seed later. 65 | 66 | ```sh 67 | $ lumen account address bob 68 | # GDTNQMX5RJ34CWU2XGPJOYHKWSATVALZZ3VCVQOQUXDO7CMHCLH6HDST 69 | $ lumen account seed bob 70 | # SAEEOOLWEQDA6H3S5US3IFQ6TE377AR7OS7WUEKJNKVU437FM4KHKJNQ 71 | 72 | ``` 73 | 74 | Great, so now that you have a key pair, let’s turn it into an account. To open an account you need a minimum balance. Since we’re using the test network and all of this is funny money anyway, you can use [Friendbot](http://friendbot.stellar.org), which is a funding bot for test networks run by the Stellar organization. 75 | 76 | You can ask Firendbot to fund a new account with the `lumen friendbot` command. 77 | 78 | ```sh 79 | $ lumen friendbot bob 80 | $ lumen balance bob 81 | # Output: 10000.0000000 82 | ``` 83 | 84 | Okay, you now have a funded account, and you can transact on the Stellar test network. This is no fun to do alone, so lets create another account for Kelly. This time, we’ll have Bob fund her account instead of Friendbot. 85 | 86 | ```sh 87 | $ lumen account new kelly 88 | 89 | # Fund Kelly via Bob's account 90 | $ lumen pay 1000 --from bob --to kelly --fund 91 | $ lumen balance kelly 92 | # Output: 1000.0000000 93 | ``` 94 | 95 | You can always look up detailed account information with `lumen info`. Don't worry about what all this means right now, we'll figure it out over the next few chapters. 96 | 97 | ```json 98 | $ lumen info bob 99 | { 100 | "address": "GADFYJK62RVQOU7BNP53TSUFEQ627H4OBZ6TLBVG4T2U25Y3GYR3MFF4", 101 | "balances": [], 102 | "signers": [ 103 | { 104 | "public_key": "GDK5X4BUL3YUDEYNDVTJ4MX6NENGKSHPGHVCQNWX3B4MK633MKRWMJJO", 105 | "weight": 1, 106 | "key": "GDK5X4BUL3YUDEYNDVTJ4MX6NENGKSHPGHVCQNWX3B4MK633MKRWMJJO", 107 | "type": "ed25519_public_key" 108 | }, 109 | { 110 | "public_key": "GADFYJK62RVQOU7BNP53TSUFEQ627H4OBZ6TLBVG4T2U25Y3GYR3MFF4", 111 | "weight": 1, 112 | "key": "GADFYJK62RVQOU7BNP53TSUFEQ627H4OBZ6TLBVG4T2U25Y3GYR3MFF4", 113 | "type": "ed25519_public_key" 114 | } 115 | ], 116 | "native_balance": { 117 | "asset": { 118 | "code": "XLM", 119 | "issuer": "", 120 | "type": "\"native\"" 121 | }, 122 | "amount": "9999.9999800", 123 | "limit": "" 124 | }, 125 | "home_domain": "", 126 | "thresholds": { 127 | "high": 2, 128 | "medium": 2, 129 | "low": 2 130 | }, 131 | "seq": "34126534528729090" 132 | } 133 | ``` 134 | 135 | ## Security PSA 136 | 137 | Note that in the real world, you would not keep your seeds lying around in the clear. For personal use it's always better to use a hardware wallet, or store your seeds in a reputable password manager like [KeePassXC](https://keepassxc.org/). 138 | 139 | For business and corporate users, you are strongly encouraged to use multisignature accounts -- this is discussed in detail in [Chapter 4](https://github.com/0xfe/hacking-stellar/blob/master/4-multisig.md). 140 | 141 | Finally, [Lumen](https://github.com/0xfe/lumen) is a tool, not a wallet. Don't rely on it to keep your seeds secure. 142 | 143 | ## Concepts 144 | 145 | There's a lot going on in what we just did. What does it mean to "fund" an account? What did we fund it with? Why did we need to fund it in the first place? 146 | 147 | The native currency of Stellar is the *lumen*, which has the currency code `XLM`. (Yep, this is also what the tool we're using is named after.) Lumens are used to pay for Stellar transactions, and can be bought and sold in many cryptocurrency exchanges. You check the market price of a lumen [here](https://coinmarketcap.com/currencies/stellar/). 148 | 149 | For an account to be valid on the Stellar network, it needs to maintain a minimum balance of 1 XLM. This is based on Stellar's **base reserve** fee, which is 0.5 XLM. Funding an account is a special operation, distinct from typical payment operations -- this is why we used the `--fund` flag when we funded Kelly's account. 150 | 151 | Each lumen is divisible into 10 million *stroops*. A stroop is the smallest divisible unit of a lumen, and is how balances are mainatained on the ledger. 152 | 153 | There is also a fee to transact on the Stellar network called the *base fee*, which today is 100 stroops per operation. Read more about Stellar fees on the [Stellar developer site](https://www.stellar.org/developers/guides/concepts/fees.html). 154 | 155 | ## Onward 156 | 157 | Move on to [Chapter 2](https://github.com/0xfe/hacking-stellar/blob/master/2-payments.md) to learn about payments, aliases, and more Stellar concepts. 158 | 159 | [Front](https://github.com/0xfe/hacking-stellar/blob/master/README.md) - 160 | [Chapter 1](https://github.com/0xfe/hacking-stellar/blob/master/1-launch.md) - 161 | [Chapter 2](https://github.com/0xfe/hacking-stellar/blob/master/2-payments.md) - 162 | [Chapter 3](https://github.com/0xfe/hacking-stellar/blob/master/3-assets.md) - 163 | [Chapter 4](https://github.com/0xfe/hacking-stellar/blob/master/4-multisig.md) - 164 | [Chapter 5](https://github.com/0xfe/hacking-stellar/blob/master/5-dex.md) - 165 | [Chapter 6](https://github.com/0xfe/hacking-stellar/blob/master/6-debugging.md) -------------------------------------------------------------------------------- /2-payments.md: -------------------------------------------------------------------------------- 1 | [Front](https://github.com/0xfe/hacking-stellar/blob/master/README.md) - 2 | [Chapter 1](https://github.com/0xfe/hacking-stellar/blob/master/1-launch.md) - 3 | [Chapter 2](https://github.com/0xfe/hacking-stellar/blob/master/2-payments.md) - 4 | [Chapter 3](https://github.com/0xfe/hacking-stellar/blob/master/3-assets.md) - 5 | [Chapter 4](https://github.com/0xfe/hacking-stellar/blob/master/4-multisig.md) - 6 | [Chapter 5](https://github.com/0xfe/hacking-stellar/blob/master/5-dex.md) - 7 | [Chapter 6](https://github.com/0xfe/hacking-stellar/blob/master/6-debugging.md) 8 | 9 | 10 | # Chapter 2. Payments 11 | 12 | Payments are the *raison d'être* of Stellar, and account holders can pay each other using a variety of currencies and assets. In this chapter, we'll discuss and experiment with payments using Stellar's native asset, the lumen. 13 | 14 | ### Detour: Working with the Lumen tool 15 | 16 | The Lumen command-line-interface (CLI) is broken up into commands, subcommands, and flags. You can always find out more about a command's usage and parameters with the `--help` flag. 17 | 18 | ```sh 19 | $ lumen --help 20 | Lumen is a commandline client for the Stellar blockchain 21 | 22 | Usage: 23 | lumen [flags] 24 | lumen [command] 25 | 26 | Available Commands: 27 | account manage stellar keypairs and accounts 28 | asset manage stellar assets 29 | balance check the balance of [asset] on [account] 30 | del delete variable 31 | dex trade assets on the DEX 32 | friendbot fund [address] on the test network with friendbot 33 | get get variable 34 | help Help about any command 35 | ns set namespace to [namespace] 36 | pay send [amount] of [asset] from [source] to [target] 37 | set set variable 38 | signer manage signers on account 39 | trust manage trustlines between accounts and assets 40 | version get version of lumen CLI 41 | watch watch the account on the ledger 42 | 43 | Flags: 44 | -h, --help help for lumen 45 | --network string network to use (test) (default "test") 46 | --ns string namespace to use (default) (default "default") 47 | --store string namespace to use (default) (default "file:/Users/mo/.lumen-data.yml") 48 | -v, --verbose verbose output (false) 49 | 50 | Use "lumen [command] --help" for more information about a command. 51 | ``` 52 | 53 | To make payments, we use `lumen pay`. You can get command-specific help for pay with `lumen pay --help`. 54 | 55 | ```sh 56 | $ lumen pay --help 57 | send [amount] of [asset] from [source] to [target] 58 | 59 | Usage: 60 | lumen pay [amount] [asset] --from [source] --to [target] [flags] 61 | 62 | Flags: 63 | --from string source account seed or name 64 | --fund fund a new account 65 | -h, --help help for pay 66 | --max string spend no more than this much during path payments 67 | --memoid string memo ID 68 | --memotext string memo text 69 | --path stringSlice comma-separated list of paths, uses auto pathfinder if empty 70 | --signers stringSlice alternate signers (comma separated) 71 | --to string target account address or name 72 | --with string make a path payment with this asset 73 | 74 | Global Flags: 75 | --network string network to use (test) (default "test") 76 | --ns string namespace to use (default) (default "default") 77 | --store string namespace to use (default) (default "file:/Users/mo/.lumen-data.yml") 78 | -v, --verbose verbose output (false) 79 | ``` 80 | 81 | ## Your first payment 82 | 83 | Before we proceed, lets make sure we're using the test network. (If you want to use the public network, type `public` instead of `test` below.) 84 | 85 | ```sh 86 | $ lumen set config:network test 87 | ``` 88 | 89 | Kelly pays Bob 5 XLM for the cookie she just bought, and leaves a thank you message with the `--memotext` flag. 90 | 91 | ```sh 92 | $ lumen pay 5 --from kelly --to bob --memotext 'thanks for the cookie' 93 | $ lumen balance kelly 94 | $ lumen balance bob 95 | ``` 96 | 97 | Done! Kelly just sent Bob 5 XLM. 98 | 99 | Every transaction can have a short memo associated (upto 28 bytes long.) The memo can used by a payment processor or business to redirect funds. For example, *Mary's Bank* can have a single stellar account for all its customers, and require payers to fill in the memo to designate the recipient. Instead of a text memo, the bank could require a numeric one, for which we use the `--memoid` flag. 100 | 101 | ```sh 102 | $ lumen account set MarysBank GAFUU44WASFPD4YHIU5TKVMGLFMOHAQIOUJTTFQ432W65PFYQVVXFSUW 103 | $ lumen pay 5 --from kelly --to MarysBank --memoid 485532245 104 | ``` 105 | 106 | Notice that we created an account alias for Mary's Bank called `MarysBank`. Aliases make it easier to work with Stellar, since you don't have to keep pasting in long addresses in your commands. Lumen keeps track of these aliases in a state file in your home directory. Lumen also recognizes if an alias is an address or seed and uses them contextually depending on the command. 107 | 108 | For example, in the above `pay` command, Lumen used Kelly's seed instead of her address (because the seed is what actually *signs* and authorizes the transaction.) If we didn't have Kelly's seed, the transaction would fail. Lets see what happens if you try to make a payment from Mary's Bank. 109 | 110 | ```sh 111 | $ lumen pay 10 --from MarysBank --to kelly --memotext 'i am h4xor' 112 | # Output: error 113 | ``` 114 | 115 | Obviously, we don't have their private seed -- and hopefully we never will. 116 | 117 | ## Exploring Transactions 118 | 119 | So, how do you know it worked? A great way to debug transactions on the Stellar platform is to use the [Stellar Laboratory](https://www.stellar.org/laboratory). 120 | 121 | You can use the [endpoint explorer](https://www.stellar.org/laboratory/#explorer?network=test) in the lab to look up accounts, ledger balances, and go through their transaction history. 122 | 123 | For example, here's the transaction history of an account on the test network: [GDELI4BPSO7SZGNNIDJ33N2HMJDQKB6PDD6P633U6LKGM26BYDVPRXU3](https://www.stellar.org/laboratory/#explorer?resource=accounts&endpoint=single&values=eyJhY2NvdW50X2lkIjoiR0RFTEk0QlBTTzdTWkdOTklESjMzTjJITUpEUUtCNlBERDZQNjMzVTZMS0dNMjZCWURWUFJYVTMifQ%3D%3D&network=test) (scroll down to see the results.) 124 | 125 | ### Generating Transactions 126 | 127 | You can use Lumen to generate transactions for you without submitting them. This is useful if you need more accounts to sign it before it can be submitted, or if you simply want to submit it later. When you use the `--nosubmit` flag, Lumen will output a base64 string encoding the requested transaction. 128 | 129 | ```sh 130 | $ lumen pay 10 --from bob --to mary --nosubmit 131 | # AAAAALiDDp5aQxVoaDvKOlVcx+DGXSKYKq9tRjERhtq4jMTaAAAAZAB5uK0AAAAHAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAAlveOUG3nLTgXeReTjtP0w79J7s1x+GcjFe9aM4LNnXgAAAAAAAAAAAX14QAAAAAAAAAAAbiMxNoAAABAO7sZLRrJyUC0xm1JFVxdiaRL9ZPJJ6hze22ZQ6npqziBmDK9JMTFf+bxm4fIqoNcqwth2pBwXFcOgc134QmnCA== 132 | ``` 133 | 134 | To submit later, use `lumen tx submit`. 135 | 136 | ```sh 137 | $ lumen tx submit AAAAA...(full string) 138 | ``` 139 | 140 | You can always read the contents of the transaction with `lumen tx decode`. 141 | 142 | ```sh 143 | $ lumen tx decode AAAAA... --pretty 144 | # Output: pretty JSON string with transaction contents 145 | ``` 146 | 147 | We'll learn more about this in [Chapter 4.](https://github.com/0xfe/hacking-stellar/blob/master/4-multisig.md) 148 | 149 | ## Managing account aliases 150 | 151 | Aliases make it simpler to work with Stellar. You can add and remove aliases with `lumen account set` and `lumen account del`. You can also generate new key pairs and alias them with `lumen account new`. 152 | 153 | ```sh 154 | $ lumen account del MarysBank 155 | $ lumen account address MarysBank 156 | # ERRO[0000] could not get address for account: MarysBank cmd=account subcmd=address 157 | 158 | $ lumen account new bill 159 | # GAT5JWOXDCHR423M7VAPMC52NH6KQS4MTATXRJT7GTXDSERKQFFQNLC5 SCKNY3E6WSYFZASR3S34NGQLZLC6WJYJN3OX4AMOPPKQQP66YF2P5NQR 160 | 161 | $ lumen account seed bill 162 | # SCKNY3E6WSYFZASR3S34NGQLZLC6WJYJN3OX4AMOPPKQQP66YF2P5NQR 163 | ``` 164 | 165 | ## Using Namespaces 166 | 167 | Sometimes, you may want to start from a clean slate, but still keep your existing aliases. You can use Lumen's *namespaces* feature to do this. Use `lumen ns mynamespace` to create a new namespace (or switch to an existing one.) 168 | 169 | ```sh 170 | $ lumen ns project1 171 | $ lumen account new bill 172 | # GCVO44W7CY4NA4WMAFW2ZAIFTQBFYNCW2QVRMLGOUFZQ67233D332UCO SDSNH72UMGBYA6ABJHVMRQLJGTTDS7EIAHKGA44RXU6JB6SDLQECW6ZI 173 | $ lumen account address bill 174 | # GCVO44W7CY4NA4WMAFW2ZAIFTQBFYNCW2QVRMLGOUFZQ67233D332UCO 175 | 176 | # Now lets switch to a new namespace 177 | $ lumen ns project2 178 | $ lumen account address bill 179 | # RRO[0000] could not get address for account: bill cmd=account subcmd=address 180 | 181 | # Switch back 182 | $ lumen ns project1 183 | $ lumen account address bill 184 | # GCVO44W7CY4NA4WMAFW2ZAIFTQBFYNCW2QVRMLGOUFZQ67233D332UCO 185 | 186 | # Get the current namespace 187 | $ lumen ns 188 | # project1 189 | ``` 190 | 191 | Namespaces are great to switch between the public and test networks and keep your addresses segregated. 192 | 193 | ```sh 194 | # Create a namespace called prod and associate it with the public Stellar network 195 | $ lumen ns prod 196 | $ lumen set config:network public 197 | 198 | # Create a namespace called test and associate it with the testnet 199 | $ lumen ns test 200 | $ lumen set config:network test 201 | 202 | # Switch to the prod namespace 203 | $ lumen ns prod 204 | 205 | # We're now transacting on the public network. Any new aliases are tied to 206 | # this network. 207 | $ lumen account new kelly 208 | $ lumen pay --from mo --to kelly --fund 209 | 210 | # Switch back to the test namespace 211 | $ lumen ns test 212 | 213 | # We're now transacting on the test network. Lets create a new alias for Kelly 214 | # here. 215 | $ lumen account new kelly 216 | ``` 217 | 218 | ## Concepts 219 | 220 | Transactions in Stellar can consist of one or more [operations](https://www.stellar.org/developers/guides/concepts/operations.html). Each of these operations modify the ledger in some way, and is charged a **base fee** of 100 stroops. So, a transaction with 9 operations would pay 900 stroops. 221 | 222 | For example, when you make a payment with Lumen using the `pay` command, it creates a [Payment Operation](https://www.stellar.org/developers/guides/concepts/list-of-operations.html#payment), and bundles it into a new transaction. It then signs it with your private seed, and submits it to the network. 223 | 224 | The transaction envelope also contains the total fee to be paid, the address of the account that pays the fee, memo information, a list of signers, etc. For example, Mary's Bank could initiate a payment between their customers, Bob and Kelly, and foot the transaction fee. (This requires multisignature accounts, which we'll learn about in Chapter 4.) 225 | 226 | To learn more about transactions read [the topic on the Stellar devlopers site](https://www.stellar.org/developers/guides/concepts/transactions.html). 227 | 228 | ## Stellar Federation 229 | 230 | Stellar Federation allows people to use user-friendly addresses in the form `user*domain.tld`, somewhat similar to e-mail addresses. Individuals or organizations can run a *federation server* that responds to name resolution requests using the [Stellar Federation Protocol](https://www.stellar.org/developers/guides/concepts/federation.html.) 231 | 232 | Lumen automatically recognizes federation addresses in its commands, and you can use addresses of the form `user*domain.tld` anywhere an account alias is used. 233 | 234 | ```sh 235 | $ lumen account address mo*qubit.sh 236 | GDEVC4BOVFMB46UHGJ6NKEBCQVY5WI56GOBWPG3QKS4QV4TKDLPE6AH6 237 | 238 | $ lumen pay 20 --from mo*qubit.sh --to kelly*happyfish.com 239 | ``` 240 | 241 | Although the federation protocol is straightforward to implement, the Stellar organization provides [lightweight server](https://github.com/stellar/go/tree/master/services/federation) that you can deploy for your use. 242 | 243 | ## Onward 244 | 245 | Now that we now how to work with aliases and make XLM payments, lets get to the fun stuff: [issuing assets](https://github.com/0xfe/hacking-stellar/blob/master/3-assets.md). 246 | 247 | [Front](https://github.com/0xfe/hacking-stellar/blob/master/README.md) - 248 | [Chapter 1](https://github.com/0xfe/hacking-stellar/blob/master/1-launch.md) - 249 | [Chapter 2](https://github.com/0xfe/hacking-stellar/blob/master/2-payments.md) - 250 | [Chapter 3](https://github.com/0xfe/hacking-stellar/blob/master/3-assets.md) - 251 | [Chapter 4](https://github.com/0xfe/hacking-stellar/blob/master/4-multisig.md) - 252 | [Chapter 5](https://github.com/0xfe/hacking-stellar/blob/master/5-dex.md) - 253 | [Chapter 6](https://github.com/0xfe/hacking-stellar/blob/master/6-debugging.md) 254 | -------------------------------------------------------------------------------- /3-assets.md: -------------------------------------------------------------------------------- 1 | [Front](https://github.com/0xfe/hacking-stellar/blob/master/README.md) - 2 | [Chapter 1](https://github.com/0xfe/hacking-stellar/blob/master/1-launch.md) - 3 | [Chapter 2](https://github.com/0xfe/hacking-stellar/blob/master/2-payments.md) - 4 | [Chapter 3](https://github.com/0xfe/hacking-stellar/blob/master/3-assets.md) - 5 | [Chapter 4](https://github.com/0xfe/hacking-stellar/blob/master/4-multisig.md) - 6 | [Chapter 5](https://github.com/0xfe/hacking-stellar/blob/master/5-dex.md) - 7 | [Chapter 6](https://github.com/0xfe/hacking-stellar/blob/master/6-debugging.md) 8 | 9 | # Chapter 3. Issuing Assets 10 | 11 | In the last two chapters, we created accounts and made payments in Stellar's native currency, the lumen. We also learned that the native currency is typically used as fees to fund the Stellar platform. 12 | 13 | In this chapter, we'll learn about **Credit Assets**, which are primitives that can hold and track any kind of real-world asset, such as fiat currencies, land, commodities, other cryptocurrencies, etc. A credit asset doesn't really hold a real-world asset -- it's more like an IOU that is used to *redeem* a real-world asset -- like how I issued five units of `AXE` for my five guitars in Chapter 1. 14 | 15 | Entities that issue assets are called **Anchors**, and Anchors can be institutions, enterprises, or even individuals. Every Anchor has one or more associated **issuing accounts** from which they distribute assets. 16 | 17 | ## Creating a new asset 18 | 19 | Every asset (except the native asset) has an **issuer** and a **code**. The issuer is the Stellar address of the account that initially issues the asset on the network, and the code is a short string representing the asset. For example, The *Bank of Canada* could create and issue Canadian Dollars on the Stellar network, with the code `CAD`. 20 | 21 | Let's try that. First create a new account for the Bank of Canada on the test network, and define an alias for our new asset. 22 | 23 | ```sh 24 | $ lumen set config:network test 25 | $ lumen account new BankOfCanada 26 | $ lumen friendbot BankOfCanada 27 | 28 | # Create an asset alias called CAD issued by BankOfCanada. Lumen uses the alias as the 29 | # as the asset code unless you explicitly specify it with the --code flag. 30 | $ lumen asset set CAD BankOfCanada 31 | ``` 32 | 33 | ## Trustlines 34 | 35 | Stellar doesn't let an anchor simply issue a new asset to anyone, nor does it allow accounts to hold arbitrary assets. Accounts must explicitly create **trustlines** to assets they want to hold. [Trustlines](https://www.stellar.org/developers/guides/concepts/assets.html#trustlines) protect users from trading the wrong type of asset, by explicitly authorizing assets from only trusted anchors and issuers. 36 | 37 | So, before Bob can hold any `CAD`, he must specifically create a trustline to the `CAD` he wants to hold with the `lumen trust` command. Since assets are defined by both their code *and* their issuer, there's no way for Bob to end up with the wrong `CAD` in his account. 38 | 39 | ```sh 40 | # Create a trustline from Bob to the CAD issued by the Bank of Canada 41 | $ lumen trust create bob CAD 42 | 43 | # You can also refer to the asset without an asset alias. 44 | $ lumen trust create bob CAD:BankOfCanada 45 | ``` 46 | 47 | ## Issuing the asset 48 | 49 | Now, the Bank of Canada can issue some CAD assets and send it to Bob. To issue an asset, simply make a payment from the issuer to the recipient. 50 | 51 | ```sh 52 | $ lumen pay 10 CAD --from BankOfCanada --to bob 53 | $ lumen balance bob CAD 54 | # 10.0000000 55 | ``` 56 | 57 | Great! Bob now has some spending money. 58 | 59 | So lets suppose that there's an Anchor run by a rogue entity called the *People's Bank of Canadian Separatists*, and they're issuing `CAD` too. 60 | 61 | ```sh 62 | $ lumen account new rogue-bank 63 | $ lumen friendbot rogue-bank 64 | $ lumen asset set CAD-rogue rogue-bank --code CAD 65 | ``` 66 | 67 | We now have two assets with the code `CAD` on the network (with the alises `CAD` and `CAD-rogue`. How does poor old Bob ensure that the only `CAD` he holds is from the Bank of Canada? Simple -- he does nothing. 68 | 69 | Let's see what happens when the People's Bank of Canadian Separatists try to issue their CAD to Bob. 70 | 71 | ```sh 72 | $ lumen pay 10 CAD-rogue --from rogue-bank --to bob 73 | ERRO[0008] payment failed: 400: Transaction Failed (&{tx_failed [op_no_trust]}) cmd=pay 74 | $ lumen balance bob CAD-rogue 75 | # 0 76 | ``` 77 | 78 | Guess that didn't work. The only `CAD` that Bob can hold is from the Bank of Canada. This model of explicitly trusting asset issuers is very different from, say Ethereum's ERC20 model, where issuers can distribute tokens to anyone on the network without their permission. 79 | 80 | If Bob decides that he never wants to hold `CAD` again, he can return the assets back to the issuer and revoke his trustline. 81 | 82 | ```sh 83 | $ lumen pay 10 CAD --from bob --to BankOfCanada 84 | $ lumen trust remove bob CAD 85 | ``` 86 | 87 | ### Trustline fees 88 | 89 | Adding a trustline to an account raises the required minimum balance by the *base reserve* fee, which is 0.5 XLM. So Bob's account with a trustline to the Bank of Canada's CAD asset, needs to maintain at least 1.5 XLM to be able to transact on the network. Any transaction that reduces the balance to below the minimum will be rejected with `INSUFFICIENT_BALANCE` 90 | 91 | You can read more about Stellar fees in the [developer guide](https://www.stellar.org/developers/guides/concepts/fees.html). 92 | 93 | ## Distributing assets 94 | 95 | Issuing accounts don't hold balances for the assets they issue -- they can technically issue an infinite supply. So sending an asset back to an issuer is equivalent to destroying the assets. 96 | 97 | To create a fixed supply, the typical strategy is to create a new *distributor* account, also managed by the anchor, issue it a fixed number of assets, and then permanently disable the issuer's account. The public can always look up the total supply by checking the issuer's ledger, and also confirm that the supply is fixed by verifying that the issuer's account is permanently disabled. 98 | 99 | To permanently disable an account, use `lumen signers masterweight`. This only works if there are no other signers on the account, and we'll discuss this in the next chapter. 100 | 101 | ```sh 102 | # Create a distributor account for BoC CAD 103 | $ lumen account new distributor 104 | $ lumen friendbot distributor 105 | 106 | # Add a trustline for the distributor and distribute a fixed supply of CAD 107 | $ lumen trust create distributor CAD 108 | $ lumen pay 10000000000 CAD --from BankOfCanada --to distributor 109 | 110 | # Now kill BoC's issuer's account 111 | $ lumen signer masterweight BankOfCanada 0 112 | ``` 113 | 114 | Bank of Canada can no longer create new CAD assets from that issuer. Their only option now is to create a new issuer account, and get customers to create a new trustline to the new asset for that account. 115 | 116 | ### Setting asset limits 117 | 118 | As an asset holder, one can limit the total amount of an asset that they hold during trustline creation. This is typically a preventative measure against malice or errors. 119 | 120 | ```sh 121 | # Don't hold more than 5000 CAD 122 | $ lumen trust create bob CAD 5000 123 | 124 | # This will fail 125 | $ lumen pay 7000 CAD-BoC --from BankOfCanada --to bob 126 | ``` 127 | 128 | As an anchor, you can also choose to pre-approve your asset holders. By marking the issuing account as `AUTH_REQUIRED`, you can require trustlines to be authorized by the issuer before they can be established. 129 | 130 | ```sh 131 | $ lumen flags BankOfCanada auth_required 132 | 133 | # Bob creates a new trustline to CAD. 134 | $ lumen trust create bob CAD-BoC 1000 135 | 136 | # Bank-of-canada authorizes it. 137 | $ lumen trust allow bob CAD-BoC --signers BankOfCanada 138 | ``` 139 | 140 | Anchors can also freeze assets on an account or revoke trustlines if they need to. To do this, they must have the `AUTH_REVOCABLE` flag on their issuing account. 141 | 142 | ```sh 143 | $ lumen flags BankOfCanada auth_revocable 144 | 145 | # Revoke Bob's trustline and freeze his assets 146 | $ lumen trust allow bob CAD-BoC --revoke --signers BankOfCanada 147 | ``` 148 | 149 | ## Managing asset aliases 150 | 151 | In the above examples, we defined aliases for the new assets that we created. Remember that these aliases are a construct of the Lumen tool, and not recognized by the Stellar network. 152 | 153 | To look up assets by their alias, you can use the `lumen asset` command. 154 | 155 | ```sh 156 | # Who issues CAD-BoC? 157 | $ lumen asset issuer CAD 158 | # GC6C225I4VIKCLUWJNAFRTTUN5UAMK7JRTCRUN3KSVXULVZ6OEH2WQRH 159 | 160 | $ lumen asset code CAD 161 | # CAD 162 | 163 | $ lumen asset code CAD-rogue 164 | # CAD 165 | 166 | # The alias `native` is reserved by Lumen and designates the 167 | # network's native asset. 168 | $ lumen balance mo native 169 | ``` 170 | 171 | Delete an asset alias with `lumen del`. 172 | 173 | ```sh 174 | $ lumen asset del CAD-BoC 175 | ``` 176 | 177 | If you don't want to create an asset, you can use colon-syntax to reference one without making an alias. The format `CODE:ISSUER` or `CODE:ISSUER:TYPE` can be used in place of any of the other commands in this chapter. 178 | 179 | ```sh 180 | $ lumen trust create bob CAD:BankOfCanada 181 | 182 | # Incase you want to specify the asset type 183 | $ lumen pay 1 USD:BankOfCanada:credit_alphanum4 --from mary --to bob 184 | 185 | # No aliases at all 186 | $ lumen balance bob CAD:GC6C225I4VIKCLUWJNAFRTTUN5UAMK7JRTCRUN3KSVXULVZ6OEH2WQRH 187 | ``` 188 | 189 | You can also use federated addresses (see [Chapter 2](https://github.com/0xfe/hacking-stellar/blob/master/2-payments.md)) when specifying your assets. 190 | 191 | ```sh 192 | $ lumen pay 1 CAD:issuer*bankofcanada.com --from mary --to bob 193 | 194 | $ lumen asset set CAD anchor*citibank.com 195 | ``` 196 | 197 | ## Onward 198 | 199 | To learn more about assets, read the section in the [Stellar developer guide](https://www.stellar.org/developers/guides/concepts/assets.html). You can explore assets in the [Stellar lab](https://www.stellar.org/laboratory/#explorer?resource=assets&endpoint=single&network=test). 200 | 201 | For now, lets move on to [Chapter 4](https://github.com/0xfe/hacking-stellar/blob/master/4-multisig.md), where we discuss multisignature accounts and transactions. 202 | 203 | [Front](https://github.com/0xfe/hacking-stellar/blob/master/README.md) - 204 | [Chapter 1](https://github.com/0xfe/hacking-stellar/blob/master/1-launch.md) - 205 | [Chapter 2](https://github.com/0xfe/hacking-stellar/blob/master/2-payments.md) - 206 | [Chapter 3](https://github.com/0xfe/hacking-stellar/blob/master/3-assets.md) - 207 | [Chapter 4](https://github.com/0xfe/hacking-stellar/blob/master/4-multisig.md) - 208 | [Chapter 5](https://github.com/0xfe/hacking-stellar/blob/master/5-dex.md) - 209 | [Chapter 6](https://github.com/0xfe/hacking-stellar/blob/master/6-debugging.md) 210 | -------------------------------------------------------------------------------- /4-multisig.md: -------------------------------------------------------------------------------- 1 | [Front](https://github.com/0xfe/hacking-stellar/blob/master/README.md) - 2 | [Chapter 1](https://github.com/0xfe/hacking-stellar/blob/master/1-launch.md) - 3 | [Chapter 2](https://github.com/0xfe/hacking-stellar/blob/master/2-payments.md) - 4 | [Chapter 3](https://github.com/0xfe/hacking-stellar/blob/master/3-assets.md) - 5 | [Chapter 4](https://github.com/0xfe/hacking-stellar/blob/master/4-multisig.md) - 6 | [Chapter 5](https://github.com/0xfe/hacking-stellar/blob/master/5-dex.md) - 7 | [Chapter 6](https://github.com/0xfe/hacking-stellar/blob/master/6-debugging.md) 8 | 9 | 10 | # Chapter 4. Managing Signers 11 | 12 | Transactions must be cryptographically signed before it can be submitted to Stellar for processing. And typically, it's the account that initiates the transaction (e.g., a payer, or a trustor) that signs it. Transactions that are not signed, or signed by the wrong parties are immediately rejected by the network. 13 | 14 | Stellar lets you setup some sophisticated signature requirements. You can add and remove multiple signers to and from an account, and set their authorization levels based on the types of transactions you want to allow. 15 | 16 | For example, Bob and Mary could share a joint Stellar account, out of which either one could spend independently. But they can set it up such that adding another person requires both Bob and Mary to approve the transaction. 17 | 18 | ## Adding a signer 19 | 20 | The Lumen `signer` command lets you manage the signature requirements of an account. 21 | 22 | ```sh 23 | $ lumen signer --help 24 | manage signers on account 25 | 26 | Usage: 27 | lumen signer [list|add|remove|thresholds|masterweight] [flags] 28 | lumen signer [command] 29 | 30 | Available Commands: 31 | add add signer_address as a signer on [account] with key weight [weight] 32 | masterweight set the weight of the accounts master key 33 | remove remove signer_address as a signer from [account] 34 | thresholds set low, medium, and high thresholds for [account] 35 | 36 | Flags: 37 | -h, --help help for signer 38 | 39 | Global Flags: 40 | --network string network to use (test) (default "test") 41 | --ns string namespace to use (default) (default "default") 42 | --store string namespace to use (default) (default "file:/Users/mo/.lumen-data.yml") 43 | -v, --verbose verbose output (false) 44 | 45 | Use "lumen signer [command] --help" for more information about a command. 46 | ``` 47 | 48 | Let's say that Mary, Bob, and Kelly want to create a pizza fund, into which they regularly contribute some money for pizza night. They elect Kelly to create the fund for them. 49 | 50 | ```sh 51 | # Kelly first creates a new account for the pizza fund and seeds it with 5 XLM 52 | $ lumen account new pizzafund 53 | $ lumen pay 5 --from kelly --to pizzafund --fund 54 | 55 | # The pizza company accepts USD from various common anchors. Let the fund 56 | # hold no more than 200 USD. 57 | $ lumen asset set USD citibank 58 | $ lumen trust create pizzafund USD 200 59 | 60 | # Kelly then adds Mary and Bob as signers on the fund. She only needs their public addresses for 61 | # this, and creates some aliases for convenience. 62 | $ lumen account set bob GCJTY3FCRCBPAPKG4NPWRLVLIL6EU4UHPBYPH75K4SNK4ELSTLS6JFDX 63 | $ lumen account set mary GAFAP7HEY3Q7YQNNXKRIMVSTDGOP7PHMRPN5UZ4C655HARYV7KHSXEAQ 64 | 65 | # Add bob, mary, and kelly as signers, with the weight of 1 each. 66 | $ lumen signer add bob 1 --to pizzafund --memotext "pizza for bob" 67 | $ lumen signer add mary 1 --to pizzafund --memotext "pizza for mary" 68 | $ lumen signer add kelly 1 --to pizzafund --memotext "pizza for kelly" 69 | ``` 70 | 71 | That's it! Now Bob, Kelly, and Mary can spend from the pizza fund and never be hungry again! Since Kelly added herself as a signer, she can throw away the pizza fund's seed. 72 | 73 | Bob and Mary don't need the seed either. They'd make a payment using their own seeds. 74 | 75 | ```sh 76 | $ lumen pay 10 USD --from pizzafund --to pizzahut --signers bob 77 | ``` 78 | 79 | ## Weights and Thresholds 80 | 81 | When we added signers to the pizza fund with the `lumen signer` command, we set their weights to `1`. To understand what that did, we first need to understand **thresholds**. 82 | 83 | Every Stellar operation is lumpted into one of three security categories: *low*, *medium*, and *high*. Each of these categories has a signing threshold, which is a number between 0 and 255. For a transaction of a specific category to be approved by the network, it must have enough signatures with weights summing up to the category's threshold. 84 | 85 | For example, payments fall into the *medium* category. Suppose we wanted to require that the pizza fund (above) can only be spent from if at least two members approve, we would need to set the account's medium threshold to 2. 86 | 87 | You can use the `signer thresholds` command to set the *low*, *medium*, and *high* thresholds for an account. 88 | 89 | ```sh 90 | # Set thresholds: low=1, medium=2, high=2 91 | $ lumen signer thresholds pizzafund 1 2 2 --signers kelly 92 | ``` 93 | 94 | Now, payments from `pizzafund` must have at least two signers (each signer has a weight of 1, and we need a minimum total of 2.) Notice that we also set the *high* threshold to 2? We needed to do this because operations to manage signers and thresholds fall into the *high* category. If we didn't also set *high* to 2, any one of them could set the *medium* threshold back to 1, and make a payment. 95 | 96 | If we wanted to require that all three of them approve any threshold or signer operations, we could set *high* to 3. 97 | 98 | ```sh 99 | $ lumen signer thresholds pizzafund 1 2 3 --signers kelly,mary 100 | ``` 101 | 102 | ## The Master Key 103 | 104 | When you first create an account you generate an address and a seed. The address is the public-facing identifier for the account, and the seed is the **master key**. As we explored in this chapter, you can always add and remove new keys to and from an account, but the master key is forever. 105 | 106 | The default weight of the master key is `1`, and the only way to disable a master key, is by setting its weight to `0`. You can do this with `lumen masterweight`. 107 | 108 | ```sh 109 | $ lumen masterweight pizzafund 0 --signers kelly,mary,bob 110 | ``` 111 | 112 | If you set the master weight to 0, and there are no other signers left, the account is permanently disabled. There's no getting it back. This is, in fact, the recommended way to lock an anchor's issuing account for fixed supply assets. 113 | 114 | ## Real-world usage 115 | 116 | In the real world, one does not typically have all the signing keys for a multisig transaction. So, the first signer usually generates a signed transaction, and passes it on to the next person to sign. After all parties have signed the transaction, anyone can submit it to the network. Let's try that out. 117 | 118 | Kelly first creates the transaction and signs it on her machine. She uses the `--nosubmit` flag to specify that the transaction should not be submitted to the Stellar network. She also pipes out the base64-encoded transaction (output by Lumen) to `pizza.txt` 119 | 120 | ```sh 121 | $ lumen pay 10 USD --from pizzafund --to pizzahut --nosubmit >pizza.txt 122 | ``` 123 | 124 | Kelly then sends `pizza.txt` to Mary, who adds her signature to the transaction, and then submits it to the network. She uses `lumen tx sign` and `lumen tx submit` for this. Before she signs it, she decodes the transaction to verify the contents. 125 | 126 | ```sh 127 | $ lumen tx decode $(cat foo.txt) --pretty 128 | $ lumen tx sign $(cat foo.txt) --signers mary >foo.signed.txt 129 | $ lumen tx submit $(cat foo.signed.txt) 130 | ``` 131 | 132 | Kelly could also have generated the initial transaction without signing it at all, asking Bob and Mary to do the honours. She would use the `--nosign` flag for this. 133 | 134 | ```sh 135 | $ lumen pay 10 USD --from pizzafund --to pizzahut --nosign --nosubmit >pizza.unsigned.txt 136 | ``` 137 | 138 | ## Miltisignature use cases 139 | 140 | ### Anchors and asset issuers 141 | 142 | If you're operating as an anchor, you can devise a scheme where at least two executives must approve asset issual, but any employee can authorize a trustline. 143 | 144 | ```sh 145 | $ lumen account set CAD-issuer ... 146 | $ lumen asset set CAD CAD-issuer 147 | 148 | # Add the three executives as signers, each with the weight 5 149 | $ lumen signer add exec1 --to CAD-issuer 5 150 | $ lumen signer add exec2 --to CAD-issuer 5 151 | $ lumen signer add exec3 --to CAD-issuer 5 152 | 153 | # Add employees with the weight 1 each 154 | $ lumen signer add employee1 --to CAD-issuer 1 155 | $ lumen signer add employee2 --to CAD-issuer 1 156 | $ lumen signer add employeeN --to CAD-issuer 1 157 | 158 | # Set the signature thresholds for the issuer 159 | $ lumen signer thresholds 1 10 15 160 | ``` 161 | 162 | Above, any employee can authorize trustlines (it's a low threshold operation), but you'll need 10 of them to collude to issue assets. In addition, any two executives can issue assets, but all three of them will have to approve changes to signers or thresholds. 163 | 164 | ### Joint accounts 165 | 166 | Jim and Bob hook up, get married, and want a joint account. Either of them can spend from the account, but the two of them must approve changes to the account. 167 | 168 | ```sh 169 | $ lumen signer add bob --to joint 1 170 | $ lumen signer add jim --to joint 1 171 | $ lumen signer thresholds joint 1 1 2 172 | $ lumen masterweight joint 0 --signers bob,jim 173 | ``` 174 | 175 | Notice that we disabled the master key so it can't be used as a signer. The only way to re-enable it is with both Jim and Bob's approval. 176 | 177 | ### Expense accounts 178 | 179 | You want to create a company expense account where a manager must approve outgoing payments buy employees. 180 | 181 | ```sh 182 | $ lumen signer add exec1 --to expense 10 183 | $ lumen signer add exec2 --to expense 10 184 | 185 | $ lumen signer add manager1 --to expense 5 186 | $ lumen signer add manager2 --to expense 5 187 | $ lumen signer add managerN --to expense 5 188 | 189 | $ lumen signer add employee1 --to expense 1 190 | $ lumen signer add employee2 --to expense 1 191 | $ lumen signer add employeeN --to expense 1 192 | $ lumen signer thresholds expense 6 6 20 193 | ``` 194 | 195 | Above, we require a total signing weight of 6 for payments, and 20 for signing changes. 196 | 197 | ### Disaster recovery 198 | 199 | An anchor or a business might want to practice sound operations by maintaining a disaster recovery (DR) key in cold storage (i.e., on an offline medium.) This key would have a higher signing weight than an online key. 200 | 201 | Taking the Anchor example from the first use case, you start with generating a key pair on an offline machine. 202 | 203 | ```sh 204 | $ lumen account new 205 | # GCXZW4IEBTCQQ6JY4COH3O2SSCBUAMPJ4WM4EU2GWBZ4MNVZJSTISBOE SCRUPYLCKDZ5HP4OBMKXUEAW52F7WFHQYKLZJUVHUPKLAI652E5XOCZY 206 | ``` 207 | 208 | Write down the seed on a piece of paper, laminate it, and put it in a safe. Then add the public address as a signer on the issuer's account with a high weight. (Note that there are much better ways to manage cold keys -- this is just an example.) 209 | 210 | ```sh 211 | $ lumen signer add GCXZW4IEBTCQQ6JY4COH3O2SSCBUAMPJ4WM4EU2GWBZ4MNVZJSTISBOE --to CAD-issuer 10 --signers exec1,exec2,exec3 212 | ``` 213 | 214 | This way, suppose two of the executives die in a car crash (why are they traveling together in the fist place?), the DR key can be recovered and the business can continue to operate. 215 | 216 | ## Onward 217 | 218 | To learn more about multisignature support in Stellar, read the [developer guide](https://www.stellar.org/developers/guides/concepts/multi-sig.html). 219 | 220 | [Front](https://github.com/0xfe/hacking-stellar/blob/master/README.md) - 221 | [Chapter 1](https://github.com/0xfe/hacking-stellar/blob/master/1-launch.md) - 222 | [Chapter 2](https://github.com/0xfe/hacking-stellar/blob/master/2-payments.md) - 223 | [Chapter 3](https://github.com/0xfe/hacking-stellar/blob/master/3-assets.md) - 224 | [Chapter 4](https://github.com/0xfe/hacking-stellar/blob/master/4-multisig.md) - 225 | [Chapter 5](https://github.com/0xfe/hacking-stellar/blob/master/5-dex.md) - 226 | [Chapter 6](https://github.com/0xfe/hacking-stellar/blob/master/6-debugging.md) -------------------------------------------------------------------------------- /5-dex.md: -------------------------------------------------------------------------------- 1 | [Front](https://github.com/0xfe/hacking-stellar/blob/master/README.md) - 2 | [Chapter 1](https://github.com/0xfe/hacking-stellar/blob/master/1-launch.md) - 3 | [Chapter 2](https://github.com/0xfe/hacking-stellar/blob/master/2-payments.md) - 4 | [Chapter 3](https://github.com/0xfe/hacking-stellar/blob/master/3-assets.md) - 5 | [Chapter 4](https://github.com/0xfe/hacking-stellar/blob/master/4-multisig.md) - 6 | [Chapter 5](https://github.com/0xfe/hacking-stellar/blob/master/5-dex.md) - 7 | [Chapter 6](https://github.com/0xfe/hacking-stellar/blob/master/6-debugging.md) 8 | 9 | # Chapter 5. The Decentralized Exchange 10 | 11 | One of the coolest features of Stellar is the decentralized distributed exchange, where users can buy and sell any of the assets on the network. Stellar actually steps this up a notch, allowing you to do instant cross-asset payments, so you can always transact with your preferred currency. 12 | 13 | ## Trading on the exchange 14 | 15 | ### Order Books 16 | Order books maintain the list of current offers between asset pairs. For example, the `USD/EUR` orderbook would contain all the bids and asks between USD (the base asset) and EUR (the counter asset.) 17 | 18 | To get the orderbook for an asset pair, use the `lumen dex orderbook` command. You can use the `--limit` flag to restrict the number of results, and `--format json` to get JSON formatted results. 19 | 20 | ```sh 21 | # Let's look at a real orderbook 22 | $ lumen set config:network public 23 | 24 | # Pick an asset from a random anchor in the stellar.org directory 25 | $ lumen asset set BTC-nao GATEMHCCKCY67ZUCKTROYN24ZYT5GK4EQZ65JJLDHKHRUZI3EUEKMTCH --code BTC 26 | 27 | # List all open orders between HAK and XLM 28 | $ lumen dex orderbook BTC-nao native 29 | ask: 0.2050541 BTC for 36575.7190805 xlm/BTC 30 | ask: 0.2040236 BTC for 36760.4449344 xlm/BTC 31 | ask: 0.2029932 BTC for 36947.0461777 xlm/BTC 32 | ask: 0.2019628 BTC for 37135.5515154 xlm/BTC 33 | ask: 0.2009324 BTC for 37325.9902411 xlm/BTC 34 | ask: 0.1999020 BTC for 37518.3922526 xlm/BTC 35 | ask: 0.1988715 BTC for 37712.7880674 xlm/BTC 36 | ask: 0.1978411 BTC for 37909.2088386 xlm/BTC 37 | ask: 0.1968107 BTC for 38107.6863718 xlm/BTC 38 | ask: 0.1957803 BTC for 38308.2531422 xlm/BTC 39 | bid: 1974.6074662 xlm for 32258.0645161 xlm/BTC 40 | bid: 3000.0000000 xlm for 29585.7988166 xlm/BTC 41 | bid: 3254.1532509 xlm for 29498.5250737 xlm/BTC 42 | bid: 71.0270171 xlm for 29411.7647059 xlm/BTC 43 | bid: 100.0000000 xlm for 29325.5131965 xlm/BTC 44 | bid: 160.0000000 xlm for 29239.7660819 xlm/BTC 45 | bid: 160.0000000 xlm for 29154.5189504 xlm/BTC 46 | bid: 160.0000000 xlm for 29069.7674419 xlm/BTC 47 | bid: 160.0000000 xlm for 28985.5072464 xlm/BTC 48 | bid: 189.4117647 xlm for 28901.7341040 xlm/BTC 49 | ``` 50 | 51 | You can also reverse the asset pair, making it simpler to compare prices and calculate spreads. Trading bots do this all the time while looking for arbitrage opportunities on the DEX. 52 | 53 | ```sh 54 | $ lumen dex orderbook native BTC-nao 55 | ask: 1974.6074662 xlm for 0.0000310 BTC/xlm 56 | ask: 3000.0000000 xlm for 0.0000338 BTC/xlm 57 | ask: 3254.1532509 xlm for 0.0000339 BTC/xlm 58 | ask: 71.0270171 xlm for 0.0000340 BTC/xlm 59 | ask: 100.0000000 xlm for 0.0000341 BTC/xlm 60 | ask: 160.0000000 xlm for 0.0000342 BTC/xlm 61 | ask: 160.0000000 xlm for 0.0000343 BTC/xlm 62 | ask: 160.0000000 xlm for 0.0000344 BTC/xlm 63 | ask: 160.0000000 xlm for 0.0000345 BTC/xlm 64 | ask: 189.4117647 xlm for 0.0000346 BTC/xlm 65 | bid: 0.2050541 BTC for 0.0000273 BTC/xlm 66 | bid: 0.2040236 BTC for 0.0000272 BTC/xlm 67 | bid: 0.2029932 BTC for 0.0000271 BTC/xlm 68 | bid: 0.2019628 BTC for 0.0000269 BTC/xlm 69 | bid: 0.2009324 BTC for 0.0000268 BTC/xlm 70 | bid: 0.1999020 BTC for 0.0000267 BTC/xlm 71 | bid: 0.1988715 BTC for 0.0000265 BTC/xlm 72 | bid: 0.1978411 BTC for 0.0000264 BTC/xlm 73 | bid: 0.1968107 BTC for 0.0000262 BTC/xlm 74 | bid: 0.1957803 BTC for 0.0000261 BTC/xlm 75 | ``` 76 | 77 | ### Buying and Selling 78 | 79 | To buy and sell assets on the Stellar exchange, use the `lumen dex trade` command. It allows you to make an offer to sell a certain amount of one asset for a price in terms of another asset. 80 | 81 | Let's have Bob make an offer to sell 10 lumens (XLM) for 5 USD each. For the arithmetically challenged, it's an offer to buy 50 USD for 10 lumens. 82 | 83 | ```sh 84 | # Recall that `native` is an internal alias for the native asset (lumens/XLM) 85 | $ lumen dex trade bob --buy USD --sell native --amount 10 --price 5 86 | ``` 87 | 88 | Once this offer is made, it remains in Stellar's order book until either someone else takes it, or Bob revokes it. 89 | 90 | To see all of Bob's offers, use `lumen dex list`. You'll notice that every offer is associated with an Offer ID (in parenthesis.) 91 | 92 | ```sh 93 | $ lumen dex list bob 94 | # (141452) selling 10.0000000 lumens for USD at 5.0000000 USD/lumen. 95 | ``` 96 | 97 | You can get more detail about Bob's offers with the `--format json` flag. 98 | 99 | ```json 100 | $ lumen dex list bob --format json 101 | { 102 | "_links": { 103 | "self": { 104 | "href": "https://horizon-testnet.stellar.org/offers/143297" 105 | }, 106 | "offer_maker": { 107 | "href": "https://horizon-testnet.stellar.org/accounts/GDELI4BPSO7SZGNNIDJ33N2HMJDQKB6PDD6P633U6LKGM26BYDVPRXU3" 108 | } 109 | }, 110 | "id": 141452, 111 | "paging_token": "141452", 112 | "seller": "GDELI4BPSO7SZGNNIDJ33N2HMJDQKB6PDD6P633U6LKGM26BYDVPRXU3", 113 | "selling": { 114 | "asset_type": "native", 115 | "asset_code": "XLM", 116 | }, 117 | "buying": { 118 | "asset_type": "credit_alphanum4", 119 | "asset_code": "USD", 120 | "asset_issuer": "GC6C225I4VIKCLUWJNAFRTTUN5UAMK7JRTCRUN3KSVXULVZ6OEH2WQRH" 121 | }, 122 | "amount": "10.0000000", 123 | "price_r": { 124 | "n": 5, 125 | "d": 1 126 | }, 127 | "price": "5.0000000" 128 | } 129 | ``` 130 | 131 | Mary can take Bob's offer by making an inverse offer on the DEX. Again, that's an offer to buy 50 units of XLM for 20¢ each. 132 | 133 | ```sh 134 | $ lumen dex trade mary --buy native --sell USD --amount 50 --price 0.2 135 | ``` 136 | 137 | ### Managing offers 138 | 139 | If nobody takes Bob's offer, he can choose to reduce the price of the existing offer with the `--update` flag, passing in the offer ID. 140 | 141 | ```sh 142 | $ lumen dex trade bob --buy USD --sell native --price 4 --update 141452 143 | ``` 144 | 145 | Alternatively, Bob can simply revoke his offer with the `--delete` flag. 146 | 147 | ```sh 148 | $ lumen dex trade bob --buy USD --sell native --price 4 --delete 141452 149 | ``` 150 | 151 | ## Cross-asset Payments 152 | 153 | Stellar lets you make transparent cross currency payments over the DEX. For example, if Mary only prefers to transact in Canadian Dollars, and Kelly only likes to transact in Euros, Stellar can facilitate an automatic currency conversion using the cheapest prices on the DEX. 154 | 155 | Stellar can sometimes do this even if there isn't a direct CAD <-> EUR offer on the DEX, by finding alternate payment paths over multiple currencies. So, if there are offers for CAD <-> USD, and EUR <-> USD, Stellar can trade the CAD for USD, and then the USD for EUR, all in a single atomic step. 156 | 157 | Cross-asset payments are simple to execute with Lumen. Use `--with [asset]` to specify the currency you want to make the payment with, and `--max [price]` to specify the maximum amount you want to spend for the payment. 158 | 159 | ```sh 160 | # Kelly deposits 10 USD into Mary's account, and pays for it with her EUR balance. She 161 | # also instructs Stellar not to spend more than 8 EUR on the transaction. 162 | $ lumen pay 10 CAD --from kelly --to mary --with EUR --max 8 163 | ``` 164 | 165 | Lumen uses automatic path finding to facilitate this payment, but you can specify your own asset path if you'd like. 166 | 167 | ```sh 168 | $ lumen pay 10 USD --from kelly --to mary --with EUR --max 8 --through native 169 | ``` 170 | 171 | ### Trying it out 172 | 173 | Let's try an end-to-end example where we create a bunch of assets, offer them on the DEX, and then make a path payment through them. 174 | 175 | First, lets create some accounts. 176 | 177 | ```sh 178 | # Switch to the test network 179 | $ lumen set config:network test 180 | 181 | # Create and fund our asset issuer. 182 | $ lumen account new issuer 183 | $ lumen friendbot issuer 184 | 185 | # Create and fund Bob and Kelly, our end-users. 186 | $ lumen account new kelly 187 | $ lumen friendbot issuer 188 | $ lumen account new bob 189 | $ lumen friendbot issuer 190 | 191 | # Create and fund Mary and Mike, active traders. 192 | $ lumen account new mary 193 | $ lumen friendbot mary 194 | $ lumen account new mike 195 | $ lumen friendbot mike 196 | ``` 197 | 198 | Now, let's create some assets for currencies `USD`, `INR`, and `EUR` all issued by `issuer`. We'll also create trustlines for Bob, Kelly, Mary, and Mike, and seed their accounts with some funds. 199 | 200 | ```sh 201 | $ lumen asset set USD issuer 202 | $ lumen asset set INR issuer 203 | $ lumen asset set EUR issuer 204 | 205 | # Kelly's preferred currency is INR, she doesn't hold anything else. 206 | $ lumen trust create kelly --to INR 207 | $ lumen pay 1000 INR --from issuer --to kelly 208 | 209 | # Bob's preferred currency is USD. 210 | $ lumen trust create bob --to USD 211 | $ lumen pay 1000 USD --from issuer --to bob 212 | 213 | # Mary's likes to trade USD and EUR. 214 | $ lumen trust create mary --to USD 215 | $ lumen pay 1000 USD --from issuer --to mary 216 | $ lumen trust create mary --to EUR 217 | $ lumen pay 1000 EUR --from issuer --to mary 218 | 219 | # Mike likes to trade EUR and INR. 220 | $ lumen trust create mike --to EUR 221 | $ lumen pay 1000 EUR --from issuer --to mike 222 | $ lumen trust create mike --to INR 223 | $ lumen pay 1000 INR --from issuer --to mike 224 | ``` 225 | 226 | Since Mary and Mike are active traders, have them put some offers up on the DEX. Let's keep the prices at `1` to keep things simple. 227 | 228 | ```sh 229 | $ lumen dex trade mary --buy USD --sell EUR --amount 50 --price 1 230 | $ lumen dex trade mike --buy EUR --sell INR --amount 50 --price 1 231 | ``` 232 | 233 | So Mary is trading USD for EUR, and Mike's trading EUR for INR. These offers hang out on the network until someone makes an inverse offer. 234 | 235 | Some time later, Kelly fixes Bob's Internet, and charges him `10 INR`, which is her preferred currency. Bob only has `USD`, which is his preferred currency. 236 | 237 | No big deal. Thanks to the DEX, Bob can pay Kelly `10 INR` with his `USD`, by making a path payment. 238 | 239 | ```sh 240 | # Bob knows that the USD <-> INR exchange rate is 1, so he sets the max spend to 10, which implies that 241 | # he spends no more than 10 USD on this transaction. 242 | $ lumen pay 10 INR --from bob --to kelly --with USD --max 10 243 | ``` 244 | 245 | That's it! Let's check their balances to verify that the transaction went through. 246 | 247 | ```sh 248 | $ lumen balance bob USD 249 | # 9990.0000000 250 | 251 | $ lumen balance kelly INR 252 | # 1010.0000000 253 | ``` 254 | 255 | To see what happened, let's take a look at the orderbook. 256 | 257 | ```sh 258 | $ lumen dex list mary 259 | # (141452) selling 40.0000000 EUR for USD at 1.0000000 USD/EUR 260 | 261 | $ lumen dex list mike 262 | # (143297) selling 40.0000000 INR for EUR at 5.0000000 USD/XLM 263 | ``` 264 | 265 | The path payment filled 10 units of both Mary's and Mike's offers. Effectively, Bob sold his `USD` to Mary, who in turn sold her `EUR` to Mike, who ended up paying Kelly the `10 INR`. Furthermore, Stellar ensured that of this happened in one atomic step, i.e., there's no way that this payment flow would only be partially executed, leaving both Bob and Kelly hanging. 266 | 267 | ## Onward 268 | 269 | As you can see, Stellar's DEX is a fantastic way to facilitate cross-asset payments, but also path payments help increase the amount of liquidity in the DEX. In the next chapter, we'll work on building an Anchor. 270 | 271 | [Front](https://github.com/0xfe/hacking-stellar/blob/master/README.md) - 272 | [Chapter 1](https://github.com/0xfe/hacking-stellar/blob/master/1-launch.md) - 273 | [Chapter 2](https://github.com/0xfe/hacking-stellar/blob/master/2-payments.md) - 274 | [Chapter 3](https://github.com/0xfe/hacking-stellar/blob/master/3-assets.md) - 275 | [Chapter 4](https://github.com/0xfe/hacking-stellar/blob/master/4-multisig.md) - 276 | [Chapter 5](https://github.com/0xfe/hacking-stellar/blob/master/5-dex.md) - 277 | [Chapter 6](https://github.com/0xfe/hacking-stellar/blob/master/6-debugging.md) -------------------------------------------------------------------------------- /6-debugging.md: -------------------------------------------------------------------------------- 1 | [Front](https://github.com/0xfe/hacking-stellar/blob/master/README.md) - 2 | [Chapter 1](https://github.com/0xfe/hacking-stellar/blob/master/1-launch.md) - 3 | [Chapter 2](https://github.com/0xfe/hacking-stellar/blob/master/2-payments.md) - 4 | [Chapter 3](https://github.com/0xfe/hacking-stellar/blob/master/3-assets.md) - 5 | [Chapter 4](https://github.com/0xfe/hacking-stellar/blob/master/4-multisig.md) - 6 | [Chapter 5](https://github.com/0xfe/hacking-stellar/blob/master/5-dex.md) - 7 | [Chapter 6](https://github.com/0xfe/hacking-stellar/blob/master/6-debugging.md) 8 | 9 | # Chapter 6. Debugging Stellar 10 | 11 | In this chapter, we'll explore the many ways to debug and troubleshoot your Stellar applications. To follow along with the examples in this chapter, you'll need the command-line tools, [jq](https://stedolan.github.io/jq/), [curl](https://curl.haxx.se/), and [Lumen](http://github.com/0xfe/lumen) (which you probably already have.) 12 | 13 | ## The Stellar Network 14 | 15 | The Stellar organization manages two publically-accessible networks, called *live* and *test*. (These are sometimes also referred to as *public* and *testnet*.) Both consist of a peer-to-peer network of nodes running the [Stellar Core](https://www.stellar.org/developers/stellar-core/learn/admin.html) software, which validate and process transactions, and commit them to the global ledgers of their specific networks. 16 | 17 | The live network is where real value is transacted. Lumens on the live network cost real money, and can be bought at many cryptocurrency exchanges. The test network on the other uses fake luments that developers can request at any time. 18 | 19 | You can see see the status of the networks on the [Stellar Network Dashboard](https://dashboard.stellar.org/). 20 | 21 | ### Horizon 22 | 23 | When you transact on Stellar with the Lumen tool (or with the SDKs), you don't directly interact with the core network. You're actually interacting with [Horizon](https://www.stellar.org/developers/reference/), which is an API gateway into the core network. Horizon actively ingests data from Stellar core, and exports a JSON/HTTP API that can be consumed by any HTTP client (including your browser.) 24 | 25 | The Stellar organization runs a set of publically available Horizon servers, which most tools and SDKs default to using. However, if you're deploying applications into production, it's always better to run your own servers. This not only lets you manage load and scale, but also protects you from security compromises of infrastructure you don't fully control. 26 | 27 | With Lumen, you can use the `set config:network` command or the `--network` flag to specify a custom Horizon server. 28 | 29 | ```sh 30 | $ lumen balance bob --network 'custom;http://my.server:8000;networkpassphrase` 31 | ``` 32 | 33 | The passphrase above is for the network you're connecting to (`live` or `test`), not for the Horizon server. You can use any type of firewalling or HTTP proxying to restrict access to your server. 34 | 35 | #### XDR Encoding 36 | 37 | Messages on the Stellar core network are encoded in a format called XDR (*External Data Representation*), specified in [RFC 4506](https://tools.ietf.org/html/rfc4506.html). XDR is a binary format designed to be both bandwidth friendly and compatible across various machine architectures. 38 | 39 | For the most part, Horizon does all the heavy lifting for us, translating messages between XDR and JSON, however the SDKs and libraries do need to work with XDR to sign and submit transactions. XDR structures embedded in JSON are always *base64*-encoded -- Base64 is a text-friendly encoding of binary data, suitable for embedding into strings. 40 | 41 | For example, let's generate an unsigned transaction without submitting it to the network: 42 | 43 | ```sh 44 | $ lumen pay 10 --from issuer --to distributor --nosign --nosubmit >payment.txt 45 | $ cat payment.txt 46 | AAAAADS+VZ+XjxzKscWEqihJhF+xc1iFEHd1g5j+/vIlSphIAAAAZAB6eYwAAAAFAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAA9PBUt4iVNaTh8rzkjyn6nhCtCCZ76N58aTjRCVW/h1cAAAAAAAAAAAX14QAAAAAAAAAAAA== 47 | ``` 48 | 49 | Lumen generated the requested payment transaction and encoded the XDR into base64. To convert it back to human-readable JSON, you can use `lumen tx decode`. 50 | 51 | ```sh 52 | $ lumen tx decode $(cat payment.txt) 53 | {"Tx":{"SourceAccount":{"Type":0,"Ed25519":[52,190,85,159,151,143,28,202,177,197,132,170,40,73,132,95,177,115,88,133,16,119,117,131,152,254,254,242,37,74,152,72]},"Fee":100,"SeqNum":34473589361082373,"TimeBounds":null,"Memo":{"Type":0,"Text":null,"Id":null,"Hash":null,"RetHash":null},"Operations":[{"SourceAccount":null,"Body":{"Type":1,"CreateAccountOp":null,"PaymentOp":{"Destination":{"Type":0,"Ed25519":[244,240,84,183,136,149,53,164,225,242,188,228,143,41,250,158,16,173,8,38,123,232,222,124,105,56,209,9,85,191,135,87]},"Asset":{"Type":0,"AlphaNum4":null,"AlphaNum12":null},"Amount":100000000},"PathPaymentOp":null,"ManageOfferOp":null,"CreatePassiveOfferOp":null,"SetOptionsOp":null,"ChangeTrustOp":null,"AllowTrustOp":null,"Destination":null,"ManageDataOp":null}}],"Ext":{"V":0}},"Signatures":null} 54 | ``` 55 | 56 | You can sign and submit this transcation to the network with `lumen tx sign` and `lumen tx submit`. 57 | 58 | ```sh 59 | $ lumen tx sign $(cat payment.txt) --signers issuer >payment.signed.txt 60 | $ lumen tx submit $(cat payment.signed.txt) 61 | ``` 62 | 63 | #### Using namespaces to switch networks 64 | 65 | It might become tedious to keep setting the network parameters when you're working across different networks. Lumen lets you segregate your configuration and aliases across namespaces. 66 | 67 | ```sh 68 | # Create a new namespace called "custom", and set its network 69 | $ lumen ns custom 70 | $ lumen set config:network 'custom:http://my.server:8000;passphrase' 71 | $ lumen account new bob 72 | 73 | 74 | # Now switch to a different namespace and set its network 75 | $ lumen ns project1 76 | $ lumen set config:network public 77 | $ lumen account address bob 78 | # unknown user: bob 79 | 80 | # Switch back to the first namespace 81 | $ lumen ns custom 82 | $ lumen get config:network 83 | # custom:http://my.server:8000;passphrase 84 | 85 | $ lumen account address bob 86 | # GVA4EAA... 87 | ``` 88 | 89 | ## Ledgers, transactions, and operations 90 | 91 | Every few seconds, the Stellar network commits a ledger to its global database. The ledger consists of a set of transactions, each containing one or more operations. The *transaction envelope* is the header that surrounds a transaction and includes common transaction-level fields. 92 | 93 | Every transaction is charged a [fee](https://www.stellar.org/developers/guides/concepts/fees.html), derived from the number of operations in the transaction, and billed to its respective *source account*. The operations could be anything from payments, to offers, to administrative tasks such as managing signers. You can see the full list of Stellar operations [here](https://www.stellar.org/developers/guides/concepts/list-of-operations.html). 94 | 95 | ## Watching the ledger 96 | 97 | Let's start off by watching Stellar for new ledger entries with `lumen watch ledger`. All `lumen watch ...` commands run forever, streaming updates to your terminal. They're a handy way to troubleshoot your applications, and can be terminated any time with `Ctrl-C`. 98 | 99 | ```json 100 | $ lumen watch ledger --network public 101 | { 102 | "_links": { 103 | "self": { 104 | "href": "https://horizon.stellar.org/ledgers/16889095" 105 | }, 106 | "transactions": { 107 | "href": "https://horizon.stellar.org/ledgers/16889095/transactions{?cursor,limit,order}", 108 | "templated": true 109 | }, 110 | "operations": { 111 | "href": "https://horizon.stellar.org/ledgers/16889095/operations{?cursor,limit,order}", 112 | "templated": true 113 | }, 114 | "payments": { 115 | "href": "https://horizon.stellar.org/ledgers/16889095/payments{?cursor,limit,order}", 116 | "templated": true 117 | }, 118 | "effects": { 119 | "href": "https://horizon.stellar.org/ledgers/16889095/effects{?cursor,limit,order}", 120 | "templated": true 121 | } 122 | }, 123 | "id": "6ecef75a9baabb85c4600ad2a12bd15a08b71e3410bb4b4780e25cec7a32ddf6", 124 | "paging_token": "72538110684037120", 125 | "hash": "6ecef75a9baabb85c4600ad2a12bd15a08b71e3410bb4b4780e25cec7a32ddf6", 126 | "prev_hash": "99beda19d3f8df030c12dfc057fb9f403b3d987ead561db866ea4450e55edc2b", 127 | "sequence": 16889095, 128 | "transaction_count": 3, 129 | "operation_count": 29, 130 | "closed_at": "2018-03-18T22:45:33Z", 131 | "total_coins": "103768249377.9199212", 132 | "fee_pool": "1417457.4202712", 133 | "base_fee_in_stroops": 100, 134 | "base_reserve_in_stroops": 5000000, 135 | "max_tx_set_size": 50, 136 | "protocol_version": 9 137 | } 138 | 139 | # ... streams forever ... 140 | ``` 141 | 142 | There are a few interesting things in the output above (which shows the most recent ledger at the time of this writing). Firstly, we used the `--network public` flag to specify that we want the live network. You could also have done `lumen set config:network public`, but it's good practice to leave the default network at `test`. 143 | 144 | You can see that there were 3 transactions and 29 operations in total -- we'll dig into those shortly. You can also see that there are abou 103 billion coins (lumens) in circulation. 145 | 146 | There's also a `_links` section that lists a set of URLs relevant to this specific ledger. For example, let's look at the first transaction in that ledger by querying the URL in the `href` field of `transactions` under `_links`. From here on we'll refer to JSON paths using dot notation, so the last path would be `_links.transactions.href`. 147 | 148 | ```sh 149 | $ curl https://horizon.stellar.org/ledgers/16889095/transactions | jq '._embedded.records[0]' 150 | ``` 151 | 152 | We used `jq '._embedded.records[0]` to filter out just the first transaction. *Exercise:* remove the filter and see what you find. 153 | 154 | ```json 155 | { 156 | "_links": { 157 | "self": { 158 | "href": "https://horizon.stellar.org/transactions/20dbabf0fbdcadbd4e96848fd4a251791af1b4cef9c35ba614b180a6d6d79b54" 159 | }, 160 | "account": { 161 | "href": "https://horizon.stellar.org/accounts/GDMIF55WK2LUUQ77TRE4RDDC5325I2GY555HRQWI5IE7MGG7662OSBWS" 162 | }, 163 | "ledger": { 164 | "href": "https://horizon.stellar.org/ledgers/16889095" 165 | }, 166 | "operations": { 167 | "href": "https://horizon.stellar.org/transactions/20dbabf0fbdcadbd4e96848fd4a251791af1b4cef9c35ba614b180a6d6d79b54/operations{?cursor,limit,order}", 168 | "templated": true 169 | }, 170 | "effects": { 171 | "href": "https://horizon.stellar.org/transactions/20dbabf0fbdcadbd4e96848fd4a251791af1b4cef9c35ba614b180a6d6d79b54/effects{?cursor,limit,order}", 172 | "templated": true 173 | }, 174 | "precedes": { 175 | "href": "https://horizon.stellar.org/transactions?order=asc&cursor=72538110684041216" 176 | }, 177 | "succeeds": { 178 | "href": "https://horizon.stellar.org/transactions?order=desc&cursor=72538110684041216" 179 | } 180 | }, 181 | "id": "20dbabf0fbdcadbd4e96848fd4a251791af1b4cef9c35ba614b180a6d6d79b54", 182 | "paging_token": "72538110684041216", 183 | "hash": "20dbabf0fbdcadbd4e96848fd4a251791af1b4cef9c35ba614b180a6d6d79b54", 184 | "ledger": 16889095, 185 | "created_at": "2018-03-18T22:45:33Z", 186 | "source_account": "GDMIF55WK2LUUQ77TRE4RDDC5325I2GY555HRQWI5IE7MGG7662OSBWS", 187 | "source_account_sequence": "72537633942667267", 188 | "fee_paid": 100, 189 | "operation_count": 1, 190 | "envelope_xdr": "AAAAANiC97ZWl0pD/5xJyIxi7vXUaNjvenjCyOoJ9hjf97TpAAAAZAEBtJgAAAADAAAAAAAAAAAAAAABAAAAAAAAAAMAAAAAAAAAAVJNVAAAAAAAq2nN4Bi7gPQYGpIp0xISfxU8xOHn/rUZdRnF/rGcukUAAAACMXnLAAABhqAAABeRAAAAAAAAAAAAAAAAAAAAAd/3tOkAAABAkQwyGKYer821RJ4Wr1vtkU4qa6EGcY8lgr8y7HkiPuUv6uiptgrUZzCxodMN44smFPW6f850XRSAqv1N+rGlCg==", 191 | "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAADAAAAAAAAAAAAAAAAAAAAANiC97ZWl0pD/5xJyIxi7vXUaNjvenjCyOoJ9hjf97TpAAAAAAAyLRIAAAAAAAAAAVJNVAAAAAAAq2nN4Bi7gPQYGpIp0xISfxU8xOHn/rUZdRnF/rGcukUAAAACMXnLAAABhqAAABeRAAAAAAAAAAAAAAAA", 192 | "result_meta_xdr": "AAAAAAAAAAEAAAADAAAAAAEBtQcAAAACAAAAANiC97ZWl0pD/5xJyIxi7vXUaNjvenjCyOoJ9hjf97TpAAAAAAAyLRIAAAAAAAAAAVJNVAAAAAAAq2nN4Bi7gPQYGpIp0xISfxU8xOHn/rUZdRnF/rGcukUAAAACMXnLAAABhqAAABeRAAAAAAAAAAAAAAAAAAAAAwEBtQcAAAAAAAAAANiC97ZWl0pD/5xJyIxi7vXUaNjvenjCyOoJ9hjf97TpAAAAAjNAgBQBAbSYAAAAAwAAAAEAAAABAAAAAMRxxkNwYslQaok0LlOKGtpATS9Bzx06JV9DIffG4OF1AAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQEBtQcAAAAAAAAAANiC97ZWl0pD/5xJyIxi7vXUaNjvenjCyOoJ9hjf97TpAAAAAjNAgBQBAbSYAAAAAwAAAAIAAAABAAAAAMRxxkNwYslQaok0LlOKGtpATS9Bzx06JV9DIffG4OF1AAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA", 193 | "fee_meta_xdr": "AAAAAgAAAAMBAbT1AAAAAAAAAADYgve2VpdKQ/+cSciMYu711GjY73p4wsjqCfYY3/e06QAAAAIzQIB4AQG0mAAAAAIAAAABAAAAAQAAAADEccZDcGLJUGqJNC5TihraQE0vQc8dOiVfQyH3xuDhdQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAEBAbUHAAAAAAAAAADYgve2VpdKQ/+cSciMYu711GjY73p4wsjqCfYY3/e06QAAAAIzQIAUAQG0mAAAAAMAAAABAAAAAQAAAADEccZDcGLJUGqJNC5TihraQE0vQc8dOiVfQyH3xuDhdQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA==", 194 | "memo_type": "none", 195 | "signatures": [ 196 | "kQwyGKYer821RJ4Wr1vtkU4qa6EGcY8lgr8y7HkiPuUv6uiptgrUZzCxodMN44smFPW6f850XRSAqv1N+rGlCg==" 197 | ] 198 | } 199 | ``` 200 | 201 | The `operation_count` field tells us that the transaction consists of just one operation, which also explains the fee of 100 stroops (charged to the address in `source_account`.) Let's grab the operations link from `_links.operations.href` and extract the first operation. 202 | 203 | ```sh 204 | curl https://horizon.stellar.org/transactions/20dbabf0fbdcadbd4e96848fd4a251791af1b4cef9c35ba614b180a6d6d79b54/operations | jq '._embedded.records[0]' 205 | { 206 | "_links": { 207 | "self": { 208 | "href": "https://horizon.stellar.org/operations/72538110684041217" 209 | }, 210 | "transaction": { 211 | "href": "https://horizon.stellar.org/transactions/20dbabf0fbdcadbd4e96848fd4a251791af1b4cef9c35ba614b180a6d6d79b54" 212 | }, 213 | "effects": { 214 | "href": "https://horizon.stellar.org/operations/72538110684041217/effects" 215 | }, 216 | "succeeds": { 217 | "href": "https://horizon.stellar.org/effects?order=desc&cursor=72538110684041217" 218 | }, 219 | "precedes": { 220 | "href": "https://horizon.stellar.org/effects?order=asc&cursor=72538110684041217" 221 | } 222 | }, 223 | "id": "72538110684041217", 224 | "paging_token": "72538110684041217", 225 | "source_account": "GDMIF55WK2LUUQ77TRE4RDDC5325I2GY555HRQWI5IE7MGG7662OSBWS", 226 | "type": "manage_offer", 227 | "type_i": 3, 228 | "created_at": "2018-03-18T22:45:33Z", 229 | "transaction_hash": "20dbabf0fbdcadbd4e96848fd4a251791af1b4cef9c35ba614b180a6d6d79b54", 230 | "amount": "942.0000000", 231 | "price": "16.5755014", 232 | "price_r": { 233 | "n": 100000, 234 | "d": 6033 235 | }, 236 | "buying_asset_type": "credit_alphanum4", 237 | "buying_asset_code": "RMT", 238 | "buying_asset_issuer": "GCVWTTPADC5YB5AYDKJCTUYSCJ7RKPGE4HT75NIZOUM4L7VRTS5EKLFN", 239 | "selling_asset_type": "native", 240 | "offer_id": 0 241 | } 242 | ``` 243 | 244 | Looks like it's an offer to sell 942 lumens for `RMT` on Stellar's distributed exchange. How can you tell? Well, the `type` of operation is `manage_offer`, which means that this is related to a trade on the DEX, the `selling_asset_type` is `native`, which is lumens (XLM), the `amount` is `942`, and `buying_asset_code` is `RMT`. 245 | 246 | *Exercise:* Use `lumen dex list [account]` to see all the offers made by an account. 247 | 248 | Now, let's dig into at the account in `source_account`. 249 | 250 | ```sh 251 | $ lumen info GDMIF55WK2LUUQ77TRE4RDDC5325I2GY555HRQWI5IE7MGG7662OSBWS --network public 252 | { 253 | "address": "GDMIF55WK2LUUQ77TRE4RDDC5325I2GY555HRQWI5IE7MGG7662OSBWS", 254 | "balances": [ 255 | { 256 | "asset": { 257 | "code": "RMT", 258 | "issuer": "GCVWTTPADC5YB5AYDKJCTUYSCJ7RKPGE4HT75NIZOUM4L7VRTS5EKLFN", 259 | "type": "\"credit_alphanum4\"" 260 | }, 261 | "amount": "13750.3198383", 262 | "limit": "922337203685.4775807" 263 | } 264 | ], 265 | "signers": [ 266 | { 267 | "public_key": "GDMIF55WK2LUUQ77TRE4RDDC5325I2GY555HRQWI5IE7MGG7662OSBWS", 268 | "weight": 1, 269 | "key": "GDMIF55WK2LUUQ77TRE4RDDC5325I2GY555HRQWI5IE7MGG7662OSBWS", 270 | "type": "ed25519_public_key" 271 | } 272 | ], 273 | "flags": { 274 | "auth_required": false, 275 | "auth_revocable": false, 276 | "auth_immutable": false 277 | }, 278 | "native_balance": { 279 | "asset": { 280 | "code": "XLM", 281 | "issuer": "", 282 | "type": "\"native\"" 283 | }, 284 | "amount": "2.8002402", 285 | "limit": "" 286 | }, 287 | "home_domain": "", 288 | "thresholds": { 289 | "high": 0, 290 | "medium": 0, 291 | "low": 0 292 | }, 293 | "data": {}, 294 | "seq": "72537633942667287" 295 | } 296 | ``` 297 | 298 | You can tell that the account holder has about 2.8 lumens and over 13000 `RMT`. The account has a single signer, which is simply the master key (see [Chapter 4](https://github.com/0xfe/hacking-stellar/blob/master/4-multisig.md) for more about signing keys.) 299 | 300 | ## Watching an account 301 | 302 | Knowing how to dig into individual ledgers is useful when you know which ledger some transacation occurred in, however a lot of the time, you just want to debug the transactions on a single account. You can use the `lumen watch transactions` and `lumen watch payments` commands with the address of the account to follow a stream of transactions or payments. 303 | 304 | Let's move back to the test network and try it out. Open up a new command-line terminal and type: 305 | 306 | ```sh 307 | $ lumen set config:network test 308 | $ lumen account new mary 309 | $ lumen watch payments mary --cursor start --format json 310 | # ... this blocks ... 311 | ``` 312 | 313 | Then, on a different terminal, type: 314 | 315 | ```sh 316 | $ lumen watch transactions mary --format json 317 | ``` 318 | 319 | Now move back to your working terminal and fund Mary's account. 320 | 321 | ```sh 322 | $ lumen friendbot mary 323 | ``` 324 | 325 | Switch back to the payment terminal -- if friendbot succeeded in funding Mary's account, you should see this: 326 | 327 | ```json 328 | { 329 | "id": "34287651636912129", 330 | "type": "create_account", 331 | "paging_token": "34287651636912129", 332 | "_links": { 333 | "transaction": { 334 | "href": "https://horizon-testnet.stellar.org/transactions/d97481dddb1fc7d4164beaf868d7a222f3dbf6ffe7fd6dd5d599681a9a262195" 335 | } 336 | }, 337 | "account": "GCLPPDSQNXTS2OAXPELZHDWT6TB36SPOZVY7QZZDCXXVUM4CZWOXR4GA", 338 | "starting_balance": "10000.0000000", 339 | "from": "", 340 | "to": "", 341 | "asset_type": "", 342 | "asset_code": "", 343 | "asset_issuer": "", 344 | "amount": "", 345 | "Memo": { 346 | "memo_type": "none", 347 | "memo": "" 348 | } 349 | } 350 | ``` 351 | 352 | There was a new `create_account` operation funding Mary's account with `10000` lumens. Let's pay her again. 353 | 354 | ```sh 355 | $ lumen pay 10 --from bob --to mary --memotext "hi mary" 356 | ``` 357 | 358 | You should now see a `payment` operation show up on the watching terminal: 359 | 360 | ```json 361 | { 362 | "id": "34287978054422529", 363 | "type": "payment", 364 | "paging_token": "34287978054422529", 365 | "_links": { 366 | "transaction": { 367 | "href": "https://horizon-testnet.stellar.org/transactions/d546ef6942625e628e5c80f7a60ad887674bcfb9a4109c845a922afa947b8504" 368 | } 369 | }, 370 | "account": "", 371 | "starting_balance": "", 372 | "from": "GBGMPKS4JY6SKHSZQ5KHM4GRSJNRXINH57HMJ4T3UXDE2WIU6PYFPRPC", 373 | "to": "GCLPPDSQNXTS2OAXPELZHDWT6TB36SPOZVY7QZZDCXXVUM4CZWOXR4GA", 374 | "asset_type": "native", 375 | "asset_code": "", 376 | "asset_issuer": "", 377 | "amount": "10.0000000", 378 | "Memo": { 379 | "memo_type": "text", 380 | "memo": "hi mary" 381 | } 382 | } 383 | ``` 384 | 385 | Notice the memo text? It's actually not part of the operation, but pulled in here for convenience. The memo fields are part of the encompassing transaction, so although you can lump many operations into a transaction, they can have only a single memo. 386 | 387 | If you switch to the transactions terminal, you should see multiple operations with just the details of the transaction envelope. 388 | 389 | #### Lumen Detour: Verbose Logging 390 | 391 | Lumen can output detailed logs for an operation with the `-v` flag. This is handy when your Stellar operations aren't behaving as expected. 392 | 393 | ```sh 394 | $ lumen pay 10 USD --from mo --to mary -v 395 | # DEBU[0000] LUMEN_ENV not set type=setup 396 | # DEBU[0000] using storage driver file with /Users/mo/.lumen-data.json type=setup 397 | # DEBU[0000] using default store type=setup 398 | # DEBU[0000] reading file: /Users/mo/.lumen-data.json method=new type=filestore 399 | # DEBU[0000] getting global:ns method=GetGlobalVar type=cli 400 | # DEBU[0000] got val: default (expires: false, expires_on: 2018-03-21 08:00:43.557659 -0400 EDT) key="global:ns" method=get type=filestore 401 | # DEBU[0000] using namespace from store type=setup 402 | # DEBU[0000] namespace: default type=setup 403 | # DEBU[0000] getting default:vars:config:network method=GetVar type=cli 404 | # DEBU[0000] not found, expired: false key="default:vars:config:network" method=get type=filestore 405 | # DEBU[0000] getting default:asset:USD:code method=GetVar type=cli 406 | # DEBU[0000] got val: USD (expires: false, expires_on: 2018-03-21 08:02:49.189346 -0400 EDT) key="default:asset:USD:code" method=get type=filestore 407 | # DEBU[0000] getting default:asset:USD:issuer method=GetVar type=cli 408 | # DEBU[0000] got val: GAGUZYRM2G7235EM3C3WY33UHTWORNR7MX2J3OT4F3D46HAFSUEA63LL (expires: false, expires_on: 2018-03-21 08:02:49.188011 -0400 EDT) key="default:asset:USD:issuer" method=get type=filestore 409 | # DEBU[0000] getting default:asset:USD:type method=GetVar type=cli 410 | # DEBU[0000] got val: credit_alphanum4 (expires: false, expires_on: 2018-03-21 08:02:49.189837 -0400 EDT) key="default:asset:USD:type" method=get type=filestore 411 | # DEBU[0000] got asset: &{Code:USD Issuer:GAGUZYRM2G7235EM3C3WY33UHTWORNR7MX2J3OT4F3D46HAFSUEA63LL Type:credit_alphanum4} 412 | # DEBU[0000] getting default:account:mo:seed method=GetVar type=cli 413 | # DEBU[0000] got val: SAZW22BHCNGEIQNSTWR5OYG3HC44CTPXV4342OEQJDJZWCPHYUQLZCC7 (expires: false, expires_on: 2018-03-06 09:14:24.691781 -0500 EST) key="default:account:mo:seed" method=get type=filestore 414 | # DEBU[0000] getting default:account:mary:address method=GetVar type=cli 415 | # DEBU[0000] got val: GD6JJSOKWI7U2YDCMZ3YGPKNOP6W3D7K34HWLC6WHD32CKJJVALV7OBK (expires: false, expires_on: 2018-03-21 08:01:13.923333 -0400 EDT) key="default:account:mary:address" method=get type=filestore 416 | # DEBU[0000] fund: false, err cmd=pay 417 | # DEBU[0000] paying 10 USD/GAGUZYRM2G7235EM3C3WY33UHTWORNR7MX2J3OT4F3D46HAFSUEA63LL from SAZW22BHCNGEIQNSTWR5OYG3HC44CTPXV4342OEQJDJZWCPHYUQLZCC7 to GD6JJSOKWI7U2YDCMZ3YGPKNOP6W3D7K34HWLC6WHD32CKJJVALV7OBK, opts: &{ctx: handlers:map[] hasFee:false fee:0 hasTimeBounds:false timeBounds:0 memoType:0 memoText: memoID:0 skipSignatures:false signerSeeds:[] hasCursor:false cursor: hasLimit:false limit:0 sortDescending:false passiveOffer:false sourceAddress: sendAsset: maxAmount: path:[] isMultiOp:false multiOpSource:} cmd=pay 418 | # DEBU[0000] signing transaction, seq: 33366067619299340 lib=microstellar method=Tx.Sign 419 | # DEBU[0000] signed transaction, payload: AAAAAPGR63kaYI062wyHd+LARbBzZOCK9pDleNq8UkGhV4sZAAAAZAB2ikMAAAAMAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAA/JTJyrI/TWBiZneDPU1z/W2P6t8PZYvWOPehKSmoF18AAAABVVNEAAAAAAANTOIs0b+t9IzYt2xvdDzs6LY/ZfSdunwux88cBZUIDwAAAAAF9eEAAAAAAAAAAAGhV4sZAAAAQIJduVNXFgBu3/OD6uLLJJlkZD4i8JoHHorCxKi0L0LnbnVvsl2pVuazburcSH43N6AYPHI9kD/M6B03kZaz4gg= lib=microstellar method=Tx.Sign 420 | # DEBU[0000] submitting transaction to network test lib=microstellar method=Tx.Submit 421 | # DEBU[0001] transaction submitted to ledger 8026171 with hash abbac2c2906342dff927c7a88075487418c787bc4550fea6353dfc2c2faa75b2 lib=microstellar method=Tx.Submit 422 | ``` 423 | 424 | ## Debugging scenario: Token distribution 425 | 426 | Let's go through a fixed-supply token distribution scenario. This is where an issuer issues some predetermined number of tokens to a distributor, and then permanently disables their issuer account so no more can be issued. 427 | 428 | ```sh 429 | # Create a new namespace called `hs` for this scenario. 430 | $ lumen ns hs 431 | 432 | # Create accounts for issuer and distributor. 433 | $ lumen account new issuer 434 | $ lumen account new distributor 435 | 436 | # Issue 1000 HAK tokens from issuer to distributor. 437 | $ lumen pay 1000 HAK:issuer_account distributor 438 | # ERRO[0000] bad --from address: issuer_account cmd=pay 439 | ``` 440 | 441 | Okay, we intentionally put the typo in there, but let's pretend that was a mistake and rerun the command with verbose logging. 442 | 443 | ```sh 444 | $ lumen pay 1000 HAK:issuer --from issuer_account --to distributor -v 445 | # ... snipped ... 446 | DEBU[0000] getting hs:account:issuer:address method=GetVar type=cli 447 | DEBU[0000] got val: GA2L4VM7S6HRZSVRYWCKUKCJQRP3C42YQUIHO5MDTD7P54RFJKMEQJ7Q (expires: false, expires_on: 2018-03-20 16:23:56.130665 -0400 EDT) key="hs:account:issuer:address" method=get type=filestore 448 | DEBU[0000] got asset: &{Code:HAK Issuer:GA2L4VM7S6HRZSVRYWCKUKCJQRP3C42YQUIHO5MDTD7P54RFJKMEQJ7Q Type:credit_alphanum4} 449 | DEBU[0000] getting hs:account:issuer_account:seed method=GetVar type=cli 450 | DEBU[0000] not found, expired: false key="hs:account:issuer_account:seed" method=get type=filestore 451 | DEBU[0000] getting hs:account:issuer_account:address method=GetVar type=cli 452 | DEBU[0000] not found, expired: false key="hs:account:issuer_account:address" method=get type=filestore 453 | DEBU[0000] invalid address, seed, or account name: issuer_account cmd=pay 454 | ERRO[0000] bad --from address: issuer_account cmd=pay 455 | ``` 456 | 457 | Right away, we'd notice that Lumen could look up the address for `hs:account:issuer` but not `hs:account:issuer_account`. (The `hs` prefix designates the current namespace.) Alright, let's try that again with the right account alias. 458 | 459 | ```sh 460 | $ lumen pay 1000 HAK:issuer --from issuer --to distributor 461 | # ERRO[0001] payment failed: 404: Resource Missing cmd=pay 462 | ``` 463 | 464 | Another error. Looking at the [horizon reference](https://www.stellar.org/developers/horizon/reference/errors/not-found.html) for `404`, we can tell that some resource in our request is unknown to Stellar. The only resources in the command are `issuer` and `distributor`. Which one is it? We'll use the `lumen info` command to investigate. 465 | 466 | ```sh 467 | $ lumen info issuer 468 | ERRO[0000] cant load account: 404: Resource Missing cmd=balance 469 | 470 | $ lumen info distributor 471 | ERRO[0000] cant load account: 404: Resource Missing cmd=balance 472 | ``` 473 | 474 | Both of them are missing! Ofcourse, we never funded the accounts, so Stellar doesn't know about them. 475 | 476 | ```sh 477 | # Ask Friendbot to create issuer's account 478 | $ lumen friendbot issuer 479 | 480 | # Verify that the resource exists 481 | $ lumen info issuer 482 | { 483 | "address": "GA2L4VM7S6HRZSVRYWCKUKCJQRP3C42YQUIHO5MDTD7P54RFJKMEQJ7Q", 484 | "balances": [], 485 | "signers": [ 486 | { 487 | "public_key": "GA2L4VM7S6HRZSVRYWCKUKCJQRP3C42YQUIHO5MDTD7P54RFJKMEQJ7Q", 488 | "weight": 1, 489 | "key": "GA2L4VM7S6HRZSVRYWCKUKCJQRP3C42YQUIHO5MDTD7P54RFJKMEQJ7Q", 490 | "type": "ed25519_public_key" 491 | } 492 | ], 493 | "flags": { 494 | "auth_required": false, 495 | "auth_revocable": false, 496 | "auth_immutable": false 497 | }, 498 | "native_balance": { 499 | "asset": { 500 | "code": "XLM", 501 | "issuer": "", 502 | "type": "\"native\"" 503 | }, 504 | "amount": "10000.0000000", 505 | "limit": "" 506 | }, 507 | "home_domain": "", 508 | "thresholds": { 509 | "high": 0, 510 | "medium": 0, 511 | "low": 0 512 | }, 513 | "data": {}, 514 | "seq": "34473589361082369" 515 | } 516 | 517 | # Use issuer to create distributor's account and verify its existence 518 | $ lumen pay 1000 --from issuer --to distributor --fund 519 | $ lumen info distributor 520 | ``` 521 | 522 | Now that the two accounts exist, lets issue our new `HAK` asset. And to save us the effort of typing in `HAK:issuer` all the time, let's create an alias for it. 523 | 524 | ```sh 525 | # Create asset alias HAK issued by issuer 526 | $ lumen asset set HAK issuer 527 | 528 | # Issue 1000 HAKs 529 | $ lumen pay 1000 HAK --from issuer to --distributor 530 | # ERRO[0005] payment failed: 400: Transaction Failed (&{tx_failed [op_no_trust]}) cmd=pay 531 | ``` 532 | 533 | Tranasaction failed. It's a bit clearer this time because of the result code `op_no_trust` -- the distributor does not have a trustline to the asset. (See [Chapter 3](https://github.com/0xfe/hacking-stellar/blob/master/3-assets.md) for more on custom assets and trustlines.) 534 | 535 | ```sh 536 | $ lumen trust create distributor HAK 537 | $ lumen pay 1001 HAK --from issuer --to distributor 538 | 539 | # That seemed to have worked, lets verify it. 540 | $ lumen balance distributor HAK 541 | # 1001.0000000 542 | ``` 543 | 544 | Darnit, we created one too many assets. No problem. It turns out that sending an asset back to the issuer destroys it. You can verify this by checking the issuer's `HAK` balance. 545 | 546 | ```sh 547 | # Issuers never carry balances for assets they issue. 548 | $ lumen balance issuer HAK 549 | 0 550 | 551 | # Send back one HAK. 552 | $ lumen pay 1 HAK --from distributor --to issuer 553 | 554 | # Verify balances. 555 | $ lumen balance distributor HAK 556 | 1000.0000000 557 | $ lumen balance issuer HAK 558 | 0.0000000 559 | ``` 560 | 561 | Great! It worked. The final step is to permanently disable the issuer's account so that no more new HAK assets can be created. 562 | 563 | ```sh 564 | # Set the weight of the issuer's master key to 0 565 | $ lumen signer masterweight issuer 0 566 | 567 | # Make sure there are no other working keys for issuer 568 | $ lumen signer list issuer 569 | # address:GA2L4VM7S6HRZSVRYWCKUKCJQRP3C42YQUIHO5MDTD7P54RFJKMEQJ7Q weight:0 570 | 571 | # Try to issue new assets (this should return an error.) 572 | $ lumen pay 1000 HAK --from issuer --to distributor 573 | # ERRO[0001] payment failed: 400: Transaction Failed (&{tx_bad_auth []}) cmd=pay 574 | ``` 575 | 576 | We now have a fixed supply of 1000 `HAK` tokens to redistribute. To close this off, lets sell a hundred of them on the DEX for 10 XLM each. 577 | 578 | ```sh 579 | $ lumen dex trade distributor --sell HAK --amount 200 --buy native --price 10 580 | $ lumen dex list distributor 581 | (149231) selling 200.0000000 HAK for lumens at 10.0000000 lumens/HAK 582 | ``` 583 | 584 | # Onward 585 | 586 | We learned a bunch of useful Stellar debugging techiques in this chapter, so to summarize: 587 | 588 | * [Horizon](https://www.stellar.org/developers/horizon/reference/index.html) is an API gateway to Stellar, and how most applications interact with the core network. 589 | * Leave the `lumen watch ...` commands running on separate terminals as you develop your application. 590 | * Use `curl` to query any relevant `_links` for misbehaving transactions. 591 | * Use Lumen's `-v` flag to debug alias errors or horizon responses. 592 | * One of the most common newbie mistakes is forgetting to create a funded account. A `404` return code is a strong clue that an account does not exist on Stellar's ledger. 593 | 594 | This concludes the current edition of Hacking Stellar (so far.) More chapters to come, vote for your favourite on the front page. 595 | 596 | [Front](https://github.com/0xfe/hacking-stellar/blob/master/README.md) - 597 | [Chapter 1](https://github.com/0xfe/hacking-stellar/blob/master/1-launch.md) - 598 | [Chapter 2](https://github.com/0xfe/hacking-stellar/blob/master/2-payments.md) - 599 | [Chapter 3](https://github.com/0xfe/hacking-stellar/blob/master/3-assets.md) - 600 | [Chapter 4](https://github.com/0xfe/hacking-stellar/blob/master/4-multisig.md) - 601 | [Chapter 5](https://github.com/0xfe/hacking-stellar/blob/master/5-dex.md) - 602 | [Chapter 6](https://github.com/0xfe/hacking-stellar/blob/master/6-debugging.md) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Attribution 4.0 International Public License 2 | 3 | By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. 4 | 5 | Section 1 – Definitions. 6 | 7 | Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. 8 | Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. 9 | Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. 10 | Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. 11 | Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. 12 | Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. 13 | Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. 14 | Licensor means the individual(s) or entity(ies) granting rights under this Public License. 15 | Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. 16 | Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. 17 | You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. 18 | Section 2 – Scope. 19 | 20 | License grant. 21 | Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: 22 | reproduce and Share the Licensed Material, in whole or in part; and 23 | produce, reproduce, and Share Adapted Material. 24 | Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 25 | Term. The term of this Public License is specified in Section 6(a). 26 | Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. 27 | Downstream recipients. 28 | Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. 29 | No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 30 | No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). 31 | Other rights. 32 | 33 | Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 34 | Patent and trademark rights are not licensed under this Public License. 35 | To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. 36 | Section 3 – License Conditions. 37 | 38 | Your exercise of the Licensed Rights is expressly made subject to the following conditions. 39 | 40 | Attribution. 41 | 42 | If You Share the Licensed Material (including in modified form), You must: 43 | 44 | retain the following if it is supplied by the Licensor with the Licensed Material: 45 | identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); 46 | a copyright notice; 47 | a notice that refers to this Public License; 48 | a notice that refers to the disclaimer of warranties; 49 | a URI or hyperlink to the Licensed Material to the extent reasonably practicable; 50 | indicate if You modified the Licensed Material and retain an indication of any previous modifications; and 51 | indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. 52 | You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 53 | If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. 54 | If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License. 55 | Section 4 – Sui Generis Database Rights. 56 | 57 | Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: 58 | 59 | for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; 60 | if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and 61 | You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. 62 | For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. 63 | Section 5 – Disclaimer of Warranties and Limitation of Liability. 64 | 65 | Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. 66 | To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. 67 | The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. 68 | Section 6 – Term and Termination. 69 | 70 | This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. 71 | Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 72 | 73 | automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 74 | upon express reinstatement by the Licensor. 75 | For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. 76 | For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. 77 | Sections 1, 5, 6, 7, and 8 survive termination of this Public License. 78 | Section 7 – Other Terms and Conditions. 79 | 80 | The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. 81 | Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. 82 | Section 8 – Interpretation. 83 | 84 | For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. 85 | To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. 86 | No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. 87 | Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |
4 |

5 | 6 | **Hacking Stellar** is an open-source e-book on [Stellar](http://stellar.org), the decentralized payment network, which allows financial institutions, businesses, and individuals around the world to transact quickly and reliably. 7 | 8 | This online book introduces you to Stellar with lots of practical examples using the command-line client, [Lumen](http://github.com/0xfe/lumen), and moves on to building complete applications using the Javascript and Go libraries. 9 | 10 | ## Table of Contents 11 | 12 | * [Chapter 1. The Basics](https://github.com/0xfe/hacking-stellar/blob/master/1-launch.md) (draft) 13 | * [Chapter 2. Making Payments](https://github.com/0xfe/hacking-stellar/blob/master/2-payments.md) (draft) 14 | * [Chapter 3. Issuing Assets](https://github.com/0xfe/hacking-stellar/blob/master/3-assets.md) (draft) 15 | * [Chapter 4. Managing Signers](https://github.com/0xfe/hacking-stellar/blob/master/4-multisig.md) (draft) 16 | * [Chapter 5. Trading on the DEX](https://github.com/0xfe/hacking-stellar/blob/master/5-dex.md) (draft) 17 | * [Chapter 6. Debugging Stellar](https://github.com/0xfe/hacking-stellar/blob/master/6-debugging.md) (draft) 18 | 19 | ### Possible future chapters (vote for your favourite) 20 | 21 | * Chapter X. Building an Anchor 22 | * Chapter X. Key management and security 23 | * Chapter X. Hacking Stellar with Go 24 | * Chapter X. Hacking Stellar with JavaScript 25 | * Chapter X. How Stellar Works 26 | * Chapter X. Appendix: Blockchains 27 | 28 | ## Contributing 29 | 30 | We welcome all kinds of contributors -- reviewers, editors, and hackers to try out the examples and spot bugs. 31 | 32 | If you'd like to support this project with lumens, send them to: `GDEVC4BOVFMB46UHGJ6NKEBCQVY5WI56GOBWPG3QKS4QV4TKDLPE6AH6`. 33 | 34 | ## License 35 | 36 | Creative Commons License
Hacking Stellar by Mohit Cheppudira is licensed under a Creative Commons Attribution 4.0 International License. 37 | 38 | 39 | --------------------------------------------------------------------------------