This document is a brief description of the swap flow, with examples, using the Junction API.
Entry point and graphQL playground: https://router-dev.junction.exchange/graphql
The swap flow is a sequence of queries and mutations.
Check all available assets or search for a specific token
The tokenFilterV5 query allows you to search for a crypto asset by symbol, name, address or chain. If no “search phrase” provided, a paginated list of assets is returned. This is a good way to check all of the supported assets.
// Example code to search tokens
const query = `
query TokenFilterV5 {
routingV2 {
tokenFilterV5(searchPhrase: "COIN", limit: 2) {
tokens {
name
symbol
chainSymbol
cryptoAsset {
id
name
symbol
chain
decimals
contract
}
}
}
}
}
`;
fetch('<https://router-dev.junction.exchange/graphql>', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query })
})
.then(res => res.json())
.then(data => console.log(data));
Output:
{
"data": {
"routingV2": {
"tokenFilterV5": {
"tokens": [
{
"name": "TONCOIN",
"symbol": "TONCOIN",
"chainSymbol": "BSC",
"cryptoAsset": {
"id": "91d36892-8bfa-4b6e-a91c-6c9dc4f0fdc4",
"name": "Toncoin",
"symbol": "TON",
"chain": "BinanceSmartChain",
"decimals": 9,
"contract": "0x76a797a59ba2c17726896976b7b3747bfd1d220f"
}
},
{
"name": "TONCOIN",
"symbol": "TONCOIN",
"chainSymbol": "ETH",
"cryptoAsset": {
"id": "91d36892-8bfa-4b6e-a91c-6c9dc4f0fdc4",
"name": "Toncoin",
"symbol": "TONCOIN",
"chain": "Ethereum",
"decimals": 9,
"contract": "0x582d872a1b094fc48f5de31d3b73f2d9be47def1"
}
}
]
}
}
}
}
Once you find tokens to swap, one can get a quote via the routeV7 query. A few parameters are required like a list of addresses by chain, the amount and tokens to swap…
// Example code to get swap route and quote
const query = `
query RouteV7($srcToken: String!, $destToken: String!, $addresses: [AddressRouteInputTypeV2!]!, $destAddress: String!, $infiniteApproval: Boolean, $slippage: String, $amountSource: String) {
routingV2 {
routeV7(srcToken: $srcToken, destToken: $destToken, addresses: $addresses, destAddress: $destAddress, infiniteApproval: $infiniteApproval, slippage: $slippage, amountSource: $amountSource) {
... on RouteTypeV5 {
addresses {
chain
address
}
destAddress
priceRate
priceRateText
slippage
autoSlippageEnabled
estimatedExecutionTime
maxExecutionTime
gasPrices
priceImpact
amountIn
approvalInfiniteFlag
tradesRoute {
provider {
id
name
time
icon
}
amountIn
amountOut
minAmountReceived
assetIn {
id
chainSymbol
asset {
decimals
symbol
chain
contract
price {
amount
}
}
listProviders
}
assetOut {
id
chainSymbol
asset {
decimals
symbol
chain
contract
}
listProviders
}
fee {
networkFeeDollar
networkFeeAsset
inboundFeeDollar
inboundFeeAsset
swapFee
feeRateTransaction
xdefiSwapFee
xdefiSwapFeeDollar
}
priceRateUsdAssetOut
priceRateUsdAssetIn
tradeType
referral {
medium
link
}
reward {
asset {
id
chainSymbol
asset {
chain
contract
}
listProviders
}
amount
amountUsd
}
isStreaming
}
errorBuildingRoute
feeTier
quoteOrigin
}
... on RouteNotAvailableV2 {
label
reason
}
}
}
}
`;
const vars = `
{
"srcToken": "ETH.ETH",
"destToken": "ETH.USDC",
"addresses": [
{
"address": "0x6bE3FeDC542904fB25B7b76b247e47248c0F9Ff2",
"chain": "ETH"
}
],
"destAddress": "0x6bE3FeDC542904fB25B7b76b247e47248c0F9Ff2",
"infiniteApproval": false,
"slippage": "1.5",
"amountSource": "1"
}
`;
fetch('<https://router-dev.junction.exchange/graphql>', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: query, variables: vars })
})
.then(res => res.json())
.then(data => console.log(data));
Output:
{
"data": {
"routingV2": {
"routeV7": {
"addresses": [
{
"chain": "ETH",
"address": "0x6bE3FeDC542904fB25B7b76b247e47248c0F9Ff2"
}
],
"destAddress": "0x6bE3FeDC542904fB25B7b76b247e47248c0F9Ff2",
"priceRate": "2611.7006220287599533103352390000000000000000",
"priceRateText": "1 ETH = 2611.700622 USDC",
"slippage": "1.5",
"autoSlippageEnabled": false,
"estimatedExecutionTime": 60,
"maxExecutionTime": 60,
"gasPrices": {},
"priceImpact": "-1.00%",
"amountIn": "1.0000000000000000000000000000000000000000",
"approvalInfiniteFlag": false,
"tradesRoute": [
{
"provider": {
"id": "5f15f329-ebf2-4dd9-b350-f20d26a2b633",
"name": "0x",
"time": "60",
"icon": "<https://assets.website-files.com/640bf70a17d12b42d97a052b/641a0fd580cd8c857eef8cb7_0x-logo-light.svg>"
},
"amountIn": "1.0000000000000000000000000000000000000000",
"amountOut": "2585.7056150000000000000000000000000000000000",
"minAmountReceived": "2546.9200307750000000000000000000000000000000",
"assetIn": {
"id": "bfb420ba-31d9-491f-9de2-7507fa6c6341",
"chainSymbol": "ETH",
"asset": {
"decimals": 18,
"symbol": "ETH",
"chain": "Ethereum",
"contract": null,
"price": {
"amount": "2619.68"
}
},
"listProviders": [
"OpenOceanV4",
"Socket",
"Squid",
"SwapKit",
"0x"
]
},
"assetOut": {
"id": "7f139aeb-17ae-4e98-a745-4dc6ec48796a",
"chainSymbol": "ETH",
"asset": {
"decimals": 6,
"symbol": "USDC",
"chain": "Ethereum",
"contract": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
},
"listProviders": [
"OpenOceanV4",
"Socket",
"Circle",
"Squid",
"SwapKit",
"0x"
]
},
"fee": {
"networkFeeDollar": "3.8835919300280000000000000000000000000000",
"networkFeeAsset": "3.8843960000000000000000000000000000000000",
"inboundFeeDollar": "5.6546761418652080473380000000000000000000",
"inboundFeeAsset": "0.0021655801030443205500000000000000000000",
"swapFee": "9.5382680718932080473380000000000000000000",
"feeRateTransaction": "12.8700000000000000000000000000000000000000",
"xdefiSwapFee": "0.000000",
"xdefiSwapFeeDollar": "0E-12"
},
"priceRateUsdAssetOut": "0.9997930000000000000000000000000000000000",
"priceRateUsdAssetIn": "2611.1600000000000000000000000000000000000000",
"tradeType": "SWAP",
"referral": {
"medium": null,
"link": null
},
"reward": null,
"isStreaming": false
}
],
"errorBuildingRoute": null,
"feeTier": 0,
"quoteOrigin": null
}
}
}
}
In order to validate the quote, the generated route needs to be sent to Junction via the transactionsV4 mutation. As result, a route Id is returned.
// Example code to validate route
const mutation = `
mutation transactionsV4($routeData: RouteInputTypeV4!) {
transactionsV4(routeData: $routeData) {
routeId
}
}
`;
// Paste contents of previous step here
const vars = `
{
"routeData": {
"addresses": [{}],
"destAddress: ""
}`;
fetch('<https://router-dev.junction.exchange/graphql>', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: mutation, variables: vars })
})
.then(res => res.json())
.then(data => console.log(data));
Output:
{
"data": {
"transactionsV4": {
"routeId": "669672ea-6d98-440a-94ad-bd7321998bd0"
}
}
}
This route Id will be used to generate transaction data to sign and broadcast in order to execute the swap or bridge. The query for that is tradesV2.
// Example code to fetch tx data
const query = `
query tradesV2 {
routingV2 {
tradesV2(routeId: "669672ea-6d98-440a-94ad-bd7321998bd0") {
transaction {
chain
amount
signer
recipient
feeRate
txType
tradeId
routeId
gasPrice
data
unsignedStdTx
gasLimit
memo
actions
signerId
receiverId
isMultiSig
}
tradeRoute {
provider {
id
name
time
icon
}
amountIn
amountOut
minAmountReceived
assetIn {
id
chainSymbol
asset {
contract
chain
}
isHotNewToken
listProviders
}
assetOut {
id
chainSymbol
asset {
chain
contract
}
isHotNewToken
listProviders
}
fee {
networkFeeDollar
networkFeeAsset
inboundFeeDollar
inboundFeeAsset
swapFee
feeRateTransaction
xdefiSwapFee
xdefiSwapFeeDollar
}
priceRateUsdAssetOut
priceRateUsdAssetIn
tradeType
isStreaming
}
routeId
tradeId
status {
status
txHash
}
}
}
}
`;
fetch('<https://router-dev.junction.exchange/graphql>', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query })
})
.then(res => res.json())
.then(data => console.log(data));
Output:
{
"data": {
"routingV2": {
"tradesV2": [
{
"transaction": {
"chain": "ETH",
"amount": "1000000000000000000",
"signer": "0x6bE3FeDC542904fB25B7b76b247e47248c0F9Ff2",
"recipient": "0x0000000000001fF3684f28c67538d4D072C22734",
"feeRate": "6730113172",
"txType": "SWAP",
"tradeId": "365",
"routeId": null,
"gasPrice": "6730113172",
"data": "0x2213bc0b0000000000000000000000005418226af9c8d5d287a78fbbbcd337b86ec07d6100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000005418226af9c8d5d287a78fbbbcd337b86ec07d6100000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000005a41fff991f0000000000000000000000006be3fedc542904fb25b7b76b247e47248c0f9ff2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000097dc6ee500000000000000000000000000000000000000000000000000000000000000a04b2b29c389f0adf5dd1d463100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000002e00000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000010438c9c147000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000000000000000000000000000000000000000002710000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000024d0e30db00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e48d68a1560000000000000000000000005418226af9c8d5d287a78fbbbcd337b86ec07d61000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002cc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2010001f4a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064c876d21d000000000000000000000000f5c4f3dc02c3fb9279495a8fef7b0741da956157000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000009a6c21af00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012438c9c147000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000044a9059cbb000000000000000000000000ad01c20d5886137e056775af56915de824c8fce50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"unsignedStdTx": null,
"gasLimit": "487372",
"memo": null,
"actions": null,
"signerId": null,
"receiverId": null,
"isMultiSig": false
},
"tradeRoute": {
"provider": {
"id": "5f15f329-ebf2-4dd9-b350-f20d26a2b633",
"name": "0x",
"time": "60",
"icon": "<https://assets.website-files.com/640bf70a17d12b42d97a052b/641a0fd580cd8c857eef8cb7_0x-logo-light.svg>"
},
"amountIn": "1.0000000000000000000000000000000000000000",
"amountOut": "2585.7056150000000000000000000000000000000000",
"minAmountReceived": "2546.9200307750000000000000000000000000000000",
"assetIn": {
"id": "bfb420ba-31d9-491f-9de2-7507fa6c6341",
"chainSymbol": "ETH",
"asset": {
"contract": null,
"chain": "Ethereum"
},
"isHotNewToken": false,
"listProviders": [
"OpenOceanV4",
"Socket",
"Squid",
"SwapKit",
"0x"
]
},
"assetOut": {
"id": "7f139aeb-17ae-4e98-a745-4dc6ec48796a",
"chainSymbol": "ETH",
"asset": {
"chain": "Ethereum",
"contract": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
},
"isHotNewToken": false,
"listProviders": [
"OpenOceanV4",
"Socket",
"Circle",
"Squid",
"SwapKit",
"0x"
]
},
"fee": {
"networkFeeDollar": "3.8835919300280000000000000000000000000000",
"networkFeeAsset": "3.8843960000000000000000000000000000000000",
"inboundFeeDollar": "5.6546761418652080473380000000000000000000",
"inboundFeeAsset": "0.0021655801030443205500000000000000000000",
"swapFee": "9.5382680718932080473380000000000000000000",
"feeRateTransaction": "12.0000000000000000000000000000000000000000",
"xdefiSwapFee": "0.000000",
"xdefiSwapFeeDollar": "0E-12"
},
"priceRateUsdAssetOut": "0.9997930000000000000000000000000000000000",
"priceRateUsdAssetIn": "2611.1600000000000000000000000000000000000000",
"tradeType": "SWAP",
"isStreaming": false
},
"routeId": "669672ea-6d98-440a-94ad-bd7321998bd0",
"tradeId": "365",
"status": {
"status": null,
"txHash": null
}
}
]
}
}
}
Once the transaction in data.routingV2.tradesV2.transaction.data is signed and broadcast by the user, the transaction hash needs to be passed to Junction’s API to track its progress. The transactionHashV3 mutation allows that.
// Example code to search tokens
const mutation = `
mutation TransactionHashV3($routeId: String!, $tradeId: String!, $transactionHash: String!, $accountId: String!) {
transactionHashV3(routeId: $routeId, tradeId: $tradeId, transactionHash: $transactionHash, accountId: $accountId)
}
`;
const vars = `
{
"routeId": "669672ea-6d98-440a-94ad-bd7321998bd0",
"tradeId": "365",
"transactionHash": "0xa4a03447154f2387cb7986b0ba05a30fd18aecb5d8de19f4fc46149fcb4dad75",
"accountId": "junction:0x6bE3FeDC542904fB25B7b76b247e47248c0F9Ff2"
}
`;
fetch('<https://router-dev.junction.exchange/graphql>', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: mutation, variables: vars })
})
.then(res => res.json())
.then(data => console.log(data));
Output:
{
"data": {
"transactionHashV3": "Success"
}
}
After the hash is posted, one can track transaction status by calling tradesV2 query until the status is SUCCESS.