cw-atomic-swap
is a simplified implementation of the ICS-100 that
allows two users on the same chain to exchange tokens with an implicit agreement on the the relative price of the two swapped assets.
The contract is a simplified version because it is made to work on a single chain and does not allow the execution of trades via IBC. The
system can be viewed as an on-chain Over The Counter (OTC) market.
The particularity of the contract is that instead of escrowing user funds as done in classical automated market maker systems,
it makes use of the x/authz
module to grant authorization to the contract to send user funds just before executing the token exchange.
The process to perform a swap of coins between two users is below described.
- The Maker send a message to authorize the contract to execute a smart contract call on their behalf with the possibility to send coins.
x/authz
store the authorization with the contract as thegrantee
and the Maker as thegranter
.- The Maker send a message to
cw-atomic-swap
to create an order. - The contract store the order info without requesting tokens to the Maker.
Please, note that (1.) and (3.) can be send with a multi-message transaction.
- The Taker accept an order by sending to the contract the required amount of coins.
- The contract receives the Taker request to perform the swap and send a message to the
x/authz
to execute a contract call. x/authz
send back to the contract a message, along with authorized funds, on behalf of the Maker to complete the order.- The smart contract send the Taker's funds to the Maker
- The smart contract send the Maker's funds to the Taker.
- The smart contact update the order status to completed.
The following sequence diagram describes the process of swap order creation and execution:
sequenceDiagram
autonumber
actor m as Maker
participant o as Osmosis
participant sc as Smart Contract
actor t as Taker
Note over m,t: Order creation
m ->>o: x/authz
o->>o: Stores authorization
m ->> sc: CreateSwapOrder
sc->>sc: Stores order
Note over m,t: Order matching
t ->> sc: AcceptSwapOrder
sc ->> o: MsgExec to call contract
o ->> sc: ConfirmSwapOrder with funds on behalf of Maker
sc ->> m: Send Taker funds
sc ->> t: Send Maker funds
sc->>sc: Update order as completed
This section described the interfaces to interact with the contract.
The instantiation requires only an optional parameter representing the owner of the contract:
{
"owner": "osmo1..."
}
The configuration of the contract can be updated by specifying a new owner:
{
"update_config": {
"new_owner": "osmo1..."
}
}
The creation of the order requires to specify:
coin_in
: the coin that the maker wants to send.coin_out
: the coin that the maker wants to receive.taker
: an optional parameter to allows only a selected user to accept the offer.timeout
: the duration in seconds of the offer.
{
"create_swap_order": {
"coin_in": {
{ "denom": "uosmo", "amount": "1" },
},
"coin_out": {
{ "denom": "uatom", "amount": "1" },
},
"taker": null,
"timeout": 1
}
}
The taker can accept an order by specifying:
order_id
: the identifier of the order.maker
: the maker of the order.
{
"accept_swap_order": {
"order_id": 0,
"maker": "osmo1..."
}
}
Once the contract receive the accept_swap_order
message, it calls into the authz module
which will send, on the behalf of the user the confirmation request specifying:
order_id
: the identifier of the order.maker
: the maker of the order.
{
"confirm_swap_order": {
"order_id": 0,
"maker": "osmo1..."
}
}
Retrieve the contract configuration:
{
"config": {}
}
Retrieve all active orders:
{
"all_swap_orders": {}
}
Retrieve all active orders from a specific maker:
{
"swap_orders_by_maker": {
"maker": "osmo1..."
}
}
These instructions will help you get a copy of the smart contract on your local machine for development and testing purposes.
- CosmWasm
- Rust: Installation Guide
- Command runner: just
-
Clone the repository and move into project directory:
git clone https://github.com/0xstepit/cw-atomic-swap.git cd cw-atomic-swap
-
Build the smart contract:
just optimize
Tests are composed of:
- Unit tests, contained in the file
./src/tests/unit_tests.rs
. - Multitest, contained in the folder
./src/tests/multitest
. - Test-tube contained in the folder
./src/tests/testube
. The execution of these tests requires the previous generation of the optimized.wasm
file.
The multitest setup uses a simple custom implementation of the Stargate
trait to allow to return a general success
response of the message execution and a general error to trigger the reply
entry point of the contract via mock. In this way it has
been possible to tests all ExecuteMsg
separately.
The test-tube setup, on the other hand, uses the Authz
structure to implement the Module
trait of test tube to
tests the smart contract execution against the real chain logic.
just test
just clippy && just fmt
just schema
cw-atomic-swap
is a just a proof of concept and this section describes possible improvements and future works:
- Improve the quality of tests. At the moment just basic scenarios and the main contract flow have been tested. Without
test-tube tests, test coverage is
$84.4%$ . - Improve storage layout to access an order just through the index using `IndexedMaps or other solutions.
- Allow users to cancel offers.
- Tests if due to the atomicity of the execution the code can be cleaned removing some of the validations.
- Give a sense to the config structure allowing to specify a fee or pause the market.
- Allow users to swap multiple coins.
- Tests a factory pattern to see if instantiating a different market for every token can improve UX.
- Support IBC to implement the full ICS20.
Other TODOs have been left in the contract to mark other possible improvements.
This project is licensed under the MIT License - see the LICENSE file for details.