Before entering nix-shell
, make sure that you have binary cache set up so that your builds would not take longer that it is needed.
substituters = https://hydra.iohk.io https://iohk.cachix.org https://cache.nixos.org/
trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= iohk.cachix.org-1:DpRUyj7h7V830dp/i6Nti+NEO2/nhblbov/8MW7Rqoo= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
Note: after changing /etc/nix/nix.conf
, restart nix-daemon otherwise changes won’t take effect.
nix = {
binaryCaches = [ "https://hydra.iohk.io" "https://iohk.cachix.org" ];
binaryCachePublicKeys = [ "hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ=" "iohk.cachix.org-1:DpRUyj7h7V830dp/i6Nti+NEO2/nhblbov/8MW7Rqoo=" ];
};
After cloning the repository, cd
into the project and do the following:
In order to run local hoogle with all project dependencies run:
nix-shell shell-hoogle.nix --run "hoogle server --local"
This will open a local Hoogle server at http://127.0.0.1:8080
export NIX_GHC="$(which ghc)"
export NIX_GHCPKG="$(which ghc-pkg)"
export NIX_GHC_DOCDIR="$NIX_GHC/../../share/doc/ghc/html"
export NIX_GHC_LIBDIR="$(ghc --print-libdir)"
Plugins
It is recommended to use ALE as a primary lint and hls integration.
However, because of some bug related to cabal build
being launched from directory containing linted file
and not from project root (vim CWD), use the following configuration:
call ale#linter#Define('haskell', {
\ 'name': 'my_cabal',
\ 'aliases': ['my-cabal'],
\ 'output_stream': 'stderr',
\ 'executable': 'cabal',
\ 'command': '%e build -fno-code -v0 -- %s </dev/null',
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\})
if !exists('g:ale_linters')
let g:ale_linters = {}
endif
let g:ale_linters.haskell = ['my-cabal', 'hls', 'hlint']
let g:ale_fixers.haskell = 'stylish-haskell'
let g:ale_haskell_hls_executable = 'haskell-language-server'
It's also useful to use haskell-vim extension.
All contract endpoints are defined in dex/src/Dex/OffChain.hs
.
createSellOrder
-- creates an exchange request, called Swap Order, i.e. a will to sell some amount of tokens of one kind for some other amount of tokens of other kind.createLiquidityOrder
-- creates a script, called Liquidity Order, that allocates some funds that can be used in exchange by other users. User can set up how much funds of two different tokens they wish to put in such pool and setup a fee.createLiquidityPool
perform
-- matches Swap Orders with other Swap Orders and/or Liquidity Orders in order to perform an exchange between them. The performer pays for the transaction, but can also gain some surplus of tokens, when there is some.stop
-- stops connection between wallet and PAB.funds
-- provides information about funds belonging to the user.allOrders
- provides information about all orders on the script.myOrders
- provides information about all orders on the script that belong to the wallet calling this endpoint.cancel
-- closes the Liquidity Order by getting remaining allocated funds back to Liquidity Order founder.collectFunds
-- a transaction that withdraws the tokens to their new owners after a properly performed swap.
This project use GitLab as CI. Check the configuration file for more information.
GitLab use custom docker image (plutus4binarapps/dex-plutus-dev
) which contains necessary dependencies.
The image is build using devcontainer.
To update it or rebuild manually:
docker load < $(nix-build default.nix -A devcontainer)
.- tag result image
docker tag dex-devcontainer silquenarmo/dex-plutus-dev:<version>
- [optional] push an image to hub repository
docker push silquenarmo/dex-plutus-dev:<version>
anddocker push silquenarmo/dex-plutus-dev:latest
NOTE: You can build docker image only on linux.
CI runs of external gitlab CI runner on AWS instance, and process is as follows:
- create r4.large instances (2vcpu, 16G ram)
- there are max 2 instances for max two jobs at runtime
- after processing job instances are waiting 1h
- after 1h waiting the instance is being removed
- if next job arises withing a 1h delay it's being processed by a free instance
- the instance creation is about 5min long
- disk capacity per instance is ~40G
CI consists of three stages:
- lint - using
hlint
to verify both projects - prebuild - using
cabal update
andcabal configure
to setup the build environment - build - using
cabal build
to compile projects
The docker image used by CI can be use to remote development with VSCode.
Usage:
- Create
.devcontainer/devcontainer.json
in your project as below - Install the Remote Development extension pack in VSCode
- Open the folder "in the container"
{
"name": "Dex Project",
"image": "silquenarmo/dex-plutus-dev:latest",
// Use 'settings' to set *default* container specific settings.json values on container create.
// You can edit these settings after create using File > Preferences > Settings > Remote.
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
"extensions": ["haskell.haskell"]
}
PAB operates on port 9080
.
To run PAB, type:
cabal run dex-pab
PAB endpoints requires a contract instance ID to identify the operator. To get contract instance ID look for a line in PAB output log that looks like:
[INFO] Activated instance d336fd95-8b42-4a1e-9600-1631f433e1d8 on W872cb83
This is an information about a contract instance for wallet with ID starting with 872cb83.
PAB has two major endpoints that are currently used in order to operate on DEX:
Example:
curl -vXPOST -H "Content-Type: application/json" -d '{"historyId":"","randomSeed":1,"content":[]}' "http://localhost:9080/api/contract/instance/d336fd95-8b42-4a1e-9600-1631f433e1d8/endpoint/funds" | jq
historyId
is an ID of the operation that can be utilized in history lookup in status endpoint response.
randomSeed
is the value required for creating a unique ID of the operation in the history.
content
is a part with serialized parameters for endpoint.
Example:
curl -v "http://localhost:9080/api/contract/instance/d336fd95-8b42-4a1e-9600-1631f433e1d8/status" | jq
Middleware operates on port 8080
.
To run middleware, type:
cabal run middleware-manual
Example:
curl -v -XPOST -d '{ "coinA": { "tokenName": { "unTokenName": "A" }, "currencySymbol": { "unCurrencySymbol": "aa906c3a72afdd99d48a001f4c73cbf8cf54c62493e0d00774f32698" } }, "coinB": { "tokenName": { "unTokenName": "B" }, "currencySymbol": { "unCurrencySymbol": "aa906c3a72afdd99d48a001f4c73cbf8cf54c62493e0d00774f32698" } }, "amountA": 1000, "poolPartsParams": { "coinAPriceChange": [100,101], "coinBPriceChange": [100,101], "numberOfParts": 3 }, "swapFee": [1,100], "exchangeRate": [100,100] }' -H "Content-Type: application/json" "http://localhost:8080/d336fd95-8b42-4a1e-9600-1631f433e1d8/createLiquidityPool" | jq
cabal test dex-test
cabal run dex-pab
To build docker image with dex application (middleware or backend) run following commands:
nix-build release.nix -A middleware
docker load < result
This operation is automated via deploy.sh
script. The script build and publish images to the docker registry.
nix-shell
docker login plutus4binarapps
./deploy.sh