- These contracts are simplified version of a leveraged AMM exchange.
- This exchange has the logic of an AMM exchange module:
(Rt + x) * (Ru + y) = Rt * Ru
.
- This exchange has the logic of an AMM exchange module:
- The contracts allow users to deposit/withdraw ERC20 tokens and swap tokens with leverage up to 10x.
- The contracts allow users to create arbitrary trading pairs (the swapped asset is called position).
- The contracts emit events for deposit, withdraw and swap functions.
- The contracts also provide a set of view functions, which can
- input asset A amount as the payment and the leverage => output asset B amount after the swap
- input asset B amount to exchange for and the leverage => output asset A amount you should pay for
- returns the remaining value of the account
- Users can open/reduce and open/close positions in cross and isolated margin modes, respectively.
- In cross margin mode, the user's position is shared across all token swaps.
- OPEN: buy tokens, REDUCE: sell tokens (part of or all).
- In isolated margin mode, the user's position is isolated to each token swap.
- OPEN: buy tokens, CLOSE: sell tokens in a specific single swap (all).
- In cross margin mode, the user's position is shared across all token swaps.
- A simple Web GUI (HTML) is also provided to interact with the contracts.
This project is established by Foundry
framework. For installation, please refer to Official Foundry Book.
- Compile the Leveraged AMM Exchange Module contracts in the folder
src/
.
$ forge compile # or `forge build`
- Run the unit tests for the contracts, which are located in the folder
test/
.
$ forge test
================================================================================
[PASS] testFuzz_Deposit(uint256) (runs: 256, μ: 96684, ~: 97247)
[PASS] testFuzz_Withdraw(uint256) (runs: 256, μ: 110898, ~: 111472)
[PASS] test_AddReserves() (gas: 148919)
[PASS] test_AddReserves_Failed() (gas: 159666)
[PASS] test_CreatePair() (gas: 154154)
[PASS] test_CreatePair_Failed() (gas: 165411)
[PASS] test_Deposit() (gas: 96861)
[PASS] test_Deposit_Failed() (gas: 27677)
[PASS] test_Withdraw() (gas: 119422)
[PASS] test_Withdraw_Failed() (gas: 101115)
[PASS] test_GetAccountRemainingValue() (gas: 234000)
[PASS] test_GetAmountCollateralReturn() (gas: 184418)
[PASS] test_GetAmountInForOut() (gas: 172022)
[PASS] test_GetAmountOutFromIn() (gas: 165341)
[PASS] test_GetPairPrice() (gas: 156486)
[PASS] test_GetPositionId() (gas: 138955)
[PASS] test_MaxLeverage() (gas: 12037)
[PASS] test_Swap_Open_CrossMode() (gas: 428795)
[PASS] test_Swap_Reduce_CrossMode() (gas: 407240)
[PASS] test_Swap_Open_IsolatedMode() (gas: 906676)
[PASS] test_Swap_Close_IsolatedMode() (gas: 392260)
[PASS] test_Swap_Failed() (gas: 118890)
- Run the following command to see the testing coverage, which is also listed below.
$ forge coverage --ir-minimum --skip src/tests/*.sol script/*.sol
================================================================================
Ran 2 test suites in 395.11ms (766.41ms CPU time): 40 tests passed, 0 failed, 0 skipped (40 total tests)
| File | % Lines | % Statements | % Branches | % Funcs |
|------------------------------------------|------------------|------------------|----------------|-----------------|
| src/LeveragedAMMExchange.sol | 100.00% (50/50) | 96.77% (90/93) | 86.36% (19/22) | 100.00% (12/12) |
| src/LeveragedAMMExchangeCrossMode.sol | 97.78% (44/45) | 93.44% (57/61) | 81.25% (13/16) | 100.00% (7/7) |
| src/LeveragedAMMExchangeIsolatedMode.sol | 97.92% (47/48) | 94.03% (63/67) | 75.00% (9/12) | 100.00% (8/8) |
| Total | 98.60% (141/143) | 95.02% (210/221) | 82.00% (41/50) | 100.00% (27/27) |
- To use the Web GUI, you should deploy the contracts on local blockchain network by Anvil in
Foundry
.- src/ILeveragedAMMExchange.sol
- src/LeveragedAMMExchange.sol
- src/LeveragedAMMExchangeCrossMode.sol
- src/LeveragedAMMExchangeIsolatedMode.sol
- src/tests/MyToken.sol
- Firstly, open another terminal and execute
Anvil
to run local network (by default setting). - Make sure you have Metamask installed in the web browser
- Change the network setting to
Local
(RPC URL => http://127.0.0.1:8545)
- Change the network setting to
$ anvil
- Rename the file
.env.example
with.env
, copy one of the private key from theAnvil
and paste it in.env
. - Insert the chosen private key into Metamask and check whether there is some ETH in this account.
- WARNING: DO NOT TAKE THE PRIVATE KEY AS YOUR OWN WALLET AND PUT THE REAL MONEY INTO IT.
- After updating the
.env
file, run the following commands to load the env variables and deploy the contracts.
$ source .env
$ forge script script/LeveragedAMMExchange.s.sol --rpc-url $RPC_URL --broadcast --private-key $PRIVATE_KEY
- Now, we need to update the new contract addresses to the Web GUI config.
- A simple script is provided to write the config (
html/contract-address.json
) automatically.
$ node load-address.js
- Install the VSCode extension: Live Server.
- This can open the HTML files in a convenient way - like running on a web server.
- Right click on files:
html/exch-isolated-mode.html
&html/exch-cross-mode.html
=>Open with Live Server
- The contracts have been scanned by the static analysis tool Slither.
- The reporting result from
Slither
is located in the folderreport/
.
- The reporting result from