Solana Perpetuals protocol is an open-source implementation of a non-custodial decentralized exchange that supports leveraged trading in a variety of assets.
- Clone the repository from https://github.com/askibin/perpetuals.git.
- Install the latest Solana tools from https://docs.solana.com/cli/install-solana-cli-tools. If you already have Solana tools, run
solana-install update
to get the latest compatible version. - Install the latest Rust stable from https://rustup.rs/. If you already have Rust, run
rustup update
to get the latest version. - Install the latest Anchor framework from https://www.anchor-lang.com/docs/installation. If you already have Anchor, run
avm update
to get the latest version.
Rustfmt is used to format the code. It requires nightly
features to be activated:
- Install
nightly
rust toolchain. https://rust-lang.github.io/rustup/installation/index.html#installing-nightly - Execute
git config core.hooksPath .githooks
to activate pre-commit hooks.
- Install
rust-analyzer
extension - If formatting doesn't work, make sure that
rust-analyzer.rustfmt.extraArgs
is set to+nightly
Steps to quickly start local validator and update oracle data
Get Solana CLI v1.14.3
sh -c "$(curl -sSfL https://release.solana.com/v1.14.13/install)"
solana --version
# solana-cli 1.14.13 (src:0a3e52ba; feat:627291041)
# Set proper solana network: localhost, devnet, testnet, mainnet
solana config set --url devnet
# Generate your personal wallet
solana-keygen new
# Generate key for Perpetuals program (ask for key file instead)
# solana-keygen new -o prog_id.json
# Airdrop tokens
solana airdrop 5
# Transfer if needed
solana transfer --allow-unfunded-recipient <ADDRESS> <AMOUNT>
Build and run docker image:
docker build --progress plain --tag perps .
docker run -ti -p 8899:8899 --entrypoint /bin/bash perps
# Inside docker
./init.sh
Start UI:
cd ui
cp .env.local.example .env.local
# Set proper `NEXT_PUBLIC_SOLANA_RPC_URL` in `.env.local` (devnet by default)
yarn run dev
cd ..
Trigger position (close if limits reached).
cd app
# HwtueJY1Brqx52SuEhwnhYs9MXCwTGcvVKjdUvoLEvnu is user address
# TestPool1 is pool name
# So11111111111111111111111111111111111111112 is position token mint
# Position is: long | short
# Optional: `--url` is `https://api.devnet.solana.com` or `http://localhost:8899`.
# Check profit or loss
npx ts-node src/cli.ts get-pnl \
HwtueJY1Brqx52SuEhwnhYs9MXCwTGcvVKjdUvoLEvnu \
TestPool1 \
So11111111111111111111111111111111111111112 \
long
npx ts-node src/cli.ts get-exit-price-and-fee \
HwtueJY1Brqx52SuEhwnhYs9MXCwTGcvVKjdUvoLEvnu \
TestPool1 \
So11111111111111111111111111111111111111112 \
long
# get actual exit price from `get-exit-price-and-fee`
npx ts-node src/cli.ts trigger-position \
TestPool1 \
So11111111111111111111111111111111111111112 \
HwtueJY1Brqx52SuEhwnhYs9MXCwTGcvVKjdUvoLEvnu \
long \
HwtueJY1Brqx52SuEhwnhYs9MXCwTGcvVKjdUvoLEvnu \
-p 183769543
cd ..
Update oracle price (if needed)
cd app
npx ts-node src/cli.ts \
--url http://localhost:8899 \
-k ~/.config/solana/id.json \
updateOracle \
J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix
cd ..
Start liquidator:
npx ts-node src/cli.ts get-pool-token-positions \
TestPool1 \
So11111111111111111111111111111111111111112
npx ts-node src/liquidator.ts run \
--url https://api.devnet.solana.com \
-k ~/.config/solana/id.json \
TestPool1 \
So11111111111111111111111111111111111111112
First, generate a new key for the program address with solana-keygen new -o <PROG_ID_JSON>
. Then replace the existing program ID with the newly generated address in Anchor.toml
and programs/perpetuals/src/lib.rs
.
Also, ensure the path to your wallet in Anchor.toml
is correct. Alternatively, when running Anchor deploy or test commands, you can specify your wallet with --provider.wallet
argument. The wallet's pubkey will be set as an upgrade authority upon initial deployment of the program. It is strongly recommended to make upgrade authority a multisig when deploying to the mainnet.
To build the program run anchor build
command from the perpetuals
directory:
cd perpetuals
anchor build
Unit tests are executed with the cargo test
command:
cargo test -- --nocapture
Integration tests (Rust) can be started as follows:
cargo test-bpf -- --nocapture
Integration tests (Typescript) can be started as follows:
npm install
anchor test -- --features test
By default, integration tests are executed on a local validator, so it won't cost you any SOL.
To deploy the program to the devnet and upload the IDL use the following commands:
anchor deploy --provider.cluster devnet --program-keypair <PROG_ID_JSON>
anchor idl init --provider.cluster devnet --filepath ./target/idl/perpetuals.json <PROGRAM ID>
A small CLI Typescript client is included to help you initialize and manage the program. By default script uses devnet cluster. Add -u https://api.mainnet-beta.solana.com
to all of the commands if you plan to execute them on mainnet.
To initialize deployed program, run the following commands:
cd app
npm install
npm install -g npx
npx ts-node src/cli.ts -k <ADMIN_WALLET> init --min-signatures <int> <ADMIN_PUBKEY1> <ADMIN_PUBKEY2> ...
Where <ADMIN_WALLET>
is the file path to the wallet that was set as the upgrade authority of the program upon deployment. <ADMIN_PUBKEY1>
, <ADMIN_PUBKEY2>
etc., will be set as protocol admins, and min-signatures
will be required to execute privileged instructions. To provide multiple signatures, just execute exactly the same command multiple times specifying different <ADMIN_WALLET>
with -k
option. The intermediate state is recorded on-chain so that commands can be executed on different computers.
To change protocol admins or minimum required signatures, run:
npx ts-node src/cli.ts -k <ADMIN_WALLET> set-authority --min-signatures <int> <ADMIN_PUBKEY1> <ADMIN_PUBKEY2> ...
To validate initialized program:
npx ts-node src/cli.ts -k <ADMIN_WALLET> get-multisig
npx ts-node src/cli.ts -k <ADMIN_WALLET> get-perpetuals
Before the program can accept any liquidity or open a trade, you need to create a token pool and add one or more token custodies to it:
npx ts-node src/cli.ts -k <ADMIN_WALLET> add-pool <POOL_NAME>
npx ts-node src/cli.ts -k <ADMIN_WALLET> add-custody <POOL_NAME> <TOKEN_MINT> <TOKEN_ORACLE> <IS_STABLE>
Where <POOL_NAME>
is a random name you want to assign to the pool, <TOKEN_MINT>
is the mint address of the token, and <TOKEN_ORACLE>
is the corresponding Pyth price account that can be found on this page. <IS_STABLE>
specifies whether the custody is for a stablecoin. For example:
npx ts-node src/cli.ts -k <ADMIN_WALLET> add-pool TestPool1
npx ts-node src/cli.ts -k <ADMIN_WALLET> add-custody TestPool1 So11111111111111111111111111111111111111112 J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix false
To validate added pools and custodies, run:
npx ts-node src/cli.ts -k <ADMIN_WALLET> get-pool <POOL_NAME>
npx ts-node src/cli.ts -k <ADMIN_WALLET> get-custody <POOL_NAME> <TOKEN_MINT>
or
npx ts-node src/cli.ts -k <ADMIN_WALLET> get-pools
npx ts-node src/cli.ts -k <ADMIN_WALLET> get-custodies <POOL_NAME>
CLI offers other useful commands. You can get the list of all of them by running the following:
npx ts-node src/cli.ts --help
We have implemented a coressponding UI for the smartcontract, written in Typescript/Tailwind/Next. To quickly spin up a UI linked to the contract, first follow the previous directions to build the contract, and to init the exchange.
In the main directory, run ./migrations/migrate-target.sh
to copy over the target build directory to the ui.
Now, you can use the following CLI commands to quickly spin-up a TestPool1
consisting of the three following tokens.
Sol Token: J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix
Test Token oracle: BLArYBCUYhdWiY8PCUTpvFE21iaJq85dvxLk9bYMobcU
USDC oracle: 5SSkXsEKQepHHAewytPVwdej4epN1nxgLVM84L4KXgy7
cd app
npx ts-node src/cli.ts -k <ADMIN_WALLET> add-pool TestPool1
npx ts-node src/cli.ts -k <ADMIN_WALLET> add-custody TestPool1 So11111111111111111111111111111111111111112 J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix
npx ts-node src/cli.ts -k <ADMIN_WALLET> add-custody TestPool1 6QGdQbaZEgpXqqbGwXJZXwbZ9xJnthfyYNZ92ARzTdAX BLArYBCUYhdWiY8PCUTpvFE21iaJq85dvxLk9bYMobcU
npx ts-node src/cli.ts -k <ADMIN_WALLET> add-custody TestPool1 Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr 5SSkXsEKQepHHAewytPVwdej4epN1nxgLVM84L4KXgy7 true
Now, use the following commands to build and run the UI, (navigate to localhost:3000 to use the UI):
cd ../ui
yarn install
yarn dev
If you are experiencing technical difficulties while working with the Perpetuals codebase, ask your question on StackExchange (tag your question with perpetuals
).
If you find a bug in the code, you can raise an issue on Github. But if this is a security issue, please don't disclose it on Github or in public channels. Send information to solana.farms@protonmail.com instead.
Contributions are very welcome. Please refer to the Contributing guidelines for more information.
Solana Perpetuals codebase is released under Apache License 2.0.
By accessing or using Solana Perpetuals or any of its components, you accept and agree with the Disclaimer.