| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- package arbitrage
- import (
- "github.com/ethereum/go-ethereum/arbitrage/api"
- "github.com/ethereum/go-ethereum/log"
- "github.com/shopspring/decimal"
- )
- // FundMovements 池子资金动向
- type FundMovements struct {
- LpHash string
- Fee int64
- InIndex uint64
- InToken string
- InReserve decimal.Decimal
- OutIndex uint64
- OutToken string
- OutReserve decimal.Decimal
- }
- // Path 交易路径
- type Path struct {
- // path.FirstLpInTokenHash = firstFm.InToken
- FirstLpInTokenHash string
- // path.LastLpOutTokenHash = lastFm.OutToken
- LastLpOutTokenHash string
- LoanLp string
- LoanIndex int64
- LoanTokenHash string
- Level int64
- Profit decimal.Decimal
- FeeTokenProfit decimal.Decimal
- Sim Simulation
- LpHashList []string
- FmList []FundMovements
- }
- // InsertionSort 不适合大量数据的排序,暂时可以先用着
- func InsertionSort(paths []Path) {
- for i := 1; i < len(paths); i++ {
- key := paths[i]
- j := i - 1
- // Move elements of paths[0..i-1], that are
- // greater than key, to one position ahead
- // of their current position
- for j >= 0 && paths[j].Profit.LessThan(key.Profit) {
- paths[j+1] = paths[j]
- j = j - 1
- }
- paths[j+1] = key
- }
- }
- func PutSimulationToPathList(pathList []Path) {
- for index, path := range pathList {
- if path.Level == 2 {
- SimulationLevel2Path(&path)
- } else if path.Level == 3 {
- SimulationLevel3Path(&path)
- }
- pathList[index] = path
- }
- }
- func GetFinalPathList(pathList []Path) []Path {
- var finalPathList []Path
- for _, path := range pathList {
- if path.Profit.GreaterThan(MinProfit) {
- finalPathList = append(finalPathList, path)
- }
- }
- return finalPathList
- }
- func GenerateTokenLpListMapping(lpList []api.V2Lp) map[string][]api.V2Lp {
- mapping := make(map[string][]api.V2Lp)
- for _, lp := range lpList {
- mapping[lp.Token0] = append(mapping[lp.Token0], lp)
- mapping[lp.Token1] = append(mapping[lp.Token1], lp)
- }
- return mapping
- }
- func LpListFilter(lpList []api.V2Lp, unfilteredMapping map[string][]api.V2Lp) []api.V2Lp {
- var filteredLpList []api.V2Lp
- for _, lp := range lpList {
- isToken0NoCorrelation := len(unfilteredMapping[lp.Token0]) <= 1
- isToken1NoCorrelation := len(unfilteredMapping[lp.Token1]) <= 1
- // 有任意一个token是孤儿token(与其他lp没有关系),则该lp是无效lp
- if isToken0NoCorrelation || isToken1NoCorrelation {
- continue
- }
- filteredLpList = append(filteredLpList, lp)
- }
- return filteredLpList
- }
- func GeneratePathListCore(finalMapping map[string][]api.V2Lp, level int64, maxLevel int64, path Path) []Path {
- var pathList []Path
- // 1. path闭环判断
- firstFm := path.FmList[0]
- lastFm := path.FmList[len(path.FmList)-1]
- // 要同时满足进出一致和LastOutToken为MagicToken的条件
- if firstFm.InToken == lastFm.OutToken && IsMagicToken(lastFm.OutToken) {
- path.Level = level - 1
- path.FirstLpInTokenHash = firstFm.InToken
- path.LastLpOutTokenHash = lastFm.OutToken
- pathList = append(pathList, path)
- return pathList
- }
- // 2. level溢出判断
- if maxLevel < level {
- return pathList
- }
- // 3. 不闭环或不溢出,继续递归
- relatedLpList := finalMapping[lastFm.OutToken]
- for _, lp := range relatedLpList {
- // 3.1 lp去重(用过的lp不再用)
- isLpUsed := false
- for _, fm := range path.FmList {
- if lp.Hash == fm.LpHash {
- isLpUsed = true
- }
- }
- if isLpUsed {
- continue
- }
- newPath := path
- // 3.2 构造FundMovements,必须要
- if lastFm.OutToken == lp.Token0 {
- newPath.FmList = append(path.FmList, FundMovements{
- LpHash: lp.Hash,
- Fee: lp.Fee,
- InIndex: 0,
- InToken: lp.Token0,
- InReserve: lp.R0,
- OutIndex: 1,
- OutToken: lp.Token1,
- OutReserve: lp.R1,
- })
- newPath.LpHashList = append(newPath.LpHashList, lp.Hash)
- } else if lastFm.OutToken == lp.Token1 {
- newPath.FmList = append(path.FmList, FundMovements{
- LpHash: lp.Hash,
- Fee: lp.Fee,
- InIndex: 1,
- InToken: lp.Token1,
- InReserve: lp.R1,
- OutIndex: 0,
- OutToken: lp.Token0,
- OutReserve: lp.R0,
- })
- newPath.LpHashList = append(newPath.LpHashList, lp.Hash)
- } else {
- log.Error("path生成有错误,请重新debug查询。", "lp hash", lp.Hash)
- continue
- }
- newPathList := GeneratePathListCore(finalMapping, level+1, maxLevel, newPath)
- pathList = append(pathList, newPathList...)
- }
- return pathList
- }
- func GeneratePathList(finalLpList []api.V2Lp, finalMapping map[string][]api.V2Lp, maxLevel int64) []Path {
- var pathList []Path
- NowLevel := int64(1)
- for _, lp := range finalLpList {
- pathA := Path{
- Level: NowLevel,
- LoanTokenHash: lp.Token1,
- LoanLp: lp.Hash,
- LoanIndex: 1,
- FmList: []FundMovements{
- {
- LpHash: lp.Hash,
- Fee: lp.Fee,
- InIndex: 0,
- InToken: lp.Token0,
- InReserve: lp.R0,
- OutIndex: 1,
- OutToken: lp.Token1,
- OutReserve: lp.R1,
- },
- },
- }
- pathA.LpHashList = append(pathA.LpHashList, lp.Hash)
- pathListA := GeneratePathListCore(finalMapping, NowLevel+1, maxLevel, pathA)
- pathB := Path{
- Level: NowLevel,
- LoanTokenHash: lp.Token0,
- LoanLp: lp.Hash,
- LoanIndex: 0,
- FmList: []FundMovements{
- {
- LpHash: lp.Hash,
- Fee: lp.Fee,
- InIndex: 1,
- InToken: lp.Token1,
- InReserve: lp.R1,
- OutIndex: 0,
- OutToken: lp.Token0,
- OutReserve: lp.R0,
- },
- },
- }
- pathB.LpHashList = append(pathB.LpHashList, lp.Hash)
- pathListB := GeneratePathListCore(finalMapping, NowLevel+1, maxLevel, pathB)
- pathList = append(pathList, pathListA...)
- pathList = append(pathList, pathListB...)
- }
- return pathList
- }
- func ParseLpToFinalLp(lpList []api.V2Lp) []api.V2Lp {
- // 1. 生成token->relatedLpList的映射结构,token为tokenHash,lpList为与该token相关的所有池子。
- //
- // 生成这个映射结构有两个目的:
- // a. 基础过滤无效lp(主要是过滤与其他lp无关的lp)
- // b. 之后可以用于生成path
- unfilteredMapping := GenerateTokenLpListMapping(lpList)
- // 2. 剔除len(lpList)<=1的映射;第二层意思:如果某个token只有一个lp,那么,该lp不属于有效池子;用于生成有效lp
- finalLpList := LpListFilter(lpList, unfilteredMapping)
- return finalLpList
- }
- func ParseLpListToPathList(finalLpList []api.V2Lp, maxLevel int64) []Path {
- // 1. 重新生成映射结构,形成最终的映射结构(token->relatedLpList)
- finalMapping := GenerateTokenLpListMapping(finalLpList)
- // 2. 根据资金流概念生成path
- pathList := GeneratePathList(finalLpList, finalMapping, maxLevel)
- return pathList
- }
- func ParseLpListToLpHashList(lpList []api.V2Lp) []string {
- var rst []string
- for _, lp := range lpList {
- rst = append(rst, lp.Hash)
- }
- return rst
- }
- func (h *HistoryArbitrage) GetLpList() []api.V2Lp {
- return h.javaApi.GetAllV2LpList(V2LpPath)
- }
- func PutR0R1ToLpList(lpList []api.V2Lp, balanceMapping map[string][2]decimal.Decimal) {
- for i := range lpList {
- lp := &(lpList[i])
- reserves := balanceMapping[lp.Hash]
- lp.R0 = reserves[0]
- lp.R1 = reserves[1]
- }
- }
- func FilterLpList(tempLpList []api.V2Lp) []api.V2Lp {
- var finalLp []api.V2Lp
- for _, lp := range tempLpList {
- if lp.R0.Equals(decimal.Zero) || lp.R1.Equals(decimal.Zero) {
- continue
- }
- finalLp = append(finalLp, lp)
- }
- return finalLp
- }
|