diff --git a/.gitignore b/.gitignore index 3b735ec..67d6924 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ # Go workspace file go.work + +.env \ No newline at end of file diff --git a/go.mod b/go.mod index fa8e49f..c1606cc 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module github.com/gnoswap-labs/vwap go 1.22.2 require ( - github.com/bxcodec/faker/v3 v3.8.1 github.com/go-sql-driver/mysql v1.8.1 github.com/stretchr/testify v1.9.0 gorm.io/driver/sqlite v1.5.5 @@ -21,10 +20,13 @@ require ( require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/alecthomas/assert v1.0.0 + github.com/bxcodec/faker v2.0.1+incompatible + github.com/bxcodec/faker/v3 v3.8.1 github.com/davecgh/go-spew v1.1.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/driver/mysql v1.5.6 ) diff --git a/go.sum b/go.sum index e7491bc..5b1f9a7 100644 --- a/go.sum +++ b/go.sum @@ -6,11 +6,14 @@ github.com/alecthomas/colour v0.1.0 h1:nOE9rJm6dsZ66RGWYSFrXw461ZIt9A6+nHgL7FRrD github.com/alecthomas/colour v0.1.0/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0= github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142 h1:8Uy0oSf5co/NZXje7U1z8Mpep++QJOldL2hs/sBQf48= github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= +github.com/bxcodec/faker v2.0.1+incompatible h1:P0KUpUw5w6WJXwrPfv35oc91i4d8nf40Nwln+M/+faA= +github.com/bxcodec/faker v2.0.1+incompatible/go.mod h1:BNzfpVdTwnFJ6GtfYTcQu6l6rHShT+veBxNCnjCx5XM= github.com/bxcodec/faker/v3 v3.8.1 h1:qO/Xq19V6uHt2xujwpaetgKhraGCapqY2CRWGD/SqcM= github.com/bxcodec/faker/v3 v3.8.1/go.mod h1:DdSDccxF5msjFo5aO4vrobRQ8nIApg8kq3QWPEQD6+o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -43,7 +46,10 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8= +gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= gorm.io/driver/sqlite v1.5.5 h1:7MDMtUZhV065SilG62E0MquljeArQZNfJnjd9i9gx3E= gorm.io/driver/sqlite v1.5.5/go.mod h1:6NgQ7sQWAIFsPrJJl1lSNSu2TABh0ZZ/zm5fosATavE= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s= gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= diff --git a/main/main.go b/main/main.go deleted file mode 100644 index ee868b4..0000000 --- a/main/main.go +++ /dev/null @@ -1,39 +0,0 @@ -package main - -import ( - "fmt" - "log" - - "github.com/gnoswap-labs/vwap" - - "gorm.io/driver/sqlite" - "gorm.io/gorm" -) - -func main() { - db, err := gorm.Open(sqlite.Open("vwap.db"), &gorm.Config{}) - if err != nil { - log.Fatalf("failed to connect database: %v", err) - } - - err = db.AutoMigrate(&vwap.VWAPData{}) - if err != nil { - log.Fatalf("failed to migrate database: %v", err) - } - - err = vwap.PopulateVWAPData(db, 10) - if err != nil { - log.Fatalf("failed to populate vwap data: %v", err) - } - - var VWAPDataList []vwap.VWAPData - result := db.Find(&VWAPDataList) - if result.Error != nil { - log.Fatalf("failed to retrieve vwap data: %v", result.Error) - } - - for _, VWAPData := range VWAPDataList { - fmt.Printf("TokenName: %s, VWAP: %.2f, TotalVolume: %.2f, CalculatedAt: %s\n", - VWAPData.TokenName, VWAPData.VWAP, VWAPData.TotalVolume, VWAPData.CalculatedAt) - } -} diff --git a/price.go b/price.go index 776e87b..6437643 100644 --- a/price.go +++ b/price.go @@ -40,7 +40,7 @@ type Last7d struct { Price string `json:"price"` } -type APIResponse struct { +type PricesResponse struct { Error json.RawMessage `json:"error"` Data []TokenPrice `json:"data"` } @@ -63,17 +63,18 @@ func fetchTokenPrices(endpoint string) ([]TokenPrice, error) { } defer resp.Body.Close() - if resp.StatusCode == http.StatusOK { - var apiResponse APIResponse - if err := json.NewDecoder(resp.Body).Decode(&apiResponse); err != nil { - log.Printf("Error decoding response: %v\n", err) - return nil, err - } - return apiResponse.Data, nil + if resp.StatusCode != http.StatusOK { + log.Printf("Received non-OK response: %d\n", resp.StatusCode) + return nil, fmt.Errorf("received non-OK status code: %d", resp.StatusCode) + } + + var apiResponse PricesResponse + if err := json.NewDecoder(resp.Body).Decode(&apiResponse); err != nil { + log.Printf("Error decoding response: %v\n", err) + return nil, err } - log.Printf("Received non-OK response: %d\n", resp.StatusCode) - return nil, fmt.Errorf("received non-OK status code: %d", resp.StatusCode) + return apiResponse.Data, nil } func extractTrades(prices []TokenPrice, volumeByToken map[string]float64) map[string][]TradeData { diff --git a/price_test.go b/price_test.go index 8c9d4e8..7c769ce 100644 --- a/price_test.go +++ b/price_test.go @@ -12,7 +12,7 @@ import ( func TestFetchTokenPrices(t *testing.T) { t.Parallel() server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - tokenPricesResponse := APIResponse{ + tokenPricesResponse := PricesResponse{ Data: []TokenPrice{ { Path: "gno.land/r/demo/bar", diff --git a/store.go b/store.go index 92e2896..970b41b 100644 --- a/store.go +++ b/store.go @@ -44,7 +44,7 @@ func store(db *gorm.DB, tokenName string, vwap, totalVolume float64, calculatedA return nil } -// testing purpose only +// testing purpose func PopulateVWAPData(db *gorm.DB, count int) error { for i := 0; i < count; i++ { diff --git a/swap_filter.go b/swap_filter.go new file mode 100644 index 0000000..c60d35a --- /dev/null +++ b/swap_filter.go @@ -0,0 +1,84 @@ +package vwap + +import ( + "context" + "encoding/json" + "fmt" + "log" + "net/http" + "time" +) + +// temporary filtering func. should move to a router later. + +type SwapToken struct { + Symbol string `json:"symbol"` +} + +type Swap struct { + Time string `json:"time"` + TokenA SwapToken `json:"tokenA"` + TokenAAmount string `json:"tokenAAmount"` + TokenB SwapToken `json:"tokenB"` + TokenBAmount string `json:"tokenBAmount"` + TotalUsd string `json:"totalUsd"` +} + +type ActivitySwapResponse struct { + Data []Swap `json:"data"` +} + +const ( + ActivitySwapEndpoint = "http://dev.api.gnoswap.io/v1/activity?type=%s" + QueryTypeSwap = "SWAP" +) + +func FetchActivitySwap(endpoint, queryType string) ([]Swap, error) { + client := &http.Client{} + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + rpc := fmt.Sprintf(endpoint, queryType) + req, err := http.NewRequestWithContext(ctx, "GET", rpc, nil) + if err != nil { + return nil, err + } + + resp, err := client.Do(req) + if err != nil { + log.Printf("error: %v", err) + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("error: %v", resp.Status) + } + + var apiResponse ActivitySwapResponse + if err := json.NewDecoder(resp.Body).Decode(&apiResponse); err != nil { + log.Printf("error: %v", err) + return nil, err + } + + return apiResponse.Data, nil +} + +var filterToken = map[string]bool{ + "USDC": true, + "GNOT": true, + "GNS": true, +} + +func FilterSwaps(swaps []Swap) []Swap { + filteredSwaps := make([]Swap, 0) + for _, swap := range swaps { + _, okA := filterToken[swap.TokenA.Symbol] + _, okB := filterToken[swap.TokenB.Symbol] + if okA || okB { + filteredSwaps = append(filteredSwaps, swap) + } + } + return filteredSwaps +}