Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit 6c09992

Browse files
joncinquebartosz-lipinskiCriesofCarrots
authored
docs: Flesh out token swap README (#1133)
* Flesh out token swap README * Add testing info * Update opening paragraphs and add link to dapp * Wrap * Update title * Update docs/src/token-swap.md Co-authored-by: Tyera Eulberg <[email protected]> Co-authored-by: B <[email protected]> Co-authored-by: Tyera Eulberg <[email protected]>
1 parent f402e39 commit 6c09992

File tree

1 file changed

+287
-3
lines changed

1 file changed

+287
-3
lines changed

docs/src/token-swap.md

Lines changed: 287 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,291 @@
11
---
2-
title: Token-Swap Program
2+
title: Token Swap Program
33
---
44

5-
A Uniswap-like exchange for the Token program on the Solana blockchain.
5+
A Uniswap-like exchange for the Token program on the Solana blockchain,
6+
implementing multiple automated market maker (AMM) curves.
67

7-
The project is under construction.
8+
## Overview
9+
10+
The Token Swap Program allows simple trading of token pairs without a
11+
centralized limit order book. The program uses a mathematical formula called
12+
"curve" to calculate the price of all trades. Curves aim to mimic normal market
13+
dynamics: for example, as traders buy a lot of one token type, the value of the
14+
other token type goes up.
15+
16+
Depositors in the token swap pool provide liquidity for the token pair. That
17+
liquidity enables trade execution at spot price. In exchange for their
18+
liquidity, depositors receive pool tokens, representing their fractional
19+
ownership in the pool. During each trade, a program withholds a portion of the
20+
input token as a fee. That fee increases the value of pool tokens by being
21+
stored in the pool.
22+
23+
This program was heavily inspired by [Uniswap](https://uniswap.org/) and
24+
[Balancer](https://balancer.finance/). More information is available in their
25+
excellent documentation and whitepapers.
26+
27+
## Background
28+
29+
Solana's programming model and the definitions of the Solana terms used in this
30+
document are available at:
31+
32+
- https://docs.solana.com/apps
33+
- https://docs.solana.com/terminology
34+
35+
## Source
36+
37+
The Token Swap Program's source is available on
38+
[github](https://github.com/solana-labs/solana-program-library).
39+
40+
## Interface
41+
42+
[JavaScript
43+
bindings](https://github.com/solana-labs/solana-program-library/blob/master/token-swap/js/client/token-swap.js)
44+
are available that support loading the Token Swap Program on to a chain and
45+
issuing instructions.
46+
47+
Example user interface built and maintained by Serum team is available
48+
[here](https://github.com/project-serum/oyster-swap)
49+
50+
## Operational overview
51+
52+
The following explains the instructions available in the Token Swap Program.
53+
Note that each instruction has a simple code example that can be found in the
54+
[end-to-end tests](https://github.com/solana-labs/solana-program-library/blob/master/token-swap/js/cli/token-swap-test.js).
55+
56+
### Creating a new token swap
57+
58+
The creation of a token swap showcases the account, instruction, and authorization
59+
models on Solana, which can be very different compared to other blockchains.
60+
61+
Initialization of a token swap between two token types, which we'll call "A"
62+
and "B" for simplicity, requires the following accounts:
63+
64+
* empty token swap state account
65+
* token swap authority
66+
* token A account
67+
* token B account
68+
* pool token mint
69+
* pool token fee account
70+
* pool token recipient account
71+
* token program
72+
73+
The token swap state account simply needs to be created using
74+
`system_instruction::create_account` with the correct size and enough lamports
75+
to be rent-free.
76+
77+
The token swap authority is a
78+
[program derived address](https://docs.solana.com/developing/programming-model/calling-between-programs#program-derived-addresses)
79+
that can "sign" instructions towards other programs. This is
80+
required for the Token Swap Program to mint pool tokens and transfer tokens from
81+
its token A and B accounts.
82+
83+
The token A / B accounts, pool token mint, and pool token accounts must all be
84+
created (using `system_instruction::create_account`) and initialized (using
85+
`spl_token::instruction::initialize_mint` or
86+
`spl_token::instruction::initialize_account`). The token A and B accounts must
87+
be funded with tokens, and their owner set to the swap authority, and the mint
88+
must also be owned by the swap authority.
89+
90+
Once all of these accounts are created, the Token Swap `initialize` instruction
91+
will properly set everything up and allow for immediate trading. Note
92+
that the token swap state account is not required to be a signer on `initialize`,
93+
so it's important to perform the `initialize` instruction in the same transaction
94+
as its `system_instruction::create_account`.
95+
96+
### Swapping
97+
98+
Once a token swap is created, users can immediately begin trading on it using
99+
the `swap` instruction. The swap instruction transfers tokens from a user's source
100+
account into the swap's source token account, and then transfers tokens from
101+
its destination token account into the user's destination token account.
102+
103+
Since Solana programs require all accounts to be declared in the instruction,
104+
users need to gather all account information from the token swap state account:
105+
the token A and B accounts, pool token mint, and fee account.
106+
107+
Additionally, the user must allow for tokens to be transferred from their source
108+
token account. The best practice is to `spl_token::instruction::approve` a
109+
precise amount to a new throwaway Keypair, and then have that new Keypair sign
110+
the swap transaction. This limits the amount of tokens that can be taken
111+
from the user's account by the program.
112+
113+
### Depositing liquidity
114+
115+
To allow any trading, the token swap needs liquidity provided from the
116+
outside. Using the `deposit_all_token_types` or
117+
`deposit_single_token_type_exact_amount_in` instructions, anyone can provide
118+
liquidity for others to trade, and in exchange, depositors receive a pool token
119+
representing fractional ownership of all A and B tokens in the token swap.
120+
121+
Additionally, the user will need to approve a delegate to transfer tokens from
122+
their A and B token accounts. This limits the amount of tokens that can be taken
123+
from the user's account by the program.
124+
125+
### Withdrawing liquidity
126+
127+
At any time, pool token holders may redeem their pool tokens in exchange for
128+
tokens A and B, returned at the current "fair" rate as determined by the curve.
129+
In the `withdraw_all_token_types` and
130+
`withdraw_single_token_type_exact_amount_out` instructions, pool tokens are
131+
burned, and tokens A and B are transferred into the user's accounts.
132+
133+
Additionally, the user will need to approve a delegate to transfer tokens from
134+
their pool token account. This limits the amount of tokens that can be taken
135+
from the user's account by the program.
136+
137+
## Curves
138+
139+
The Token Swap Program is completely customizable for any possible trading curve
140+
that implements the
141+
[CurveCalculator](https://github.com/solana-labs/solana-program-library/blob/master/token-swap/program/src/curve/calculator.rs)
142+
trait. If you would like to implement a new automated market maker, it may be
143+
as easy as forking the Token Swap Program and implementing a new curve. The
144+
following curves are all provided out of the box for reference.
145+
146+
### Constant product
147+
148+
The [constant product
149+
curve](https://github.com/solana-labs/solana-program-library/blob/master/token-swap/program/src/curve/constant_product.rs)
150+
is the well-known Uniswap and Balancer style curve that preserves an invariant
151+
on all swaps, expressed as the product of the quantity of token A and token B
152+
in the swap.
153+
154+
```
155+
A_total * B_total = invariant
156+
```
157+
158+
If a trader wishes to put in token A for some amount of token B, the calculation
159+
for token B becomes:
160+
161+
```
162+
(A_total + A_in) * (B_total - B_out) = invariant
163+
```
164+
165+
For example, if the swap has 100 token A and 5,000 token B, and a trader wishes
166+
to put in 10 token A, we can solve for the `invariant` and then `B_out`:
167+
168+
```
169+
A_total * B_total = 100 * 5,000 = 500,000 = invariant
170+
```
171+
172+
And
173+
174+
```
175+
(A_total + A_in) * (B_total - B_out) = invariant
176+
(100 + 10) * (5,000 - B_out) = 500,000
177+
5,000 - B_out = 500,000 / 110
178+
5,000 - (500,000 / 110) = B_out
179+
B_out = 454.5454...
180+
```
181+
182+
More information can be found on the [Uniswap
183+
whitepaper](https://uniswap.org/whitepaper.pdf) and the [Balancer
184+
whitepaper](https://balancer.finance/whitepaper/).
185+
186+
### Constant price
187+
188+
The [constant price curve](https://github.com/solana-labs/solana-program-library/blob/master/token-swap/program/src/curve/constant_price.rs)
189+
is a simple curve that always maintains the price of token A with respect to
190+
token B. At initialization, the swap creator sets the cost for 1 token B in
191+
terms of token A. For example, if the price is set to 17, 17 token A will always
192+
be required to receive 1 token B, and 1 token B will always be required to
193+
receive 17 token A.
194+
195+
Note that this curve does not follow traditional market dynamics, since the
196+
price is always the same.
197+
198+
Constant price curves are most useful for fixed offerings of new tokens that
199+
explicitly should not have market dynamics. For example, a decentralized
200+
game creator wants to sell new "SOLGAME" tokens to be used in their
201+
game, so they create a constant price swap of 2 USDC per SOLGAME, and supply all
202+
of the SOLGAME tokens at swap creation. Users can go to the swap and purchase all
203+
of the tokens they want and not worry about the market making SOLGAME tokens too
204+
expensive.
205+
206+
### Stable (under construction)
207+
208+
The [stable curve](https://github.com/solana-labs/solana-program-library/blob/master/token-swap/program/src/curve/stable.rs)
209+
from [curve.fi](https://www.curve.fi/), has a different shape to prioritize
210+
"stable" trading, meaning prices that stay constant through trading. Most
211+
importantly, prices don't change as quickly as the constant product curve, so a
212+
stable swap between two coins that represent the same value should be as close
213+
to 1:1 as possible. For example, stablecoins that represent a value in USD (USDC,
214+
TUSD, USDT, DAI), should not have big price discrepancies due to the amount of
215+
tokens in the swap.
216+
217+
The curve mirrors the dynamics of the curve
218+
More information can be found on their [whitepaper](https://www.curve.fi/stableswap-paper.pdf).
219+
220+
The Token Swap Program implementation of the stable curve is under construction,
221+
and a more complete version can be found at the
222+
[stable-swap-program](https://github.com/michaelhly/stable-swap-program/).
223+
224+
### Offset
225+
226+
The [offset curve](https://github.com/solana-labs/solana-program-library/blob/master/token-swap/program/src/curve/offset.rs)
227+
can be seen as a combination of the constant price and constant product curve.
228+
It follows the constant product curve dynamics, but allows for the token swap
229+
creator to set an "offset" on one side. The invariant for the curve is:
230+
231+
```
232+
(A_total) * (B_total + B_offset) = invariant
233+
```
234+
235+
This is useful for initial token
236+
offerings, where the token creator wants to sell some new token as a swap without
237+
putting up the capital to fund the other side of the swap. This is similar to the
238+
constant price curve, but the key difference is that the offset curve captures
239+
normal market dynamics, in that the offered token price will increase as it is
240+
bought.
241+
242+
For example, a decentralized betting application creator wants to sell new "SOLBET"
243+
tokens on the market in exchange for USDC, and they believe each token is worth
244+
at least 4 USDC. They create a token swap between SOLBET and USDC, funding
245+
one side with 1,000 SOLBET, and the other side with 0 USDC, but an offset
246+
of 4,000 USDC.
247+
248+
If a trader tries to buy SOLBET with 40 USDC, the invariant is calculated
249+
with the offset:
250+
251+
```
252+
(SOLBET_total) * (USDC_total + USDC_offset) = invariant
253+
1,000 * (0 + 4,000) = 4,000,000
254+
255+
(SOLBET_total - SOLBET_out) * (USDC_total + USDC_offset + USDC_in) = invariant
256+
SOLBET_out = 9.901
257+
```
258+
259+
The trader received 9.901 SOLBET for 40 USDC, so the price per SOLBET was
260+
roughly 4.04, slightly higher than the minimum of 4 USDC per SOLBET.
261+
262+
Conversely, if a trader tries to buy USDC with SOLBET immediately after creation,
263+
it will fail because there is no USDC actually present in the pool.
264+
265+
## Testing
266+
267+
The token-swap program is tested using various strategies, including unit tests,
268+
integration tests, property tests, and fuzzing. Since unit tests and integration
269+
tests are well-known, we highlight property tests and fuzzing here.
270+
271+
### Property testing
272+
273+
Using the [proptest](https://altsysrq.github.io/proptest-book/intro.html)
274+
crate, we test specific mathematical properties of curves, specifically to avoid
275+
leaking value on any trades, deposits, or withdrawals. It is out of scope of
276+
this document to explain property testing, but the specific property tests for
277+
the Token Swap Program can be found in the
278+
[curves](https://github.com/solana-labs/solana-program-library/blob/master/token-swap/program/src/curve/constant_product.rs)
279+
and
280+
[math](https://github.com/solana-labs/solana-program-library/blob/master/token-swap/program/src/curve/math.rs)
281+
portions of the repo.
282+
283+
### Fuzzing
284+
285+
Using [honggfuzz](https://github.com/rust-fuzz/honggfuzz-rs), we regularly
286+
test all possible inputs to the Token Swap Program, ensuring that the program
287+
does not crash unexpectedly or leak tokens. It is out of scope of this document
288+
to explain fuzzing, but the specific implementation for the program can be found
289+
in the [instruction fuzz
290+
tests](https://github.com/solana-labs/solana-program-library/blob/master/token-swap/program/fuzz/src/instructions.rs)
291+
of the repo.

0 commit comments

Comments
 (0)