github.com/diadata-org/diadata@v1.4.593/pkg/dia/helpers/velarhelper/mapper.go (about) 1 package velarhelper 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 "strings" 7 8 stacks "github.com/diadata-org/diadata/pkg/dia/helpers/stackshelper" 9 ) 10 11 func DecodeSwapEvents(tx stacks.Transaction) ([]SwapEvent, error) { 12 result := make([]SwapEvent, 0, len(tx.Events)) 13 lastEventIndex := -1 14 15 for i, e := range tx.Events { 16 if !isSwapEvent(e) { 17 continue 18 } 19 bytes, err := hex.DecodeString(e.ContractLog.Value.Hex[2:]) 20 if err != nil { 21 return nil, err 22 } 23 event, err := stacks.DeserializeCVTuple(bytes) 24 if err != nil { 25 return nil, err 26 } 27 28 info := SwapEvent{TxID: tx.TxID, Timestamp: tx.BlockTime} 29 info.AmountIn, err = stacks.DeserializeCVUint(event["amt-in"]) 30 if err != nil { 31 return nil, err 32 } 33 info.AmountOut, err = stacks.DeserializeCVUint(event["amt-out"]) 34 if err != nil { 35 return nil, err 36 } 37 38 poolAssets, err := decodePoolAssets(event["pool"]) 39 if err != nil { 40 return nil, err 41 } 42 info.TickerID = poolAssets[0] + "_" + poolAssets[1] 43 44 if val, ok := event["token-in"]; ok { 45 info.TokenIn, err = stacks.DeserializeCVPrincipal(val) 46 if err != nil { 47 return nil, err 48 } 49 } else { 50 sender, err := stacks.DeserializeCVPrincipal(event["user"]) 51 if err != nil { 52 return nil, err 53 } 54 outer: 55 for j := lastEventIndex + 1; j < i; j++ { 56 ev := &tx.Events[j] 57 if ev.Asset.EventType != "transfer" || 58 ev.Asset.Sender != sender || 59 ev.Asset.Recipient != e.ContractLog.ContractID { 60 continue 61 } 62 63 switch ev.Type { 64 case "fungible_token_asset": 65 info.TokenIn = strings.Split(ev.Asset.ID, "::")[0] 66 break outer 67 case "stx_asset": 68 for _, a := range poolAssets { 69 if a == DeployerAddress+".wstx" { 70 info.TokenIn = a 71 break outer 72 } 73 } 74 } 75 } 76 } 77 78 switch info.TokenIn { 79 case poolAssets[0]: 80 info.TokenOut = poolAssets[1] 81 case poolAssets[1]: 82 info.TokenOut = poolAssets[0] 83 default: 84 err = fmt.Errorf("unable to decode input token address: no matches for %s", info.TokenIn) 85 return nil, err 86 } 87 88 result = append(result, info) 89 lastEventIndex = i 90 } 91 92 return result, nil 93 } 94 95 func isSwapEvent(ev stacks.Event) bool { 96 log := ev.ContractLog 97 return ev.Type == "smart_contract_log" && 98 log.Topic == "print" && 99 (strings.HasPrefix(log.ContractID, DeployerAddress) || strings.HasPrefix(log.ContractID, DeployerAddressV2)) && 100 strings.Contains(log.Value.Repr, "(op \"swap\")") 101 } 102 103 func decodePoolAssets(src []byte) ([2]string, error) { 104 result := [2]string{} 105 106 pool, err := stacks.DeserializeCVTuple(src) 107 if err != nil { 108 return result, err 109 } 110 111 result[0], err = stacks.DeserializeCVPrincipal(pool["token0"]) 112 if err != nil { 113 return result, err 114 } 115 result[1], err = stacks.DeserializeCVPrincipal(pool["token1"]) 116 if err != nil { 117 return result, err 118 } 119 120 return result, nil 121 }