| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- package arbitrage
- import (
- "github.com/ethereum/go-ethereum/arbitrage/api"
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/params"
- "github.com/shopspring/decimal"
- "math/big"
- )
- // FundMovements 池子资金动向
- type FundMovements struct {
- LpHash string
- Fee int64
- InIndex uint64
- InToken string
- InReserve *big.Int
- OutIndex uint64
- OutToken string
- OutReserve *big.Int
- }
- // Path 交易路径
- type Path struct {
- InTokenHash string
- OutTokenHash string
- LoanLp string
- LoanIndex int64
- LoanTokenHash string
- Level int64
- Profit decimal.Decimal
- Sim Simulation
- FmList []FundMovements
- }
- func GenerateMapping(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]
- if firstFm.InToken == lastFm.OutToken {
- path.Level = level - 1
- path.InTokenHash = firstFm.InToken
- path.OutTokenHash = 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,
- })
- } 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,
- })
- } 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,
- OutReserve: lp.R0,
- OutIndex: 1,
- OutToken: lp.Token1,
- InReserve: lp.R1,
- },
- },
- }
- 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,
- },
- },
- }
- 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 := GenerateMapping(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 := GenerateMapping(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 {
- rst, err := h.javaApi.V2LpListByChainIdAndPaginate(api.V2LpListByChainIdAndPaginateRequest{
- ChainId: params.CoreChainConfig.ChainID.Uint64(),
- PageNumber: 1,
- PageSize: MaxLpLength,
- AuthObj: api.GenerateAuth(),
- })
- if err != nil {
- HistoryError("Get lp list error.", err.Error())
- return nil
- }
- if !rst.State {
- HistoryError("Get lp list java error.", err.Error())
- return nil
- }
- return rst.Data
- }
- func PutR0R1ToLpList(lpList *[]api.V2Lp, balanceMapping map[string][2]*big.Int) {
- for i := range *lpList {
- lp := &((*lpList)[i])
- reserves := balanceMapping[lp.Hash]
- lp.R0 = reserves[0]
- lp.R1 = reserves[1]
- }
- }
|