# How to Exchange Tokens
Any token issued on the Waves blockchain can be exchanged to another on a decentralized exchange. When you submit an order to a matcher (exchange engine), you do not transfer your tokens to the exchange: they remain on your account until the matcher executes the order and creates the exchange transaction. The blockchain guarantees that the terms of the exchange will be no worse than those specified in the order. See details in the Order article.
An example of a decentralized exchange is the WX Network application developed by the third-party team from the community.
WX Network does not support the exchange of NFTs and smart assets.
# Create Order
# Using WX Network
You can use online, desktop or mobile app. See the Start Trading on WX Network article in the WX Network Help Center.
# Using CCXT
CCXT (CryptoCurrency eXchange Trading) is a JavaScript/Python/PHP library for cryptocurrency trading and quick access to market data. It supports over 100 exchanges, including WX Network.
Exchange using CCXT is only available for recommended token pairs. To exchange any token pairs, use other client libraries — see examples below.
For more information about using CCXT, see the CCXT for WX Network article of the WX Network documentation.
# Using JavaScript
# Set Matcher Params
Use the following matcher URL:
- Testnet: https://matcher-testnet.wx.network
- Mainnet: https://matcher.wx.network
Use the GET /matcher
method of matcher API to retrieve matcher public key.
# Set Asset Pair
An asset pair consists of two assets you want to exchange: amount asset and price asset. Under the order, you can either sell or buy the amount asset for the price asset.
You can see asset pairs and asset IDs on the Trading page of WX Network on Mainnet and on Testnet. The first asset in pair is the amount asset and the second one is the price asset.
You can also get asset pairs using GET /matcher/orderbook
or GET /matcher/settings
API methods. For more information, see the Matcher API article of the WX Network documentation.
Asset IDs differ on Mainnet and Testnet.
WAVES, the core token of Waves blockchain, doesn't have an asset ID, use 'WAVES' instead.
# Set Orders Fields, Sign Order and Send to Matcher
Use functions of waves-transactions
library:
order
function creates and signs an order. Order proof is derived from seed.submitOrder
sends the signed order to matcher.
See function descriptions in waves-transactions documentation on Github.
The matcher fee for the order can be obtained using the POST /matcher/orderbook/{amountAsset}/{priceAsset}/calculateFee
method of the matcher API. Depending on the assets pair, the fee can be fixed or percentage. For details, see the Matcher Fee article of the WX Network documentation.
import { order, submitOrder } from '@waves/waves-transactions';
import fetch from 'node-fetch';
const seed = 'insert your seed here';
const matcherUrl = 'https://matcher-testnet.wx.network';
// For Mainnet, specify 'https://matcher.wx.network'
const matcherPublicKey = '8QUAqtTckM5B8gvcuP7mMswat9SjKUuafJMusEoSn1Gy';
// For Mainnet, specify '9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5'
const amountAssetId = 'WAVES';
const priceAssetId = '25FEqEjRkqK6yCkiT7Lz6SAYz7gUFCtxfCChnrVFD5AT'; // XTN on Testnet
// For Mainnet, specify 'DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p'
// Actual amount of amount asset multiplied by 10^amountAssetDecimals
const amount = 100000000; // 1 WAVES
// Actual price denominated in priceAsset and multiplied by 10^(8 + priceAssetDecimals – amountAssetDecimals)
const price = 9500000; // 9.5 XTN for 1 WAVES
// Obtain matcher fee based on order params
let response = await fetch(matcherUrl + '/matcher/orderbook/'
+ amountAssetId + '/' + priceAssetId + '/calculateFee',
{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ orderType: 'buy', amount: amount, price: price })
});
if (!response.ok) console.log("Failed to obtain the order fee");
let fee = await response.json();
let orderParams = {
amount: amount,
price: price,
amountAsset: amountAssetId,
priceAsset: priceAssetId,
matcherPublicKey: matcherPublicKey,
orderType: 'buy',
version: 3,
matcherFee: fee.base.matcherFee,
matcherFeeAssetId: fee.base.feeAssetId
}
const signedOrder = order(orderParams, seed);
await submitOrder(signedOrder, matcherUrl);
let orderId = signedOrder.id;
console.log('Order ID: '+ orderId);
# Using Python
The matcher fee for the order can be obtained using the POST /matcher/orderbook/{amountAsset}/{priceAsset}/calculateFee
method of the matcher API. Depending on the assets pair, the fee can be fixed or percentage. For details, see the Matcher Fee article of the WX Network documentation.
import pywaves as pw
import requests
pw.setNode('https://nodes-testnet.wavesnodes.com', chain = 'testnet')
# For Mainnet: pw.setNode()
pw.setMatcher('https://matcher-testnet.wx.network')
# For Mainnet: pw.setMatcher()
waves = 'WAVES'
xtn = '25FEqEjRkqK6yCkiT7Lz6SAYz7gUFCtxfCChnrVFD5AT' # XTN on Testnet
# For Mainnet, specify 'DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p'
asset_pair = pw.AssetPair(pw.Asset(waves), pw.Asset(xtn))
# Actual amount of amount asset multiplied by 10^amountAssetDecimals
amount = 100_000_000 # 1 WAVES
price = 9.5 # 9.5 XTN for 1 WAVES
# Actual price denominated in priceAsset and multiplied by 10^(8 + priceAssetDecimals – amountAssetDecimals)
norm_price = 9_500_000
# Obtain matcher fee based on order params
matcher_fee = requests.post(f'{pw.MATCHER}/matcher/orderbook/{waves}/{xtn}/calculateFee',
headers = { 'Accept': 'application/json' },
json = { 'orderType': 'buy', 'amount': amount, 'price': norm_price }
).json()['base']['matcherFee']
my_address = pw.Address(seed = 'insert your seed here')
buy_order = my_address.buy(asset_pair, amount = amount, price = price,
matcherFee = matcher_fee, matcherFeeAssetId = xtn)
print(f'Buy order ID: {buy_order.orderId}')
# Get Order Status
# Using WX Network
The submitted order is displayed on the My Open Orders tab (Online & Desktop app) or on the My Orders tab (Mobile) until it is completed.
# Using Matcher API
To get order status, you need to know order ID and asset pair. Use GET /matcher/orderbook/{amountAsset}/{priceAsset}/{orderId}
method. Status is returned for orders submitted not earlier than 30 days ago. For partially filled orders, the method aslo returns filled amount.
See method description in Matcher API article of the WX Network documentation.
Request example:
curl 'https://matcher-testnet.wx.network/matcher/orderbook/WAVES/3KFXBGGLCjA5Z2DuW4Dq9fDDrHjJJP1ZEkaoajSzuKsC/9kRXfmrhWhsGBohygMoo91RgcnmJUB37K4rQQN4rEidT'
The example is suitable for the cURL
utility. You can adjust the proposed request to your app written in any programming language.
# Using JavaScript
const matcherUrl = 'https://matcher-testnet.wx.network';
const amountAssetId = 'WAVES';
const priceAssetId = '25FEqEjRkqK6yCkiT7Lz6SAYz7gUFCtxfCChnrVFD5AT'; // XTN on Testnet
// For Mainnet, specify 'DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p'
const orderId = '9kRXfmrhWhsGBohygMoo91RgcnmJUB37K4rQQN4rEidT';
let response = await fetch(matcherUrl + '/matcher/orderbook/' + amountAsset + '/' + priceAsset + '/' + orderId);
let json = await response.json();
console.log('Order status: ' + json.status);
# Using Python
# Using the order from the previous example
print(buy_order.status())
# Cancel Order
You can cancel previously submitted order if it's not already filled completely.
# Using WX Network
You can cancel an order:
- In Online or Desktop app: click Cancel on the My Open Orders tab.
- In Mobile app: tap X on the My orders tab.
# Using JavaScript
The request to cancel the order must be signed by the order sender.
Use functions of waves-transactions
library:
cancelOrder
function creates and signs cancel order request.cancelSubmittedOrder
sends signed request to matcher.
See function descriptions in waves-transactions documentation on Github.
Example:
import {cancelOrder, cancelSubmittedOrder } from "@waves/waves-transactions";
const matcherUrl = 'https://matcher-testnet.wx.network';
const amountAssetId = 'WAVES';
const priceAssetId = '25FEqEjRkqK6yCkiT7Lz6SAYz7gUFCtxfCChnrVFD5AT'; // XTN on Testnet
// For Mainnet, specify 'DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p'
const seed = 'insert your seed here';
const orderId= '9kRXfmrhWhsGBohygMoo91RgcnmJUB37K4rQQN4rEidT';
const co = cancelOrder({ orderId: orderId }, seed);
const canceledOrder = await cancelSubmittedOrder(co, amountAsset, priceAsset, matcherUrl);
console.log(canceledOrder.status);
# Using Python
# Using the order from the previous example
buy_order.cancel()
# Get Order List
# Using WX Network
Your orders are displayed on the My Open Orders and My Order History tabs (Online & Desktop app) or on the My Orders tab (Mobile) until it is completed.
# Using JavaScript
To get the list of orders that are placed by account use the GET /matcher/orderbook/{publicKey}
method. See method description in Matcher API article of WX Network documentation.
In the request header, you should specify the signature of the byte array that consists of bytes of the public key and bytes of the current timestamp. The signature is generated by the signBytes function using account seed.
import { libs } from '@waves/waves-transactions';
const matcherUrl = 'https://matcher-testnet.wx.network';
const seed = 'insert your seed here';
const { LONG, BASE58_STRING } = libs.marshall.serializePrimitives;
const getOrdersApiSignature = (seed, senderPublicKey, timestamp) => {
const pBytes = BASE58_STRING(senderPublicKey);
const timestampBytes = LONG(timestamp);
const bytes = Uint8Array.from([
...Array.from(pBytes),
...Array.from(timestampBytes),
]);
return libs.crypto.signBytes(seed, bytes);
};
const timestamp = Date.now();
const senderPublicKey = libs.crypto.publicKey(seed);
const signature = getOrdersApiSignature(seed, senderPublicKey, timestamp);
const url = `${matcherUrl}/matcher/orderbook/${senderPublicKey}`; // Append ?activeOnly=true to receive active orders only
let response = await fetch(url, {
headers: {
"Timestamp": timestamp,
"Signature": signature
}
});
let json = await response.json();
console.table(json);
# Using Python
To get order list by a certain asset pair and account public key use the getOrderHistory
function of the PyWaves library.
import pywaves as pw
my_address = pw.Address(seed='insert your seed here')
pw.setNode('https://nodes-testnet.wavesnodes.com', chain = 'testnet')
# For Mainnet: pw.setNode()
pw.setMatcher('https://matcher-testnet.wx.network')
# For Mainnet: pw.setMatcher()
waves = 'WAVES'
xtn = '25FEqEjRkqK6yCkiT7Lz6SAYz7gUFCtxfCChnrVFD5AT' # XTN on Testnet
# For Mainnet, specify 'DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p'
asset_pair = pw.AssetPair(pw.Asset(waves), pw.Asset(xtn))
my_orders = my_address.getOrderHistory(asset_pair)