- Contributing
Come and build the decentralized universal exchange with us! 🚀
Fork this repo, make the changes, and send a PR to the main branch. Run into issues? Ping us on discord or Telegram or raise an issue here on github.
Install the following tools (if not already installed).
- rust
# Install rust (see https://www.rust-lang.org) curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
- go (for utilities to deploy the contract and auto generate code etc)
# Install go (see https://go.dev and https://github.com/stefanmaric/g) curl -sSL https://git.io/g-install | sh -s source ~/.bashrc g install latest
- node.js (for frontend)
# Install and enable nvm (see https://github.com/nvm-sh/nvm#install--update-script) curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | bash source ~/.bashrc nvm install 18 nvm use 18 corepack enable yarn set version berry echo 'nvm use 18; corepack enable' >> ~/.bashrc
- yarn
yarn install
- rust support softwares
sudo apt install build-essential clang pkg-config libssl-dev
Aptos cli is also needed, after rust is installed. Either use the pre-compiled binaries following the instructures from here, or build from source with:
RUSTFLAGS="--cfg tokio_unstable" cargo install --git https://github.com/aptos-labs/aptos-core.git --rev <LATEST_RELEASE_TAG> aptos
(rust is tricky and the dependencies often vary from platform/os to platform/os. Feel free to reach out to us on discord or raise an issue)
- aptos/contrat/aux contains the main contract code.
- aptos/contract/deployer contains the code/rust binary to deploy the code
- aptos/api/aux-ts contains all the typescript/javascript/nodejs client.
- aptos/testing contains podman based containerized testing.
- go-util contains deploy/code-gen utilities.
- docs contains documentation on math behind some of the contracts.
Make sure you have installed the above pre-requisites and local
profile setup (you can initiate one by running the aptos init
command).
-
Setup Aptos and deploy AUX to localnet:
# cwd: aux-exchange go run ./go-util/aptos/cmd/setup-aux -f --network "local"
-
Run end to end tests:
cd aptos/api/aux-ts # cwd: aux-exchange/aptos/api/aux-ts APTOS_NETWORK="local" yarn test
Run aux-exchange/aptos/testing/run.sh
to start a podman container. The
container will have a local validator with the aux
contract deployed.
In the container: - Run ./example_amm.sh
to trade the AMM locally - Run ./example_clob.sh
to trade the CLOB locally
The example code is located in aptos/api/aux-ts/examples
.
The core package is located in aptos/api/aux-ts
. You can modify
the code and rerun the example scripts in the container.
Run the integration tests with ./test.sh
. Note that the integration tests
pollute the container state so subsequent runs may not be reliable, especially
if you have been interacting with the local validator in other ways.
Below are details on how to deploy AUX smart contracts to devnet or mainnet ONLY. For local development, follow the quickstart above.
To understand why some of these are needed, see the deployer section.
NOTE: all operations are assumed to run in the root folder of the repository.
The contract code needs to sign for itself, and therefore deployed into a resource account. The original creator of the resource account is the first owner of the exchange, and can make certain changes/updates to the account. The aux resource account is always created with seed "aux".
Given an owner address, the aux address can be verified by the following go binary
go run ./go-util/aptos/cmd/calculate-resource-address -a "<owner-address>" -s aux
A global aptos profile for the desired network should be initialized before deployment.
# set aptos to use global profile
aptos config set-global-config --config-type global
Make sure profile is in the global config (on linux and mac, this should be $HOME/.aptos/config.yaml
) - below is an example of the config with devnet
profile setup.
profiles:
devnet:
private_key: "0x12345678" # <private key hex string>
public_key: "0x98765432" # <public key hex string>
account: abcdefg # <account address hex string>
rest_url: "https://fullnode.devnet.aptoslabs.com/v1" # <url to the rest endpoint>
faucet_url: ""
If the profile is not there, you can initiate one by using the aptos init
command.
During the deployment process, the setup-aux
command will delete the .move
folder in the user's home directory (to remove all downloaded move dependencies) and build
folder in the contract directory (to remove all compiled codes).
IF aux resource account is not created yet and the contract is not deployed, use the following command to create the resource account and deploy the contract
go run ./go-util/aptos/cmd/setup-aux --network devnet # network to deploy
IF aux resource account is created and the contract is already deployed, do an update
go run ./go-util/aptos/cmd/setup-aux --network devnet --redeploy # require redeploy
A very convoluted way of redeploying to a resource account and allow it to self-sign.
-
For a module to self-sign, the module needs to get the
SignerCapability
from somewhere. The VM cannot create a signer even from the private key. -
The
SignerCapability
can either be inside the module address itself (withfriend
modules), or obtained from a call to an outside module, such asmodule some_other_address::some_other_module { public fun get_signer(resource_account_addr: address): signer { } }
However, the input must be an
address
, which is not guarded, and anyone can get the signer by just calling that function. If that function is to be guarded by a signer, we run into the chicken egg problem, since module cannot sign yet.Therefore, the module must hold the signer capability inside itself.
-
It turns out the same package cannot update itself through an entry function inside itself.
-
deployer
'screate-resource-account
binary creates a resource account, and save theSignerCapability
and creator'saddress
in the resource account. -
A module that is supposed to be self-sign will need to add a dependency to
deployer
and retrieves the signer capability and owner's address by calling the functiondeployer::retrieve_resource_account_signer(source)
, wheresource
is asigner
that is the resource account address. See below code for some inspiration of using this ininit_module
. See an example in examples/selfsigned.however, this can also be called from any other module that is signed by
owner
beforeretrieve_resource_account_signer
is called. TheSignerCapability
must be obtained from the resource account modules once it's retrieved.module resource_account_address::a_module { use std::signer; use aptos_framework::account::{Self, SignerCapability}; use deployer::deployer; friend selfsigned::another_mod; const E_NOT_SELF_SIGNED: u64 = 1001; const E_CANNOT_SIGN_FOR_OTHER: u64 = 1002; const E_NOT_OWNER: u64 = 1003; struct Authority has key { signer_capability: SignerCapability, owner_address: address, } // on module initialization, the module will tries to get the signer capability from deployer. fun init_module(source: &signer) { let source_addr = signer::address_of(source); if(!exists<Authority>(source_addr) && deployer::resource_account_signer_exists(source_addr)) { let (owner_address, signer_capability) = deployer::retrieve_resource_account_signer(source); let auth_signer = account::create_signer_with_capability(&signer_capability); assert!( signer::address_of(source) == signer::address_of(&auth_signer), E_CANNOT_SIGN_FOR_OTHER, ); move_to(source, Authority { signer_capability, owner_address, }); } } }
Publishing code can be done either through
create-resource-account-and-publish
binary, orpublish-to-resource-account
binary (given theSignerCapability
is not retrieved yet). -
If the resource account's module doesn't expose a function to retrieve the
SignerCapability
, it's sealed. However, if the it does expose, we can create another module to deploy to that account. The signature of the function must be like follows to use therepublish-to-resource-account
binary: Note, the module that resides inside the target resource account needs to be added as a dependency. See examples/redeployer for an example.module redeployer::redeploy { use aptos_framework::code::publish_package_txn; use selfsigned::authority::get_signer; public entry fun redeploy(owner:&signer, metadata: vector<u8>, code: vector<vector<u8>>) { let resource_account_signer = get_signer(owner); publish_package_txn(&resource_account_signer, metadata, code) } }
git push origin feat/my-new-feature:devnet -f
ssh <YOUR USERNAME>@devbox
ssh prod@<...>
devnet # aliases to cd ~/aux-exchange-devnet/aptos/api/aux-ts
./scripts/deploy/hard_restart.sh devnet
# You're done!
If you changed the UI, then to deploy a new version of frontend (UI) you need to:
- set two env vars,
AUX_EXCHANGE
andAUX_FRONTEND
corresponding to where your local repos live- e.g.
AUX_EXCHANGE=~/projects/aux-exchange
- e.g.
AUX_FRONTEND=~/projects/aux-frontend
- e.g.
- in your local
aux-exchange
repo, insideaux-ts
run./scripts/update_uis.sh
APTOS_NETWORK=mainnet yarn start:graphql
- Update/add the appropriate schema in:
typeDefs
- Run
yarn codegen:graphql
from theaux-ts
directory - Update/add resolvers in
resolvers
Make sure you have Redis running on the box you're starting the indexer on.
APTOS_NETWORK=mainnet yarn start:indexer
Push to one of the following branches. This can be main
or your own branch.
origin/mainnet
origin/mainnet-beta
origin/testnet
origin/devnet
Inside the prod box, cd
into the corresponding directory (e.g. aux-exchange-mainnet-beta
),
into the aux-ts
folder, and run this:
./scripts/deploy/rolling_restart.sh mainnet-beta
./scripts/deploy/hard_restart.sh mainnet-beta
This will cd aux-exchange-mainnet
, git checkout origin/mainnet
and restart PM2 process group named mainnet
.
Hard restart has more downtime but is cleaner.
./rolling_restart.sh <branch>
Example: ./rolling_restart.sh mainnet
Example: ./rolling_restart.sh devnet
./hard_restart.sh <branch>
Contributors on MS Windows may have difficulties downloading or checking out the codes: aux.exchange started on *nix, and we are deep into the development cycle to find that aux
is a reserved name on MS Windows (see here for details). We are still in a build-out phase, but will push out a reorganisation of the repo to fix this later. Stay tuned!.
To contribute a typescript example using the SDK:
- Add the example under
aptos/api/aux-ts/examples
- Add a run script to
aptos/api/aux-ts/package.json
:
"scripts": {
"start:my-example": "APTOS_NETWORK=<devnet|localnet|mainnet> ts-node examples/my-example.ts"
}
- Run the example from inside
aptos/api/aux-ts
with:
yarn start:my-example