lp_utils.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. package arbitrage
  2. import (
  3. "github.com/ethereum/go-ethereum/arbitrage/api"
  4. "github.com/ethereum/go-ethereum/log"
  5. "github.com/ethereum/go-ethereum/params"
  6. "github.com/shopspring/decimal"
  7. "math/big"
  8. )
  9. // FundMovements 池子资金动向
  10. type FundMovements struct {
  11. LpHash string
  12. Fee int64
  13. InIndex uint64
  14. InToken string
  15. InReserve *big.Int
  16. OutIndex uint64
  17. OutToken string
  18. OutReserve *big.Int
  19. }
  20. // Path 交易路径
  21. type Path struct {
  22. InTokenHash string
  23. OutTokenHash string
  24. LoanLp string
  25. LoanIndex int64
  26. LoanTokenHash string
  27. Level int64
  28. Profit decimal.Decimal
  29. Sim Simulation
  30. FmList []FundMovements
  31. }
  32. func GenerateMapping(lpList []api.V2Lp) map[string][]api.V2Lp {
  33. mapping := make(map[string][]api.V2Lp)
  34. for _, lp := range lpList {
  35. mapping[lp.Token0] = append(mapping[lp.Token0], lp)
  36. mapping[lp.Token1] = append(mapping[lp.Token1], lp)
  37. }
  38. return mapping
  39. }
  40. func LpListFilter(lpList []api.V2Lp, unfilteredMapping map[string][]api.V2Lp) []api.V2Lp {
  41. var filteredLpList []api.V2Lp
  42. for _, lp := range lpList {
  43. isToken0NoCorrelation := len(unfilteredMapping[lp.Token0]) <= 1
  44. isToken1NoCorrelation := len(unfilteredMapping[lp.Token1]) <= 1
  45. // 有任意一个token是孤儿token(与其他lp没有关系),则该lp是无效lp
  46. if isToken0NoCorrelation || isToken1NoCorrelation {
  47. continue
  48. }
  49. filteredLpList = append(filteredLpList, lp)
  50. }
  51. return filteredLpList
  52. }
  53. func GeneratePathListCore(finalMapping map[string][]api.V2Lp, level int64, maxLevel int64, path Path) []Path {
  54. var pathList []Path
  55. // 1. path闭环判断
  56. firstFm := path.FmList[0]
  57. lastFm := path.FmList[len(path.FmList)-1]
  58. if firstFm.InToken == lastFm.OutToken {
  59. path.Level = level - 1
  60. path.InTokenHash = firstFm.InToken
  61. path.OutTokenHash = lastFm.OutToken
  62. pathList = append(pathList, path)
  63. return pathList
  64. }
  65. // 2. level溢出判断
  66. if maxLevel < level {
  67. return pathList
  68. }
  69. // 3. 不闭环或不溢出,继续递归
  70. relatedLpList := finalMapping[lastFm.OutToken]
  71. for _, lp := range relatedLpList {
  72. // 3.1 lp去重(用过的lp不再用)
  73. isLpUsed := false
  74. for _, fm := range path.FmList {
  75. if lp.Hash == fm.LpHash {
  76. isLpUsed = true
  77. }
  78. }
  79. if isLpUsed {
  80. continue
  81. }
  82. newPath := path
  83. // 3.2 构造FundMovements,必须要
  84. if lastFm.OutToken == lp.Token0 {
  85. newPath.FmList = append(path.FmList, FundMovements{
  86. LpHash: lp.Hash,
  87. Fee: lp.Fee,
  88. InIndex: 0,
  89. InToken: lp.Token0,
  90. InReserve: lp.R0,
  91. OutIndex: 1,
  92. OutToken: lp.Token1,
  93. OutReserve: lp.R1,
  94. })
  95. } else if lastFm.OutToken == lp.Token1 {
  96. newPath.FmList = append(path.FmList, FundMovements{
  97. LpHash: lp.Hash,
  98. Fee: lp.Fee,
  99. InIndex: 1,
  100. InToken: lp.Token1,
  101. InReserve: lp.R1,
  102. OutIndex: 0,
  103. OutToken: lp.Token0,
  104. OutReserve: lp.R0,
  105. })
  106. } else {
  107. log.Error("path生成有错误,请重新debug查询。", "lp hash", lp.Hash)
  108. continue
  109. }
  110. newPathList := GeneratePathListCore(finalMapping, level+1, maxLevel, newPath)
  111. pathList = append(pathList, newPathList...)
  112. }
  113. return pathList
  114. }
  115. func GeneratePathList(finalLpList []api.V2Lp, finalMapping map[string][]api.V2Lp, maxLevel int64) []Path {
  116. var pathList []Path
  117. NowLevel := int64(1)
  118. for _, lp := range finalLpList {
  119. pathA := Path{
  120. Level: NowLevel,
  121. LoanTokenHash: lp.Token1,
  122. LoanLp: lp.Hash,
  123. LoanIndex: 1,
  124. FmList: []FundMovements{
  125. {
  126. LpHash: lp.Hash,
  127. Fee: lp.Fee,
  128. InIndex: 0,
  129. InToken: lp.Token0,
  130. OutReserve: lp.R0,
  131. OutIndex: 1,
  132. OutToken: lp.Token1,
  133. InReserve: lp.R1,
  134. },
  135. },
  136. }
  137. pathListA := GeneratePathListCore(finalMapping, NowLevel+1, maxLevel, pathA)
  138. pathB := Path{
  139. Level: NowLevel,
  140. LoanTokenHash: lp.Token0,
  141. LoanLp: lp.Hash,
  142. LoanIndex: 0,
  143. FmList: []FundMovements{
  144. {
  145. LpHash: lp.Hash,
  146. Fee: lp.Fee,
  147. InIndex: 1,
  148. InToken: lp.Token1,
  149. InReserve: lp.R1,
  150. OutIndex: 0,
  151. OutToken: lp.Token0,
  152. OutReserve: lp.R0,
  153. },
  154. },
  155. }
  156. pathListB := GeneratePathListCore(finalMapping, NowLevel+1, maxLevel, pathB)
  157. pathList = append(pathList, pathListA...)
  158. pathList = append(pathList, pathListB...)
  159. }
  160. return pathList
  161. }
  162. func ParseLpToFinalLp(lpList []api.V2Lp) []api.V2Lp {
  163. // 1. 生成token->relatedLpList的映射结构,token为tokenHash,lpList为与该token相关的所有池子。
  164. //
  165. // 生成这个映射结构有两个目的:
  166. // a. 基础过滤无效lp(主要是过滤与其他lp无关的lp)
  167. // b. 之后可以用于生成path
  168. unfilteredMapping := GenerateMapping(lpList)
  169. // 2. 剔除len(lpList)<=1的映射;第二层意思:如果某个token只有一个lp,那么,该lp不属于有效池子;用于生成有效lp
  170. finalLpList := LpListFilter(lpList, unfilteredMapping)
  171. return finalLpList
  172. }
  173. func ParseLpListToPathList(finalLpList []api.V2Lp, maxLevel int64) []Path {
  174. // 1. 重新生成映射结构,形成最终的映射结构(token->relatedLpList)
  175. finalMapping := GenerateMapping(finalLpList)
  176. // 2. 根据资金流概念生成path
  177. pathList := GeneratePathList(finalLpList, finalMapping, maxLevel)
  178. return pathList
  179. }
  180. func ParseLpListToLpHashList(lpList []api.V2Lp) []string {
  181. var rst []string
  182. for _, lp := range lpList {
  183. rst = append(rst, lp.Hash)
  184. }
  185. return rst
  186. }
  187. func (h *HistoryArbitrage) GetLpList() []api.V2Lp {
  188. rst, err := h.javaApi.V2LpListByChainIdAndPaginate(api.V2LpListByChainIdAndPaginateRequest{
  189. ChainId: params.CoreChainConfig.ChainID.Uint64(),
  190. PageNumber: 1,
  191. PageSize: MaxLpLength,
  192. AuthObj: api.GenerateAuth(),
  193. })
  194. if err != nil {
  195. HistoryError("Get lp list error.", err.Error())
  196. return nil
  197. }
  198. if !rst.State {
  199. HistoryError("Get lp list java error.", err.Error())
  200. return nil
  201. }
  202. return rst.Data
  203. }
  204. func PutR0R1ToLpList(lpList *[]api.V2Lp, balanceMapping map[string][2]*big.Int) {
  205. for i := range *lpList {
  206. lp := &((*lpList)[i])
  207. reserves := balanceMapping[lp.Hash]
  208. lp.R0 = reserves[0]
  209. lp.R1 = reserves[1]
  210. }
  211. }