diff --git a/static/.eslintrc.json b/.eslintrc.json similarity index 100% rename from static/.eslintrc.json rename to .eslintrc.json diff --git a/cmd/website/caching.go b/cmd/website/caching.go deleted file mode 100644 index 804d82a..0000000 --- a/cmd/website/caching.go +++ /dev/null @@ -1,345 +0,0 @@ -package main - -import ( - "bytes" - "context" - "fmt" - "html/template" - "log" - "math/big" - "os" - "sort" - "sync" - "sync/atomic" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/gelfand/mettu/cmd/website/util" - "github.com/gelfand/mettu/internal/ethclient" - "github.com/gelfand/mettu/lib" - "github.com/gelfand/mettu/repo" -) - -var client, _ = ethclient.DialContext(context.Background(), rpcAddr) - -// Templates. -var ( - tokensTmpl = template.Must(template.New("tokens.tmpl.html").ParseFiles("./static/templates/tokens.tmpl.html")) - patternsTmpl = template.Must(template.New("patterns.tmpl.html").ParseFiles("./static/templates/patterns.tmpl.html")) - walletsTmpl = template.Must(template.New("wallets.tmpl.html").ParseFiles("./static/templates/wallets.tmpl.html")) - exchangesTmpl = template.Must(template.New("exchanges.tmpl.html").ParseFiles("./static/templates/exchanges.tmpl.html")) - swapsTmpl = template.Must(template.New("swaps.tmpl.html").ParseFiles("./static/templates/swaps.tmpl.html")) - - tokenDenominator = big.NewInt(1e18) -) - -var rat0 = new(big.Rat).SetInt64(0) - -// Atomic caching. -var ( - walletsDat atomic.Value - tokensDat atomic.Value - patternsDat atomic.Value - swapsDat atomic.Value - exchangesDat atomic.Value -) - -func runCaching(ctx context.Context, db *repo.DB) { - ticker := time.NewTicker(5 * time.Minute) - wg := sync.WaitGroup{} - - cache := func(ctx context.Context, db *repo.DB, wg *sync.WaitGroup) error { - wg.Add(5) - - go cacheSwaps(ctx, db, wg) - go cacheExchanges(ctx, db, wg) - go cachePatterns(ctx, db, wg) - go cacheTokens(ctx, db, wg) - go cacheWallets(ctx, db, wg) - - wg.Wait() - return nil - } - - cache(ctx, db, &wg) - for { - select { - case <-ctx.Done(): - os.Exit(0) - case <-ticker.C: - cache(ctx, db, &wg) - } - } -} - -// cacheTokens retrieves all tokens data and atomicly stores it in tokensDat. -func cacheTokens(ctx context.Context, db *repo.DB, wg *sync.WaitGroup) { - defer wg.Done() - - tx, err := db.BeginRo(ctx) - if err != nil { - log.Fatal(err) - } - defer tx.Rollback() - - swaps, err := db.AllSwaps(tx) - if err != nil { - log.Fatal(err) - } - - tokens := make(map[common.Address]repo.Swap) - for i := range swaps { - if _, ok := tokens[swaps[i].TokenAddr]; ok { - continue - } - tokens[swaps[i].TokenAddr] = swaps[i] - } - - type tokenData struct { - Token repo.Token - TotalBought *big.Int - Price string - CurrPrice string - Diff string - DiffRat *big.Rat - } - - i := 0 - tt := make([]tokenData, len(tokens)) - for tokenAddr, v := range tokens { - t, err := db.PeekToken(tx, tokenAddr) - if err != nil { - panic(err) - } - - priceRat := new(big.Rat).SetInt(t.Price) - priceRat = new(big.Rat).Quo(priceRat, new(big.Rat).SetInt64(1e18)) - - r, err := client.GetReservesPath(v.Factory, v.Path) - if err != nil { - panic(err) - } - - currPrice := lib.CalculatePrice(t.Denominator(), r) - currPriceRat := new(big.Rat).SetInt(currPrice) - currPriceRat = new(big.Rat).Quo(currPriceRat, new(big.Rat).SetInt64(1e18)) - - diff := new(big.Rat).Set(rat0) - if currPriceRat.Cmp(priceRat) > 0 && priceRat.Cmp(rat0) != 0 { - diff = new(big.Rat).Quo(currPriceRat, priceRat) - } - - tDat := tokenData{ - Token: t, - TotalBought: util.NormalizePrecision(t.TotalBought), - Price: priceRat.FloatString(6), - CurrPrice: currPriceRat.FloatString(6), - Diff: diff.FloatString(2), - DiffRat: diff, - } - tt[i] = tDat - i++ - } - if err := tx.Commit(); err != nil { - log.Fatalf("could not commit read-only transaction: %v", err) - } - - sort.SliceStable(tt, func(i, j int) bool { - diffRat0, diffRat1 := tt[i].DiffRat, tt[j].DiffRat - if diffRat0 == nil || diffRat1 == nil { - fmt.Println(tt[i]) - return true - } - - return diffRat0.Cmp(diffRat1) > 0 - }) - - var buf bytes.Buffer - if err := tokensTmpl.Execute(&buf, tt); err != nil { - log.Fatalf("could not execute html template: %v", err) - } - tokensDat.Store(buf.Bytes()) -} - -// cacheExchanges retrieves all exchanges data and atomicly stores it in exchangesDat. -func cacheExchanges(ctx context.Context, db *repo.DB, wg *sync.WaitGroup) { - defer wg.Done() - - tx, err := db.BeginRo(ctx) - if err != nil { - log.Fatalf("could not begin read-only transaction: %v", err) - } - defer tx.Rollback() - - exchanges, err := db.AllExchanges(tx) - if err != nil { - log.Fatalf("could not retrieve all exchanges from the db: %v", err) - } - if err := tx.Commit(); err != nil { - log.Fatalf("could not commit read-only transaction: %v", err) - } - - var buf bytes.Buffer - if err := exchangesTmpl.Execute(&buf, exchanges); err != nil { - log.Fatalf("could not execute exchanges template: %v", err) - } - exchangesDat.Store(buf.Bytes()) -} - -func cacheWallets(ctx context.Context, db *repo.DB, wg *sync.WaitGroup) { - defer wg.Done() - - tx, err := db.BeginRo(ctx) - if err != nil { - log.Fatalf("could not begin read-only transaction: %v", err) - } - defer tx.Rollback() - - wallets, err := db.AllAccounts(tx) - if err != nil { - log.Fatalf("could not retrieve all accounts from the database: %v", err) - } - - if err := tx.Commit(); err != nil { - log.Fatal(err) - } - - sort.SliceStable(wallets, func(i, j int) bool { - return wallets[i].TotalSpent.Cmp(wallets[j].TotalSpent) == 1 - }) - - // normalize big Ints to be in human readable format - for i := range wallets { - util.NormalizePrecision(wallets[i].TotalSpent) - util.NormalizePrecision(wallets[i].TotalReceived) - } - - var buf bytes.Buffer - if err := walletsTmpl.Execute(&buf, wallets); err != nil { - log.Fatalf("could not execute wallets template: %v", err) - } - - walletsDat.Store(buf.Bytes()) -} - -func cachePatterns(ctx context.Context, db *repo.DB, wg *sync.WaitGroup) { - defer wg.Done() - - tx, err := db.BeginRo(ctx) - if err != nil { - log.Fatalf("could not begin read-only transaction: %v", err) - } - defer tx.Rollback() - - patterns, err := db.AllPatternsData(tx) - if err != nil { - log.Fatalf("could not retieve all patterns data: %v", err) - } - - if err := tx.Commit(); err != nil { - log.Fatalf("could not commit read-only transaction: %v", err) - } - - for i := range patterns { - util.NormalizePrecision(patterns[i].Value) - } - - sort.SliceStable(patterns, func(i, j int) bool { - return patterns[i].Value.Cmp(patterns[j].Value) == 1 - }) - - var buf bytes.Buffer - if err := patternsTmpl.Execute(&buf, patterns); err != nil { - log.Fatalf("could not execute patterns template: %v", err) - } - - patternsDat.Store(buf.Bytes()) -} - -func cacheSwaps(ctx context.Context, db *repo.DB, wg *sync.WaitGroup) { - defer wg.Done() - - tx, err := db.BeginRo(ctx) - if err != nil { - log.Fatalf("could not begin read-only transaction: %v", err) - } - defer tx.Rollback() - - tokens, err := db.AllTokensMap(tx) - if err != nil { - log.Fatalf("could not retrieve all tokens: %v", err) - } - swaps, err := db.AllSwaps(tx) - if err != nil { - log.Fatalf("could not retrieve swaps data from the kv storage: %v", err) - } - - type swapData struct { - TokenAddr string - Swap repo.Swap - Wallet string - Symbol string - Value string - Price string - CurrentPrice string - Diff string - DiffRat *big.Rat - } - - swapsData := make([]swapData, len(swaps)) - for i, swap := range swaps { - token := tokens[swap.TokenAddr] - fmt.Println(token) - - v := swapData{ - TokenAddr: swap.TokenAddr.String(), - Swap: swap, - Wallet: swap.Wallet.String(), - Symbol: token.Symbol, - Value: "", - Price: "", - CurrentPrice: "", - } - - reserves, err := client.GetReservesPath(swap.Factory, swap.Path) - if err != nil { - log.Fatalf("could not retrieve reserves for: %v, err: %v", swap.Path, err) - } - - numerator := new(big.Rat).SetInt(swap.Price) - denominator := new(big.Rat).SetInt64(1e18) - priceRat := new(big.Rat).Quo(numerator, denominator) - v.Price = priceRat.FloatString(6) - - price := lib.CalculatePrice(token.Denominator(), reserves) - - numerator = new(big.Rat).SetInt(price) - priceRat = new(big.Rat).Quo(numerator, denominator) - v.CurrentPrice = priceRat.FloatString(6) - - v.Value = new(big.Int).Div(swap.Value, tokenDenominator).String() - - var diff *big.Rat - if price.Cmp(swap.Price) > 0 && swap.Price.Cmp(common.Big0) != 0 { - diff = new(big.Rat).Quo(new(big.Rat).SetInt(price), new(big.Rat).SetInt(swap.Price)) - } else { - diff = new(big.Rat).Set(rat0) - } - - v.Diff = diff.FloatString(2) - v.DiffRat = diff - - swapsData[i] = v - } - - sort.SliceStable(swapsData, func(i, j int) bool { - return swapsData[i].DiffRat.Cmp(swapsData[j].DiffRat) > 0 - }) - - var buf bytes.Buffer - if err := swapsTmpl.Execute(&buf, swapsData); err != nil { - log.Fatalf("could not execute swaps template: %v", err) - } - - swapsDat.Store(buf.Bytes()) -} diff --git a/cmd/website/coordinator/coordinator.go b/cmd/website/coordinator/coordinator.go deleted file mode 100644 index 279559b..0000000 --- a/cmd/website/coordinator/coordinator.go +++ /dev/null @@ -1,62 +0,0 @@ -package crawler - -import ( - "context" - "sync" - "sync/atomic" - "time" - - "github.com/gelfand/mettu/repo" - "github.com/go-chi/chi/v5" -) - -type Coordinator struct { - r chi.Router - - db *repo.DB - wg sync.WaitGroup - - exchanges atomic.Value - tokens atomic.Value - patterns atomic.Value - swaps atomic.Value - wallets atomic.Value -} - -func (c *Coordinator) ServeHTTP() { -} - -func New(db *repo.DB) *Coordinator { - c := &Coordinator{ - r: chi.NewRouter(), - db: db, - wg: sync.WaitGroup{}, - exchanges: atomic.Value{}, - tokens: atomic.Value{}, - patterns: atomic.Value{}, - swaps: atomic.Value{}, - wallets: atomic.Value{}, - } - return c -} - -func (c *Coordinator) Run(ctx context.Context) error { - cacheCycle := time.NewTicker(1 * time.Minute) - - for { - select { - case <-ctx.Done(): - return nil - case <-cacheCycle.C: - c.wg.Add(1) - c.doCacheCycle(ctx) - c.wg.Wait() - - } - } -} - -func (c *Coordinator) doCacheCycle(ctx context.Context) { - defer c.wg.Done() - c.wg.Add(5) -} diff --git a/cmd/website/crawler.go b/cmd/website/crawler.go deleted file mode 100644 index fbf9f09..0000000 --- a/cmd/website/crawler.go +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - "sync/atomic" - - "github.com/gelfand/mettu/internal/ethclient" - "github.com/gelfand/mettu/repo" -) - -type crawler struct { - db *repo.DB - client *ethclient.Client - - swaps atomic.Value -} diff --git a/cmd/website/handlers.go b/cmd/website/handlers.go deleted file mode 100644 index e7dcf04..0000000 --- a/cmd/website/handlers.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "net/http" -) - -// walletsHandler atomicly loads cached response for exchanges and writes it. -func walletsHandler(w http.ResponseWriter, _ *http.Request) { - v, ok := walletsDat.Load().([]byte) - if !ok { - return - } - w.Write(v) -} - -// exchangesHandler atomicly loads cached response for exchanges and writes it. -func exchangesHandler(w http.ResponseWriter, _ *http.Request) { - v, ok := exchangesDat.Load().([]byte) - if !ok { - return - } - - w.Write(v) -} - -func patternsHandler(w http.ResponseWriter, _ *http.Request) { - v, ok := patternsDat.Load().([]byte) - if !ok { - return - } - w.Write(v) -} - -// tokensHandler atomicly loads cached response for tokens and writes it. -func tokensHandler(w http.ResponseWriter, _ *http.Request) { - v, ok := tokensDat.Load().([]byte) - if !ok { - return - } - w.Write(v) -} - -// swapsHandler atomicly loads cached response for swaps and writes it. -func swapsHandler(w http.ResponseWriter, _ *http.Request) { - v, ok := swapsDat.Load().([]byte) - if !ok { - return - } - w.Write(v) -} diff --git a/cmd/website/internal/config/config.go b/cmd/website/internal/config/config.go new file mode 100644 index 0000000..0c1e60b --- /dev/null +++ b/cmd/website/internal/config/config.go @@ -0,0 +1,20 @@ +package config + +import "os" + +type Config struct { + // Addr is a server address. + Addr string + // RPCAddr is an address of Ethereum RPC server. + RPCAddr string + + DBPath string +} + +var userHomeDir, _ = os.UserHomeDir() + +var DefaultConfig = &Config{ + Addr: "0.0.0.0:443", + RPCAddr: "ws://127.0.0.1:8545", + DBPath: userHomeDir + "/.mettu/", +} diff --git a/cmd/website/internal/dathtml/html.go b/cmd/website/internal/dathtml/html.go new file mode 100644 index 0000000..196c44d --- /dev/null +++ b/cmd/website/internal/dathtml/html.go @@ -0,0 +1,10 @@ +package dathtml + +import "html/template" + +func LoadHTML() map[string]*template.Template { + accountsTmpl := template.Must(template.New("accounts.tmpl.html").ParseFiles("./static/templates/accounts.tmpl.html")) + exchangesTmpl := template.Must(template.New("exchanges.tmpl.html").ParseFiles("./static/templates/exchanges.tmpl.html")) + + return map[string]*template.Template{"accounts": accountsTmpl, "exchanges": exchangesTmpl} +} diff --git a/cmd/website/internal/server/server.go b/cmd/website/internal/server/server.go new file mode 100644 index 0000000..9b0cc99 --- /dev/null +++ b/cmd/website/internal/server/server.go @@ -0,0 +1,96 @@ +package server + +import ( + "html/template" + "net/http" + "os" + + "github.com/gelfand/log" + "github.com/gelfand/mettu/cmd/website/internal/config" + "github.com/gelfand/mettu/cmd/website/internal/dathtml" + "github.com/gelfand/mettu/repo" + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" +) + +type Server struct { + mux *chi.Mux + templates map[string]*template.Template + db *repo.DB +} + +func NewServer(cfg *config.Config) (*Server, error) { + if cfg == nil { + cfg = config.DefaultConfig + } + db, err := repo.NewDB(cfg.DBPath) + if err != nil { + return nil, err + } + + s := &Server{ + mux: chi.NewMux(), + templates: dathtml.LoadHTML(), + db: db, + } + + return s, nil +} + +func (s *Server) ListenAndServeTLS(addr, certFile, keyFile string) { + http.ListenAndServeTLS(addr, certFile, keyFile, s.mux) +} + +func (s *Server) Install() { + s.mux.Use(middleware.Logger) + s.mux.Use(middleware.CleanPath) + s.mux.Use(middleware.NoCache) + // mux.Use(middleware.BasicAuth("Alpha Leak", creds)) + + s.mux.Mount("/static/css/", http.StripPrefix("/static/css/", http.FileServer(http.Dir("static/css")))) + s.mux.Mount("/static/js/", http.StripPrefix("/static/js/", http.FileServer(http.Dir("static/js")))) + s.mux.Get("/", func(w http.ResponseWriter, _ *http.Request) { + f, err := os.Open("./static/index.html") + if err != nil { + log.Fatalf("Unable to read index html template: %v", err) + } + + buf := make([]byte, 8192) + n, _ := f.Read(buf) + w.Write(buf[:n]) + }) + s.mux.Route("/swaps", func(r chi.Router) { + r.Get("/", func(w http.ResponseWriter, r *http.Request) { + }) + }) + s.mux.HandleFunc("/exchanges", func(w http.ResponseWriter, r *http.Request) { + tx, err := s.db.BeginRo(r.Context()) + if err != nil { + log.Error("could not begin transaction: %v", err) + return + } + defer tx.Rollback() + + exchs, err := s.db.AllExchanges(tx) + if err != nil { + log.Fatal(err) + } + s.templates["exchanges"].Execute(w, exchs) + }) + s.mux.HandleFunc("/accounts", func(w http.ResponseWriter, r *http.Request) { + tx, err := s.db.BeginRo(r.Context()) + if err != nil { + log.Errorf("could not begin database transaction: %v", err) + return + } + defer tx.Rollback() + + accs, err := s.db.AllAccounts(tx) + if err != nil { + log.Fatal(err) + } + + t := s.templates["accounts"] + t.Execute(w, accs) + }) +} diff --git a/cmd/website/main.go b/cmd/website/main.go index 623923e..c7f679c 100644 --- a/cmd/website/main.go +++ b/cmd/website/main.go @@ -3,38 +3,37 @@ package main import ( "flag" "fmt" - "log" "net/http" "os" - "os/signal" - "github.com/gelfand/mettu/repo" - "github.com/go-chi/chi/v5" - "github.com/go-chi/chi/v5/middleware" - "golang.org/x/net/context" + "github.com/gelfand/log" + "github.com/gelfand/mettu/cmd/website/internal/config" + "github.com/gelfand/mettu/cmd/website/internal/server" ) -var ( - db *repo.DB - - rpcAddr = "ws://127.0.0.1:8545" - creds = map[string]string{ - "Eugene": "9b1e8a94fcdb88c8391ec1200718b3ddd73fb631b9c6b5d56619852a47833665", - "Sats": "75408122edc81988b92988054d2b4339f88e01d3efb7ec55cd275a558be71ac2", - "user1": "0a041b9462caa4a31bac3567e0b6e6fd9100787db2ab433d96f6d178cabfce90", - "user2": "6025d18fe48abd45168528f18a82e265dd98d421a7084aa09f61b341703901a3", - "user3": "5860faf02b6bc6222ba5aca523560f0e364ccd8b67bee486fe8bf7c01d492ccb", - "user4": "5269ef980de47819ba3d14340f4665262c41e933dc92c1a27dd5d01b047ac80e", - "user5": "5a39bead318f306939acb1d016647be2e38c6501c58367fdb3e9f52542aa2442", - } +const ( + serverAddr = "0.0.0.0:443" + rpcAddr = "ws://127.0.0.1:8545" ) -var homedir, _ = os.UserHomeDir() +var creds = map[string]string{ + "test": "test", + "Eugene": "9b1e8a94fcdb88c8391ec1200718b3ddd73fb631b9c6b5d56619852a47833665", + "Sats": "75408122edc81988b92988054d2b4339f88e01d3efb7ec55cd275a558be71ac2", + "user1": "0a041b9462caa4a31bac3567e0b6e6fd9100787db2ab433d96f6d178cabfce90", + "user2": "6025d18fe48abd45168528f18a82e265dd98d421a7084aa09f61b341703901a3", + "user3": "5860faf02b6bc6222ba5aca523560f0e364ccd8b67bee486fe8bf7c01d492ccb", + "user4": "5269ef980de47819ba3d14340f4665262c41e933dc92c1a27dd5d01b047ac80e", + "user5": "5a39bead318f306939acb1d016647be2e38c6501c58367fdb3e9f52542aa2442", +} var ( - datadir = flag.String("datadir", homedir+"/.mettu", "path to the database.") - cert = flag.String("cert", homedir+"/.x509/cert.pem", "path to the certificate.") - certkey = flag.String("key", homedir+"/.x509/key.pem", "path to the certificate key.") + homedir, _ = os.UserHomeDir() + + datadirFlag = flag.String("datadir", homedir+"/.mettu", "path to the database.") + certFlag = flag.String("cert", homedir+"/.x509/cert.pem", "path to the certificate.") + certkeyFlag = flag.String("key", homedir+"/.x509/key.pem", "path to the certificate key.") + addrFlag = flag.String("addr", serverAddr, "server address.") ) func usage() { @@ -46,48 +45,65 @@ func main() { flag.Usage = usage flag.Parse() - ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) - go func() { - <-ctx.Done() - os.Exit(0) - }() - defer cancel() - - var err error - db, err = repo.NewDB(*datadir) + cfg := &config.Config{ + Addr: "127.0.0.1:8080", + RPCAddr: rpcAddr, + DBPath: *datadirFlag, + } + server, err := server.NewServer(cfg) if err != nil { log.Fatal(err) } - defer db.Close() - - go runCaching(ctx, db) - - r := chi.NewRouter() - r.Use(middleware.Logger) - r.Use(middleware.CleanPath) - r.Use(middleware.NoCache) - r.Use(middleware.BasicAuth("Alpha Leak", creds)) - - r.Mount("/static/css/", http.StripPrefix("/static/css/", http.FileServer(http.Dir("static/css")))) - r.Mount("/static/js/", http.StripPrefix("/static/js/", http.FileServer(http.Dir("static/js")))) - - r.Get("/", func(w http.ResponseWriter, _ *http.Request) { - f, err := os.Open("./static/index.html") - log.Fatalf("Unable to read index html template: %v", err) + server.Install() + server.ListenAndServeTLS("127.0.0.1:4444", *certFlag, *certkeyFlag) + + // ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) + // go func() { + // <-ctx.Done() + // os.Exit(0) + // }() + // defer cancel() + + // c, err := newCrawler(context.Background(), nil) + // if err != nil { + // log.Fatal(err) + // } + // go c.run(ctx) + // mux := chi.NewMux() + // mux.Route("/patterns", func(r chi.Router) { + // }) + + // listAccounts := func(w http.ResponseWriter, r *http.Request) { + // accs, ok := c.Accounts() + // if !ok { + // w.Write([]byte("Not ready yet...")) + // } + + // if err := accountsTemplate.Execute(w, accs); err != nil { + // panic(err) + // } + // } + + // mux.Route("/accounts", func(r chi.Router) { + // r.Get("/", listAccounts) + // }) + + // // r.Get("/swaps", swapsHandler) + // // r.Get("/patterns", patternsHandler) + // // r.Get("/tokens", tokensHandler) + // // r.Get("/wallets", walletsHandler) + + // server := &http.Server{ + // Addr: *addr, + // Handler: mux, + // } + // log.Fatal(server.ListenAndServeTLS(*cert, *certkey)) +} - buf := make([]byte, 8192) - n, _ := f.Read(buf) - w.Write(buf[:n]) +func paginate(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // just a stub.. some ideas are to look at URL query params for something like + // the page number, or the limit, and send a query cursor down the chain + next.ServeHTTP(w, r) }) - r.Get("/exchanges", exchangesHandler) - r.Get("/swaps", swapsHandler) - r.Get("/patterns", patternsHandler) - r.Get("/tokens", tokensHandler) - r.Get("/wallets", walletsHandler) - - server := &http.Server{ - Addr: "0.0.0.0:433", - Handler: r, - } - log.Fatal(server.ListenAndServeTLS(*cert, *certkey)) } diff --git a/cmd/website/swap.go b/cmd/website/swap.go deleted file mode 100644 index 9381acd..0000000 --- a/cmd/website/swap.go +++ /dev/null @@ -1,39 +0,0 @@ -package main - -import ( - "net/http" - "sync/atomic" - - "github.com/gelfand/mettu/repo" -) - -var swaps atomic.Value - -type swap struct { - Swap repo.Swap -} - -func ListSwaps(w http.ResponseWriter, r *http.Request) { - v, ok := swapsDat.Load().([]swap) - if !ok { - return - } - _ = v -} - -func ListSwapsByWallet(w http.ResponseWriter, r *http.Request) { - v, ok := swaps.Load().([]swap) - if !ok { - w.Write([]byte("ERROR: Something isn't okay with cached data!")) - return - } - _ = v -} - -func paginateSwaps(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // just a stub.. some ideas are to look at URL query params for something like - // the page number, or the limit, and send a query cursor down the chain - next.ServeHTTP(w, r) - }) -} diff --git a/cmd/website/util/util.go b/cmd/website/util/util.go deleted file mode 100644 index fea2068..0000000 --- a/cmd/website/util/util.go +++ /dev/null @@ -1,25 +0,0 @@ -package util - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" -) - -var decPrecision = big.NewInt(1e18) - -func NormalizePrecision(v *big.Int) *big.Int { - if v == nil { - v = new(big.Int).SetInt64(0) - } - v = v.Div(v, decPrecision) - return v -} - -func AddressShort(addr common.Address) string { - return addr.String()[:8] + "..." + addr.String()[36:] -} - -func HashShort(hash common.Hash) string { - return hash.String()[:8] + "..." + hash.String()[60:] -} diff --git a/core/coordinator.go b/core/coordinator.go index 329e0c4..3c03355 100644 --- a/core/coordinator.go +++ b/core/coordinator.go @@ -20,15 +20,12 @@ type Coordinator struct { // TODO: maybe make use of this lock. lock sync.Mutex - db *repo.DB - client *ethclient.Client - signer types.Signer - + db *repo.DB + client *ethclient.Client + signer types.Signer exchanges map[common.Address]repo.Exchange headersCh chan *types.Header txsChan chan []*types.Transaction - - exitCh chan struct{} } // NewCoordinator creates new Coordinator. @@ -66,7 +63,6 @@ func NewCoordinator(ctx context.Context, dbPath string, rpcAddr string) (*Coordi exchanges: exchanges, headersCh: make(chan *types.Header), txsChan: make(chan []*types.Transaction), - exitCh: make(chan struct{}, 1), } fmt.Println(len(c.exchanges)) return c, tx.Commit() @@ -105,13 +101,13 @@ func (c *Coordinator) processTransactions(ctx context.Context, txs []*types.Tran if err != nil { return fmt.Errorf("could not peek account: %w", err) } - acc.TotalReceived = new(big.Int).Add(acc.TotalReceived, txn.Value()) + acc.Received = new(big.Int).Add(acc.Received, txn.Value()) } else { acc = repo.Account{ - Address: *txn.To(), - TotalReceived: txn.Value(), - TotalSpent: big.NewInt(0), - Exchange: cex.Name, + Address: *txn.To(), + Received: txn.Value(), + Spent: big.NewInt(0), + Exchange: cex.Name, } } @@ -222,7 +218,7 @@ func (c *Coordinator) processTransactions(ctx context.Context, txs []*types.Tran pattern.TimesOccured++ pattern.Value = new(big.Int).Add(pattern.Value, txn.Value()) - acc.TotalSpent = new(big.Int).Add(acc.TotalSpent, txn.Value()) + acc.Spent = new(big.Int).Add(acc.Spent, txn.Value()) if err = c.db.PutAccount(tx, acc); err != nil { return fmt.Errorf("unable to put updated account data: %w", err) diff --git a/deno/deno.json b/deno/deno.json deleted file mode 100644 index e69de29..0000000 diff --git a/deno/main.ts b/deno/main.ts deleted file mode 100644 index 702f428..0000000 --- a/deno/main.ts +++ /dev/null @@ -1 +0,0 @@ -console.log("hello"); diff --git a/go.mod b/go.mod index 03ce0d1..64b1321 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,12 @@ go 1.17 require ( github.com/ethereum/go-ethereum v1.10.14 + github.com/gelfand/log v0.0.0-20211224165732-100e98773481 github.com/go-chi/chi/v5 v5.0.7 - github.com/google/go-cmp v0.5.6 + github.com/google/go-cmp v0.5.5 github.com/jackc/pgx/v4 v4.14.1 github.com/ledgerwatch/erigon-lib v0.0.0-20211222073434-bf21599d2322 github.com/ugorji/go/codec v1.2.6 - golang.org/x/net v0.0.0-20211216030914-fe4d6282115f ) require ( @@ -46,3 +46,5 @@ require ( google.golang.org/protobuf v1.27.1 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect ) + +replace github.com/gelfand/log => ../log diff --git a/go.sum b/go.sum index daf2a8c..03c8d47 100644 --- a/go.sum +++ b/go.sum @@ -137,6 +137,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gelfand/log v0.0.0-20211224165732-100e98773481 h1:8GvC/NgrEZqNDV0S1x+0Ffy7pkcKoqKMETnJxjd0fDg= +github.com/gelfand/log v0.0.0-20211224165732-100e98773481/go.mod h1:yzF+oyKOzR7MvJB4BBp3wF2+1mZg5KvSqKTevBwzYDE= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -206,9 +208,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -588,9 +589,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= diff --git a/repo/account.go b/repo/account.go index 6d6b1ae..dd0643d 100644 --- a/repo/account.go +++ b/repo/account.go @@ -11,23 +11,26 @@ import ( ) type Account struct { - Address common.Address - TotalReceived *big.Int - TotalSpent *big.Int - Exchange string + Address common.Address + Balance *big.Int + Received *big.Int + Spent *big.Int + Exchange string } type _account struct { - TotalReceived []byte - TotalSpent []byte - Exchange string + Balance []byte + Received []byte + Spent []byte + Exchange string } func (db *DB) PutAccount(tx kv.RwTx, acc Account) error { a := _account{ - TotalReceived: acc.TotalReceived.Bytes(), - TotalSpent: acc.TotalSpent.Bytes(), - Exchange: acc.Exchange, + Balance: acc.Balance.Bytes(), + Received: acc.Received.Bytes(), + Spent: acc.Spent.Bytes(), + Exchange: acc.Exchange, } var accBuf bytes.Buffer @@ -56,10 +59,11 @@ func (db *DB) PeekAccount(tx kv.Tx, address common.Address) (Account, error) { } return Account{ - Address: address, - TotalReceived: new(big.Int).SetBytes(a.TotalReceived), - TotalSpent: new(big.Int).SetBytes(a.TotalSpent), - Exchange: a.Exchange, + Address: address, + Balance: new(big.Int).SetBytes(a.Balance), + Received: new(big.Int).SetBytes(a.Received), + Spent: new(big.Int).SetBytes(a.Spent), + Exchange: a.Exchange, }, nil } @@ -73,10 +77,11 @@ func (db *DB) AllAccounts(tx kv.Tx) ([]Account, error) { } acc := Account{ - Address: addr, - TotalReceived: new(big.Int).SetBytes(a.TotalReceived), - TotalSpent: new(big.Int).SetBytes(a.TotalSpent), - Exchange: a.Exchange, + Address: addr, + Balance: new(big.Int).SetBytes(a.Balance), + Received: new(big.Int).SetBytes(a.Received), + Spent: new(big.Int).SetBytes(a.Spent), + Exchange: a.Exchange, } accounts = append(accounts, acc) return nil @@ -97,10 +102,11 @@ func (db *DB) AllAccountsMap(tx kv.Tx) (map[common.Address]Account, error) { } acc := Account{ - Address: addr, - TotalReceived: new(big.Int).SetBytes(a.TotalReceived), - TotalSpent: new(big.Int).SetBytes(a.TotalSpent), - Exchange: a.Exchange, + Address: addr, + Balance: new(big.Int).SetBytes(a.Balance), + Received: new(big.Int).SetBytes(a.Received), + Spent: new(big.Int).SetBytes(a.Spent), + Exchange: a.Exchange, } accounts[addr] = acc return nil diff --git a/repo/account_test.go b/repo/account_test.go index 36fc360..932be09 100644 --- a/repo/account_test.go +++ b/repo/account_test.go @@ -42,10 +42,10 @@ func TestDB_PutAccount(t *testing.T) { args: args{ tx: nil, acc: Account{ - Address: common.BytesToAddress([]byte("acc0")), - TotalReceived: hugeNumber, - TotalSpent: hugeNumber, - Exchange: "Binance", + Address: common.BytesToAddress([]byte("acc0")), + Received: hugeNumber, + Spent: hugeNumber, + Exchange: "Binance", }, }, wantErr: false, @@ -56,10 +56,10 @@ func TestDB_PutAccount(t *testing.T) { args: args{ tx: nil, acc: Account{ - Address: common.BytesToAddress([]byte("qwerty")), - TotalReceived: hugeNumber, - TotalSpent: hugeNumber, - Exchange: "Binance", + Address: common.BytesToAddress([]byte("qwerty")), + Received: hugeNumber, + Spent: hugeNumber, + Exchange: "Binance", }, }, wantErr: false, @@ -146,10 +146,10 @@ func TestDB_HasAccount(t *testing.T) { go func() { tx, _ := db.BeginRw(context.Background()) db.PutAccount(tx, Account{ - Address: common.BytesToAddress([]byte("has account test0")), - TotalReceived: &big.Int{}, - TotalSpent: &big.Int{}, - Exchange: "", + Address: common.BytesToAddress([]byte("has account test0")), + Received: &big.Int{}, + Spent: &big.Int{}, + Exchange: "", }) tx.Commit() done <- true @@ -256,16 +256,16 @@ func TestDB_AllAccountsMap(t *testing.T) { args: args{}, want: map[common.Address]Account{ {0xff}: { - Address: common.Address{0xff}, - TotalReceived: big.NewInt(0), - TotalSpent: big.NewInt(0), - Exchange: "", + Address: common.Address{0xff}, + Received: big.NewInt(0), + Spent: big.NewInt(0), + Exchange: "", }, {0xfe, 0xfe}: { - Address: common.Address{0xfe, 0xfe}, - TotalReceived: big.NewInt(0), - TotalSpent: big.NewInt(0), - Exchange: "", + Address: common.Address{0xfe, 0xfe}, + Received: big.NewInt(0), + Spent: big.NewInt(0), + Exchange: "", }, }, wantErr: false, @@ -304,17 +304,17 @@ func accountsTestdata(db *DB) { defer tx.Rollback() db.PutAccount(tx, Account{ - Address: common.Address{0xff}, - TotalReceived: big.NewInt(0), - TotalSpent: big.NewInt(0), - Exchange: "", + Address: common.Address{0xff}, + Received: big.NewInt(0), + Spent: big.NewInt(0), + Exchange: "", }) db.PutAccount(tx, Account{ - Address: common.Address{0xfe, 0xfe}, - TotalReceived: big.NewInt(0), - TotalSpent: big.NewInt(0), - Exchange: "", + Address: common.Address{0xfe, 0xfe}, + Received: big.NewInt(0), + Spent: big.NewInt(0), + Exchange: "", }) if err := tx.Commit(); err != nil { panic(err) diff --git a/repo/swap_test.go b/repo/swap_test.go index 3bb7fb4..7e78637 100644 --- a/repo/swap_test.go +++ b/repo/swap_test.go @@ -319,16 +319,16 @@ func testDB_swap(t *testing.T) kv.RwDB { accounts := []Account{ { - Address: common.BytesToAddress([]byte("wallet1")), - TotalReceived: &big.Int{}, - TotalSpent: &big.Int{}, - Exchange: "", + Address: common.BytesToAddress([]byte("wallet1")), + Received: &big.Int{}, + Spent: &big.Int{}, + Exchange: "", }, { - Address: common.BytesToAddress([]byte("wallet2")), - TotalReceived: &big.Int{}, - TotalSpent: &big.Int{}, - Exchange: "", + Address: common.BytesToAddress([]byte("wallet2")), + Received: &big.Int{}, + Spent: &big.Int{}, + Exchange: "", }, } diff --git a/static/templates/wallets.tmpl.html b/static/templates/accounts.tmpl.html similarity index 87% rename from static/templates/wallets.tmpl.html rename to static/templates/accounts.tmpl.html index 645d4c2..63af2fb 100644 --- a/static/templates/wallets.tmpl.html +++ b/static/templates/accounts.tmpl.html @@ -1,7 +1,7 @@
-