How to use the Totle API

How it works

Steps to integrate with Totle's API

  • Get access
  • Send request
  • Get response
  • Display summary
  • Sign transaction data
  • Submit signed transaction to network
  • Wait to be mined

How Totle works in the background

  • Submit a request to the service specifying which token they would like to buy or sell.
  • Totle then queries through a list of DEXs to find any order that has the potential to fill the request.
    • Orders are retrieved from the database
    • Real-time price discovery
  • The Totle API applies algorithms to the set of discovered orders to find the best combination for the request.

How and what Totle queries

  • Finding Orders - Getting orders from each exchange and determining which ones to execute can be quite difficult since some exchanges operate much differently than others. Totle uses specific queries to optimize this process, here's how:
    • Some DEXs require individual orders to be created, signed, and stored in an orderbook for each exchange. Totle queries these DEXs for all their open orders and then keeps a live updated copy of this orderbook in their own database.
    • Other DEXs act as liquidity providers. Instead of having an orderbook, these DEXs have smart contracts that hold tokens which provides a dynamiclly calculated price based on the ratio of tokens they hold. The hardest part when quering them for prices is that the more tokens requested to trade, the more the price slips and the worse the rate becomes.
    • Lastly, there is a special case. Totle has also integrated with AirSwap. For comparison, AirSwap is similar to the liquidity provider DEXs as there are no prebuilt orders to query. You simply signal an “intent” to make a trade then Totle queries for these intents and then makes a request to trade a token for a certain amount.

Totle then takes all these DEXs and optimizes the process of finding orders to fill the request.

Submitting a request

curl 'https://services.totlesystem.com/suggester' \
-H 'Accept: application/json, text/plain, */*' \
-H 'Content-Type: application/json;charset=UTF-8' \ --data-binary '{"buys":
[

{

"token": "0x9992ec3cf6a55b00978cddf2b27bc6882d88d1ec" "amount": "99999999999"

}

],
"sells":
[

{

"token": "0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2" "amount": "10000000000"

}

],
"address": "0x7EBB71274C871143A8C3Ce56e804837684dDa0aA"
}'

Making a request requires a token address but can also take an array of multiple token addresses, the amounts of each token wanted to trade and a wallet address and lastly, signify if it is a buy or sell request.

Example (request)

```

{

"address": "0xD18CEC4907b50f4eDa4a197a50b619741E921B4D",

"exchanges": { // optional, default: search all exchanges

"list": [ 4, 7 ],

"type": "black" // or "white"

},

"buys": [

{

"token": "0x1985365e9f78359a9b6ad760e32412f4a445e862",

"amount": "1000000000000000000"

}

],

sells": [

{

"token": "0xe41d2489571d322189246dafa5ebde1f4699f498",

"amount": "1000000000000000000",

"isOptional": true, // default: false

"minFillPercent": 85, // default: 100

"minSlippagePercent": 1 // default: 3

}

],

"breakdown": true // Get extra debugging information for each trade

}

```

Example (response)

```

{

"success": true,

"response": {

"contractAddress": "0x55251f1733c0004c3e86ec39893d782c8bc50fe0",

"ethValue": "71817359507015568",

"summary": {

"sells": [

{

"token": "0xe41d2489571d322189246dafa5ebde1f4699f498",

"exchange": "Kyber",

"price": "0.003428358245615946",

"amount": "1000000000000000000",

"fee": "0"

}

],

"buys": [

{

"token": "0x1985365e9f78359a9b6ad760e32412f4a445e862",

"exchange": "AirSwap",

"price": "0.073153949999999993",

"amount": "1000000000000000000",

"fee": "0"

}

]

},

"payload": {

"data":

"0xa4ead2b500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000bd0880d21852c0000000000000000000000000000000000000000000000000bcbce7f1b15000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001400000000000000000000000008ce714e6f9ff6bcd3653af376924e893c2c029ff000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000bd0880d21852c000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000ac025ab3de12c71c244f690d66a96c02e3b479f9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000003310b055015a94a2f2e37014b944d8ca6bd2b845000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000ac025ab3de12c71c244f690d66a96c02e3b479f9000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000c19c55f2848180000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000005c09809b0000000000000000000000000000000000000000000000005ccc9d5a97ea30e4000000000000000000000000000000000000000000000000000000000000001b1c3e4da86760abd197d6923562b6ff463b3bc9fbb87b85aee085884c26403d575a739b5d4b8c7f0745eae0d77e891959f77628699b7111cfe62d141dcc08785c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001985365e9f78359a9b6ad760e32412f4a445e8620000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b803f1f93ae5c31c0000000000000000000000000000000000000000000000000d7621dc5821000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000ac025ab3de12c71c244f690d66a96c02e3b479f9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000001550d41be3651686e1aeeea073d8d403d0bd2e300000000000000000000000001985365e9f78359a9b6ad760e32412f4a445e862000000000000000000000000ac025ab3de12c71c244f690d66a96c02e3b479f900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000103e52143aaabf9000000000000000000000000000000000000000000000000000000005c0980a800000000000000000000000000000000000000000000000000000000032dfb43000000000000000000000000000000000000000000000000000000000000001c35d6bf7c95c1abd38ca47ae5c2c0187fb11983f0ab2ce5412688fb3555d01b4e51c4ed10e43fb5b5867661fcf6191aafa033b601dfaaf2d6dbe6a2c8e2b7e6f8",

"breakdown": [

{

"isSell": true,

"tokenAddress": "0xe41d2489571d322189246dafa5ebde1f4699f498",

"tokenAmount": "1000000000000000000",

"optionalTrade": true,

"minimumExchangeRate": "3325507498247468",

"minimumAcceptableTokenAmount": "850000000000000000",

"orders": [

{

"exchangeHandler": "0x8Ce714e6F9fF6bCD3653AF376924E893c2c029fF",

"genericPayload":

"0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000bd0880d21852c000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"

},

{

"exchangeHandler": "0xAC025aB3de12c71C244f690d66A96c02e3b479f9",

"genericPayload":

"0x0000000000000000000000003310b055015a94a2f2e37014b944d8ca6bd2b845000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000ac025ab3de12c71c244f690d66a96c02e3b479f9000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000c19c55f2848180000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000005c09809b0000000000000000000000000000000000000000000000005ccc9d5a97ea30e4000000000000000000000000000000000000000000000000000000000000001b1c3e4da86760abd197d6923562b6ff463b3bc9fbb87b85aee085884c26403d575a739b5d4b8c7f0745eae0d77e891959f77628699b7111cfe62d141dcc08785c"

}

]

},

{

"isSell": false,

"tokenAddress": "0x1985365e9f78359a9b6ad760e32412f4a445e862",

"tokenAmount": "1000000000000000000",

"optionalTrade": false,

"minimumExchangeRate": "13259707780646159132",

"minimumAcceptableTokenAmount": "970000000000000000",

"orders": [

{

"exchangeHandler": "0xAC025aB3de12c71C244f690d66A96c02e3b479f9",

"genericPayload":

"0x0000000000000000000000001550d41be3651686e1aeeea073d8d403d0bd2e300000000000000000000000001985365e9f78359a9b6ad760e32412f4a445e862000000000000000000000000ac025ab3de12c71c244f690d66a96c02e3b479f900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000103e52143aaabf9000000000000000000000000000000000000000000000000000000005c0980a800000000000000000000000000000000000000000000000000000000032dfb43000000000000000000000000000000000000000000000000000000000000001c35d6bf7c95c1abd38ca47ae5c2c0187fb11983f0ab2ce5412688fb3555d01b4e51c4ed10e43fb5b5867661fcf6191aafa033b601dfaaf2d6dbe6a2c8e2b7e6f8"

}

]

}

]

},

"gas": {

"price": "10000000000",

"strict": false,

"limit": "1360000"

}

}

}

```

Required Parameters

  • `address` string - wallet address
  • `buys` or `sells` array - array of trades
    • `token` string - token address
    • `isOptional` boolean (optional, default *false*) - if trade can be skipped
    • `minFillPercent` number (optional, default *100*) - minimum percent ranges from 1-100 of the `amount` to be filled that is acceptable (some orders fail for whatever reason. In the case of it failing and Totle can still fill some of the orders, this percentage would determine that threshold)

Optional Parameters

  • `exchanges` object
    • `list` array - list of exchange ids
    • `type` string ("white" or "black") - determines if list is a white or black list of exchanges to use
  • `breakdown` boolean - get extra information of token trades

Required Addresses

There is a separate GraphQL endpoint that needs to be called: https://services.totlesystem.com/graph to grab just the addresses, this is the query that needs to be sent:

```

{

tokens {

address

name

symbol

}

}

```

Example response

```

{

"data": {

"tokens": [

{

"address": "0x0371a82e4a9d0a4312f3ee2ac9c6958512891372",

"name": "Student Coin",

"symbol": "STU"

},

{

"address": "0x05f4a42e251f2d52b8ed15e9fedaacfcef1fad27",

"name": "Zilliqa",

"symbol": "ZIL"

},

// ....

]

}

}

```

Example request

```

{

exchanges {

id

name

iconUrl

}

}

```

Example response

```

{

"data": {

"exchanges": [

{

"id": 1,

"name": "EtherDelta",

"iconUrl": "https://s3.amazonaws.com/totle-dex-icons/EtherDelta.png"

},

{

"id": 2,

"name": "Kyber",

"iconUrl": "https://s3.amazonaws.com/totle-dex-icons/Kyber.png"

},

{

"id": 3,

"name": "RadarRelay",

"iconUrl": "https://s3.amazonaws.com/totle-dex-icons/RadarRelay.png"

},

{

"id": 4,

"name": "Bancor",

"iconUrl": "https://s3.amazonaws.com/totle-dex-icons/Bancor.png"

},

{

"id": 5,

"name": "AirSwap",

"iconUrl": "https://s3.amazonaws.com/totle-dex-icons/DEX-AirSwap.png"

},

{

"id": 8,

"name": "Oasis",

"iconUrl": "https://s3.amazonaws.com/totle-dex-icons/DEX-Oasis.png"

},

{

"id": 10,

"name": "weiDex",

"iconUrl": "https://s3.amazonaws.com/totle-dex-icons/DEX-WeiDex.png"

}

]

}

}

```

Understanding the output results

  • ethValue ​- the total amount of Ether (in Wei) that is required to fill all the orders.
  • summary​- gives you details of all the orders that the API has found for you. The summary provides information for each order (buy or sell) including the address of the token contract, the name of the DEX it is from, the amount of the token to be used, the price and any required DEX fees that will be needed to complete the transaction.
  • payload ​- this output returns the formatted data of the orders which are then used as input parameters for our smart contract to execute.
  • contractAddress​- the address of the Totle’s Primary Smart Contract that transactions are sent to.

Example (Buy request)

```

{

"success": true,

"response": {

"contractAddress": "0x55251f1733c0004c3e86ec39893d782c8bc50fe0",

"ethValue": "62805",

"summary": {

"sells": [],

"buys": [

{

"token": "0x1985365e9f78359a9b6ad760e32412f4a445e862",

"exchange": "Ethex",

"price": "0.060976800000000000000000000000",

"amount": "1000000",

"fee": "0"

}

]

},

"payload": {

"data":

"0xa4ead2b500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001985365e9f78359a9b6ad760e32412f4a445e86200000000000000000000000000000000000000000000000000000000000f42400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dcc4351ea1576fb500000000000000000000000000000000000000000000000000000000000ecd1000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000001985365e9f78359a9b6ad760e32412f4a445e862000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000001985365e9f78359a9b6ad760e32412f4a445e86200000000000000000000000000000000000000000000000029a2241af62c00000000000000000000000000000000000000000000000000000289e63ac69ec0000000000000000000000000001360c849d955422994875e99502f6c134eb76a270000000000000000000000000000000000000000000000000000000000000001",

"breakdown": [

{

"isSell": false,

"tokenAddress": "0x1985365e9f78359a9b6ad760e32412f4a445e862",

"tokenAmount": "1000000",

"optionalTrade": false,

"minimumExchangeRate": "15907898189451587509",

"minimumAcceptableTokenAmount": "970000",

"orders": [

{

"exchangeHandler": "0x1985365e9f78359a9b6ad760e32412f4a445e862",

"genericPayload":

"0x0000000000000000000000001985365e9f78359a9b6ad760e32412f4a445e86200000000000000000000000000000000000000000000000029a2241af62c00000000000000000000000000000000000000000000000000000289e63ac69ec0000000000000000000000000001360c849d955422994875e99502f6c134eb76a270000000000000000000000000000000000000000000000000000000000000001"

}

]

}

]

},

"gas": {

"price": "10000000000",

"strict": false,

"limit": "500000"

}

}

}

```

NOTE

  • `payload.data` is the data that needs to be passed with the transaction.
  • `payload.breakdown` gives more info about each trade
  • `gas` is the estimated amount of gas required for the transaction.
    • Example: You must pay gas for a request except if `gas.strict` is true, it means there is an exchange that has a gas price limit that this value should not be changed or the transaction will most likely fail.

Payload

  • How to set up a transaction (payload) 
  • How to initiate a transaction

In response to the above points, to set up a payload and to initiate a transaction you must first construct a transaction and then sign it.

1. How to up a transaction (payload)

Command for signing a transaction:

`web3.eth.personal.signTransaction(transaction, password [, callback])`

Don’t know how to sign a transaction? Click here to learn more

Example (Buy request)

```

{

web3.eth.signTransaction({

from: "0xEB014f8c8B418Db6b45774c326A0E64C78914dC0",

gasPrice: "20000000000",

gas: "21000",

to: '0x3535353535353535353535353535353535353535',

value: "1000000000000000000",

data: ""

}, 'PrivateKey').then(console.log);

> {

raw:

'0xf86c808504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a04f4c17305743700648bc4f6cd3038ec6f6af0df73e31757007b7f59df7bee88da07e1941b264348e80c78c4027afc65a87b0a5e43e86742b8ca0823584c6788fd0',

tx: {

nonce: '0x0',

gasPrice: '0x4a817c800',

gas: '0x5208',

to: '0x3535353535353535353535353535353535353535',

input: '0x',

v: '0x25',

r:

'0x4f4c17305743700648bc4f6cd3038ec6f6af0df73e31757007b7f59df7bee88d',

s:

'0x7e1941b264348e80c78c4027afc65a87b0a5e43e86742b8ca0823584c6788fd0',

hash:

'0xda3be87732110de6c1354c83770aae630ede9ac308d9f7b399ecfba23d923384'

}

}

```

2. How to initiate a transaction

Sending a transaction to the network

`web3.eth.sendTransaction(transactionObject [, callback])`

The `sendTransaction` is the only available function that you can call when you are working with a MetaMask web3 dapp. This is due to the fact that MetaMask restricts access to just sign a transaction object and hold on to it. The `sendTransaction` will take all the passed transaction data, sign a transaction and submit it to the network all at the same time.

The Parameters

1. Object - The transaction object to send:
from - String|Number: The address for the sending account. Uses the web3.eth.defaultAccount property, if not specified. Or an address or index of a local wallet in web3.eth.accounts.wallet.
to - String: (optional) The destination address of the message, left undefined for a contract-creation transaction.
value - Number|String|BN|BigNumber: (optional) The value transferred for the transaction in wei, also the endowment if it’s a contract-creation transaction.
gas - Number: (optional, default: To-Be-Determined) The amount of gas to use for the transaction (unused gas is refunded).
gasPrice - Number|String|BN|BigNumber: (optional) The price of gas for this transaction in wei, defaults to web3.eth.gasPrice.
data - String: (optional) Either a ABI byte string containing the data of the function call on a contract, or in the case of a contract-creation transaction the initialisation code.
nonce - Number: (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.

NOTES

Without the SendTransaction function you would otherwise have to use the `signTransaction` function to get the transaction object and then pass it to `sendSignedTransaction` to submit it to the network.

Example of how it looks:

Compiled solidity source code using http://remix.ethereum.org

```

var code =

"603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b6007600435028060005260206000f3";

```

Using the callback

```

web3.eth.sendTransaction({

from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe',

data: code // deploying a contract

}, function(error, hash){

...

});

Using the promise

```

web3.eth.sendTransaction({

from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe',

to: '0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe',

value: '1000000000000000'

})

.then(function(receipt){

...

});

Using the event emitter

```

web3.eth.sendTransaction({

from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe',

to: '0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe',

value: '1000000000000000'

})

.on('transactionHash', function(hash){

...

})

.on('receipt', function(receipt){

...

})

.on('confirmation', function(confirmationNumber, receipt){ ... })

.on('error', console.error); // If a out of gas error, the second parameter is the receipt.

```

Gas

Can you change the gas limit? Are there consequences of changing the gas limit other than slow transaction speeds or possible failed transaction?

Firstly, it’s important to differentiate between what the gas price does and what the gas limit does. In short, the gas price affects the speed of the mining and is limited by the gas cap on some exchanges, and gas limit is the maximum gas the transaction can use.

The gas value returned from the Totle API is the suggested minimum value of gas to use. A higher gas price can be set, however, if the gas.strict flag is set in the response, we strongly recommend to use the returned value as provided and not change it as the transaction will most likely fail. Our API optimizes the gas values for optimal execution.

Smart Contracts