balancednetwork / balanced-network-interface

An open-source interface for the Balanced Network protocol (https://balanced.network)
https://app.balanced.network/
23 stars 22 forks source link

Documentation needed for aggregators #1428

Open FezBox opened 2 months ago

FezBox commented 2 months ago

we need to get updated documentation for use to get on aggregator services. A lot of what we need is inside your brains hehe

can we please document all the the below asap please The following is information relevant to dex aggregators that is being added to a new page called “DEX Aggregator Integration” on docs.balanced.network

FAQ

POST requests are submitted to source chain and propagated to the destination chain thru ICON chain.

GET requests are submitted to ICON chain. ICON integration is useful for swapping native ICON assets but not necessary beyond that.

also a few more things

can you please look at this form and document everything we need in this link that we know https://forms.fillout.com/t/xrsvjHm85Hus

hetfly commented 2 months ago

@FezBox

  • Instructions for programmatically querying routes and prices
    • Instructions for programmatically querying a pool and submitting transactions to it

I don't think this is a matter of documenting as of now. This functionality is not accessible outside of Balanced frontend app context. It needs to be extracted to a standalone package or a backend service, which is not a trivial task.

CyrusVorwald commented 2 months ago

Hey @hetfly , @FidelVe was able to write about programmatically querying prices and pools here https://docs.balanced.network/dex-aggregator.

To my understanding, the rest is possible too from calling the DEX contract or some endpoint. Otherwise I'm not sure I see how the frontend would be able to do it either.

FidelVe commented 2 months ago

the execution of a swap is initiated by a contract call on the ICON chain, what we want to know is how to create the payload of that call and explain the steps, basically what information do we need to be able to create the transaction calls that initiates the swap.

here are a couple of examples:

example 1:

The following is a swap between sICX and bnUSD: https://tracker.icon.community/transaction/0xe360d39a6daa7d7228de00e8616a783d289bafe87ca7b509315a42dbbf45f899

The amount of sICX sent for the swap was 1723.9820658217857 ( in hex "0x5d750eaad103a369d9")

the transaction called the transfer method of the sICX token smart contract, with the following payload

{
    "method": "transfer",
    "params": {
        "_data": "0x7b226d6574686f64223a225f73776170222c22706172616d73223a7b22746f546f6b656e223a22637838386664376466376464666638326637636337333563383731646335313938333863623233356262222c226d696e696d756d52656365697665223a22333038353236353631383738363534383137323436222c2270617468223a5b22637838386664376466376464666638326637636337333563383731646335313938333863623233356262225d2c227265636569766572223a22687830653034306438646637656664353738343239396566333438366237313838313738623461386337227d7d",
        "_to": "cx21e94c08c03daee80c25d8ee3ea22a20786ec231",
        "_value": "0x5d750eaad103a369d9"
    }
}

the receiver was the contract cx21e94c08c03daee80c25d8ee3ea22a20786ec231 which is the balance router contract.

decoding the _data field we get the following:

{
  "method": "_swap",
  "params": {
    "toToken": "cx88fd7df7ddff82f7cc735c871dc519838cb235bb",
    "minimumReceive": "308526561878654817246",
    "path": [
      "cx88fd7df7ddff82f7cc735c871dc519838cb235bb"
    ],
    "receiver": "hx0e040d8df7efd5784299ef3486b7188178b4a8c7"
  }
}

For this case it seems pretty straightforward, the steps to initiate a swap between sICX and bnUSD are:

It looks simple enough, the only thing I dont know yet is how to calculate the minimuReceive value

example 2

The following is a swap from ICX to bnUSD for an amount of 480 ICX https://tracker.icon.community/transaction/0x41faf6b36cf8ab2dc9c580c8f3fa708dc8a38f6e2fbc9232debeaf77bc759650

In this case what is being called is the method routeV2 of the balanced router contract (cx21e94c08c03daee80c25d8ee3ea22a20786ec231)

The JSON RPC payload is the following:

{
    "method": "routeV2",
    "params": {
        "_minReceive": "0x36a2512d49f1fad7c",
        "_path": "f0d70195012609b924e33ef00b648a409245c7ea394c467824d701950188fd7df7ddff82f7cc735c871dc519838cb235bb",
        "_receiver": "hx9fa9d224306b0722099d30471b3c2306421aead7"
    }
}

the _receiver is the same wallet that initiated the transaction (since is a swap the sender sends ICX and receives bnUSD) the _minReceive I still dont know how to calculate and the _path field is a complete mystery to me, the only thing I was able to piece together is that is was encoded using RLP and this is the decoded string

[
  [ '01', '012609b924e33ef00b648a409245c7ea394c467824' ],
  [ '01', '0188fd7df7ddff82f7cc735c871dc519838cb235bb' ]
]

How do we create the values in this RLP encoded hex string?

Conclusion

We are working on growing Balanced, one part of that process is having well documented how to do all of these stuffs, even if we create a library that will make this easy to execute (which is something that we will have to eventually create) we still are going to be needing to have these things documented in detail somewhere

hetfly commented 2 months ago

Hey @CyrusVorwald

To my understanding, the rest is possible too from calling the DEX contract or some endpoint.

Yeah, you're right of course. You can manually query the contracts from the frontend. What I meant is that we are missing an sdk / api abstraction accessible to others.

Hey @FidelVe thanks, I understand now. I'll try to answer some of those question later today.

CyrusVorwald commented 2 months ago

These are accessible by anyone without any additional layers of abstraction. Please answer with how it is done currently, not considering additional abstraction.

hetfly commented 2 months ago

@FidelVe I hope this helps. Feel free to DM me on the Discord with any additional questions.

Determining the trade route

Trade route contains token contracts through which the trade hops, ending on the last token contract, being the swap currency output. For trades ending in ICX, the trade route ends with null item.

  1. Get all common pairs(*) for currncyIn and currencyOut https://github.com/balancednetwork/balanced-network-interface/blob/master/apps/web/src/store/swap/trade.ts#L13
  2. Determine the best swap route using the common pairs (the best swap route gives the highest output currency amount) https://github.com/balancednetwork/balanced-network-interface/blob/master/apps/web/src/store/swap/trade.ts#L54

(*) Pair info is fetched from the DEX contract: getPoolStatsForPair on cxa0af3165c08318e988cb30993b3048335b94af6c


Determining price and _minReceive

Price and currency output amount are derived during the route selection, https://github.com/balancednetwork/v1-sdk/blob/main/src/entities/trade.ts#L86

Determining _minReceive is just getting the currency output amount and applying user set slippage tolerance to it. Default slippage tolerance is set to half a percent.


Getting RLP encoded data

Here is a function that encodes the swap data to RLP format https://github.com/balancednetwork/balanced-network-interface/blob/master/apps/web/src/lib/xcall/utils.ts#L27


With the route, minReceive and RLP encoding described above, you should have everything needed for ICON-ICON swaps.

For ICON-SPOKE swaps, only difference is adding _receiver param with network address, so for arbitrum for example: 0xa4b1.arbitrum /0xE1598501d3ec2b0094eDc14487b01eB042919c2F, which is networkID/address or networkID/contract

List of network Ids:

  '0x1.icon': icon,
  'archway-1': archway,
  '0xa4b1.arbitrum': arbitrum,
  '0xa86a.avax': avalanche,
  '0x100.icon': havah,
  '0x38.bsc': bsc,
  '0x2105.base': base,
  'injective-1': injective

For SPOKE-ICON and SPOKE-SPOKE, its a bit more complicated, there are 3 different types.

Swapping:

  1. native asset - depositNative method on spoke Asset Manager contract (for ETH on arbitrum, AVAX on avalanche)
  2. assetManager asset - deposit method on spoke Asset Manager contract (for ETH on BNB chain, sARCH on Archway)
  3. crosschain token - crossTransfer method on token contract address (currently only for bnUSD, will be the case for sICX and BALN, as well)

For EVM chains, here is a code for initiating the swap transaction https://github.com/balancednetwork/balanced-network-interface/blob/master/apps/web/src/xwagmi/xchains/evm/EvmXWalletClient.ts#L56


Only difference between SPOKE-ICON and SPOKE-SPOKE is again the receiver network address.


Note that swaps ending or starting on a SPOKE chain consists of multiple xCall transactions, user however must sign only the initial transaction, the rest is executed automatically by the Balanced contracts.

FidelVe commented 2 months ago

@FidelVe I hope this helps. Feel free to DM me on the Discord with any additional questions.

Determining the trade route

Trade route contains token contracts through which the trade hops, ending on the last token contract, being the swap currency output. For trades ending in ICX, the trade route ends with null item.

1. Get all common pairs(*) for currncyIn and currencyOut https://github.com/balancednetwork/balanced-network-interface/blob/master/apps/web/src/store/swap/trade.ts#L13

2. Determine the best swap route using the common pairs (the best swap route gives the highest output currency amount) https://github.com/balancednetwork/balanced-network-interface/blob/master/apps/web/src/store/swap/trade.ts#L54

(*) Pair info is fetched from the DEX contract: getPoolStatsForPair on cxa0af3165c08318e988cb30993b3048335b94af6c

Determining price and _minReceive

Price and currency output amount are derived during the route selection, https://github.com/balancednetwork/v1-sdk/blob/main/src/entities/trade.ts#L86

Determining _minReceive is just getting the currency output amount and applying user set slippage tolerance to it. Default slippage tolerance is set to half a percent.

Getting RLP encoded data

Here is a function that encodes the swap data to RLP format https://github.com/balancednetwork/balanced-network-interface/blob/master/apps/web/src/lib/xcall/utils.ts#L27

With the route, minReceive and RLP encoding described above, you should have everything needed for ICON-ICON swaps.

For ICON-SPOKE swaps, only difference is adding _receiver param with network address, so for arbitrum for example: 0xa4b1.arbitrum /0xE1598501d3ec2b0094eDc14487b01eB042919c2F, which is networkID/address or networkID/contract

List of network Ids:

  '0x1.icon': icon,
  'archway-1': archway,
  '0xa4b1.arbitrum': arbitrum,
  '0xa86a.avax': avalanche,
  '0x100.icon': havah,
  '0x38.bsc': bsc,
  '0x2105.base': base,
  'injective-1': injective

For SPOKE-ICON and SPOKE-SPOKE, its a bit more complicated, there are 3 different types.

Swapping:

1. native asset - `depositNative` method on spoke Asset Manager contract (for ETH on arbitrum, AVAX on avalanche)

2. assetManager asset - `deposit` method on spoke Asset Manager contract (for ETH on BNB chain, sARCH on Archway)

3. crosschain token - `crossTransfer` method on token contract address (currently only for bnUSD, will be the case for sICX and BALN, as well)

For EVM chains, here is a code for initiating the swap transaction https://github.com/balancednetwork/balanced-network-interface/blob/master/apps/web/src/xwagmi/xchains/evm/EvmXWalletClient.ts#L56

Only difference between SPOKE-ICON and SPOKE-SPOKE is again the receiver network address.

Note that swaps ending or starting on a SPOKE chain consists of multiple xCall transactions, user however must sign only the initial transaction, the rest is executed automatically by the Balanced contracts.

thanks for the reply, ill work on a draft document detailing these trade executions, ill let you know if I need any extra info.

FidelVe commented 2 months ago

Here is a function that encodes the swap data to RLP format https://github.com/balancednetwork/balanced-network-interface/blob/master/apps/web/src/lib/xcall/utils.ts#L27

@hetfly this link is broken, please share again the correct link to the RLP function for the swaps

hetfly commented 2 months ago

@FidelVe https://github.com/balancednetwork/balanced-network-interface/blob/master/apps/web/src/xwagmi/xcall/utils.ts#L27

FidelVe commented 2 months ago

For ICON-SPOKE swaps, only difference is adding _receiver param with network address, so for arbitrum for example: 0xa4b1.arbitrum /0xE1598501d3ec2b0094eDc14487b01eB042919c2F, which is networkID/address or networkID/contract

List of network Ids:

  '0x1.icon': icon,
  'archway-1': archway,
  '0xa4b1.arbitrum': arbitrum,
  '0xa86a.avax': avalanche,
  '0x100.icon': havah,
  '0x38.bsc': bsc,
  '0x2105.base': base,
  'injective-1': injective

where can I find the list of networks ids for testnet?

hetfly commented 2 months ago

@FidelVe https://github.com/balancednetwork/balanced-network-interface/blob/master/apps/web/src/xwagmi/constants/xChains.ts#L277

FidelVe commented 2 months ago

@hetfly @AntonAndell

Im getting a bit confused with the subject of making a token to token swap on ICON, more specifically on how to properly format the data that is encoded and being sent to the smart contract.

Take for example the case of swapping bnusd to baln token, it would be something like this:

I want to know how to properly encode the information in the _data field, I have found 2 different transactions where the data is encoded in different ways:

Example 1

https://tracker.icon.community/transaction/0xc87bebcd53e06aca817ae01d3900b13796a24945dcd4386d8fb33fc5bf248eba

payload:

{
    "method": "transfer",
    "params": {
        "_data": "f852855f73776170aa687834303663653637653462326430396537313465616634383232346632653062613439653134666263880c0c78540bfeda96d7019501f61cd5a45dc9f91c15aa65831a30a90d59a09619",
        "_to": "cx21e94c08c03daee80c25d8ee3ea22a20786ec231",
        "_value": "0x351da03b95eb6b4"
    }
}

Decoded _data using RLP:

[
  '_swap',
  'hx406ce67e4b2d09e714eaf48224f2e0ba49e14fbc',
  '0c0c78540bfeda96',
  [ 1, 'cxf61cd5a45dc9f91c15aa65831a30a90d59a09619' ]
]

example 2:

https://tracker.lisbon.icon.community/transaction/0x1ed3fb0fe6ff6e6d43d240bc7981aa71e0ed3bab10785a2899f5176fabdd6bc4

Payload:

{
    "method": "transfer",
    "params": {
        "_data": "0x7b226d6574686f64223a225f73776170222c22706172616d73223a7b22746f546f6b656e223a22637863336335353230353462613638323331303762353630383631333463326166633236616231646661222c226d696e696d756d52656365697665223a22343237373330343635353930323232393035313231222c2270617468223a5b22637863336335353230353462613638323331303762353630383631333463326166633236616231646661225d7d7d",
        "_to": "cx2576925d931f3be8ff195914c10a87da2094c5e5",
        "_value": "0x3635c9adc5dea00000"
    }
}

Decoded data using IconConverter.toUtf8():

{
  method: '_swap',
  params: {
    toToken: 'cxc3c552054ba6823107b56086134c2afc26ab1dfa',
    minimumReceive: '427730465590222905121',
    path: [ 'cxc3c552054ba6823107b56086134c2afc26ab1dfa' ]
  }
}

Which of these 2 is the one i should be documenting in the docs or it doesnt matter which one?