The code base is only tested regularly with Ubuntu 22.04 on X86-64, but we would like to support most 64-bit Linux distributions, macOS, and WSL on Windows both with X86-64 and ARM processors.
- go 1.21+ (see build instructions to download Go.)
- node/npm (to install ganache, see suggestions after list)
- ganache (can be installed with
npm install --location=global ganache
) - jq, curl, bzip2, realpath
The suggested way to install
node/npm is using nvm. If you install npm using a package manager like snap, ensure
the install prefix (npm config get prefix
) is a directory that you have write
access to without sudo. You can change the directory with this command:
npm config set prefix ~/.npm-packages
See this document if you want a more sophisticated setup.
If you are testing, you'll want jq
installed. curl
and bzip2
are normally
preinstalled, but if you are running in a docker container, you might have to
install them.
sudo apt install curl bzip2 jq
On macOS, you'll need to install realpath
(from the coreutils
package). If you
are using Homebrew, you can use these commands to install all the needed tools:
brew install coreutils go jq nvm bash
nvm install node
npm install --location=global ganache
Note: the scripts/install-monero-linux.sh
script will download the monero binaries needed for you.
You can invoke it directly, but the next script below will run it if there is no symbolic link named
monero-bin
to a monero installation in the project's root directory.
Use this command to launch ganache, an ethereum simulator, and monerod in regtest mode.
"regtest" mode is stand-alone (non-networked) mode of monerod for testing purposes.
Warning: the command below will kill running instances of ganache
, monerod
,
monero-wallet-rpc
or swapd
.
./scripts/setup-env.sh
To avoid confusion, delete any data directories from old runs of swapd
that used
the flags --dev-xmrtaker
or --dev-xmrmaker
:
rm -rf "${TMPDIR:-/tmp}"/xmr[mt]aker-*
You have several options. If you are looking to do production swaps, use one of
the first two release options. All 3 options create swapd
and swapcli
binaries in the bin
directory at the top of the project.
make build-release
make build-release-in-docker
make build
To launch Alice's swapd instance, use this command:
./bin/swapd --dev-xmrtaker --deploy &> alice.log &
We are going to use Alice's instance as a bootnode for Bob's instance. To configure this, we need one of the multi-addresses that Alice is listening on. Alice will be listing both on a TCP port and a UDP/QUIC port, it doesn't matter which one you pick. Use this command to list Alice's listening libp2p multi-addresses:
./bin/swapcli addresses
Assign the value you picked to a variable. Your value will be different, this is just an example below:
BOOT_NODE=/ip4/127.0.0.1/udp/9933/quic-v1/p2p/12D3KooWHRi24PVZ6TBnQJHdVyewDRcKFZtYV3qmB4KQo8iMyqik
Now get the ethereum contract address that Alice deployed to. This can be pulled
from the Alice's logs, or from a version
RPC request.
CONTRACT_ADDR=$(./bin/swapcli version | grep '^swap creator address' | sed 's/.*: //')
Now start Bob's swapd instance:
./bin/swapd --dev-xmrmaker --bootnodes "${BOOT_NODE}" --contract-address "${CONTRACT_ADDR}" &> bob.log &
swapcli
is an executable to interact with a swapd
instance via it's RPC port on the
local host (127.0.0.1
). The current security model of swapd assumes connections
originating from the local host are authorized, so you should not run swapd
for
production swaps on multi-user hosts or hosts with malicious software running on them.
Note: when using the --dev-xmrtaker
and --dev-xmrmaker
flags, Alice's RPC server runs
on http://localhost:5000 (the default port) and Bob's runs on http://localhost:5001. Since
Bob's swapd
RPC port is not the default, you will need to pass --swapd-port 5001
to
swapcli
when interacting with his daemon.
Alice and Bob are both using Ethereum wallet keys that are prefunded by Ganache.
Background Monero mining was started for Bob, because his swapd instance used the
--dev-xmrmaker
flag.
You can check Alice's balance with this command:
./bin/swapcli balances
And Bob's balances with this command:
./bin/swapcli balances --swapd-port 5001
If Bob doesn't have enough balance, you can mine more blocks using:
source scripts/testlib.sh
mine-monero-for-swapd 5001
Next we need Bob to make an offer and advertise it, so that Alice can take it. You will get notified when the swap is taken. This command will block waiting for update messages, so you will need to dedicate a separate terminal for it:
./bin/swapcli make --min-amount 0.1 --max-amount 1 --exchange-rate 0.05 --swapd-port 5001
Example output:
Published:
Offer ID: 0x09dd41c7b8620cdc3716463dc947a11edf3af45ff07c8b0ff89dd23592e732ca
Peer ID: 12D3KooWK7989g6xmAaEsKFPuZTj2CVknRxQuk7dFL55CC1rpEWW
Taker Min: 0.005 ETH
Taker Max: 0.05 ETH
> Stage updated: KeysExchanged
> Stage updated: XMRLocked
> Stage updated: Success
Alternatively, you can make the offer without subscribing to swap updates:
./bin/swapcli make --min-amount 0.1 --max-amount 1 --exchange-rate 0.05 --swapd-port 5001 --detached
Now, Alice can discover peers who have advertised offers.
./bin/swapcli discover --provides XMR --search-time 3
Peer 0: 12D3KooWAE3zH374qcxyFCA8B5g1uMqhgeiHoXT5KKD6A54SGGsp
Query the returned peer to find the range of XMR they are willing to swap and at what exchange rate. Note: You need to update the peer ID below with the one from your output in the previous step.
./bin/swapcli query --peer-id 12D3KooWAE3zH374qcxyFCA8B5g1uMqhgeiHoXT5KKD6A54SGGsp
Offer ID: 0xcc57d3d1b9d8186118f1f1581a8dc4dca0e5aa6c39a5255bd0c2ebb824cfe2eb
Provides: XMR
Min Amount: 0.1
Max Amount: 1
Exchange Rate: 0.05
ETH Asset: ETH
Alice now has the information needed to start a swap with Bob. You'll need Bob's peer ID and his offer ID from the previous step to update the command below:
./bin/swapcli take \
--peer-id 12D3KooWAE3zH374qcxyFCA8B5g1uMqhgeiHoXT5KKD6A54SGGsp \
--offer-id 0xcc57d3d1b9d8186118f1f1581a8dc4dca0e5aa6c39a5255bd0c2ebb824cfe2eb \
--provides-amount 0.05
Initiated swap with offer ID 0xcc57d3d1b9d8186118f1f1581a8dc4dca0e5aa6c39a5255bd0c2ebb824cfe2eb
> Stage updated: ExpectingKeys
> Stage updated: ETHLocked
> Stage updated: ContractReady
> Stage updated: Success
Alternatively, you can take the offer without subscribing to swap updates:
./bin/swapcli take \
--peer-id 12D3KooWAE3zH374qcxyFCA8B5g1uMqhgeiHoXT5KKD6A54SGGsp \
--offer-id 0xcc57d3d1b9d8186118f1f1581a8dc4dca0e5aa6c39a5255bd0c2ebb824cfe2eb \
--provides-amount 0.05 --detached
If all goes well, you should see Alice and Bob successfully exchange messages and execute the swap protocol.
To query the information for an ongoing swap, you can run:
./bin/swapcli ongoing --offer-id <id>
To query information for a past swap using its ID, you can run:
./bin/swapcli past --offer-id <id>
For both of these commands, if no --offer-id
is passed, all ongoing or past swaps will be returned.