Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the corpopress domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /data/wwwroot/blog.mathquant.com/wp-includes/functions.php on line 6121 Practice of Web3 Tron Encapsulated and Access to SunSwap DEX Based on FMZ Platform – FMZ Quant
In the field of blockchain tradings, decentralized exchanges (DEX) provide a trustless way to exchange assets, and SunSwap, as a representative DEX in the Tron ecosystem, supports smart contract interactions based on Web3. We FMZ platform provides a powerful quantitative trading framework that enables developers to integrate multiple trading strategies.
The FMZ platform already supports the encapsulation of Web3 Ethereum (ETH) exchange objects, and added support for Web3 TRON recently, encapsulating the exchange objects of the TRON chain. Just like accessing UniSwap DEX, access to SunSwap DEX is also possible.
This article will explore how to encapsulate the Web3 interface based on the FMZ Quant platform and access SunSwap DEX for trading. We will introduce the Web3 interaction method of the Tron network, the SunSwap smart contract call, and show how to query liquidity, execute transactions, and obtain transaction results through code examples, so as to build an efficient quantitative trading strategy.
Disclaimer
All codes and designs shared in this article have been tested and are intended for learning and communication. However, even after testing, these contents may still need to be adjusted according to actual needs. If you want to apply them to live trading, please be sure to evaluate, optimize and modify them yourself to ensure that they meet your needs.
Preparation
Configure the Web3 TRON exchange object of the FMZ platform
In the previous article FMZ Quant Web3 Expansion: Tron Support Added, Expand On-chain Tradings, we have introduced the common methods of Tron gRPC nodes and learned how to configure Web3 TRON exchange objects on FMZ. This article will not repeat these contents. As for the node address, we will use the node provided by TRON official directly.
Deploy the docker
Unlike CEX exchanges, there is no wall to worry about. You can access the official node by deploying a docker locally.
The address on TRON is base58 encoded, which is different from Ethereum. Sometimes, in order to view and compare data, some conversion is required. On FMZ, you can use the base58 encoded address directly. Some smart contracts return data in HEX encoding, which requires some conversion. Several functions are simply implemented to convert the address format:
The following are the main conversion functions. Due to limited space, I will not post all the codes. The complete code is in the "Tron SunSwap V3 Trading Library" template library disclosed at the end of the article.
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
functionethAddressToTron(ethAddress){
if(!/^0x[0-9a-fA-F]{40}$/.test(ethAddress)){
throw"Invalid Ethereum address"
}
const ethAddressBytes = newUint8Array(20)
for(let i = 0; i <20; i++){
ethAddressBytes[i] = parseInt(ethAddress.substr(2 + i *2, 2), 16)
Because sometimes you need to read data from multiple methods at once, calling them one by one is time-consuming and laborious. So a packaged calling function is encapsulated:
functionmulticall(e, multicallContractAddress, data, outTypes) {
let ret = e.IO("api", multicallContractAddress, "aggregate", data)
if (!ret || !ret["returnData"] || !Array.isArray(ret["returnData"])) {
Log("invalid ret:", ret)
returnnull
}
let arrRet = ret["returnData"]
if (outTypes.length != arrRet.length) {
Log("Arrays have unequal lengths:", arrRet, outTypes)
returnnull
}
let outData = []
for (let i in arrRet) {
outData.push(e.IO("decode", outTypes[i], arrRet[i]))
}
return outData
}
functionmulticall(e, multicallContractAddress, data, outTypes) {
let ret = e.IO("api", multicallContractAddress, "aggregate", data)
if (!ret || !ret["returnData"] || !Array.isArray(ret["returnData"])) {
Log("invalid ret:", ret)
returnnull
}
let arrRet = ret["returnData"]
if (outTypes.length != arrRet.length) {
Log("Arrays have unequal lengths:", arrRet, outTypes)
returnnull
}
let outData = []
for (let i in arrRet) {
outData.push(e.IO("decode", outTypes[i], arrRet[i]))
}
return outData
}
Tron SunSwap V3 Trading Library
The design of SunSwap V3 trading library is modeled after the UniSwap trading library template of the FMZ platform. Since the SunSwap template code is long, I will not post it here, and will mainly explain the functions implemented.
Create SunSwap Trading Object
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
let e = $.CreateSunSwapEx()// By default, the exchange exchanges[0] is used to initialize the SunSwap trading object.// let e = $.CreateSunSwapEx(exchanges[1]) // Initialize the SunSwap trading object using the secondary exchange object.
let e = $.CreateSunSwapEx() // By default, the exchange exchanges[0] is used to initialize the SunSwap trading object.// let e = $.CreateSunSwapEx(exchanges[1]) // Initialize the SunSwap trading object using the secondary exchange object.
let e = $.CreateSunSwapEx() // By default, the exchange exchanges[0] is used to initialize the SunSwap trading object.// let e = $.CreateSunSwapEx(exchanges[1]) // Initialize the SunSwap trading object using the secondary exchange object.
This template has only one interface function, namely: $.CreateSunSwapEx(), which is used to create a SunSwap trading object. After the object is created, you can call the method of this object to perform some function calls, such as: exchange transactions, query pool prices, obtain all V3 pool information, pledge, decompression, etc.
GetMarkets
The test codes of "Tron SunSwap V3 Trading Library" are all recorded in the main() function of the template and will not be repeated here.
let markets = e.GetMarkets()
let idx = 0let tbl = {"type": "table", "title": "test GetMarkets", "cols": ["Index", "PoolAddress", "Symbol", "BaseAsset", "QuoteAsset", "BaseName", "QuoteName", "BaseDecimals", "QuoteDecimals", "BaseAddress", "QuoteAddress"], "rows": []}
for (let currency in markets) {
let arrMarket = markets[currency]
for (let market of arrMarket) {
tbl["rows"].push([idx, market["PoolAddress"], market["Symbol"], market["BaseAsset"], market["QuoteAsset"], market["BaseName"], market["QuoteName"], market["BaseDecimals"], market["QuoteDecimals"], market["BaseAddress"], market["QuoteAddress"]])
idx++
}
}
LogStatus("`" + JSON.stringify(tbl) + "`")
let markets = e.GetMarkets()
let idx = 0let tbl = {"type": "table", "title": "test GetMarkets", "cols": ["Index", "PoolAddress", "Symbol", "BaseAsset", "QuoteAsset", "BaseName", "QuoteName", "BaseDecimals", "QuoteDecimals", "BaseAddress", "QuoteAddress"], "rows": []}
for (let currency in markets) {
let arrMarket = markets[currency]
for (let market of arrMarket) {
tbl["rows"].push([idx, market["PoolAddress"], market["Symbol"], market["BaseAsset"], market["QuoteAsset"], market["BaseName"], market["QuoteName"], market["BaseDecimals"], market["QuoteDecimals"], market["BaseAddress"], market["QuoteAddress"]])
idx++
}
}
LogStatus("`" + JSON.stringify(tbl) + "`")
The function GetMarkets() is used to obtain the relevant information of all exchange pools in the SunSwap V3 pool, cached in the variables of the SunSwap trading object, and used to query accuracy, address and other information during other operations.
After running the test code, the information of all V3 pools will be displayed:
The code has removed some of the contract addresses currently seen, such as "phishing contracts" and "invalid contracts".
GetTicker
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
let ticker1 = e.GetTicker("WTRX_USDT")
Log("symbol:", "WTRX_USDT", ", ticker:", ticker1)
let ticker2 = e.GetTicker("iCMX_USDT", "TLVDozYEBgeaJXH7oKBsougzEJKNrogFun")// iCMX_USDTLog("symbol:", "iCMX_USDT", ", ticker:", ticker2)
let ticker1 = e.GetTicker("WTRX_USDT")
Log("symbol:", "WTRX_USDT", ", ticker:", ticker1)
let ticker2 = e.GetTicker("iCMX_USDT", "TLVDozYEBgeaJXH7oKBsougzEJKNrogFun") // iCMX_USDTLog("symbol:", "iCMX_USDT", ", ticker:", ticker2)
let ticker1 = e.GetTicker("WTRX_USDT")
Log("symbol:", "WTRX_USDT", ", ticker:", ticker1)
let ticker2 = e.GetTicker("iCMX_USDT", "TLVDozYEBgeaJXH7oKBsougzEJKNrogFun") // iCMX_USDTLog("symbol:", "iCMX_USDT", ", ticker:", ticker2)
You can use the GetTicker() function to query the price of a certain exchange pool, and you can specify the address of a specific pool. Note that some pools have poor liquidity and the price is only for reference.
let ret = multicall(exchange, "TGXuuKAb4bnrn137u39EKbYzKNXvdCes98", data, ["uint256", "uint256"])
Log(ret, toAmount(ret[0], 6))
let data = []
let walletAddress = exchange.IO("address")
data.push(["TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "0x" + exchange.IO("encode", "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "balanceOf", walletAddress)])
data.push(["TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "0x" + exchange.IO("encode", "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "balanceOf", walletAddress)])
Log(data)
let ret = multicall(exchange, "TGXuuKAb4bnrn137u39EKbYzKNXvdCes98", data, ["uint256", "uint256"])
Log(ret, toAmount(ret[0], 6))
let data = []
let walletAddress = exchange.IO("address")
data.push(["TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "0x" + exchange.IO("encode", "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "balanceOf", walletAddress)])
data.push(["TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "0x" + exchange.IO("encode", "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "balanceOf", walletAddress)])
Log(data)
let ret = multicall(exchange, "TGXuuKAb4bnrn137u39EKbYzKNXvdCes98", data, ["uint256", "uint256"])
Log(ret, toAmount(ret[0], 6))
This function can be used for subsequent function encapsulation. For example, in the example, two balanceOf method calls can be encoded and the data can be requested once.
This is an important function, which encapsulates SunSwap's intelligent routing service. Given tokenInSymbol and tokenOutSymbol, it can return possible exchange paths, the number of output tokens and other information.
let assets = e.GetAssets()
let tbl = {"type": "table", "title": "test GetAssets", "cols": ["Name", "Address", "Decimals", "Balance"], "rows": []}
for (let asset of assets) {
tbl["rows"].push([asset.Currency, asset.Address, asset.Decimals, asset.Amount])
}
LogStatus("`" + JSON.stringify(tbl) + "`")
let assets = e.GetAssets()
let tbl = {"type": "table", "title": "test GetAssets", "cols": ["Name", "Address", "Decimals", "Balance"], "rows": []}
for (let asset of assets) {
tbl["rows"].push([asset.Currency, asset.Address, asset.Decimals, asset.Amount])
}
LogStatus("`" + JSON.stringify(tbl) + "`")
Since there is no good mechanism to traverse TRC20 tokens, with the help of tronscan's function, this third-party interface is used to query account asset information.
// 10 TRX -> ? WTRX// let ret = e.Swap("TRX_WTRX", 10, "sell")// Log(ret)
// 6 USDT -> ? WTRXlet ret = e.Swap("WTRX_USDT", 6, "buy")
Log(ret)
// 10 TRX -> ? WTRX// let ret = e.Swap("TRX_WTRX", 10, "sell")// Log(ret)
// 6 USDT -> ? WTRXlet ret = e.Swap("WTRX_USDT", 6, "buy")
Log(ret)
// 10 TRX -> ? WTRX// let ret = e.Swap("TRX_WTRX", 10, "sell")// Log(ret)
The most important function is this exchange. When executing the exchange, the exchange path will be formulated according to the smart routing first, and then the exchange method will be called to exchange the token. It should be noted that if it is a TRX package/unpackage exchange, it is only executed using the WTRX contract method.
We perform the following tests:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
let ret = e.Swap("TRX_USDT", 5, "sell")
Log(ret)
let ret = e.Swap("TRX_USDT", 5, "sell")
Log(ret)
let ret = e.Swap("TRX_USDT", 5, "sell")
Log(ret)
Other Encapsulations
There are some other functions such as "staking" and "unstaking". You can check them in the main() function in the template code, so I won't go into details. You can also expand and add functions such as adding liquidity and removing liquidity.
Template Code
This template does not have any interaction design and interface parameters. It only implements the basic function of accessing SunSwap DEX. More functions can be optimized and added later.
// [amount of the token to be swapped, minimum acceptable amount of the token obtained from the swap, address to receive the token obtained from the swap, deadline]let data = [String(amount), String(minAmount), walletAddress, expiredTS]
let poolABI = `[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"indexed":true,"name":"owner","internalType":"address","type":"address"},{"indexed":true,"name":"tickLower","internalType":"int24","type":"int24"},{"indexed":true,"name":"tickUpper","internalType":"int24","type":"int24"},{"indexed":false,"name":"amount","internalType":"uint128","type":"uint128"},{"indexed":false,"name":"amount0","internalType":"uint256","type":"uint256"},{"indexed":false,"name":"amount1","internalType":"uint256","type":"uint256"}],"name":"Burn","anonymous":false,"type":"event"},{"inputs":[{"indexed":true,"name":"owner","internalType":"address","type":"address"},{"indexed":false,"name":"recipient","internalType":"address","type":"address"},{"indexed":true,"name":"tickLower","internalType":"int24","type":"int24"},{"indexed":true,"name":"tickUpper","internalType":"int24","type":"int24"},{"indexed":false,"name":"amount0","internalType":"uint128","type":"uint128"},{"indexed":false,"name":"amount1","internalType":"uint128","type":"uint128"}],"name":"Collect","anonymous":false,"type":"event"},{"inputs":[{"indexed":true,"name":"sender","internalType":"address","type":"address"},{"indexed":true,"name":"recipient","internalType":"address","type":"address"},{"indexed":false,"name":"amount0","internalType":"uint128","type":"uint128"},{"indexed":false,"name":"amount1","internalType":"uint128","type":"uint128"}],"name":"CollectProtocol","anonymous":false,"type":"event"},{"inputs":[{"indexed":true,"name":"sender","internalType":"address","type":"address"},{"indexed":true,"name":"recipient","internalType":"address","type":"address"},{"indexed":false,"name":"amount0","internalType":"uint256","type":"uint256"},{"indexed":false,"name":"amount1","internalType":"uint256","type":"uint256"},{"indexed":false,"name":"paid0","internalType":"uint256","type":"uint256"},{"indexed":false,"name":"paid1","internalType":"uint256","type":"uint256"}],"name":"Flash","anonymous":false,"type":"event"},{"inputs":[{"indexed":false,"name":"observationCardinalityNextOld","internalType":"uint16","type":"uint16"},{"indexed":false,"name":"observationCardinalityNextNew","internalType":"uint16","type":"uint16"}],"name":"IncreaseObservationCardinalityNext","anonymous":false,"type":"event"},{"inputs":[{"indexed":false,"name":"sqrtPriceX96","internalType":"uint160","type":"uint160"},{"indexed":false,"name":"tick","internalType":"int24","type":"int24"}],"name":"Initialize","anonymous":false,"type":"event"},{"inputs":[{"indexed":false,"name":"sender","internalType":"address","type":"address"},{"indexed":true,"name":"owner","internalType":"address","type":"address"},{"indexed":true,"name":"tickLower","internalType":"int24","type":"int24"},{"indexed":true,"name":"tickUpper","internalType":"int24","type":"int24"},{"indexed":false,"name":"amount","internalType":"uint128","type":"uint128"},{"indexed":false,"name":"amount0","internalType":"uint256","type":"uint256"},{"indexed":false,"name":"amount1","internalType":"uint256","type":"uint256"}],"name":"Mint","anonymous":false,"type":"event"},{"inputs":[{"indexed":false,"name":"feeProtocol0Old","internalType":"uint8","type":"uint8"},{"indexed":false,"name":"feeProtocol1Old","internalType":"uint8","type":"uint8"},{"indexed":false,"name":"feeProtocol0New","internalType":"uint8","type":"uint8"},{"indexed":false,"name":"feeProtocol1New","internalType":"uint8","type":"uint8"}],"name":"SetFeeProtocol","anonymous":false,"type":"event"},{"inputs":[{"indexed":true,"name":"sender","internalType":"address","type":"address"},{"indexed":true,"name":"recipient","internalType":"address","type":"address"},{"indexed":false,"name":"amount0","internalType":"int256","type":"int256"},{"indexed":false,"name":"amount1","internalType":"int256","type":"int256"},{"indexed":false,"name":"sqrtPriceX96","internalType":"uint160","type":"uint160"},{"indexed":false,"name":"liquidity","internalType":"uint128","type":"uint128"},{"indexed":false,"name":"tick","internalType":"int24","type":"int24"}],"name":"Swap","anonymous":false,"type":"event"},{"outputs":[{"name":"","internalType":"address","type":"address"}],"inputs":[],"name":"factory","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint24","type":"uint24"}],"inputs":[],"name":"fee","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint256","type":"uint256"}],"inputs":[],"name":"feeGrowthGlobal0X128","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint256","type":"uint256"}],"inputs":[],"name":"feeGrowthGlobal1X128","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint128","type":"uint128"}],"inputs":[],"name":"liquidity","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint128","type":"uint128"}],"inputs":[],"name":"maxLiquidityPerTick","stateMutability":"view","type":"function"},{"outputs":[{"name":"blockTimestamp","internalType":"uint32","type":"uint32"},{"name":"tickCumulative","internalType":"int56","type":"int56"},{"name":"secondsPerLiquidityCumulativeX128","internalType":"uint160","type":"uint160"},{"name":"initialized","internalType":"bool","type":"bool"}],"inputs":[{"name":"","internalType":"uint256","type":"uint256"}],"name":"observations","stateMutability":"view","type":"function"},{"outputs":[{"name":"liquidity","internalType":"uint128","type":"uint128"},{"name":"feeGrowthInside0LastX128","internalType":"uint256","type":"uint256"},{"name":"feeGrowthInside1LastX128","internalType":"uint256","type":"uint256"},{"name":"tokensOwed0","internalType":"uint128","type":"uint128"},{"name":"tokensOwed1","internalType":"uint128","type":"uint128"}],"inputs":[{"name":"","internalType":"bytes32","type":"bytes32"}],"name":"positions","stateMutability":"view","type":"function"},{"outputs":[{"name":"token0","internalType":"uint128","type":"uint128"},{"name":"token1","internalType":"uint128","type":"uint128"}],"inputs":[],"name":"protocolFees","stateMutability":"view","type":"function"},{"outputs":[{"name":"sqrtPriceX96","internalType":"uint160","type":"uint160"},{"name":"tick","internalType":"int24","type":"int24"},{"name":"observationIndex","internalType":"uint16","type":"uint16"},{"name":"observationCardinality","internalType":"uint16","type":"uint16"},{"name":"observationCardinalityNext","internalType":"uint16","type":"uint16"},{"name":"feeProtocol","internalType":"uint8","type":"uint8"},{"name":"unlocked","internalType":"bool","type":"bool"}],"inputs":[],"name":"slot0","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint256","type":"uint256"}],"inputs":[{"name":"","internalType":"int16","type":"int16"}],"name":"tickBitmap","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"int24","type":"int24"}],"inputs":[],"name":"tickSpacing","stateMutability":"view","type":"function"},{"outputs":[{"name":"liquidityGross","internalType":"uint128","type":"uint128"},{"name":"liquidityNet","internalType":"int128","type":"int128"},{"name":"feeGrowthOutside0X128","internalType":"uint256","type":"uint256"},{"name":"feeGrowthOutside1X128","internalType":"uint256","type":"uint256"},{"name":"tickCumulativeOutside","internalType":"int56","type":"int56"},{"name":"secondsPerLiquidityOutsideX128","internalType":"uint160","type":"uint160"},{"name":"secondsOutside","internalType":"uint32","type":"uint32"},{"name":"initialized","internalType":"bool","type":"bool"}],"inputs":[{"name":"","internalType":"int24","type":"int24"}],"name":"ticks","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"address","type":"address"}],"inputs":[],"name":"token0","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"address","type":"address"}],"inputs":[],"name":"token1","stateMutability":"view","type":"function"},{"outputs":[{"name":"tickCumulativeInside","internalType":"int56","type":"int56"},{"name":"secondsPerLiquidityInsideX128","internalType":"uint160","type":"uint160"},{"name":"secondsInside","internalType":"uint32","type":"uint32"}],"inputs":[{"name":"tickLower","internalType":"int24","type":"int24"},{"name":"tickUpper","internalType":"int24","type":"int24"}],"name":"snapshotCumulativesInside","stateMutability":"view","type":"function"},{"outputs":[{"name":"tickCumulatives","internalType":"int56[]","type":"int56[]"},{"name":"secondsPerLiquidityCumulativeX128s","internalType":"uint160[]","type":"uint160[]"}],"inputs":[{"name":"secondsAgos","internalType":"uint32[]","type":"uint32[]"}],"name":"observe","stateMutability":"view","type":"function"},{"outputs":[],"inputs":[{"name":"observationCardinalityNext","internalType":"uint16","type":"uint16"}],"name":"increaseObservationCardinalityNext","stateMutability":"nonpayable","type":"function"},{"outputs":[],"inputs":[{"name":"sqrtPriceX96","internalType":"uint160","type":"uint160"}],"name":"initialize","stateMutability":"nonpayable","type":"function"},{"outputs":[{"name":"amount0","internalType":"uint256","type":"uint256"},{"name":"amount1","internalType":"uint256","type":"uint256"}],"inputs":[{"name":"recipient","internalType":"address","type":"address"},{"name":"tickLower","internalType":"int24","type":"int24"},{"name":"tickUpper","internalType":"int24","type":"int24"},{"name":"amount","internalType":"uint128","type":"uint128"},{"name":"data","internalType":"bytes","type":"bytes"}],"name":"mint","stateMutability":"nonpayable","type":"function"},{"outputs":[{"name":"amount0","internalType":"uint128","type":"uint128"},{"name":"amount1","internalType":"uint128","type":"uint128"}],"inputs":[{"name":"recipient","internalType":"address","type":"address"},{"name":"tickLower","internalType":"int24","type":"int24"},{"name":"tickUpper","internalType":"int24","type":"int24"},{"name":"amount0Requested","internalType":"uint128","type":"uint128"},{"name":"amount1Requested","internalType":"uint128","type":"uint128"}],"name":"collect","stateMutability":"nonpayable","type":"function"},{"outputs":[{"name":"amount0","internalType":"uint256","type":"uint256"},{"name":"amount1","internalType":"uint256","type":"uint256"}],"inputs":[{"name":"tickLower","internalType":"int24","type":"int24"},{"name":"tickUpper","internalType":"int24","type":"int24"},{"name":"amount","internalType":"uint128","type":"uint128"}],"name":"burn","stateMutability":"nonpayable","type":"function"},{"outputs":[{"name":"amount0","internalType":"int256","type":"int256"},{"name":"amount1","internalType":"int256","type":"int256"}],"inputs":[{"name":"recipient","internalType":"address","type":"address"},{"name":"zeroForOne","internalType":"bool","type":"bool"},{"name":"amountSpecified","internalType":"int256","type":"int256"},{"name":"sqrtPriceLimitX96","internalType":"uint160","type":"uint160"},{"name":"data","internalType":"bytes","type":"bytes"}],"name":"swap","stateMutability":"nonpayable","type":"function"},{"outputs":[],"inputs":[{"name":"recipient","internalType":"address","type":"address"},{"name":"amount0","internalType":"uint256","type":"uint256"},{"name":"amount1","internalType":"uint256","type":"uint256"},{"name":"data","internalType":"bytes","type":"bytes"}],"name":"flash","stateMutability":"nonpayable","type":"function"},{"outputs":[],"inputs":[{"name":"feeProtocol0","internalType":"uint8","type":"uint8"},{"name":"feeProtocol1","internalType":"uint8","type":"uint8"}],"name":"setFeeProtocol","stateMutability":"nonpayable","type":"function"},{"outputs":[{"name":"amount0","internalType":"uint128","type":"uint128"},{"name":"amount1","internalType":"uint128","type":"uint128"}],"inputs":[{"name":"recipient","internalType":"address","type":"address"},{"name":"amount0Requested","internalType":"uint128","type":"uint128"},{"name":"amount1Requested","internalType":"uint128","type":"uint128"}],"name":"collectProtocol","stateMutability":"nonpayable","type":"function"}]`
sunSwapEx.poolABI = poolABI
let multicallContractAddress = "TGXuuKAb4bnrn137u39EKbYzKNXvdCes98"
let multicallContractABI = `[{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct TronMulticall.Call[]","name":"calls","type":"tuple[]"}],"name":"aggregate","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"bytes[]","name":"returnData","type":"bytes[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBasefee","outputs":[{"internalType":"uint256","name":"basefee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getBlockHash","outputs":[{"internalType":"bytes32","name":"blockHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBlockNumber","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getChainId","outputs":[{"internalType":"uint256","name":"chainid","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentBlockCoinbase","outputs":[{"internalType":"address","name":"coinbase","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentBlockDifficulty","outputs":[{"internalType":"uint256","name":"difficulty","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentBlockTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"getEthBalance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastBlockHash","outputs":[{"internalType":"bytes32","name":"blockHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"accountAddress","type":"address"},{"internalType":"trcToken","name":"id","type":"trcToken"}],"name":"getTokenBalance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isContract","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"view","type":"function"}]`
let smartRouterAddress = "TCFNp179Lg46D16zKoumd4Poa2WFFdtqYj"
sunSwapEx.smartRouterAddress = smartRouterAddress
let smartRouterABI = `[{"outputs":[{"name":"amountsOut","type":"uint256[]"}],"inputs":[{"name":"path","type":"address[]"},{"name":"poolVersion","type":"string[]"},{"name":"versionLen","type":"uint256[]"},{"name":"fees","type":"uint24[]"},{"name":"data","type":"tuple"}],"name":"swapExactInput","stateMutability":"payable","type":"function","payable":true}]`
let retStakeTRX = e.StakeTRX("ENERGY", 10)// Stake TRX
Log("retStakeTRX:", retStakeTRX)
// let retUnStakeTRX = e.UnStakeTRX("ENERGY", 100) // UnStake TRX
// Log("retUnStakeTRX:", retUnStakeTRX)
*//* send
// let ret = e.SendTRX("...", 180)
// Log("SendTRX ret:", ret)
*/
}
functionisEmptyObject(obj) {
returnObject.keys(obj).length === 0
}
functioncomputePoolPrice(decimals0, decimals1, sqrtPriceX96) {
[decimals0, decimals1, sqrtPriceX96] = [decimals0, decimals1, sqrtPriceX96].map(BigInt)
constTWO = BigInt(2)
constTEN = BigInt(10)
constSIX_TENTH = BigInt(1000000)
constQ192 = (TWO ** BigInt(96)) ** TWOreturn (Number((sqrtPriceX96 ** TWO * TEN ** decimals0 * SIX_TENTH) / (Q192 * TEN ** decimals1)) / Number(SIX_TENTH))
}
functionmulticall(e, multicallContractAddress, data, outTypes) {
let ret = e.IO("api", multicallContractAddress, "aggregate", data)
if (!ret || !ret["returnData"] || !Array.isArray(ret["returnData"])) {
Log("invalid ret:", ret)
returnnull
}
let arrRet = ret["returnData"]
if (outTypes.length != arrRet.length) {
Log("Arrays have unequal lengths:", arrRet, outTypes)
returnnull
}
let outData = []
for (let i in arrRet) {
outData.push(e.IO("decode", outTypes[i], arrRet[i]))
}
return outData
}
functiontoAmount(s, decimals) {
returnNumber((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}
functiontoInnerAmount(n, decimals) {
return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0)
}
functionhexToUint8Array(hex) {
if (hex.length % 2 !== 0) {
thrownewError("Invalid hex string length")
}
returnUint8Array.from(
hex.match(/.{1,2}/g).map(byte =>parseInt(byte, 16))
)
}
functionuint8ArrayToHex(array) {
returnArray.from(array).map(byte => byte.toString(16).padStart(2, "0")).join("")
}
functionethAddressToTron(ethAddress) {
if (!/^0x[0-9a-fA-F]{40}$/.test(ethAddress)) {
throw"Invalid Ethereum address"
}
const ethAddressBytes = newUint8Array(20)
for (let i = 0; i < 20; i++) {
ethAddressBytes[i] = parseInt(ethAddress.substr(2 + i * 2, 2), 16)
}
const tronAddressBytes = newUint8Array(21)
tronAddressBytes[0] = 0x41
tronAddressBytes.set(ethAddressBytes, 1)
const hash1 = Encode("sha256", "hex", "hex", uint8ArrayToHex(tronAddressBytes))
const hash2 = Encode("sha256", "hex", "hex", hash1)
const checksum = hash2.slice(0, 8)
const fullAddress = newUint8Array(25)
fullAddress.set(tronAddressBytes, 0)
fullAddress.set(hexToUint8Array(checksum), 21)
returnbase58Encode(fullAddress)
}
functionbase58Encode(buffer) {
const base58Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"let num = BigInt("0x" + Array.from(buffer).map(b => b.toString(16).padStart(2, "0")).join(""))
let encoded = ""while (num > 0) {
let remainder = num % 58n
num = num / 58n
encoded = base58Alphabet[Number(remainder)] + encoded
}
for (let byte of buffer) {
if (byte === 0) {
encoded = base58Alphabet[0] + encoded
} else {
break
}
}
return encoded
}
functionbase58ToHex(base58Str) {
constALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"var num = BigInt(0)
for (var char of base58Str) {
var digit = BigInt(ALPHABET.indexOf(char))
if (digit === BigInt(-1)) thrownewError("Invalid Base58 character: " + char)
num = num * BigInt(58) + digit
}
var hex = num.toString(16)
if (hex.length % 2 !== 0) {
hex = "0" + hex
}
return"0x" + hex
}
$.CreateSunSwapEx = function(e) {
let sunSwapEx = {}
sunSwapEx.registerABI = function(address, codeABI) {
let e = sunSwapEx.eif (typeof(address) == "undefined" || typeof(codeABI) == "undefined") {
throw"need address, codeABI"
}
return e.IO("abi", address, codeABI)
}
sunSwapEx.getCurrencyInfo = function(token0Address, token1Address) {
let e = sunSwapEx.elet arrTokenAddress = [token0Address, token1Address]
let tokenInfoCallData = []
let tokenInfoRetType = []
for (let tokenAddress of arrTokenAddress) {
tokenInfoCallData.push([tokenAddress, "0x" + e.IO("encode", tokenAddress, "symbol")])
tokenInfoRetType.push("string")
tokenInfoCallData.push([tokenAddress, "0x" + e.IO("encode", tokenAddress, "name")])
tokenInfoRetType.push("string")
tokenInfoCallData.push([tokenAddress, "0x" + e.IO("encode", tokenAddress, "decimals")])
tokenInfoRetType.push("uint8")
}
let currencyInfo = _C(multicall, e, multicallContractAddress, tokenInfoCallData, tokenInfoRetType)
if (currencyInfo.length != 6) {
Log("invalid currency Info:", currencyInfo)
returnnull
}
let ret = {
"token0Symbol": currencyInfo[0],
"token0Name": currencyInfo[1],
"token0Decimals": currencyInfo[2],
"token1Symbol": currencyInfo[3],
"token1Name": currencyInfo[4],
"token1Decimals": currencyInfo[5]
}
return ret
}
sunSwapEx.waitMined = function(tx) {
let e = sunSwapEx.elet i = 0let maxLoop = 10while (true) {
Sleep(3000)
let info = e.IO("api", "tron", "GetTransactionInfoByID", tx)
if (info && info.receipt && typeof(info.receipt.result) == "number") {
Log("GetTransactionInfoByID:", info)
if (info.receipt.result == 1) {
returntrue
} else {
returnfalse
}
}
Log("Transaction not yet mined", tx)
if (i > maxLoop) {
break
}
i++
}
Log(`Transaction: ${tx} not found`)
returnfalse
}
sunSwapEx.getTokenInfo = function(tokenSymbol) {
let markets = sunSwapEx.marketsif (!markets || isEmptyObject(markets)) {
markets = sunSwapEx.GetMarkets()
}
if (tokenSymbol == "TRX") {
return {"tokenSymbol": tokenSymbol, "tokenName": tokenSymbol, "tokenDecimals": 6, "tokenAddress": "--"}
}
for (let currency in markets) {
for (let market of markets[currency]) {
if (market["BaseAsset"] == tokenSymbol) {
return {"tokenSymbol": market["BaseAsset"], "tokenName": market["BaseName"], "tokenDecimals": market["BaseDecimals"], "tokenAddress": market["BaseAddress"]}
} elseif (market["QuoteAsset"] == tokenSymbol) {
return {"tokenSymbol": market["QuoteAsset"], "tokenName": market["QuoteName"], "tokenDecimals": market["QuoteDecimals"], "tokenAddress": market["QuoteAddress"]}
}
}
}
Log("not found token symbol:", tokenSymbol)
returnnull
}
sunSwapEx.dealStakeTRX = function(methodName, resourceName, amount) {
let e = sunSwapEx.elet walletAddress = e.IO("address")
let balance = toInnerAmount(amount, 6)
let resourceCode = -1if (resourceName == "BANDWIDTH") {
resourceCode = 0
} elseif (resourceName == "ENERGY") {
resourceCode = 1
} elseif (resourceName == "TRON_POWER") {
resourceCode = 2
} else {
Log("not support resourceName:", resourceName)
returnnull
}
return e.IO("api", "tron", methodName, walletAddress, resourceCode, balance)
}
sunSwapEx.GetMarkets = function() {
// sunswap v3 poollet e = sunSwapEx.eif (!sunSwapEx.markets) {
sunSwapEx.markets = {}
}
let markets = sunSwapEx.marketsif (!isEmptyObject(markets)) {
return markets
}
let factoryV3Address = sunSwapEx.factoryV3Address// allPoolsLengthlet poolIdx = e.IO("api", factoryV3Address, "allPoolsLength")
if (!poolIdx) {
Log("invalid poolIdx:", poolIdx)
returnnull
}
Log("allPoolsLength:", poolIdx)
// multicallContractAddresslet multicallContractAddress = sunSwapEx.multicallContractAddress// get All pool addresslet retPools = []
let getPoolsData = []
let retPoolsType = []
for (let i = 0; i < poolIdx; i++) {
getPoolsData.push([factoryV3Address, "0x" + e.IO("encode", factoryV3Address, "allPools", String(i))])
retPoolsType.push("address")
if (getPoolsData.length > 30 || i == poolIdx - 1) {
let arr = _C(multicall, e, multicallContractAddress, getPoolsData, retPoolsType)
retPools.push(...arr)
getPoolsData = []
retPoolsType = []
}
}
// allPoolslet poolABI = sunSwapEx.poolABIfor (let i in retPools) {
// poolAddresslet poolAddress = ethAddressToTron(retPools[i])
// register pool ABI
sunSwapEx.registerABI(poolAddress, poolABI)
// get token address of the poollet tokenCallData = [[poolAddress, "0x" + e.IO("encode", poolAddress, "token0")], [poolAddress, "0x" + e.IO("encode", poolAddress, "token1")]]
let tokenRetType = ["address", "address"]
let arrTokenAddress = _C(multicall, e, multicallContractAddress, tokenCallData, tokenRetType)
let token0Address = ethAddressToTron(arrTokenAddress[0])
let token1Address = ethAddressToTron(arrTokenAddress[1])
// symbol , name , decimalslet currencyInfo = sunSwapEx.getCurrencyInfo(token0Address, token1Address)
if (!currencyInfo) {
returnnull
}
let token0Symbol = currencyInfo["token0Symbol"]
let token0Name = currencyInfo["token0Name"]
let token0Decimals = currencyInfo["token0Decimals"]
let token1Symbol = currencyInfo["token1Symbol"]
let token1Name = currencyInfo["token1Name"]
let token1Decimals = currencyInfo["token1Decimals"]
// Aliaslet mapAlias = {
"TJWm3jWaJeCdyRckEXfopsJBvZi6wXVK2p": "PAPA",
"TPYmHEhy5n8TCEfYGqW2rPxsghSfzghPDn": "USDDOLD",
"TTiwtPv4MFHMoCpGDBEF85qQjD2v4e99ck": "HOUSDOLD",
"TRFe3hT5oYhjSZ6f3ji5FJ7YCfrkWnHRvh": "ETHB"
}
if (typeof(mapAlias[token0Address]) != "undefined") {
token0Symbol = mapAlias[token0Address]
}
if (typeof(mapAlias[token1Address]) != "undefined") {
token1Symbol = mapAlias[token1Address]
}
// badlet mapBad = {
"TMEmRKPob42vhkqEGopCnfBPixN5XTkdUc": "U S D T", // Attention: Fishing contract"TXioUZK8ju3R54KvzSqPc6Ufq5wkxFqpq9": "U S D T", // Attention: Fishing contract"TU41FWQQT8hZ6t72gVEjtSGn1Dshbevi7g": "CNY Coin", // Attention: Invalid"TYB7oXNq4VyuiH5BHb4os8rTh7Ca8pxqSx": "BULL", // Attention: Fishing contract"TYJxozCVMUiHg3TbQp9PKeuXdTsX9ugJz9": "SHISHA", // Attention: Not circulated"TF9io9LGyjuK3uTpr73pAaQ5m9scxd9xvr": "TestToken18", // Attention: Test trading pairs"TK8E3sFhBt3EB6gTT6d6co8RMB6DFUnNwE": "TestToken6"// Attention: Test trading pairs
}
if (typeof(mapBad[token0Address]) != "undefined" || typeof(mapBad[token1Address]) != "undefined") {
continue
}
// marketlet currency = token0Symbol + "_" + token1Symbol
let market = {
"Symbol": currency,
"BaseAsset": token0Symbol,
"QuoteAsset": token1Symbol,
"BaseName": token0Name,
"QuoteName": token1Name,
"BaseDecimals": token0Decimals,
"QuoteDecimals": token1Decimals,
"BaseAddress": token0Address,
"QuoteAddress": token1Address,
"PoolAddress": poolAddress,
"PoolIndex": i
}
if (!Array.isArray(markets[currency])) {
markets[currency] = []
}
markets[currency].push(market)
LogStatus(_D(), "get markets, length:", Object.keys(markets).length)
Sleep(200)
}
_G("sunswap_markets", markets)
sunSwapEx.markets = markets
return markets
}
sunSwapEx.GetTicker = function(symbol, targetPoolAddress) {
let e = sunSwapEx.elet markets = sunSwapEx.marketsif (!markets || isEmptyObject(markets)) {
markets = sunSwapEx.GetMarkets()
}
let arrPoolAddress = []
let arrToken0Decimals = []
let arrToken1Decimals = []
for (let currency in markets) {
if (!Array.isArray(markets[currency]) || markets[currency].length == 0) {
continue
}
if (currency == symbol) {
for (let ele of markets[currency]) {
if (typeof(targetPoolAddress) != "undefined" && ele["PoolAddress"] != targetPoolAddress) {
continue
}
arrPoolAddress.push(ele["PoolAddress"])
arrToken0Decimals.push(ele["BaseDecimals"])
arrToken1Decimals.push(ele["QuoteDecimals"])
}
}
}
if (arrPoolAddress.length == 0) {
Log(`${symbol} and ${targetPoolAddress} not found`)
sunSwapEx.markets = {}
returnnull
}
let arrPrice = []
let slot0CallData = []
let slot0RetType = []
for (let i in arrPoolAddress) {
let poolAddress = arrPoolAddress[i]
let poolABI = sunSwapEx.poolABI
e.IO("abi", poolAddress, poolABI)
slot0CallData.push([poolAddress, "0x" + e.IO("encode", poolAddress, "slot0")])
slot0RetType.push("(uint160,int24,uint16,uint16,uint16,uint8,bool)")
}
let multicallContractAddress = sunSwapEx.multicallContractAddresslet arrSlot0 = _C(multicall, e, multicallContractAddress, slot0CallData, slot0RetType)
for (let i in arrSlot0) {
let slot0 = arrSlot0[i]
let token0Decimals = arrToken0Decimals[i]
let token1Decimals = arrToken1Decimals[i]
let sqrtPriceX96 = slot0["Field1"]
let poolAddress = arrPoolAddress[i]
let price = computePoolPrice(token0Decimals, token1Decimals, sqrtPriceX96)
arrPrice.push({"price": price, "poolAddress": poolAddress})
}
return arrPrice
}
sunSwapEx.GetSwapOutAmount = function(symbol, amountIn, type) {
let arrCurrency = symbol.split("_")
if (arrCurrency.length != 2) {
Log("invalid symbol:", symbol)
returnnull
}
let baseCurrencyInfo = sunSwapEx.getTokenInfo(arrCurrency[0])
let quoteCurrencyInfo = sunSwapEx.getTokenInfo(arrCurrency[1])
if (!baseCurrencyInfo || !quoteCurrencyInfo) {
returnnull
}
let baseSymbol = baseCurrencyInfo["tokenSymbol"]
let baseAddress = baseCurrencyInfo["tokenAddress"]
let baseDecimals = baseCurrencyInfo["tokenDecimals"]
let quoteSymbol = quoteCurrencyInfo["tokenSymbol"]
let quoteAddress = quoteCurrencyInfo["tokenAddress"]
let quoteDecimals = quoteCurrencyInfo["tokenDecimals"]
// black hole addressif (baseSymbol == "TRX") {
baseAddress = "T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb"
}
if (quoteSymbol == "TRX") {
quoteAddress = "T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb"
}
let query = nullif (type == "buy") {
let amount = toInnerAmount(amountIn, quoteDecimals)
query = `?fromToken=${quoteAddress}&toToken=${baseAddress}&amountIn=${amount}&typeList=WTRX,SUNSWAP_V1,SUNSWAP_V2,SUNSWAP_V3`
} elseif (type == "sell") {
let amount = toInnerAmount(amountIn, baseDecimals)
query = `?fromToken=${baseAddress}&toToken=${quoteAddress}&amountIn=${amount}&typeList=WTRX,SUNSWAP_V1,SUNSWAP_V2,SUNSWAP_V3`
} else {
Log("not support type:", type)
returnnull
}
try {
let ret = JSON.parse(HttpQuery("https://rot.endjgfsv.link/swap/router" + query))
Log("https://rot.endjgfsv.link/swap/router" + query, "GetSwapOutAmount ret:", ret)
if (!ret || ret["message"] != "SUCCESS") {
Log("invalid data:", ret)
returnnull
}
let outAmount = nulllet best = nulllet info = ret["data"]
for (let ele of info) {
if (!outAmount) {
outAmount = parseFloat(ele["amountOut"])
best = ele
} else {
let amount = parseFloat(ele["amountOut"])
if (amount > outAmount) {
outAmount = amount
best = ele
}
}
}
if (!outAmount || !best) {
Log("info:", info)
returnnull
}
return {"info": info, "outAmount": outAmount, "best": best, "baseCurrencyInfo": baseCurrencyInfo, "quoteCurrencyInfo": quoteCurrencyInfo}
} catch(e) {
Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
returnnull
}
}
sunSwapEx.GetAccount = function() {
let e = sunSwapEx.elet walletAddress = e.IO("address")
let account = e.IO("api", "tron", "GetAccount", walletAddress)
if (!account) {
Log("get account failed, account:", account)
returnnull
}
let trxBalance = toAmount(account["balance"], 6)
let resource = e.IO("api", "tron", "GetAccountResource", walletAddress)
if (!resource) {
Log("get resource failed, resource:", resource)
returnnull
}
let energyLimit = resource["EnergyLimit"] ? resource["EnergyLimit"] : 0let freeNetLimit = resource["freeNetLimit"] ? resource["freeNetLimit"] : 0return {"Info": {"GetAccount": account, "GetAccountResource": resource}, "TRX": trxBalance, "Bandwidth": freeNetLimit, "Energy": energyLimit}
}
sunSwapEx.GetAssets = function() {
let e = sunSwapEx.elet walletAddress = e.IO("address")
try {
let ret = JSON.parse(HttpQuery("https://apilist.tronscanapi.com/api/account/token_asset_overview?address=" + walletAddress))
let assets = []
for (let info of ret["data"]) {
let decimals = parseInt(info["tokenDecimal"])
let asset = {
"Currency": info["tokenAbbr"] == "trx" ? "TRX" : info["tokenAbbr"],
"Decimals": decimals,
"Amount": toAmount(info["balance"], decimals),
"Address": info["tokenId"],
}
assets.push(asset)
}
return assets
} catch(e) {
Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
returnnull
}
}
sunSwapEx.StakeTRX = function(resourceName, frozenBalance) {
return sunSwapEx.dealStakeTRX("FreezeBalanceV2", resourceName, frozenBalance)
}
sunSwapEx.UnStakeTRX = function(resourceName, unfreezeBalance) {
return sunSwapEx.dealStakeTRX("UnfreezeBalanceV2", resourceName, unfreezeBalance)
}
sunSwapEx.WrappedTRX = function(actionType, amountIn) {
let e = sunSwapEx.elet tx = nullif (actionType == "deposit") {
let amount = toInnerAmount(amountIn, 6)
tx = e.IO("api", "TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR", "deposit", amount, {gasLimit: toInnerAmount(sunSwapEx.feeLimit, 6)})
} elseif (actionType == "withdraw") {
tx = e.IO("api", "TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR", "withdraw(uint256)", toInnerAmount(amountIn, 6), {gasLimit: toInnerAmount(sunSwapEx.feeLimit, 6)})
} else {
Log("not support actionType:", actionType)
returnfalse
}
if (tx) {
Log("tx: ", tx)
let txRet = sunSwapEx.waitMined(tx)
if (!txRet) {
Log(actionType, "failed")
returnfalse
} else {
Log(actionType, "success")
returntrue
}
} else {
Log("trans error")
returnfalse
}
}
sunSwapEx.Swap = function(symbol, amountIn, type) {
let e = sunSwapEx.elet smartRouterAddress = sunSwapEx.smartRouterAddressif (symbol == "TRX_WTRX" || symbol == "WTRX_TRX") {
let actionType = nullif (type == "buy") {
actionType = symbol == "TRX_WTRX" ? "withdraw" : "deposit"
} elseif (type == "sell") {
actionType = symbol == "TRX_WTRX" ? "deposit" : "withdraw"
} else {
Log("invalid type:", type)
returnfalse
}
return sunSwapEx.WrappedTRX(actionType, amountIn)
}
let swapInfo = sunSwapEx.GetSwapOutAmount(symbol, amountIn, type)
if (!swapInfo || !swapInfo["best"]) {
Log("invalid swapInfo:", swapInfo)
returnfalse
}
let outAmount = swapInfo["outAmount"]
let best = swapInfo["best"]
// pathlet path = best["tokens"]
if (!path || path.length < 2) {
Log("invalid path:", path)
returnfalse
}
// poolVersions and versionsLenlet poolVersions = []
let versionsLen = []
for (var v of best["poolVersions"]) {
if (poolVersions.length == 0) {
poolVersions.push(v)
versionsLen.push(2)
} else {
if (poolVersions[poolVersions.length - 1] == v) {
versionsLen[versionsLen.length - 1] += 1
} else {
poolVersions.push(v)
versionsLen.push(1)
}
}
}
// fees let poolFees = best["poolFees"]
// get decimals , token name let token0Decimals = swapInfo["baseCurrencyInfo"]["tokenDecimals"]
let token1Decimals = swapInfo["quoteCurrencyInfo"]["tokenDecimals"]
let tokenInName = type == "buy" ? swapInfo["quoteCurrencyInfo"]["tokenSymbol"] : swapInfo["baseCurrencyInfo"]["tokenSymbol"]
let tokenOutName = type == "buy" ? swapInfo["baseCurrencyInfo"]["tokenSymbol"] : swapInfo["quoteCurrencyInfo"]["tokenSymbol"]
let tokenInAddress = type == "buy" ? swapInfo["quoteCurrencyInfo"]["tokenAddress"] : swapInfo["baseCurrencyInfo"]["tokenAddress"]
let tokenOutAddress = type == "buy" ? swapInfo["baseCurrencyInfo"]["tokenAddress"] : swapInfo["quoteCurrencyInfo"]["tokenAddress"]
let tokenInDecimals = type == "buy" ? token1Decimals : token0Decimals
// calc amountlet amount = nulllet minAmount = nullif (type == "buy") {
amount = toInnerAmount(amountIn, token1Decimals)
minAmount = toInnerAmount(outAmount * 0.99, token0Decimals)
} elseif (type == "sell") {
amount = toInnerAmount(amountIn, token0Decimals)
minAmount = toInnerAmount(outAmount * 0.99, token1Decimals)
} else {
Log("invalid type:", type)
returnfalse
}
// wallet address let walletAddress = e.IO("address")
// expired timestamplet expiredTS = parseInt((newDate().getTime() + 1000 * 60 * 5) / 1000)
// [amount of the token to be swapped, minimum acceptable amount of the token obtained from the swap, address to receive the token obtained from the swap, deadline]let data = [String(amount), String(minAmount), walletAddress, expiredTS]
// allowanceif (tokenInName != "TRX" && !(tokenInName == "WTRX" && tokenOutName == "TRX")) {
let allowanceAmount = e.IO("api", tokenInAddress, "allowance", walletAddress, smartRouterAddress)
let realAmount = toAmount(allowanceAmount, tokenInDecimals)
if (realAmount < amountIn) {
// approveLog("realAmount is", realAmount, "too small, try to approve large amount")
let txApprove = e.IO("api", tokenInAddress, "approve(address,uint256)", smartRouterAddress, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", {gasLimit: toInnerAmount(sunSwapEx.feeLimit, 6)})
if (!txApprove) {
throw"approve error"
}
let txRet = sunSwapEx.waitMined(txApprove)
if (!txRet) {
Log("approve failed")
returnfalse
} else {
Log("approve success")
}
} else {
Log("allowance", realAmount, "no need to approve")
}
}
// swapLog(`path:${path}, poolVersions:${poolVersions}, versionsLen:${versionsLen}, poolFees:${poolFees}, data:${data}`)
Log("best swap:", best)
let tx = e.IO("api", smartRouterAddress, "swapExactInput(address[],string[],uint256[],uint24[],(uint256,uint256,address,uint256))", tokenInName == "TRX" ? toInnerAmount(amountIn, 6) : 0, path, poolVersions, versionsLen, poolFees, data, {gasLimit: toInnerAmount(sunSwapEx.feeLimit, 6)})
if (tx) {
Log("tx: ", tx)
let txRet = sunSwapEx.waitMined(tx)
if (!txRet) {
Log("swap", tokenInName, "to", tokenOutName, "failed")
returnfalse
} else {
Log("swap", tokenInName, "to", tokenOutName, "success")
returntrue
}
} else {
Log("trans error")
returnfalse
}
}
sunSwapEx.SendTRX = function(to, amount) {
let e = sunSwapEx.ereturn e.IO("api", "tron", "send", to, toInnerAmount(amount, 6))
}
sunSwapEx.SetFeeLimit = function(feeLimit) {
sunSwapEx.feeLimit = feeLimit
Log("SetFeeLimit, feeLimit:", sunSwapEx.feeLimit, ", toInnerAmount:", toInnerAmount(sunSwapEx.feeLimit, 6))
}
// initif (typeof(e) == "undefined") {
e = exchange
Log("By default, the exchange configuration is used")
}
sunSwapEx.e = e
// tronlet ret = e.IO("api", "tron", "GetNodeInfo")
if (!ret) {
throw"The current Web3 tron exchange object may be misconfigured"
} else {
Log("node information:", ret)
}
// feeLimit
sunSwapEx.feeLimit = 50// register abilet factoryV3Address = "TThJt8zaJzJMhCEScH7zWKnp5buVZqys9x"
sunSwapEx.factoryV3Address = factoryV3Address
let poolABI = `[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"indexed":true,"name":"owner","internalType":"address","type":"address"},{"indexed":true,"name":"tickLower","internalType":"int24","type":"int24"},{"indexed":true,"name":"tickUpper","internalType":"int24","type":"int24"},{"indexed":false,"name":"amount","internalType":"uint128","type":"uint128"},{"indexed":false,"name":"amount0","internalType":"uint256","type":"uint256"},{"indexed":false,"name":"amount1","internalType":"uint256","type":"uint256"}],"name":"Burn","anonymous":false,"type":"event"},{"inputs":[{"indexed":true,"name":"owner","internalType":"address","type":"address"},{"indexed":false,"name":"recipient","internalType":"address","type":"address"},{"indexed":true,"name":"tickLower","internalType":"int24","type":"int24"},{"indexed":true,"name":"tickUpper","internalType":"int24","type":"int24"},{"indexed":false,"name":"amount0","internalType":"uint128","type":"uint128"},{"indexed":false,"name":"amount1","internalType":"uint128","type":"uint128"}],"name":"Collect","anonymous":false,"type":"event"},{"inputs":[{"indexed":true,"name":"sender","internalType":"address","type":"address"},{"indexed":true,"name":"recipient","internalType":"address","type":"address"},{"indexed":false,"name":"amount0","internalType":"uint128","type":"uint128"},{"indexed":false,"name":"amount1","internalType":"uint128","type":"uint128"}],"name":"CollectProtocol","anonymous":false,"type":"event"},{"inputs":[{"indexed":true,"name":"sender","internalType":"address","type":"address"},{"indexed":true,"name":"recipient","internalType":"address","type":"address"},{"indexed":false,"name":"amount0","internalType":"uint256","type":"uint256"},{"indexed":false,"name":"amount1","internalType":"uint256","type":"uint256"},{"indexed":false,"name":"paid0","internalType":"uint256","type":"uint256"},{"indexed":false,"name":"paid1","internalType":"uint256","type":"uint256"}],"name":"Flash","anonymous":false,"type":"event"},{"inputs":[{"indexed":false,"name":"observationCardinalityNextOld","internalType":"uint16","type":"uint16"},{"indexed":false,"name":"observationCardinalityNextNew","internalType":"uint16","type":"uint16"}],"name":"IncreaseObservationCardinalityNext","anonymous":false,"type":"event"},{"inputs":[{"indexed":false,"name":"sqrtPriceX96","internalType":"uint160","type":"uint160"},{"indexed":false,"name":"tick","internalType":"int24","type":"int24"}],"name":"Initialize","anonymous":false,"type":"event"},{"inputs":[{"indexed":false,"name":"sender","internalType":"address","type":"address"},{"indexed":true,"name":"owner","internalType":"address","type":"address"},{"indexed":true,"name":"tickLower","internalType":"int24","type":"int24"},{"indexed":true,"name":"tickUpper","internalType":"int24","type":"int24"},{"indexed":false,"name":"amount","internalType":"uint128","type":"uint128"},{"indexed":false,"name":"amount0","internalType":"uint256","type":"uint256"},{"indexed":false,"name":"amount1","internalType":"uint256","type":"uint256"}],"name":"Mint","anonymous":false,"type":"event"},{"inputs":[{"indexed":false,"name":"feeProtocol0Old","internalType":"uint8","type":"uint8"},{"indexed":false,"name":"feeProtocol1Old","internalType":"uint8","type":"uint8"},{"indexed":false,"name":"feeProtocol0New","internalType":"uint8","type":"uint8"},{"indexed":false,"name":"feeProtocol1New","internalType":"uint8","type":"uint8"}],"name":"SetFeeProtocol","anonymous":false,"type":"event"},{"inputs":[{"indexed":true,"name":"sender","internalType":"address","type":"address"},{"indexed":true,"name":"recipient","internalType":"address","type":"address"},{"indexed":false,"name":"amount0","internalType":"int256","type":"int256"},{"indexed":false,"name":"amount1","internalType":"int256","type":"int256"},{"indexed":false,"name":"sqrtPriceX96","internalType":"uint160","type":"uint160"},{"indexed":false,"name":"liquidity","internalType":"uint128","type":"uint128"},{"indexed":false,"name":"tick","internalType":"int24","type":"int24"}],"name":"Swap","anonymous":false,"type":"event"},{"outputs":[{"name":"","internalType":"address","type":"address"}],"inputs":[],"name":"factory","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint24","type":"uint24"}],"inputs":[],"name":"fee","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint256","type":"uint256"}],"inputs":[],"name":"feeGrowthGlobal0X128","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint256","type":"uint256"}],"inputs":[],"name":"feeGrowthGlobal1X128","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint128","type":"uint128"}],"inputs":[],"name":"liquidity","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint128","type":"uint128"}],"inputs":[],"name":"maxLiquidityPerTick","stateMutability":"view","type":"function"},{"outputs":[{"name":"blockTimestamp","internalType":"uint32","type":"uint32"},{"name":"tickCumulative","internalType":"int56","type":"int56"},{"name":"secondsPerLiquidityCumulativeX128","internalType":"uint160","type":"uint160"},{"name":"initialized","internalType":"bool","type":"bool"}],"inputs":[{"name":"","internalType":"uint256","type":"uint256"}],"name":"observations","stateMutability":"view","type":"function"},{"outputs":[{"name":"liquidity","internalType":"uint128","type":"uint128"},{"name":"feeGrowthInside0LastX128","internalType":"uint256","type":"uint256"},{"name":"feeGrowthInside1LastX128","internalType":"uint256","type":"uint256"},{"name":"tokensOwed0","internalType":"uint128","type":"uint128"},{"name":"tokensOwed1","internalType":"uint128","type":"uint128"}],"inputs":[{"name":"","internalType":"bytes32","type":"bytes32"}],"name":"positions","stateMutability":"view","type":"function"},{"outputs":[{"name":"token0","internalType":"uint128","type":"uint128"},{"name":"token1","internalType":"uint128","type":"uint128"}],"inputs":[],"name":"protocolFees","stateMutability":"view","type":"function"},{"outputs":[{"name":"sqrtPriceX96","internalType":"uint160","type":"uint160"},{"name":"tick","internalType":"int24","type":"int24"},{"name":"observationIndex","internalType":"uint16","type":"uint16"},{"name":"observationCardinality","internalType":"uint16","type":"uint16"},{"name":"observationCardinalityNext","internalType":"uint16","type":"uint16"},{"name":"feeProtocol","internalType":"uint8","type":"uint8"},{"name":"unlocked","internalType":"bool","type":"bool"}],"inputs":[],"name":"slot0","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint256","type":"uint256"}],"inputs":[{"name":"","internalType":"int16","type":"int16"}],"name":"tickBitmap","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"int24","type":"int24"}],"inputs":[],"name":"tickSpacing","stateMutability":"view","type":"function"},{"outputs":[{"name":"liquidityGross","internalType":"uint128","type":"uint128"},{"name":"liquidityNet","internalType":"int128","type":"int128"},{"name":"feeGrowthOutside0X128","internalType":"uint256","type":"uint256"},{"name":"feeGrowthOutside1X128","internalType":"uint256","type":"uint256"},{"name":"tickCumulativeOutside","internalType":"int56","type":"int56"},{"name":"secondsPerLiquidityOutsideX128","internalType":"uint160","type":"uint160"},{"name":"secondsOutside","internalType":"uint32","type":"uint32"},{"name":"initialized","internalType":"bool","type":"bool"}],"inputs":[{"name":"","internalType":"int24","type":"int24"}],"name":"ticks","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"address","type":"address"}],"inputs":[],"name":"token0","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"address","type":"address"}],"inputs":[],"name":"token1","stateMutability":"view","type":"function"},{"outputs":[{"name":"tickCumulativeInside","internalType":"int56","type":"int56"},{"name":"secondsPerLiquidityInsideX128","internalType":"uint160","type":"uint160"},{"name":"secondsInside","internalType":"uint32","type":"uint32"}],"inputs":[{"name":"tickLower","internalType":"int24","type":"int24"},{"name":"tickUpper","internalType":"int24","type":"int24"}],"name":"snapshotCumulativesInside","stateMutability":"view","type":"function"},{"outputs":[{"name":"tickCumulatives","internalType":"int56[]","type":"int56[]"},{"name":"secondsPerLiquidityCumulativeX128s","internalType":"uint160[]","type":"uint160[]"}],"inputs":[{"name":"secondsAgos","internalType":"uint32[]","type":"uint32[]"}],"name":"observe","stateMutability":"view","type":"function"},{"outputs":[],"inputs":[{"name":"observationCardinalityNext","internalType":"uint16","type":"uint16"}],"name":"increaseObservationCardinalityNext","stateMutability":"nonpayable","type":"function"},{"outputs":[],"inputs":[{"name":"sqrtPriceX96","internalType":"uint160","type":"uint160"}],"name":"initialize","stateMutability":"nonpayable","type":"function"},{"outputs":[{"name":"amount0","internalType":"uint256","type":"uint256"},{"name":"amount1","internalType":"uint256","type":"uint256"}],"inputs":[{"name":"recipient","internalType":"address","type":"address"},{"name":"tickLower","internalType":"int24","type":"int24"},{"name":"tickUpper","internalType":"int24","type":"int24"},{"name":"amount","internalType":"uint128","type":"uint128"},{"name":"data","internalType":"bytes","type":"bytes"}],"name":"mint","stateMutability":"nonpayable","type":"function"},{"outputs":[{"name":"amount0","internalType":"uint128","type":"uint128"},{"name":"amount1","internalType":"uint128","type":"uint128"}],"inputs":[{"name":"recipient","internalType":"address","type":"address"},{"name":"tickLower","internalType":"int24","type":"int24"},{"name":"tickUpper","internalType":"int24","type":"int24"},{"name":"amount0Requested","internalType":"uint128","type":"uint128"},{"name":"amount1Requested","internalType":"uint128","type":"uint128"}],"name":"collect","stateMutability":"nonpayable","type":"function"},{"outputs":[{"name":"amount0","internalType":"uint256","type":"uint256"},{"name":"amount1","internalType":"uint256","type":"uint256"}],"inputs":[{"name":"tickLower","internalType":"int24","type":"int24"},{"name":"tickUpper","internalType":"int24","type":"int24"},{"name":"amount","internalType":"uint128","type":"uint128"}],"name":"burn","stateMutability":"nonpayable","type":"function"},{"outputs":[{"name":"amount0","internalType":"int256","type":"int256"},{"name":"amount1","internalType":"int256","type":"int256"}],"inputs":[{"name":"recipient","internalType":"address","type":"address"},{"name":"zeroForOne","internalType":"bool","type":"bool"},{"name":"amountSpecified","internalType":"int256","type":"int256"},{"name":"sqrtPriceLimitX96","internalType":"uint160","type":"uint160"},{"name":"data","internalType":"bytes","type":"bytes"}],"name":"swap","stateMutability":"nonpayable","type":"function"},{"outputs":[],"inputs":[{"name":"recipient","internalType":"address","type":"address"},{"name":"amount0","internalType":"uint256","type":"uint256"},{"name":"amount1","internalType":"uint256","type":"uint256"},{"name":"data","internalType":"bytes","type":"bytes"}],"name":"flash","stateMutability":"nonpayable","type":"function"},{"outputs":[],"inputs":[{"name":"feeProtocol0","internalType":"uint8","type":"uint8"},{"name":"feeProtocol1","internalType":"uint8","type":"uint8"}],"name":"setFeeProtocol","stateMutability":"nonpayable","type":"function"},{"outputs":[{"name":"amount0","internalType":"uint128","type":"uint128"},{"name":"amount1","internalType":"uint128","type":"uint128"}],"inputs":[{"name":"recipient","internalType":"address","type":"address"},{"name":"amount0Requested","internalType":"uint128","type":"uint128"},{"name":"amount1Requested","internalType":"uint128","type":"uint128"}],"name":"collectProtocol","stateMutability":"nonpayable","type":"function"}]`
sunSwapEx.poolABI = poolABI
let multicallContractAddress = "TGXuuKAb4bnrn137u39EKbYzKNXvdCes98"
sunSwapEx.multicallContractAddress = multicallContractAddress
let multicallContractABI = `[{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct TronMulticall.Call[]","name":"calls","type":"tuple[]"}],"name":"aggregate","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"bytes[]","name":"returnData","type":"bytes[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBasefee","outputs":[{"internalType":"uint256","name":"basefee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getBlockHash","outputs":[{"internalType":"bytes32","name":"blockHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBlockNumber","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getChainId","outputs":[{"internalType":"uint256","name":"chainid","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentBlockCoinbase","outputs":[{"internalType":"address","name":"coinbase","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentBlockDifficulty","outputs":[{"internalType":"uint256","name":"difficulty","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentBlockTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"getEthBalance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastBlockHash","outputs":[{"internalType":"bytes32","name":"blockHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"accountAddress","type":"address"},{"internalType":"trcToken","name":"id","type":"trcToken"}],"name":"getTokenBalance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isContract","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"view","type":"function"}]`
sunSwapEx.registerABI(multicallContractAddress, multicallContractABI)
let smartRouterAddress = "TCFNp179Lg46D16zKoumd4Poa2WFFdtqYj"
sunSwapEx.smartRouterAddress = smartRouterAddress
let smartRouterABI = `[{"outputs":[{"name":"amountsOut","type":"uint256[]"}],"inputs":[{"name":"path","type":"address[]"},{"name":"poolVersion","type":"string[]"},{"name":"versionLen","type":"uint256[]"},{"name":"fees","type":"uint24[]"},{"name":"data","type":"tuple"}],"name":"swapExactInput","stateMutability":"payable","type":"function","payable":true}]`
sunSwapEx.registerABI(smartRouterAddress, smartRouterABI)
// get sunswap_markets
sunSwapEx.markets = _G("sunswap_markets")
return sunSwapEx
}
// for testfunctionmain() {
// reset logLogReset(1)
// reset _G()// _G(null)// Create SunswapEx let e = $.CreateSunSwapEx()
// let e = $.CreateSunSwapEx(exchanges[1])// /* GetMarketslet markets = e.GetMarkets()
let idx = 0let tbl = {"type": "table", "title": "test GetMarkets", "cols": ["Index", "PoolAddress", "Symbol", "BaseAsset", "QuoteAsset", "BaseName", "QuoteName", "BaseDecimals", "QuoteDecimals", "BaseAddress", "QuoteAddress"], "rows": []}
for (let currency in markets) {
let arrMarket = markets[currency]
for (let market of arrMarket) {
tbl["rows"].push([idx, market["PoolAddress"], market["Symbol"], market["BaseAsset"], market["QuoteAsset"], market["BaseName"], market["QuoteName"], market["BaseDecimals"], market["QuoteDecimals"], market["BaseAddress"], market["QuoteAddress"]])
idx++
}
}
LogStatus("`" + JSON.stringify(tbl) + "`")
// *//* GetTicker
let ticker1 = e.GetTicker("WTRX_USDT")
Log("symbol:", "WTRX_USDT", ", ticker:", ticker1)
let ticker2 = e.GetTicker("iCMX_USDT", "TLVDozYEBgeaJXH7oKBsougzEJKNrogFun") // iCMX_USDT
Log("symbol:", "iCMX_USDT", ", ticker:", ticker2)
*//* multicall
let data = []
let walletAddress = exchange.IO("address")
data.push(["TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "0x" + exchange.IO("encode", "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "balanceOf", walletAddress)])
data.push(["TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "0x" + exchange.IO("encode", "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "balanceOf", walletAddress)])
Log(data)
let ret = multicall(exchange, "TGXuuKAb4bnrn137u39EKbYzKNXvdCes98", data, ["uint256", "uint256"])
Log(ret, toAmount(ret[0], 6))
*//* GetSwapOutAmount
let retBuy = e.GetSwapOutAmount("WTRX_USDT", 1, "buy") // 1 quote -> base
Log("WTRX_USDT", "buy outAmount:", retBuy["outAmount"], ", ask:", (1 / retBuy["outAmount"]))
let retSell = e.GetSwapOutAmount("WTRX_USDT", 1, "sell") // 1 base -> quote
Log("WTRX_USDT", "sell outAmount:", retSell["outAmount"], ", bid:", (retSell["outAmount"] / 1))
*//* GetAssets
let assets = e.GetAssets()
let tbl = {"type": "table", "title": "test GetAssets", "cols": ["Name", "Address", "Decimals", "Balance"], "rows": []}
for (let asset of assets) {
tbl["rows"].push([asset.Currency, asset.Address, asset.Decimals, asset.Amount])
}
LogStatus("`" + JSON.stringify(tbl) + "`")
*//* Swap
// let ret = e.Swap("WTRX_USDT", 6, "buy")
// let ret = e.Swap("WTRX_TUSD", 6, "buy")
// let ret = e.Swap("WTRX_TUSD", 10, "sell")
// let ret = e.Swap("TRX_WTRX", 10, "sell")
// let ret = e.Swap("TRX_WTRX", 10, "buy")
// let ret = e.Swap("TUSD_TRX", 0.3, "sell")
// let ret = e.Swap("WTRX_USDT", 20, "sell")
// let ret = e.Swap("USDT_TRX", 6, "sell")
Log(ret)
*//* check token
let mapFilter = {}
let checkMarkets = e.GetMarkets()
for (let currency in checkMarkets) {
for (let market of checkMarkets[currency]) {
let base = market["BaseAsset"]
let quote = market["QuoteAsset"]
if (typeof(mapFilter[base]) == "undefined") {
mapFilter[base] = market["BaseAddress"]
}
if (typeof(mapFilter[quote]) == "undefined") {
mapFilter[quote] = market["QuoteAddress"]
}
if (market["BaseAddress"] != mapFilter[base]) {
Log(market["BaseAsset"], market["BaseAddress"], " --- ", base, mapFilter[base])
}
if (market["QuoteAddress"] != mapFilter[quote]) {
Log(market["QuoteAsset"], market["QuoteAddress"], " --- ", quote, mapFilter[quote])
}
}
}
*//* GetAccount
let account = e.GetAccount()
Log(account)
*//* StakeTRX
// BANDWIDTH, ENERGY, TRON_POWER
let retStakeTRX = e.StakeTRX("ENERGY", 10) // Stake TRX
Log("retStakeTRX:", retStakeTRX)
// let retUnStakeTRX = e.UnStakeTRX("ENERGY", 100) // UnStake TRX
// Log("retUnStakeTRX:", retUnStakeTRX)
*//* send
// let ret = e.SendTRX("...", 180)
// Log("SendTRX ret:", ret)
*/
}
functionisEmptyObject(obj) {
returnObject.keys(obj).length === 0
}
functioncomputePoolPrice(decimals0, decimals1, sqrtPriceX96) {
[decimals0, decimals1, sqrtPriceX96] = [decimals0, decimals1, sqrtPriceX96].map(BigInt)
constTWO = BigInt(2)
constTEN = BigInt(10)
constSIX_TENTH = BigInt(1000000)
constQ192 = (TWO ** BigInt(96)) ** TWOreturn (Number((sqrtPriceX96 ** TWO * TEN ** decimals0 * SIX_TENTH) / (Q192 * TEN ** decimals1)) / Number(SIX_TENTH))
}
functionmulticall(e, multicallContractAddress, data, outTypes) {
let ret = e.IO("api", multicallContractAddress, "aggregate", data)
if (!ret || !ret["returnData"] || !Array.isArray(ret["returnData"])) {
Log("invalid ret:", ret)
returnnull
}
let arrRet = ret["returnData"]
if (outTypes.length != arrRet.length) {
Log("Arrays have unequal lengths:", arrRet, outTypes)
returnnull
}
let outData = []
for (let i in arrRet) {
outData.push(e.IO("decode", outTypes[i], arrRet[i]))
}
return outData
}
functiontoAmount(s, decimals) {
returnNumber((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}
functiontoInnerAmount(n, decimals) {
return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0)
}
functionhexToUint8Array(hex) {
if (hex.length % 2 !== 0) {
thrownewError("Invalid hex string length")
}
returnUint8Array.from(
hex.match(/.{1,2}/g).map(byte =>parseInt(byte, 16))
)
}
functionuint8ArrayToHex(array) {
returnArray.from(array).map(byte => byte.toString(16).padStart(2, "0")).join("")
}
functionethAddressToTron(ethAddress) {
if (!/^0x[0-9a-fA-F]{40}$/.test(ethAddress)) {
throw"Invalid Ethereum address"
}
const ethAddressBytes = newUint8Array(20)
for (let i = 0; i < 20; i++) {
ethAddressBytes[i] = parseInt(ethAddress.substr(2 + i * 2, 2), 16)
}
const tronAddressBytes = newUint8Array(21)
tronAddressBytes[0] = 0x41
tronAddressBytes.set(ethAddressBytes, 1)
const hash1 = Encode("sha256", "hex", "hex", uint8ArrayToHex(tronAddressBytes))
const hash2 = Encode("sha256", "hex", "hex", hash1)
const checksum = hash2.slice(0, 8)
const fullAddress = newUint8Array(25)
fullAddress.set(tronAddressBytes, 0)
fullAddress.set(hexToUint8Array(checksum), 21)
returnbase58Encode(fullAddress)
}
functionbase58Encode(buffer) {
const base58Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"let num = BigInt("0x" + Array.from(buffer).map(b => b.toString(16).padStart(2, "0")).join(""))
let encoded = ""while (num > 0) {
let remainder = num % 58n
num = num / 58n
encoded = base58Alphabet[Number(remainder)] + encoded
}
for (let byte of buffer) {
if (byte === 0) {
encoded = base58Alphabet[0] + encoded
} else {
break
}
}
return encoded
}
functionbase58ToHex(base58Str) {
constALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"var num = BigInt(0)
for (var char of base58Str) {
var digit = BigInt(ALPHABET.indexOf(char))
if (digit === BigInt(-1)) thrownewError("Invalid Base58 character: " + char)
num = num * BigInt(58) + digit
}
var hex = num.toString(16)
if (hex.length % 2 !== 0) {
hex = "0" + hex
}
return"0x" + hex
}
$.CreateSunSwapEx = function(e) {
let sunSwapEx = {}
sunSwapEx.registerABI = function(address, codeABI) {
let e = sunSwapEx.eif (typeof(address) == "undefined" || typeof(codeABI) == "undefined") {
throw"need address, codeABI"
}
return e.IO("abi", address, codeABI)
}
sunSwapEx.getCurrencyInfo = function(token0Address, token1Address) {
let e = sunSwapEx.elet arrTokenAddress = [token0Address, token1Address]
let tokenInfoCallData = []
let tokenInfoRetType = []
for (let tokenAddress of arrTokenAddress) {
tokenInfoCallData.push([tokenAddress, "0x" + e.IO("encode", tokenAddress, "symbol")])
tokenInfoRetType.push("string")
tokenInfoCallData.push([tokenAddress, "0x" + e.IO("encode", tokenAddress, "name")])
tokenInfoRetType.push("string")
tokenInfoCallData.push([tokenAddress, "0x" + e.IO("encode", tokenAddress, "decimals")])
tokenInfoRetType.push("uint8")
}
let currencyInfo = _C(multicall, e, multicallContractAddress, tokenInfoCallData, tokenInfoRetType)
if (currencyInfo.length != 6) {
Log("invalid currency Info:", currencyInfo)
returnnull
}
let ret = {
"token0Symbol": currencyInfo[0],
"token0Name": currencyInfo[1],
"token0Decimals": currencyInfo[2],
"token1Symbol": currencyInfo[3],
"token1Name": currencyInfo[4],
"token1Decimals": currencyInfo[5]
}
return ret
}
sunSwapEx.waitMined = function(tx) {
let e = sunSwapEx.elet i = 0let maxLoop = 10while (true) {
Sleep(3000)
let info = e.IO("api", "tron", "GetTransactionInfoByID", tx)
if (info && info.receipt && typeof(info.receipt.result) == "number") {
Log("GetTransactionInfoByID:", info)
if (info.receipt.result == 1) {
returntrue
} else {
returnfalse
}
}
Log("Transaction not yet mined", tx)
if (i > maxLoop) {
break
}
i++
}
Log(`Transaction: ${tx} not found`)
returnfalse
}
sunSwapEx.getTokenInfo = function(tokenSymbol) {
let markets = sunSwapEx.marketsif (!markets || isEmptyObject(markets)) {
markets = sunSwapEx.GetMarkets()
}
if (tokenSymbol == "TRX") {
return {"tokenSymbol": tokenSymbol, "tokenName": tokenSymbol, "tokenDecimals": 6, "tokenAddress": "--"}
}
for (let currency in markets) {
for (let market of markets[currency]) {
if (market["BaseAsset"] == tokenSymbol) {
return {"tokenSymbol": market["BaseAsset"], "tokenName": market["BaseName"], "tokenDecimals": market["BaseDecimals"], "tokenAddress": market["BaseAddress"]}
} elseif (market["QuoteAsset"] == tokenSymbol) {
return {"tokenSymbol": market["QuoteAsset"], "tokenName": market["QuoteName"], "tokenDecimals": market["QuoteDecimals"], "tokenAddress": market["QuoteAddress"]}
}
}
}
Log("not found token symbol:", tokenSymbol)
returnnull
}
sunSwapEx.dealStakeTRX = function(methodName, resourceName, amount) {
let e = sunSwapEx.elet walletAddress = e.IO("address")
let balance = toInnerAmount(amount, 6)
let resourceCode = -1if (resourceName == "BANDWIDTH") {
resourceCode = 0
} elseif (resourceName == "ENERGY") {
resourceCode = 1
} elseif (resourceName == "TRON_POWER") {
resourceCode = 2
} else {
Log("not support resourceName:", resourceName)
returnnull
}
return e.IO("api", "tron", methodName, walletAddress, resourceCode, balance)
}
sunSwapEx.GetMarkets = function() {
// sunswap v3 poollet e = sunSwapEx.eif (!sunSwapEx.markets) {
sunSwapEx.markets = {}
}
let markets = sunSwapEx.marketsif (!isEmptyObject(markets)) {
return markets
}
let factoryV3Address = sunSwapEx.factoryV3Address// allPoolsLengthlet poolIdx = e.IO("api", factoryV3Address, "allPoolsLength")
if (!poolIdx) {
Log("invalid poolIdx:", poolIdx)
returnnull
}
Log("allPoolsLength:", poolIdx)
// multicallContractAddresslet multicallContractAddress = sunSwapEx.multicallContractAddress// get All pool addresslet retPools = []
let getPoolsData = []
let retPoolsType = []
for (let i = 0; i < poolIdx; i++) {
getPoolsData.push([factoryV3Address, "0x" + e.IO("encode", factoryV3Address, "allPools", String(i))])
retPoolsType.push("address")
if (getPoolsData.length > 30 || i == poolIdx - 1) {
let arr = _C(multicall, e, multicallContractAddress, getPoolsData, retPoolsType)
retPools.push(...arr)
getPoolsData = []
retPoolsType = []
}
}
// allPoolslet poolABI = sunSwapEx.poolABIfor (let i in retPools) {
// poolAddresslet poolAddress = ethAddressToTron(retPools[i])
// register pool ABI
sunSwapEx.registerABI(poolAddress, poolABI)
// get token address of the poollet tokenCallData = [[poolAddress, "0x" + e.IO("encode", poolAddress, "token0")], [poolAddress, "0x" + e.IO("encode", poolAddress, "token1")]]
let tokenRetType = ["address", "address"]
let arrTokenAddress = _C(multicall, e, multicallContractAddress, tokenCallData, tokenRetType)
let token0Address = ethAddressToTron(arrTokenAddress[0])
let token1Address = ethAddressToTron(arrTokenAddress[1])
// symbol , name , decimalslet currencyInfo = sunSwapEx.getCurrencyInfo(token0Address, token1Address)
if (!currencyInfo) {
returnnull
}
let token0Symbol = currencyInfo["token0Symbol"]
let token0Name = currencyInfo["token0Name"]
let token0Decimals = currencyInfo["token0Decimals"]
let token1Symbol = currencyInfo["token1Symbol"]
let token1Name = currencyInfo["token1Name"]
let token1Decimals = currencyInfo["token1Decimals"]
// Aliaslet mapAlias = {
"TJWm3jWaJeCdyRckEXfopsJBvZi6wXVK2p": "PAPA",
"TPYmHEhy5n8TCEfYGqW2rPxsghSfzghPDn": "USDDOLD",
"TTiwtPv4MFHMoCpGDBEF85qQjD2v4e99ck": "HOUSDOLD",
"TRFe3hT5oYhjSZ6f3ji5FJ7YCfrkWnHRvh": "ETHB"
}
if (typeof(mapAlias[token0Address]) != "undefined") {
token0Symbol = mapAlias[token0Address]
}
if (typeof(mapAlias[token1Address]) != "undefined") {
token1Symbol = mapAlias[token1Address]
}
// badlet mapBad = {
"TMEmRKPob42vhkqEGopCnfBPixN5XTkdUc": "U S D T", // Attention: Fishing contract"TXioUZK8ju3R54KvzSqPc6Ufq5wkxFqpq9": "U S D T", // Attention: Fishing contract"TU41FWQQT8hZ6t72gVEjtSGn1Dshbevi7g": "CNY Coin", // Attention: Invalid"TYB7oXNq4VyuiH5BHb4os8rTh7Ca8pxqSx": "BULL", // Attention: Fishing contract"TYJxozCVMUiHg3TbQp9PKeuXdTsX9ugJz9": "SHISHA", // Attention: Not circulated"TF9io9LGyjuK3uTpr73pAaQ5m9scxd9xvr": "TestToken18", // Attention: Test trading pairs"TK8E3sFhBt3EB6gTT6d6co8RMB6DFUnNwE": "TestToken6"// Attention: Test trading pairs
}
if (typeof(mapBad[token0Address]) != "undefined" || typeof(mapBad[token1Address]) != "undefined") {
continue
}
// marketlet currency = token0Symbol + "_" + token1Symbol
let market = {
"Symbol": currency,
"BaseAsset": token0Symbol,
"QuoteAsset": token1Symbol,
"BaseName": token0Name,
"QuoteName": token1Name,
"BaseDecimals": token0Decimals,
"QuoteDecimals": token1Decimals,
"BaseAddress": token0Address,
"QuoteAddress": token1Address,
"PoolAddress": poolAddress,
"PoolIndex": i
}
if (!Array.isArray(markets[currency])) {
markets[currency] = []
}
markets[currency].push(market)
LogStatus(_D(), "get markets, length:", Object.keys(markets).length)
Sleep(200)
}
_G("sunswap_markets", markets)
sunSwapEx.markets = markets
return markets
}
sunSwapEx.GetTicker = function(symbol, targetPoolAddress) {
let e = sunSwapEx.elet markets = sunSwapEx.marketsif (!markets || isEmptyObject(markets)) {
markets = sunSwapEx.GetMarkets()
}
let arrPoolAddress = []
let arrToken0Decimals = []
let arrToken1Decimals = []
for (let currency in markets) {
if (!Array.isArray(markets[currency]) || markets[currency].length == 0) {
continue
}
if (currency == symbol) {
for (let ele of markets[currency]) {
if (typeof(targetPoolAddress) != "undefined" && ele["PoolAddress"] != targetPoolAddress) {
continue
}
arrPoolAddress.push(ele["PoolAddress"])
arrToken0Decimals.push(ele["BaseDecimals"])
arrToken1Decimals.push(ele["QuoteDecimals"])
}
}
}
if (arrPoolAddress.length == 0) {
Log(`${symbol} and ${targetPoolAddress} not found`)
sunSwapEx.markets = {}
returnnull
}
let arrPrice = []
let slot0CallData = []
let slot0RetType = []
for (let i in arrPoolAddress) {
let poolAddress = arrPoolAddress[i]
let poolABI = sunSwapEx.poolABI
e.IO("abi", poolAddress, poolABI)
slot0CallData.push([poolAddress, "0x" + e.IO("encode", poolAddress, "slot0")])
slot0RetType.push("(uint160,int24,uint16,uint16,uint16,uint8,bool)")
}
let multicallContractAddress = sunSwapEx.multicallContractAddresslet arrSlot0 = _C(multicall, e, multicallContractAddress, slot0CallData, slot0RetType)
for (let i in arrSlot0) {
let slot0 = arrSlot0[i]
let token0Decimals = arrToken0Decimals[i]
let token1Decimals = arrToken1Decimals[i]
let sqrtPriceX96 = slot0["Field1"]
let poolAddress = arrPoolAddress[i]
let price = computePoolPrice(token0Decimals, token1Decimals, sqrtPriceX96)
arrPrice.push({"price": price, "poolAddress": poolAddress})
}
return arrPrice
}
sunSwapEx.GetSwapOutAmount = function(symbol, amountIn, type) {
let arrCurrency = symbol.split("_")
if (arrCurrency.length != 2) {
Log("invalid symbol:", symbol)
returnnull
}
let baseCurrencyInfo = sunSwapEx.getTokenInfo(arrCurrency[0])
let quoteCurrencyInfo = sunSwapEx.getTokenInfo(arrCurrency[1])
if (!baseCurrencyInfo || !quoteCurrencyInfo) {
returnnull
}
let baseSymbol = baseCurrencyInfo["tokenSymbol"]
let baseAddress = baseCurrencyInfo["tokenAddress"]
let baseDecimals = baseCurrencyInfo["tokenDecimals"]
let quoteSymbol = quoteCurrencyInfo["tokenSymbol"]
let quoteAddress = quoteCurrencyInfo["tokenAddress"]
let quoteDecimals = quoteCurrencyInfo["tokenDecimals"]
// black hole addressif (baseSymbol == "TRX") {
baseAddress = "T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb"
}
if (quoteSymbol == "TRX") {
quoteAddress = "T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb"
}
let query = nullif (type == "buy") {
let amount = toInnerAmount(amountIn, quoteDecimals)
query = `?fromToken=${quoteAddress}&toToken=${baseAddress}&amountIn=${amount}&typeList=WTRX,SUNSWAP_V1,SUNSWAP_V2,SUNSWAP_V3`
} elseif (type == "sell") {
let amount = toInnerAmount(amountIn, baseDecimals)
query = `?fromToken=${baseAddress}&toToken=${quoteAddress}&amountIn=${amount}&typeList=WTRX,SUNSWAP_V1,SUNSWAP_V2,SUNSWAP_V3`
} else {
Log("not support type:", type)
returnnull
}
try {
let ret = JSON.parse(HttpQuery("https://rot.endjgfsv.link/swap/router" + query))
Log("https://rot.endjgfsv.link/swap/router" + query, "GetSwapOutAmount ret:", ret)
if (!ret || ret["message"] != "SUCCESS") {
Log("invalid data:", ret)
returnnull
}
let outAmount = nulllet best = nulllet info = ret["data"]
for (let ele of info) {
if (!outAmount) {
outAmount = parseFloat(ele["amountOut"])
best = ele
} else {
let amount = parseFloat(ele["amountOut"])
if (amount > outAmount) {
outAmount = amount
best = ele
}
}
}
if (!outAmount || !best) {
Log("info:", info)
returnnull
}
return {"info": info, "outAmount": outAmount, "best": best, "baseCurrencyInfo": baseCurrencyInfo, "quoteCurrencyInfo": quoteCurrencyInfo}
} catch(e) {
Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
returnnull
}
}
sunSwapEx.GetAccount = function() {
let e = sunSwapEx.elet walletAddress = e.IO("address")
let account = e.IO("api", "tron", "GetAccount", walletAddress)
if (!account) {
Log("get account failed, account:", account)
returnnull
}
let trxBalance = toAmount(account["balance"], 6)
let resource = e.IO("api", "tron", "GetAccountResource", walletAddress)
if (!resource) {
Log("get resource failed, resource:", resource)
returnnull
}
let energyLimit = resource["EnergyLimit"] ? resource["EnergyLimit"] : 0let freeNetLimit = resource["freeNetLimit"] ? resource["freeNetLimit"] : 0return {"Info": {"GetAccount": account, "GetAccountResource": resource}, "TRX": trxBalance, "Bandwidth": freeNetLimit, "Energy": energyLimit}
}
sunSwapEx.GetAssets = function() {
let e = sunSwapEx.elet walletAddress = e.IO("address")
try {
let ret = JSON.parse(HttpQuery("https://apilist.tronscanapi.com/api/account/token_asset_overview?address=" + walletAddress))
let assets = []
for (let info of ret["data"]) {
let decimals = parseInt(info["tokenDecimal"])
let asset = {
"Currency": info["tokenAbbr"] == "trx" ? "TRX" : info["tokenAbbr"],
"Decimals": decimals,
"Amount": toAmount(info["balance"], decimals),
"Address": info["tokenId"],
}
assets.push(asset)
}
return assets
} catch(e) {
Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
returnnull
}
}
sunSwapEx.StakeTRX = function(resourceName, frozenBalance) {
return sunSwapEx.dealStakeTRX("FreezeBalanceV2", resourceName, frozenBalance)
}
sunSwapEx.UnStakeTRX = function(resourceName, unfreezeBalance) {
return sunSwapEx.dealStakeTRX("UnfreezeBalanceV2", resourceName, unfreezeBalance)
}
sunSwapEx.WrappedTRX = function(actionType, amountIn) {
let e = sunSwapEx.elet tx = nullif (actionType == "deposit") {
let amount = toInnerAmount(amountIn, 6)
tx = e.IO("api", "TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR", "deposit", amount, {gasLimit: toInnerAmount(sunSwapEx.feeLimit, 6)})
} elseif (actionType == "withdraw") {
tx = e.IO("api", "TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR", "withdraw(uint256)", toInnerAmount(amountIn, 6), {gasLimit: toInnerAmount(sunSwapEx.feeLimit, 6)})
} else {
Log("not support actionType:", actionType)
returnfalse
}
if (tx) {
Log("tx: ", tx)
let txRet = sunSwapEx.waitMined(tx)
if (!txRet) {
Log(actionType, "failed")
returnfalse
} else {
Log(actionType, "success")
returntrue
}
} else {
Log("trans error")
returnfalse
}
}
sunSwapEx.Swap = function(symbol, amountIn, type) {
let e = sunSwapEx.elet smartRouterAddress = sunSwapEx.smartRouterAddressif (symbol == "TRX_WTRX" || symbol == "WTRX_TRX") {
let actionType = nullif (type == "buy") {
actionType = symbol == "TRX_WTRX" ? "withdraw" : "deposit"
} elseif (type == "sell") {
actionType = symbol == "TRX_WTRX" ? "deposit" : "withdraw"
} else {
Log("invalid type:", type)
returnfalse
}
return sunSwapEx.WrappedTRX(actionType, amountIn)
}
let swapInfo = sunSwapEx.GetSwapOutAmount(symbol, amountIn, type)
if (!swapInfo || !swapInfo["best"]) {
Log("invalid swapInfo:", swapInfo)
returnfalse
}
let outAmount = swapInfo["outAmount"]
let best = swapInfo["best"]
// pathlet path = best["tokens"]
if (!path || path.length < 2) {
Log("invalid path:", path)
returnfalse
}
// poolVersions and versionsLenlet poolVersions = []
let versionsLen = []
for (var v of best["poolVersions"]) {
if (poolVersions.length == 0) {
poolVersions.push(v)
versionsLen.push(2)
} else {
if (poolVersions[poolVersions.length - 1] == v) {
versionsLen[versionsLen.length - 1] += 1
} else {
poolVersions.push(v)
versionsLen.push(1)
}
}
}
// fees let poolFees = best["poolFees"]
// get decimals , token name let token0Decimals = swapInfo["baseCurrencyInfo"]["tokenDecimals"]
let token1Decimals = swapInfo["quoteCurrencyInfo"]["tokenDecimals"]
let tokenInName = type == "buy" ? swapInfo["quoteCurrencyInfo"]["tokenSymbol"] : swapInfo["baseCurrencyInfo"]["tokenSymbol"]
let tokenOutName = type == "buy" ? swapInfo["baseCurrencyInfo"]["tokenSymbol"] : swapInfo["quoteCurrencyInfo"]["tokenSymbol"]
let tokenInAddress = type == "buy" ? swapInfo["quoteCurrencyInfo"]["tokenAddress"] : swapInfo["baseCurrencyInfo"]["tokenAddress"]
let tokenOutAddress = type == "buy" ? swapInfo["baseCurrencyInfo"]["tokenAddress"] : swapInfo["quoteCurrencyInfo"]["tokenAddress"]
let tokenInDecimals = type == "buy" ? token1Decimals : token0Decimals
// calc amountlet amount = nulllet minAmount = nullif (type == "buy") {
amount = toInnerAmount(amountIn, token1Decimals)
minAmount = toInnerAmount(outAmount * 0.99, token0Decimals)
} elseif (type == "sell") {
amount = toInnerAmount(amountIn, token0Decimals)
minAmount = toInnerAmount(outAmount * 0.99, token1Decimals)
} else {
Log("invalid type:", type)
returnfalse
}
// wallet address let walletAddress = e.IO("address")
// expired timestamplet expiredTS = parseInt((newDate().getTime() + 1000 * 60 * 5) / 1000)
// [amount of the token to be swapped, minimum acceptable amount of the token obtained from the swap, address to receive the token obtained from the swap, deadline]let data = [String(amount), String(minAmount), walletAddress, expiredTS]
// allowanceif (tokenInName != "TRX" && !(tokenInName == "WTRX" && tokenOutName == "TRX")) {
let allowanceAmount = e.IO("api", tokenInAddress, "allowance", walletAddress, smartRouterAddress)
let realAmount = toAmount(allowanceAmount, tokenInDecimals)
if (realAmount < amountIn) {
// approveLog("realAmount is", realAmount, "too small, try to approve large amount")
let txApprove = e.IO("api", tokenInAddress, "approve(address,uint256)", smartRouterAddress, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", {gasLimit: toInnerAmount(sunSwapEx.feeLimit, 6)})
if (!txApprove) {
throw"approve error"
}
let txRet = sunSwapEx.waitMined(txApprove)
if (!txRet) {
Log("approve failed")
returnfalse
} else {
Log("approve success")
}
} else {
Log("allowance", realAmount, "no need to approve")
}
}
// swapLog(`path:${path}, poolVersions:${poolVersions}, versionsLen:${versionsLen}, poolFees:${poolFees}, data:${data}`)
Log("best swap:", best)
let tx = e.IO("api", smartRouterAddress, "swapExactInput(address[],string[],uint256[],uint24[],(uint256,uint256,address,uint256))", tokenInName == "TRX" ? toInnerAmount(amountIn, 6) : 0, path, poolVersions, versionsLen, poolFees, data, {gasLimit: toInnerAmount(sunSwapEx.feeLimit, 6)})
if (tx) {
Log("tx: ", tx)
let txRet = sunSwapEx.waitMined(tx)
if (!txRet) {
Log("swap", tokenInName, "to", tokenOutName, "failed")
returnfalse
} else {
Log("swap", tokenInName, "to", tokenOutName, "success")
returntrue
}
} else {
Log("trans error")
returnfalse
}
}
sunSwapEx.SendTRX = function(to, amount) {
let e = sunSwapEx.ereturn e.IO("api", "tron", "send", to, toInnerAmount(amount, 6))
}
sunSwapEx.SetFeeLimit = function(feeLimit) {
sunSwapEx.feeLimit = feeLimit
Log("SetFeeLimit, feeLimit:", sunSwapEx.feeLimit, ", toInnerAmount:", toInnerAmount(sunSwapEx.feeLimit, 6))
}
// initif (typeof(e) == "undefined") {
e = exchange
Log("By default, the exchange configuration is used")
}
sunSwapEx.e = e
// tronlet ret = e.IO("api", "tron", "GetNodeInfo")
if (!ret) {
throw"The current Web3 tron exchange object may be misconfigured"
} else {
Log("node information:", ret)
}
// feeLimit
sunSwapEx.feeLimit = 50// register abilet factoryV3Address = "TThJt8zaJzJMhCEScH7zWKnp5buVZqys9x"
sunSwapEx.factoryV3Address = factoryV3Address
let poolABI = `[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"indexed":true,"name":"owner","internalType":"address","type":"address"},{"indexed":true,"name":"tickLower","internalType":"int24","type":"int24"},{"indexed":true,"name":"tickUpper","internalType":"int24","type":"int24"},{"indexed":false,"name":"amount","internalType":"uint128","type":"uint128"},{"indexed":false,"name":"amount0","internalType":"uint256","type":"uint256"},{"indexed":false,"name":"amount1","internalType":"uint256","type":"uint256"}],"name":"Burn","anonymous":false,"type":"event"},{"inputs":[{"indexed":true,"name":"owner","internalType":"address","type":"address"},{"indexed":false,"name":"recipient","internalType":"address","type":"address"},{"indexed":true,"name":"tickLower","internalType":"int24","type":"int24"},{"indexed":true,"name":"tickUpper","internalType":"int24","type":"int24"},{"indexed":false,"name":"amount0","internalType":"uint128","type":"uint128"},{"indexed":false,"name":"amount1","internalType":"uint128","type":"uint128"}],"name":"Collect","anonymous":false,"type":"event"},{"inputs":[{"indexed":true,"name":"sender","internalType":"address","type":"address"},{"indexed":true,"name":"recipient","internalType":"address","type":"address"},{"indexed":false,"name":"amount0","internalType":"uint128","type":"uint128"},{"indexed":false,"name":"amount1","internalType":"uint128","type":"uint128"}],"name":"CollectProtocol","anonymous":false,"type":"event"},{"inputs":[{"indexed":true,"name":"sender","internalType":"address","type":"address"},{"indexed":true,"name":"recipient","internalType":"address","type":"address"},{"indexed":false,"name":"amount0","internalType":"uint256","type":"uint256"},{"indexed":false,"name":"amount1","internalType":"uint256","type":"uint256"},{"indexed":false,"name":"paid0","internalType":"uint256","type":"uint256"},{"indexed":false,"name":"paid1","internalType":"uint256","type":"uint256"}],"name":"Flash","anonymous":false,"type":"event"},{"inputs":[{"indexed":false,"name":"observationCardinalityNextOld","internalType":"uint16","type":"uint16"},{"indexed":false,"name":"observationCardinalityNextNew","internalType":"uint16","type":"uint16"}],"name":"IncreaseObservationCardinalityNext","anonymous":false,"type":"event"},{"inputs":[{"indexed":false,"name":"sqrtPriceX96","internalType":"uint160","type":"uint160"},{"indexed":false,"name":"tick","internalType":"int24","type":"int24"}],"name":"Initialize","anonymous":false,"type":"event"},{"inputs":[{"indexed":false,"name":"sender","internalType":"address","type":"address"},{"indexed":true,"name":"owner","internalType":"address","type":"address"},{"indexed":true,"name":"tickLower","internalType":"int24","type":"int24"},{"indexed":true,"name":"tickUpper","internalType":"int24","type":"int24"},{"indexed":false,"name":"amount","internalType":"uint128","type":"uint128"},{"indexed":false,"name":"amount0","internalType":"uint256","type":"uint256"},{"indexed":false,"name":"amount1","internalType":"uint256","type":"uint256"}],"name":"Mint","anonymous":false,"type":"event"},{"inputs":[{"indexed":false,"name":"feeProtocol0Old","internalType":"uint8","type":"uint8"},{"indexed":false,"name":"feeProtocol1Old","internalType":"uint8","type":"uint8"},{"indexed":false,"name":"feeProtocol0New","internalType":"uint8","type":"uint8"},{"indexed":false,"name":"feeProtocol1New","internalType":"uint8","type":"uint8"}],"name":"SetFeeProtocol","anonymous":false,"type":"event"},{"inputs":[{"indexed":true,"name":"sender","internalType":"address","type":"address"},{"indexed":true,"name":"recipient","internalType":"address","type":"address"},{"indexed":false,"name":"amount0","internalType":"int256","type":"int256"},{"indexed":false,"name":"amount1","internalType":"int256","type":"int256"},{"indexed":false,"name":"sqrtPriceX96","internalType":"uint160","type":"uint160"},{"indexed":false,"name":"liquidity","internalType":"uint128","type":"uint128"},{"indexed":false,"name":"tick","internalType":"int24","type":"int24"}],"name":"Swap","anonymous":false,"type":"event"},{"outputs":[{"name":"","internalType":"address","type":"address"}],"inputs":[],"name":"factory","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint24","type":"uint24"}],"inputs":[],"name":"fee","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint256","type":"uint256"}],"inputs":[],"name":"feeGrowthGlobal0X128","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint256","type":"uint256"}],"inputs":[],"name":"feeGrowthGlobal1X128","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint128","type":"uint128"}],"inputs":[],"name":"liquidity","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint128","type":"uint128"}],"inputs":[],"name":"maxLiquidityPerTick","stateMutability":"view","type":"function"},{"outputs":[{"name":"blockTimestamp","internalType":"uint32","type":"uint32"},{"name":"tickCumulative","internalType":"int56","type":"int56"},{"name":"secondsPerLiquidityCumulativeX128","internalType":"uint160","type":"uint160"},{"name":"initialized","internalType":"bool","type":"bool"}],"inputs":[{"name":"","internalType":"uint256","type":"uint256"}],"name":"observations","stateMutability":"view","type":"function"},{"outputs":[{"name":"liquidity","internalType":"uint128","type":"uint128"},{"name":"feeGrowthInside0LastX128","internalType":"uint256","type":"uint256"},{"name":"feeGrowthInside1LastX128","internalType":"uint256","type":"uint256"},{"name":"tokensOwed0","internalType":"uint128","type":"uint128"},{"name":"tokensOwed1","internalType":"uint128","type":"uint128"}],"inputs":[{"name":"","internalType":"bytes32","type":"bytes32"}],"name":"positions","stateMutability":"view","type":"function"},{"outputs":[{"name":"token0","internalType":"uint128","type":"uint128"},{"name":"token1","internalType":"uint128","type":"uint128"}],"inputs":[],"name":"protocolFees","stateMutability":"view","type":"function"},{"outputs":[{"name":"sqrtPriceX96","internalType":"uint160","type":"uint160"},{"name":"tick","internalType":"int24","type":"int24"},{"name":"observationIndex","internalType":"uint16","type":"uint16"},{"name":"observationCardinality","internalType":"uint16","type":"uint16"},{"name":"observationCardinalityNext","internalType":"uint16","type":"uint16"},{"name":"feeProtocol","internalType":"uint8","type":"uint8"},{"name":"unlocked","internalType":"bool","type":"bool"}],"inputs":[],"name":"slot0","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"uint256","type":"uint256"}],"inputs":[{"name":"","internalType":"int16","type":"int16"}],"name":"tickBitmap","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"int24","type":"int24"}],"inputs":[],"name":"tickSpacing","stateMutability":"view","type":"function"},{"outputs":[{"name":"liquidityGross","internalType":"uint128","type":"uint128"},{"name":"liquidityNet","internalType":"int128","type":"int128"},{"name":"feeGrowthOutside0X128","internalType":"uint256","type":"uint256"},{"name":"feeGrowthOutside1X128","internalType":"uint256","type":"uint256"},{"name":"tickCumulativeOutside","internalType":"int56","type":"int56"},{"name":"secondsPerLiquidityOutsideX128","internalType":"uint160","type":"uint160"},{"name":"secondsOutside","internalType":"uint32","type":"uint32"},{"name":"initialized","internalType":"bool","type":"bool"}],"inputs":[{"name":"","internalType":"int24","type":"int24"}],"name":"ticks","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"address","type":"address"}],"inputs":[],"name":"token0","stateMutability":"view","type":"function"},{"outputs":[{"name":"","internalType":"address","type":"address"}],"inputs":[],"name":"token1","stateMutability":"view","type":"function"},{"outputs":[{"name":"tickCumulativeInside","internalType":"int56","type":"int56"},{"name":"secondsPerLiquidityInsideX128","internalType":"uint160","type":"uint160"},{"name":"secondsInside","internalType":"uint32","type":"uint32"}],"inputs":[{"name":"tickLower","internalType":"int24","type":"int24"},{"name":"tickUpper","internalType":"int24","type":"int24"}],"name":"snapshotCumulativesInside","stateMutability":"view","type":"function"},{"outputs":[{"name":"tickCumulatives","internalType":"int56[]","type":"int56[]"},{"name":"secondsPerLiquidityCumulativeX128s","internalType":"uint160[]","type":"uint160[]"}],"inputs":[{"name":"secondsAgos","internalType":"uint32[]","type":"uint32[]"}],"name":"observe","stateMutability":"view","type":"function"},{"outputs":[],"inputs":[{"name":"observationCardinalityNext","internalType":"uint16","type":"uint16"}],"name":"increaseObservationCardinalityNext","stateMutability":"nonpayable","type":"function"},{"outputs":[],"inputs":[{"name":"sqrtPriceX96","internalType":"uint160","type":"uint160"}],"name":"initialize","stateMutability":"nonpayable","type":"function"},{"outputs":[{"name":"amount0","internalType":"uint256","type":"uint256"},{"name":"amount1","internalType":"uint256","type":"uint256"}],"inputs":[{"name":"recipient","internalType":"address","type":"address"},{"name":"tickLower","internalType":"int24","type":"int24"},{"name":"tickUpper","internalType":"int24","type":"int24"},{"name":"amount","internalType":"uint128","type":"uint128"},{"name":"data","internalType":"bytes","type":"bytes"}],"name":"mint","stateMutability":"nonpayable","type":"function"},{"outputs":[{"name":"amount0","internalType":"uint128","type":"uint128"},{"name":"amount1","internalType":"uint128","type":"uint128"}],"inputs":[{"name":"recipient","internalType":"address","type":"address"},{"name":"tickLower","internalType":"int24","type":"int24"},{"name":"tickUpper","internalType":"int24","type":"int24"},{"name":"amount0Requested","internalType":"uint128","type":"uint128"},{"name":"amount1Requested","internalType":"uint128","type":"uint128"}],"name":"collect","stateMutability":"nonpayable","type":"function"},{"outputs":[{"name":"amount0","internalType":"uint256","type":"uint256"},{"name":"amount1","internalType":"uint256","type":"uint256"}],"inputs":[{"name":"tickLower","internalType":"int24","type":"int24"},{"name":"tickUpper","internalType":"int24","type":"int24"},{"name":"amount","internalType":"uint128","type":"uint128"}],"name":"burn","stateMutability":"nonpayable","type":"function"},{"outputs":[{"name":"amount0","internalType":"int256","type":"int256"},{"name":"amount1","internalType":"int256","type":"int256"}],"inputs":[{"name":"recipient","internalType":"address","type":"address"},{"name":"zeroForOne","internalType":"bool","type":"bool"},{"name":"amountSpecified","internalType":"int256","type":"int256"},{"name":"sqrtPriceLimitX96","internalType":"uint160","type":"uint160"},{"name":"data","internalType":"bytes","type":"bytes"}],"name":"swap","stateMutability":"nonpayable","type":"function"},{"outputs":[],"inputs":[{"name":"recipient","internalType":"address","type":"address"},{"name":"amount0","internalType":"uint256","type":"uint256"},{"name":"amount1","internalType":"uint256","type":"uint256"},{"name":"data","internalType":"bytes","type":"bytes"}],"name":"flash","stateMutability":"nonpayable","type":"function"},{"outputs":[],"inputs":[{"name":"feeProtocol0","internalType":"uint8","type":"uint8"},{"name":"feeProtocol1","internalType":"uint8","type":"uint8"}],"name":"setFeeProtocol","stateMutability":"nonpayable","type":"function"},{"outputs":[{"name":"amount0","internalType":"uint128","type":"uint128"},{"name":"amount1","internalType":"uint128","type":"uint128"}],"inputs":[{"name":"recipient","internalType":"address","type":"address"},{"name":"amount0Requested","internalType":"uint128","type":"uint128"},{"name":"amount1Requested","internalType":"uint128","type":"uint128"}],"name":"collectProtocol","stateMutability":"nonpayable","type":"function"}]`
sunSwapEx.poolABI = poolABI
let multicallContractAddress = "TGXuuKAb4bnrn137u39EKbYzKNXvdCes98"
sunSwapEx.multicallContractAddress = multicallContractAddress
let multicallContractABI = `[{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct TronMulticall.Call[]","name":"calls","type":"tuple[]"}],"name":"aggregate","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"bytes[]","name":"returnData","type":"bytes[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBasefee","outputs":[{"internalType":"uint256","name":"basefee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getBlockHash","outputs":[{"internalType":"bytes32","name":"blockHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBlockNumber","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getChainId","outputs":[{"internalType":"uint256","name":"chainid","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentBlockCoinbase","outputs":[{"internalType":"address","name":"coinbase","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentBlockDifficulty","outputs":[{"internalType":"uint256","name":"difficulty","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentBlockTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"getEthBalance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastBlockHash","outputs":[{"internalType":"bytes32","name":"blockHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"accountAddress","type":"address"},{"internalType":"trcToken","name":"id","type":"trcToken"}],"name":"getTokenBalance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isContract","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"view","type":"function"}]`
sunSwapEx.registerABI(multicallContractAddress, multicallContractABI)
let smartRouterAddress = "TCFNp179Lg46D16zKoumd4Poa2WFFdtqYj"
sunSwapEx.smartRouterAddress = smartRouterAddress
let smartRouterABI = `[{"outputs":[{"name":"amountsOut","type":"uint256[]"}],"inputs":[{"name":"path","type":"address[]"},{"name":"poolVersion","type":"string[]"},{"name":"versionLen","type":"uint256[]"},{"name":"fees","type":"uint24[]"},{"name":"data","type":"tuple"}],"name":"swapExactInput","stateMutability":"payable","type":"function","payable":true}]`
sunSwapEx.registerABI(smartRouterAddress, smartRouterABI)
// get sunswap_markets
sunSwapEx.markets = _G("sunswap_markets")
return sunSwapEx
}
// for testfunctionmain() {
// reset logLogReset(1)
// reset _G()// _G(null)// Create SunswapEx let e = $.CreateSunSwapEx()
// let e = $.CreateSunSwapEx(exchanges[1])// /* GetMarketslet markets = e.GetMarkets()
let idx = 0let tbl = {"type": "table", "title": "test GetMarkets", "cols": ["Index", "PoolAddress", "Symbol", "BaseAsset", "QuoteAsset", "BaseName", "QuoteName", "BaseDecimals", "QuoteDecimals", "BaseAddress", "QuoteAddress"], "rows": []}
for (let currency in markets) {
let arrMarket = markets[currency]
for (let market of arrMarket) {
tbl["rows"].push([idx, market["PoolAddress"], market["Symbol"], market["BaseAsset"], market["QuoteAsset"], market["BaseName"], market["QuoteName"], market["BaseDecimals"], market["QuoteDecimals"], market["BaseAddress"], market["QuoteAddress"]])
idx++
}
}
LogStatus("`" + JSON.stringify(tbl) + "`")
// *//* GetTicker
let ticker1 = e.GetTicker("WTRX_USDT")
Log("symbol:", "WTRX_USDT", ", ticker:", ticker1)
let ticker2 = e.GetTicker("iCMX_USDT", "TLVDozYEBgeaJXH7oKBsougzEJKNrogFun") // iCMX_USDT
Log("symbol:", "iCMX_USDT", ", ticker:", ticker2)
*//* multicall
let data = []
let walletAddress = exchange.IO("address")
data.push(["TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "0x" + exchange.IO("encode", "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "balanceOf", walletAddress)])
data.push(["TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "0x" + exchange.IO("encode", "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "balanceOf", walletAddress)])
Log(data)
let ret = multicall(exchange, "TGXuuKAb4bnrn137u39EKbYzKNXvdCes98", data, ["uint256", "uint256"])
Log(ret, toAmount(ret[0], 6))
*//* GetSwapOutAmount
let retBuy = e.GetSwapOutAmount("WTRX_USDT", 1, "buy") // 1 quote -> base
Log("WTRX_USDT", "buy outAmount:", retBuy["outAmount"], ", ask:", (1 / retBuy["outAmount"]))
let retSell = e.GetSwapOutAmount("WTRX_USDT", 1, "sell") // 1 base -> quote
Log("WTRX_USDT", "sell outAmount:", retSell["outAmount"], ", bid:", (retSell["outAmount"] / 1))
*//* GetAssets
let assets = e.GetAssets()
let tbl = {"type": "table", "title": "test GetAssets", "cols": ["Name", "Address", "Decimals", "Balance"], "rows": []}
for (let asset of assets) {
tbl["rows"].push([asset.Currency, asset.Address, asset.Decimals, asset.Amount])
}
LogStatus("`" + JSON.stringify(tbl) + "`")
*//* Swap
// let ret = e.Swap("WTRX_USDT", 6, "buy")
// let ret = e.Swap("WTRX_TUSD", 6, "buy")
// let ret = e.Swap("WTRX_TUSD", 10, "sell")
// let ret = e.Swap("TRX_WTRX", 10, "sell")
// let ret = e.Swap("TRX_WTRX", 10, "buy")
// let ret = e.Swap("TUSD_TRX", 0.3, "sell")
// let ret = e.Swap("WTRX_USDT", 20, "sell")
// let ret = e.Swap("USDT_TRX", 6, "sell")
Log(ret)
*//* check token
let mapFilter = {}
let checkMarkets = e.GetMarkets()
for (let currency in checkMarkets) {
for (let market of checkMarkets[currency]) {
let base = market["BaseAsset"]
let quote = market["QuoteAsset"]
if (typeof(mapFilter[base]) == "undefined") {
mapFilter[base] = market["BaseAddress"]
}
if (typeof(mapFilter[quote]) == "undefined") {
mapFilter[quote] = market["QuoteAddress"]
}
if (market["BaseAddress"] != mapFilter[base]) {
Log(market["BaseAsset"], market["BaseAddress"], " --- ", base, mapFilter[base])
}
if (market["QuoteAddress"] != mapFilter[quote]) {
Log(market["QuoteAsset"], market["QuoteAddress"], " --- ", quote, mapFilter[quote])
}
}
}
*//* GetAccount
let account = e.GetAccount()
Log(account)
*//* StakeTRX
// BANDWIDTH, ENERGY, TRON_POWER
let retStakeTRX = e.StakeTRX("ENERGY", 10) // Stake TRX
Log("retStakeTRX:", retStakeTRX)
// let retUnStakeTRX = e.UnStakeTRX("ENERGY", 100) // UnStake TRX
// Log("retUnStakeTRX:", retUnStakeTRX)
*//* send
// let ret = e.SendTRX("...", 180)
// Log("SendTRX ret:", ret)
*/
}
END
Through this article, we have realized the Web3 Tron package based on the FMZ Quant platform, and connected to SunSwap DEX successfully, completing the complete process from querying the trading pool to executing the exchange and parsing the transaction results. This not only provides an efficient automation solution for DEX transactions in the Tron ecosystem, but also demonstrates the powerful scalability of the FMZ Quant platform.
I hope that the practical experience in this article can provide valuable reference for your quantitative trading system. Next, I will study the DEX on SOL. Thank you for reading~