mirror of
https://github.com/grassrootseconomics/eth-tracker.git
synced 2025-12-27 19:27:59 +01:00
Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 679d7f9927 | |||
| ef28ec1298 | |||
| 5cf5f9894c | |||
| 20ba62f313 | |||
| e370d7eae5 | |||
| 574b42f75e | |||
| 8417a43277 | |||
| f90cc75323 | |||
| 20434beb17 | |||
| 838810dc14 | |||
| 0efd01e058 | |||
| cf23978621 | |||
| 2d30901aa3 | |||
| 9c97ce2d2f | |||
| 414b14a92e | |||
| 4470095769 | |||
| e503ecff5c | |||
| 23a7561edc | |||
| 5962c26659 | |||
| 0b5af2f938 | |||
| cf263c7d15 | |||
| faa428c583 | |||
| f912f6835a | |||
| fd1cced053 | |||
| dca3b4d211 | |||
| 513912f361 | |||
| 90cc1563ec | |||
| d4d3763732 | |||
| 078ad3614d | |||
| c93cc8270f | |||
| 115f6817e6 | |||
| 7a64f29dc7 | |||
| e5ea697403 | |||
| b650e44392 | |||
| eee3757895 | |||
|
|
2283190147 | ||
| 75b402bbf6 | |||
| 6f850bb1d4 | |||
| e03dabdf0f | |||
| 0e3bf47f83 | |||
| e1158ab14a | |||
| 1def49c3ab | |||
|
|
f15373e34e | ||
|
|
9f9f564f84 | ||
|
|
98e6b3bf68 | ||
| 725c18c0ff | |||
| 05d142664d | |||
|
|
4b2ad3daf9 | ||
| f1086fcdc1 | |||
| fd59d286f5 | |||
| 8e3e027044 | |||
| 17c7f5825b | |||
| 22d5582643 | |||
| 55159196f4 | |||
| 1c7c53a12f | |||
| 6057208b50 | |||
| ffdac26c41 | |||
| 404e769655 | |||
| 8c15109238 | |||
|
|
afacc4425d | ||
| efc84970cc | |||
| 6cb5ea4f02 | |||
| bb8122a576 | |||
|
|
cb14939367 | ||
|
|
0c7a35c0c7 | ||
| 14e85dc1e5 | |||
| 8ced6a02b1 | |||
|
|
a80d387838 | ||
|
|
d398ed2198 | ||
| 22ffc224ca |
3
.github/workflows/docker.yaml
vendored
3
.github/workflows/docker.yaml
vendored
@ -52,5 +52,4 @@ jobs:
|
||||
cache-from: type=local,src=/tmp/.buildx-cache
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
||||
tags: |
|
||||
ghcr.io/grassrootseconomics/celo-tracker:latest
|
||||
ghcr.io/grassrootseconomics/celo-tracker:${{ env.RELEASE_TAG }}
|
||||
ghcr.io/grassrootseconomics/eth-tracker:${{ env.RELEASE_TAG }}
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@ -2,5 +2,6 @@ tracker_db
|
||||
.vscode
|
||||
.idx
|
||||
**/*.env
|
||||
celo-tracker
|
||||
celo-tracker-cache-bootstrap
|
||||
eth-tracker
|
||||
eth-tracker-cache-bootstrap
|
||||
*.pprof
|
||||
@ -1,6 +1,6 @@
|
||||
FROM golang:1.23.0-bookworm AS build
|
||||
FROM golang:1.24-bookworm AS build
|
||||
|
||||
ENV CGO_ENABLED=1
|
||||
ENV CGO_ENABLED=0
|
||||
|
||||
ARG BUILDPLATFORM
|
||||
ARG TARGETPLATFORM
|
||||
@ -11,8 +11,7 @@ WORKDIR /build
|
||||
|
||||
COPY . .
|
||||
RUN go mod download
|
||||
RUN go build -o celo-tracker-cache-bootstrap -ldflags="-X main.build=${BUILD} -s -w" cmd/bootstrap/main.go
|
||||
RUN go build -o celo-tracker -ldflags="-X main.build=${BUILD} -s -w" cmd/service/main.go
|
||||
RUN go build -o eth-tracker -ldflags="-X main.build=${BUILD} -s -w" cmd/service/*.go
|
||||
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
@ -25,4 +24,4 @@ COPY --from=build /build/* .
|
||||
|
||||
EXPOSE 5001
|
||||
|
||||
CMD ["./celo-tracker"]
|
||||
CMD ["./eth-tracker"]
|
||||
11
Makefile
11
Makefile
@ -1,7 +1,7 @@
|
||||
BIN := celo-tracker
|
||||
BOOTSTRAP_BIN := celo-tracker-cache-bootstrap
|
||||
BIN := eth-tracker
|
||||
BOOTSTRAP_BIN := eth-tracker-cache-bootstrap
|
||||
DB_FILE := tracker_db
|
||||
BUILD_CONF := CGO_ENABLED=1 GOOS=linux GOARCH=amd64
|
||||
BUILD_CONF := CGO_ENABLED=0 GOOS=linux GOARCH=amd64
|
||||
BUILD_COMMIT := $(shell git rev-parse --short HEAD 2> /dev/null)
|
||||
DEBUG := DEV=true
|
||||
|
||||
@ -14,11 +14,10 @@ clean-db:
|
||||
rm ${DB_FILE}
|
||||
|
||||
build:
|
||||
${BUILD_CONF} go build -ldflags="-X main.build=${BUILD_COMMIT} -s -w" -o ${BOOTSTRAP_BIN} cmd/bootstrap/main.go
|
||||
${BUILD_CONF} go build -ldflags="-X main.build=${BUILD_COMMIT} -s -w" -o ${BIN} cmd/service/main.go
|
||||
${BUILD_CONF} go build -ldflags="-X main.build=${BUILD_COMMIT} -s -w" -o ${BIN} cmd/service/*.go
|
||||
|
||||
run-bootstrap:
|
||||
${BUILD_CONF} ${DEBUG} go run cmd/bootstrap/main.go
|
||||
|
||||
run:
|
||||
${BUILD_CONF} ${DEBUG} go run cmd/service/main.go
|
||||
${BUILD_CONF} ${DEBUG} go run cmd/service/*.go
|
||||
71
README.md
71
README.md
@ -1,30 +1,48 @@
|
||||
# celo-tracker
|
||||
# eth-tracker
|
||||
|
||||

|
||||

|
||||
|
||||
A fast and lightweight tracker designed to monitor the Celo blockchain for live and historical transaction events, including reverted transactions. It filters these events and publishes them to NATS for further processing.
|
||||
A fast and lightweight tracker designed to monitor EVM blockchains for live and
|
||||
historical transaction events, including reverted transactions. It filters these
|
||||
events and publishes them to NATS for further processing.
|
||||
|
||||
It applies deduplication at the NATS level, making it safe to run in a distributed fashion.
|
||||
On a warmed up archive RPC node (HTTP) with the default config, it can process
|
||||
in excess of 10k blocks/min utilizing not more than 50 MB of RAM.
|
||||
|
||||
It applies deduplication at the NATS level, making it safe to run in a
|
||||
distributed fashion.
|
||||
|
||||
Note: To run it against an L2/EVM chain, you will need to manually add a replace
|
||||
directive in the `go.mod` file pointing to the EVM chain's `*geth` compatible
|
||||
source code. This will allow the tracker to process transaction types other than
|
||||
Ethereum's `0x0, 0x1 and 0x2`.
|
||||
|
||||
### CEL2
|
||||
|
||||
We maintain a CEL2 compatible tracker (source and container image) on the `cel2`
|
||||
branch.
|
||||
|
||||
## Getting Started
|
||||
|
||||
A `Makefile` is also provided to build the required binaries to run celo-tracker.
|
||||
A `Makefile` is also provided to build the required binaries to run eth-tracker.
|
||||
|
||||
### Bootstrap Cache
|
||||
### Cache Bootstrap
|
||||
|
||||
An optional binary, `celo-tracker-cache-bootstrap`, is included to build the Redis cache with all relevant Grassroots Economics smart contract and user addresses to allow filtering on very busy smart contracts e.g. cUSD.
|
||||
During startup `eth-tracker` will always build the cache with all relevant
|
||||
Grassroots Economics smart contract and user addresses to allow filtering on
|
||||
very busy smart contracts e.g. cUSD.
|
||||
|
||||
The cache will auto-update based on any additions/removals from all indexes.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
* Git
|
||||
* Docker
|
||||
* NATS server
|
||||
* Redis server
|
||||
* Access to a Celo RPC node
|
||||
- Git
|
||||
- Docker
|
||||
- NATS server
|
||||
- Access to an RPC node, archive preffered
|
||||
|
||||
See [docker-compose.yaml](dev/docker-compose.yaml) for an example on how to run and deploy a single instance.
|
||||
See [docker-compose.yaml](dev/docker-compose.yaml) for an example on how to run
|
||||
and deploy a single instance.
|
||||
|
||||
### 1. Build the Docker image
|
||||
|
||||
@ -33,18 +51,21 @@ We provide pre-built images for `linux/amd64`. See the packages tab on Github.
|
||||
If you are on any other platform:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/grassrootseconomics/celo-tracker.git
|
||||
cd celo-tracker
|
||||
docker buildx build --build-arg BUILD=$(git rev-parse --short HEAD) --tag celo-tracker:$(git rev-parse --short HEAD) --tag celo-tracker:latest .
|
||||
git clone https://github.com/grassrootseconomics/eth-tracker.git
|
||||
cd eth-tracker
|
||||
docker buildx build --build-arg BUILD=$(git rev-parse --short HEAD) --tag eth-tracker:$(git rev-parse --short HEAD) --tag eth-tracker:latest .
|
||||
docker images
|
||||
```
|
||||
|
||||
### 2. Run NATS and Redis
|
||||
### 2. Run NATS
|
||||
|
||||
For an example, see `dev/docker-compose.yaml`.
|
||||
|
||||
### 3. Update config values
|
||||
|
||||
See `.env.example` on how to override default values defined in `config.toml` using env variables. Alternatively, mount your own config.toml either during build time or Docker runtime.
|
||||
See `.env.example` on how to override default values defined in `config.toml`
|
||||
using env variables. Alternatively, mount your own config.toml either during
|
||||
build time or Docker runtime.
|
||||
|
||||
```bash
|
||||
# Override only specific config values
|
||||
@ -52,8 +73,8 @@ nano .env.example
|
||||
mv .env.example .env
|
||||
```
|
||||
|
||||
Refer to [`config.toml`](config.toml) to understand different config value settings.
|
||||
|
||||
Refer to [`config.toml`](config.toml) to understand different config value
|
||||
settings.
|
||||
|
||||
### 4. Run the tracker
|
||||
|
||||
@ -80,7 +101,8 @@ docker compose up
|
||||
|
||||
### Monitoring with NATS CLI
|
||||
|
||||
Install NATS CLI from [here](https://github.com/nats-io/natscli?tab=readme-ov-file#installation).
|
||||
Install NATS CLI from
|
||||
[here](https://github.com/nats-io/natscli?tab=readme-ov-file#installation).
|
||||
|
||||
```bash
|
||||
nats subscribe "TRACKER.*"
|
||||
@ -88,8 +110,11 @@ nats subscribe "TRACKER.*"
|
||||
|
||||
### DB File
|
||||
|
||||
A `tracker_db` file is created on the first run. This keeps track of all blocks missed by the processor to attempt a retry later on. This file should not be deleted if you want to maintain resume support for historical tracking across restarts.
|
||||
A `tracker_db` file is created on the first run. This keeps track of all blocks
|
||||
missed by the processor to attempt a retry later on. This file should not be
|
||||
deleted if you want to maintain resume support for historical tracking across
|
||||
restarts.
|
||||
|
||||
## License
|
||||
|
||||
[AGPL-3.0](LICENSE).
|
||||
[AGPL-3.0](LICENSE).
|
||||
|
||||
@ -1,236 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"log/slog"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/celo-org/celo-blockchain/common"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/cache"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/chain"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/util"
|
||||
"github.com/grassrootseconomics/celoutils/v3"
|
||||
"github.com/grassrootseconomics/w3-celo"
|
||||
"github.com/grassrootseconomics/w3-celo/module/eth"
|
||||
"github.com/knadh/koanf/v2"
|
||||
)
|
||||
|
||||
const cacheType = "redis"
|
||||
|
||||
var (
|
||||
build = "dev"
|
||||
|
||||
confFlag string
|
||||
|
||||
lo *slog.Logger
|
||||
ko *koanf.Koanf
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&confFlag, "config", "config.toml", "Config file location")
|
||||
flag.Parse()
|
||||
|
||||
lo = util.InitLogger()
|
||||
ko = util.InitConfig(lo, confFlag)
|
||||
|
||||
lo.Info("starting GE redis cache bootstrapper", "build", build)
|
||||
}
|
||||
|
||||
func main() {
|
||||
var (
|
||||
tokenRegistryGetter = w3.MustNewFunc("tokenRegistry()", "address")
|
||||
quoterGetter = w3.MustNewFunc("quoter()", "address")
|
||||
)
|
||||
|
||||
chain, err := chain.NewRPCFetcher(chain.CeloRPCOpts{
|
||||
RPCEndpoint: ko.MustString("chain.rpc_endpoint"),
|
||||
ChainID: ko.MustInt64("chain.chainid"),
|
||||
})
|
||||
if err != nil {
|
||||
lo.Error("could not initialize chain client", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
cache, err := cache.New(cache.CacheOpts{
|
||||
Logg: lo,
|
||||
CacheType: cacheType,
|
||||
RedisDSN: ko.MustString("redis.dsn"),
|
||||
})
|
||||
if err != nil {
|
||||
lo.Error("could not initialize cache", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5)
|
||||
defer cancel()
|
||||
|
||||
for _, registry := range ko.MustStrings("bootstrap.ge_registries") {
|
||||
registryMap, err := chain.Provider().RegistryMap(ctx, celoutils.HexToAddress(registry))
|
||||
if err != nil {
|
||||
lo.Error("could not fetch registry", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if tokenIndex := registryMap[celoutils.TokenIndex]; tokenIndex != celoutils.ZeroAddress {
|
||||
tokenIndexIter, err := chain.Provider().NewBatchIterator(ctx, tokenIndex)
|
||||
if err != nil {
|
||||
lo.Error("could not create token index iter", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
for {
|
||||
batch, err := tokenIndexIter.Next(ctx)
|
||||
if err != nil {
|
||||
lo.Error("error fetching next token index batch", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if batch == nil {
|
||||
break
|
||||
}
|
||||
lo.Debug("index batch", "index", tokenIndex.Hex(), "size", len(batch))
|
||||
for _, address := range batch {
|
||||
if err := cache.Add(ctx, address.Hex()); err != nil {
|
||||
lo.Error("redis error setting key", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if poolIndex := registryMap[celoutils.PoolIndex]; poolIndex != celoutils.ZeroAddress {
|
||||
poolIndexIter, err := chain.Provider().NewBatchIterator(ctx, poolIndex)
|
||||
if err != nil {
|
||||
lo.Error("cache could create pool index iter", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
for {
|
||||
batch, err := poolIndexIter.Next(ctx)
|
||||
if err != nil {
|
||||
lo.Error("error fetching next pool index batch", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if batch == nil {
|
||||
break
|
||||
}
|
||||
lo.Debug("index batch", "index", poolIndex.Hex(), "size", len(batch))
|
||||
for _, address := range batch {
|
||||
if err := cache.Add(ctx, address.Hex()); err != nil {
|
||||
lo.Error("redis error setting key", "error", err, "address", address.Hex())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var poolTokenIndex, priceQuoter common.Address
|
||||
err := chain.Provider().Client.CallCtx(
|
||||
ctx,
|
||||
eth.CallFunc(address, tokenRegistryGetter).Returns(&poolTokenIndex),
|
||||
eth.CallFunc(address, quoterGetter).Returns(&priceQuoter),
|
||||
)
|
||||
if err != nil {
|
||||
lo.Error("error fetching pool token index and/or quoter", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if priceQuoter != celoutils.ZeroAddress {
|
||||
if err := cache.Add(ctx, priceQuoter.Hex()); err != nil {
|
||||
lo.Error("redis error setting key", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
if poolTokenIndex != celoutils.ZeroAddress {
|
||||
if err := cache.Add(ctx, poolTokenIndex.Hex()); err != nil {
|
||||
lo.Error("redis error setting key", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
poolTokenIndexIter, err := chain.Provider().NewBatchIterator(ctx, poolTokenIndex)
|
||||
if err != nil {
|
||||
lo.Error("error creating pool token index iter", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
for {
|
||||
batch, err := poolTokenIndexIter.Next(ctx)
|
||||
if err != nil {
|
||||
lo.Error("error fetching next pool token index batch", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if batch == nil {
|
||||
break
|
||||
}
|
||||
lo.Debug("index batch", "index", poolTokenIndex.Hex(), "size", len(batch))
|
||||
for _, address := range batch {
|
||||
if address != celoutils.ZeroAddress {
|
||||
if err := cache.Add(ctx, address.Hex()); err != nil {
|
||||
lo.Error("redis error setting key", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if accountsIndex := registryMap[celoutils.AccountIndex]; accountsIndex != celoutils.ZeroAddress {
|
||||
accountsIndexIter, err := chain.Provider().NewBatchIterator(ctx, accountsIndex)
|
||||
if err != nil {
|
||||
lo.Error("could not create accounts index iter", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
for {
|
||||
batch, err := accountsIndexIter.Next(ctx)
|
||||
if err != nil {
|
||||
lo.Error("error fetching next accounts index batch", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if batch == nil {
|
||||
break
|
||||
}
|
||||
lo.Debug("index batch", "index", accountsIndex.Hex(), "size", len(batch))
|
||||
for _, address := range batch {
|
||||
if err := cache.Add(ctx, address.Hex()); err != nil {
|
||||
lo.Error("redis error setting key", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range registryMap {
|
||||
if err := cache.Add(ctx, v.Hex()); err != nil {
|
||||
lo.Error("redis error setting key", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, address := range ko.MustStrings("bootstrap.watchlist") {
|
||||
if err := cache.Add(ctx, address); err != nil {
|
||||
lo.Error("redis error setting key", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
for _, address := range ko.MustStrings("bootstrap.blacklist") {
|
||||
if err := cache.Remove(ctx, address); err != nil {
|
||||
lo.Error("redis error deleting key", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
if err := cache.Remove(ctx, celoutils.ZeroAddress.Hex()); err != nil {
|
||||
lo.Error("redis error deleting key", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
cacheSize, err := cache.Size(ctx)
|
||||
if err != nil {
|
||||
lo.Warn("error fetching cache size")
|
||||
}
|
||||
|
||||
lo.Info("redis cache bootstrap complete", "addresses_cached", cacheSize)
|
||||
}
|
||||
@ -13,18 +13,17 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/grassrootseconomics/celo-tracker/db"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/api"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/backfill"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/cache"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/chain"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/pool"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/processor"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/pub"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/router"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/stats"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/syncer"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/util"
|
||||
"github.com/grassrootseconomics/eth-tracker/db"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/api"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/backfill"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/cache"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/chain"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/pool"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/processor"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/pub"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/stats"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/syncer"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/util"
|
||||
"github.com/knadh/koanf/v2"
|
||||
)
|
||||
|
||||
@ -45,15 +44,15 @@ func init() {
|
||||
|
||||
lo = util.InitLogger()
|
||||
ko = util.InitConfig(lo, confFlag)
|
||||
|
||||
lo.Info("starting celo tracker", "build", build)
|
||||
}
|
||||
|
||||
func main() {
|
||||
lo.Info("starting celo tracker", "build", build)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
ctx, stop := notifyShutdown()
|
||||
|
||||
chain, err := chain.NewRPCFetcher(chain.CeloRPCOpts{
|
||||
chain, err := chain.NewRPCFetcher(chain.EthRPCOpts{
|
||||
RPCEndpoint: ko.MustString("chain.rpc_endpoint"),
|
||||
ChainID: ko.MustInt64("chain.chainid"),
|
||||
})
|
||||
@ -61,6 +60,7 @@ func main() {
|
||||
lo.Error("could not initialize chain client", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
lo.Debug("loaded rpc fetcher")
|
||||
|
||||
db, err := db.New(db.DBOpts{
|
||||
Logg: lo,
|
||||
@ -70,32 +70,39 @@ func main() {
|
||||
lo.Error("could not initialize blocks db", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
lo.Debug("loaded blocks db")
|
||||
|
||||
cache, err := cache.New(cache.CacheOpts{
|
||||
Logg: lo,
|
||||
CacheType: ko.MustString("core.cache_type"),
|
||||
RedisDSN: ko.MustString("redis.dsn"),
|
||||
})
|
||||
cacheOpts := cache.CacheOpts{
|
||||
Chain: chain,
|
||||
Registries: ko.MustStrings("bootstrap.ge_registry"),
|
||||
Watchlist: ko.Strings("bootstrap.watchlist"),
|
||||
Blacklist: ko.Strings("bootstrap.blacklist"),
|
||||
CacheType: ko.MustString("core.cache_type"),
|
||||
Logg: lo,
|
||||
}
|
||||
if ko.MustString("core.cache_type") == "redis" {
|
||||
cacheOpts.RedisDSN = ko.MustString("redis.dsn")
|
||||
}
|
||||
cache, err := cache.New(cacheOpts)
|
||||
if err != nil {
|
||||
lo.Error("could not initialize cache", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
lo.Debug("loaded and boostrapped cache")
|
||||
|
||||
jetStreamPub, err := pub.NewJetStreamPub(pub.JetStreamOpts{
|
||||
Endpoint: ko.MustString("jetstream.endpoint"),
|
||||
PersistDuration: time.Duration(ko.MustInt("jetstream.persist_duration_hrs")) * time.Hour,
|
||||
DedupDuration: time.Duration(ko.MustInt("jetstream.dedup_duration_hrs")) * time.Hour,
|
||||
Logg: lo,
|
||||
})
|
||||
if err != nil {
|
||||
lo.Error("could not initialize jetstream pub", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
lo.Debug("loaded jetstream publisher")
|
||||
|
||||
router := router.New(router.RouterOpts{
|
||||
Pub: jetStreamPub,
|
||||
Cache: cache,
|
||||
})
|
||||
router := bootstrapEventRouter(cache, jetStreamPub.Send)
|
||||
lo.Debug("bootstrapped event router")
|
||||
|
||||
blockProcessor := processor.NewProcessor(processor.ProcessorOpts{
|
||||
Cache: cache,
|
||||
@ -104,6 +111,7 @@ func main() {
|
||||
Router: router,
|
||||
Logg: lo,
|
||||
})
|
||||
lo.Debug("bootstrapped processor")
|
||||
|
||||
poolOpts := pool.PoolOpts{
|
||||
Logg: lo,
|
||||
@ -114,12 +122,14 @@ func main() {
|
||||
poolOpts.WorkerCount = runtime.NumCPU() * 3
|
||||
}
|
||||
workerPool := pool.New(poolOpts)
|
||||
lo.Debug("bootstrapped worker pool")
|
||||
|
||||
stats := stats.New(stats.StatsOpts{
|
||||
Cache: cache,
|
||||
Logg: lo,
|
||||
Pool: workerPool,
|
||||
})
|
||||
lo.Debug("bootstrapped stats provider")
|
||||
|
||||
chainSyncer, err := syncer.New(syncer.SyncerOpts{
|
||||
DB: db,
|
||||
@ -134,22 +144,28 @@ func main() {
|
||||
lo.Error("could not initialize chain syncer", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
lo.Debug("bootstrapped realtime syncer")
|
||||
|
||||
backfill := backfill.New(backfill.BackfillOpts{
|
||||
DB: db,
|
||||
Logg: lo,
|
||||
Pool: workerPool,
|
||||
BatchSize: ko.MustInt("core.batch_size"),
|
||||
DB: db,
|
||||
Logg: lo,
|
||||
Pool: workerPool,
|
||||
})
|
||||
lo.Debug("bootstrapped backfiller")
|
||||
|
||||
apiServer := &http.Server{
|
||||
Addr: ko.MustString("api.address"),
|
||||
Handler: api.New(),
|
||||
}
|
||||
lo.Debug("bootstrapped API server")
|
||||
lo.Debug("starting routines")
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
chainSyncer.Start()
|
||||
lo.Debug("started chain syncer")
|
||||
}()
|
||||
|
||||
wg.Add(1)
|
||||
@ -158,7 +174,9 @@ func main() {
|
||||
if err := backfill.Run(false); err != nil {
|
||||
lo.Error("backfiller initial run error", "error", err)
|
||||
}
|
||||
lo.Debug("completed initial backfill run")
|
||||
backfill.Start()
|
||||
lo.Debug("started periodic backfiller")
|
||||
}()
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
51
cmd/service/router.go
Normal file
51
cmd/service/router.go
Normal file
@ -0,0 +1,51 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/cache"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/handler"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/router"
|
||||
"github.com/lmittmann/w3"
|
||||
)
|
||||
|
||||
func bootstrapEventRouter(cacheProvider cache.Cache, pubCB router.Callback) *router.Router {
|
||||
handlerContainer := handler.New(cacheProvider)
|
||||
router := router.New(pubCB)
|
||||
|
||||
router.RegisterContractCreationHandler(handler.HandleContractCreation(handlerContainer))
|
||||
|
||||
router.RegisterLogRoute(w3.H("0x26162814817e23ec5035d6a2edc6c422da2da2119e27cfca6be65cc2dc55ca4c"), handler.HandleFaucetGiveLog())
|
||||
router.RegisterLogRoute(w3.H("0xa226db3f664042183ee0281230bba26cbf7b5057e50aee7f25a175ff45ce4d7f"), handler.HandleIndexAddLog(handlerContainer))
|
||||
router.RegisterLogRoute(w3.H("0x24a12366c02e13fe4a9e03d86a8952e85bb74a456c16e4a18b6d8295700b74bb"), handler.HandleIndexRemoveLog(handlerContainer))
|
||||
router.RegisterLogRoute(w3.H("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0"), handler.HandleOwnershipLog())
|
||||
router.RegisterLogRoute(w3.H("0x5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62"), handler.HandlePoolDepositLog())
|
||||
router.RegisterLogRoute(w3.H("0xd6d34547c69c5ee3d2667625c188acf1006abb93e0ee7cf03925c67cf7760413"), handler.HandlePoolSwapLog())
|
||||
router.RegisterLogRoute(w3.H("0xdb9ce1a76955721ca61ac50cd1b87f9ab8620325c8619a62192c2dc7871d56b1"), handler.HandleQuoterPriceUpdateLog())
|
||||
router.RegisterLogRoute(w3.H("0x6b7e2e653f93b645d4ed7292d6429f96637084363e477c8aaea1a43ed13c284e"), handler.HandleSealStateChangeLog())
|
||||
router.RegisterLogRoute(w3.H("0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5"), handler.HandleTokenBurnLog())
|
||||
router.RegisterLogRoute(w3.H("0xab8530f87dc9b59234c4623bf917212bb2536d647574c8e7e5da92c2ede0c9f8"), handler.HandleTokenMintLog())
|
||||
router.RegisterLogRoute(w3.H("0x894e56e1dac400b4475c83d8af0f0aa44de17c62764bd82f6e768a504e242461"), handler.HandleCustodialRegistrationLog())
|
||||
router.RegisterLogRoute(w3.H("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), handler.HandleTokenTransferLog(handlerContainer))
|
||||
router.RegisterLogRoute(w3.H("0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"), handler.HandleTokenApproveLog(handlerContainer))
|
||||
router.RegisterLogRoute(w3.H("0x5f7542858008eeb041631f30e6109ae94b83a58e9a58261dd2c42c508850f939"), handler.HandleTokenTransferFromLog(handlerContainer))
|
||||
router.RegisterLogRoute(w3.H("0x06526a30af2ff868c2686df12e95844d8ae300416bbec5d5ccc2d2f4afdb17a0"), handler.HandleQuoterUpdatedLog())
|
||||
|
||||
router.RegisterInputDataRoute("63e4bff4", handler.HandleFaucetGiveInputData())
|
||||
router.RegisterInputDataRoute("de82efb4", handler.HandleFaucetGiveInputData())
|
||||
router.RegisterInputDataRoute("0a3b0a4f", handler.HandleIndexAddInputData())
|
||||
router.RegisterInputDataRoute("4420e486", handler.HandleIndexAddInputData())
|
||||
router.RegisterInputDataRoute("29092d0e", handler.HandleIndexRemoveInputData())
|
||||
router.RegisterInputDataRoute("f2fde38b", handler.HandleOwnershipInputData())
|
||||
router.RegisterInputDataRoute("47e7ef24", handler.HandlePoolDepositInputData())
|
||||
router.RegisterInputDataRoute("d9caed12", handler.HandlePoolSwapInputData())
|
||||
router.RegisterInputDataRoute("ebc59dff", handler.HandleQuoterPriceUpdateInputdata())
|
||||
router.RegisterInputDataRoute("86fe212d", handler.HandleSealStateChangeInputData())
|
||||
router.RegisterInputDataRoute("42966c68", handler.HandleTokenBurnInputData())
|
||||
router.RegisterInputDataRoute("449a52f8", handler.HandleTokenMintInputData())
|
||||
router.RegisterInputDataRoute("4420e486", handler.HandleCustodialRegistrationInputData())
|
||||
router.RegisterInputDataRoute("a9059cbb", handler.HandleTokenTransferInputData(handlerContainer))
|
||||
router.RegisterInputDataRoute("23b872dd", handler.HandleTokenTransferInputData(handlerContainer))
|
||||
router.RegisterInputDataRoute("095ea7b3", handler.HandleTokenApproveInputData(handlerContainer))
|
||||
router.RegisterInputDataRoute("f912c64b", handler.HandleQuoterUpdatedInputData())
|
||||
|
||||
return router
|
||||
}
|
||||
19
config.toml
19
config.toml
@ -4,34 +4,30 @@ address = ":5001"
|
||||
|
||||
[core]
|
||||
# Use a specific cache implementation
|
||||
cache_type = "redis"
|
||||
cache_type = "internal"
|
||||
# Use a specific db implementation
|
||||
db_type = "bolt"
|
||||
# Tune max go routines that can process blocks
|
||||
# Defaults to (nproc * 3)
|
||||
pool_size = 0
|
||||
# If you are using an archive node, set this to true
|
||||
batch_size = 100
|
||||
|
||||
|
||||
[redis]
|
||||
dsn = "127.0.0.1:6379"
|
||||
|
||||
[chain]
|
||||
ws_endpoint = "wss://ws.celo.grassecon.net"
|
||||
rpc_endpoint = "https://celo.grassecon.net"
|
||||
ws_endpoint = "ws://localhost:8546"
|
||||
rpc_endpoint = "http://localhost:8545"
|
||||
# Defaults to Celo mainnet
|
||||
# At the moment only support Celo based blockchains
|
||||
chainid = 42220
|
||||
chainid = 1337
|
||||
# This will start a backfill if set to any other value
|
||||
# Ideally this should remain 0
|
||||
start_block = 0
|
||||
|
||||
[bootstrap]
|
||||
# This will bootstrap the cache on which addresses to track
|
||||
# Grassroots Economics specific registries that autoload all other smart contracts
|
||||
ge_registries = [
|
||||
"0xd1FB944748aca327a1ba036B082993D9dd9Bfa0C",
|
||||
"0x0cc9f4fff962def35bb34a53691180b13e653030",
|
||||
]
|
||||
ge_registry = ["0x0f8E97ef2d6A42CF62549D4924FCBdcE83A1C6A5"]
|
||||
watchlist = [""]
|
||||
blacklist = [""]
|
||||
|
||||
@ -39,4 +35,3 @@ blacklist = [""]
|
||||
enable = true
|
||||
endpoint = "nats://127.0.0.1:4222"
|
||||
persist_duration_hrs = 48
|
||||
dedup_duration_hrs = 6
|
||||
|
||||
@ -14,7 +14,7 @@ type boltDB struct {
|
||||
}
|
||||
|
||||
const (
|
||||
dbFolderName = "tracker_db"
|
||||
dbFolderName = "db/tracker_db"
|
||||
|
||||
upperBoundKey = "upper"
|
||||
lowerBoundKey = "lower"
|
||||
|
||||
@ -1 +0,0 @@
|
||||
package db
|
||||
@ -1,17 +1,4 @@
|
||||
services:
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
restart: unless-stopped
|
||||
command: redis-server --save 60 1 --loglevel warning
|
||||
volumes:
|
||||
- tracker-redis:/data
|
||||
ports:
|
||||
- "127.0.0.1:6379:6379"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
nats:
|
||||
image: nats:2
|
||||
restart: unless-stopped
|
||||
|
||||
109
go.mod
109
go.mod
@ -1,83 +1,64 @@
|
||||
module github.com/grassrootseconomics/celo-tracker
|
||||
module github.com/grassrootseconomics/eth-tracker
|
||||
|
||||
go 1.23.0
|
||||
go 1.24
|
||||
|
||||
require (
|
||||
github.com/VictoriaMetrics/metrics v1.35.1
|
||||
github.com/alitto/pond v1.9.1
|
||||
github.com/bits-and-blooms/bitset v1.13.0
|
||||
github.com/celo-org/celo-blockchain v1.8.4
|
||||
github.com/grassrootseconomics/celoutils/v3 v3.3.1
|
||||
github.com/grassrootseconomics/w3-celo v0.19.0
|
||||
github.com/VictoriaMetrics/metrics v1.37.0
|
||||
github.com/alitto/pond/v2 v2.3.4
|
||||
github.com/bits-and-blooms/bitset v1.22.0
|
||||
github.com/ethereum/go-ethereum v1.15.11
|
||||
github.com/grassrootseconomics/ethutils v1.4.0
|
||||
github.com/kamikazechaser/common v0.2.0
|
||||
github.com/knadh/koanf/parsers/toml v0.1.0
|
||||
github.com/knadh/koanf/providers/env v0.1.0
|
||||
github.com/knadh/koanf/providers/file v1.1.0
|
||||
github.com/knadh/koanf/v2 v2.1.1
|
||||
github.com/nats-io/nats.go v1.36.0
|
||||
github.com/puzpuzpuz/xsync/v3 v3.4.0
|
||||
github.com/redis/rueidis v1.0.44
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/uptrace/bunrouter v1.0.21
|
||||
go.etcd.io/bbolt v1.3.10
|
||||
github.com/knadh/koanf/providers/env v1.0.0
|
||||
github.com/knadh/koanf/providers/file v1.1.2
|
||||
github.com/knadh/koanf/v2 v2.2.0
|
||||
github.com/lmittmann/w3 v0.19.5
|
||||
github.com/nats-io/nats.go v1.42.0
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/uptrace/bunrouter v1.0.23
|
||||
go.etcd.io/bbolt v1.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.0.0-alpha.2 // indirect
|
||||
github.com/StackExchange/wmi v1.2.1 // indirect
|
||||
github.com/VictoriaMetrics/fastcache v1.12.2 // indirect
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
|
||||
github.com/celo-org/celo-bls-go v0.3.4 // indirect
|
||||
github.com/celo-org/celo-bls-go-android v0.3.3 // indirect
|
||||
github.com/celo-org/celo-bls-go-ios v0.3.3 // indirect
|
||||
github.com/celo-org/celo-bls-go-linux v0.3.3 // indirect
|
||||
github.com/celo-org/celo-bls-go-macos v0.3.3 // indirect
|
||||
github.com/celo-org/celo-bls-go-other v0.3.3 // indirect
|
||||
github.com/celo-org/celo-bls-go-windows v0.3.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/deckarep/golang-set v1.8.0 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/consensys/bavard v0.1.30 // indirect
|
||||
github.com/consensys/gnark-crypto v0.17.0 // indirect
|
||||
github.com/crate-crypto/go-eth-kzg v1.3.0 // indirect
|
||||
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/deckarep/golang-set/v2 v2.8.0 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
|
||||
github.com/ethereum/c-kzg-4844/v2 v2.1.1 // indirect
|
||||
github.com/ethereum/go-verkle v0.2.2 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect
|
||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
|
||||
github.com/hdevalence/ed25519consensus v0.0.0-20201207055737-7fde80a9d5ff // indirect
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
||||
github.com/holiman/uint256 v1.3.0 // indirect
|
||||
github.com/huin/goupnp v1.3.0 // indirect
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||
github.com/klauspost/compress v1.17.2 // indirect
|
||||
github.com/knadh/koanf/maps v0.1.1 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/holiman/uint256 v1.3.2 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/knadh/koanf/maps v0.1.2 // indirect
|
||||
github.com/lmittmann/tint v1.0.4 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/nats-io/nkeys v0.4.7 // indirect
|
||||
github.com/mmcloughlin/addchain v0.4.0 // indirect
|
||||
github.com/nats-io/nkeys v0.4.11 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/onsi/gomega v1.31.1 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/tsdb v0.7.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.2 // indirect
|
||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
||||
github.com/supranational/blst v0.3.14 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
||||
github.com/tklauser/numcpus v0.10.0 // indirect
|
||||
github.com/valyala/fastrand v1.1.0 // indirect
|
||||
github.com/valyala/histogram v1.2.0 // indirect
|
||||
golang.org/x/crypto v0.25.0 // indirect
|
||||
golang.org/x/net v0.24.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
golang.org/x/crypto v0.38.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/sync v0.14.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
rsc.io/tmplfunc v0.0.3 // indirect
|
||||
)
|
||||
|
||||
399
go.sum
399
go.sum
@ -1,151 +1,131 @@
|
||||
filippo.io/edwards25519 v1.0.0-alpha.2 h1:EWbZLqGEPSIj2W69gx04KtNVkyPIfe3uj0DhDQJonbQ=
|
||||
filippo.io/edwards25519 v1.0.0-alpha.2/go.mod h1:X+pm78QAUPtFLi1z9PYIlS/bdDnvbCOGKtZ+ACWEf7o=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
|
||||
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
|
||||
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
|
||||
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI=
|
||||
github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI=
|
||||
github.com/VictoriaMetrics/metrics v1.35.1 h1:o84wtBKQbzLdDy14XeskkCZih6anG+veZ1SwJHFGwrU=
|
||||
github.com/VictoriaMetrics/metrics v1.35.1/go.mod h1:r7hveu6xMdUACXvB8TYdAj8WEsKzWB0EkpJN+RDtOf8=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alitto/pond v1.9.1 h1:OfCpIrMyrWJpn34f647DcFmUxjK8+7Nu3eoVN/WTP+o=
|
||||
github.com/alitto/pond v1.9.1/go.mod h1:xQn3P/sHTYcU/1BR3i86IGIrilcrGC2LiS+E2+CJWsI=
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
|
||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
|
||||
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/btcsuite/btcd v0.23.2 h1:/YOgUp25sdCnP5ho6Hl3s0E438zlX+Kak7E6TgBgoT0=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
||||
github.com/buraksezer/consistent v0.0.0-20191006190839-693edf70fd72 h1:fUmDBbSvv1uOzo/t8WaxZMVb7BxJ8JECo5lGoR9c5bA=
|
||||
github.com/buraksezer/consistent v0.0.0-20191006190839-693edf70fd72/go.mod h1:OEE5igu/CDjGegM1Jn6ZMo7R6LlV/JChAkjfQQIRLpg=
|
||||
github.com/celo-org/celo-blockchain v1.8.4 h1:QJiRRGcZyO+PutT8WkFO1juORANAOGhN8yGNP7HvBqk=
|
||||
github.com/celo-org/celo-blockchain v1.8.4/go.mod h1:0udpV9QnZ2rnVu3vf8G9Wjs5di6Bf9urjwGVgAUEGB8=
|
||||
github.com/celo-org/celo-bls-go v0.3.4 h1:slNePT/gVjgUi7f8M4KTwBz/YYgv3JWU6XqyY0xKN84=
|
||||
github.com/celo-org/celo-bls-go v0.3.4/go.mod h1:qDZHMC3bBqOw5qle28cRtKlEyJhslZtckcc2Tomqdks=
|
||||
github.com/celo-org/celo-bls-go-android v0.3.3 h1:iZ2Gragn3JItkptmppeq1SENmNVc1f1W25UE4u231HY=
|
||||
github.com/celo-org/celo-bls-go-android v0.3.3/go.mod h1:cFgtFRH8+6x5b+EyG5SqniXY3aKd03NBSGDgITscX34=
|
||||
github.com/celo-org/celo-bls-go-ios v0.3.3 h1:/yHaEYft9WfXyPIGuJz7V2/r+tp2IqSpkvKsMsVgbuY=
|
||||
github.com/celo-org/celo-bls-go-ios v0.3.3/go.mod h1:eaSoMpx29YV5oF7jXVChzJpNfxeZHnAa8G4PjL5CyW0=
|
||||
github.com/celo-org/celo-bls-go-linux v0.3.3 h1:ukSQSIRyFCQeC1i7LJJunRKvlLuG1JMwNZ6DQZC51fE=
|
||||
github.com/celo-org/celo-bls-go-linux v0.3.3/go.mod h1:DVpJadg22OrxBtMb0ub6iNVdqDBL/r6EDdWVAA0bHa0=
|
||||
github.com/celo-org/celo-bls-go-macos v0.3.3 h1:H4ZGc+kS3e/w9Q6qru6FtlkYtVDS8eIQgw6UURB/Jlo=
|
||||
github.com/celo-org/celo-bls-go-macos v0.3.3/go.mod h1:mYPuRqGMVxj6yZUeL6Q6ggtP52HPBS1jz+FvBPXQ7QA=
|
||||
github.com/celo-org/celo-bls-go-other v0.3.3 h1:/Q9SLJK22hibPm/WI/OPxbBmgXTgUhjUgobfzz7qj/w=
|
||||
github.com/celo-org/celo-bls-go-other v0.3.3/go.mod h1:tNxZNfekzyT7TdYQbyNPhkfpcYtA3KCU/IKX5FNxM/U=
|
||||
github.com/celo-org/celo-bls-go-windows v0.3.3 h1:0IP+Ad9l+op50TIfkmFr+j7+TIjKksVROe+EoF7Ixa4=
|
||||
github.com/celo-org/celo-bls-go-windows v0.3.3/go.mod h1:82GC5iJA9Qw5gynhYqR8ht3J+l/MO8eSNzgSTMI8UdA=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/VictoriaMetrics/metrics v1.37.0 h1:u5Yr+HFofQyn7kgmmkufgkX0nEA6G1oEyK2eaKsVaUM=
|
||||
github.com/VictoriaMetrics/metrics v1.37.0/go.mod h1:r7hveu6xMdUACXvB8TYdAj8WEsKzWB0EkpJN+RDtOf8=
|
||||
github.com/alitto/pond/v2 v2.3.4 h1:hR0bqAwJiI2chu3cLN4gVyNC7rc5mj/l5wg0710nxsY=
|
||||
github.com/alitto/pond/v2 v2.3.4/go.mod h1:xkjYEgQ05RSpWdfSd1nM3OVv7TBhLdy7rMp3+2Nq+yE=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4=
|
||||
github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
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/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4=
|
||||
github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
|
||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I=
|
||||
github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8=
|
||||
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4=
|
||||
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M=
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
|
||||
github.com/cockroachdb/pebble v1.1.2 h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA=
|
||||
github.com/cockroachdb/pebble v1.1.2/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU=
|
||||
github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
|
||||
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
|
||||
github.com/consensys/bavard v0.1.30 h1:wwAj9lSnMLFXjEclKwyhf7Oslg8EoaFz9u1QGgt0bsk=
|
||||
github.com/consensys/bavard v0.1.30/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs=
|
||||
github.com/consensys/gnark-crypto v0.17.0 h1:vKDhZMOrySbpZDCvGMOELrHFv/A9mJ7+9I8HEfRZSkI=
|
||||
github.com/consensys/gnark-crypto v0.17.0/go.mod h1:A2URlMHUT81ifJ0UlLzSlm7TmnE3t7VxEThApdMukJw=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/crate-crypto/go-eth-kzg v1.3.0 h1:05GrhASN9kDAidaFJOda6A4BEvgvuXbazXg/0E3OOdI=
|
||||
github.com/crate-crypto/go-eth-kzg v1.3.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI=
|
||||
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg=
|
||||
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM=
|
||||
github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4=
|
||||
github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/deckarep/golang-set/v2 v2.8.0 h1:swm0rlPCmdWn9mESxKOjWk8hXSqoxOp+ZlfuyaAdFlQ=
|
||||
github.com/deckarep/golang-set/v2 v2.8.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
|
||||
github.com/ethereum/c-kzg-4844/v2 v2.1.1 h1:KhzBVjmURsfr1+S3k/VE35T02+AW2qU9t9gr4R6YpSo=
|
||||
github.com/ethereum/c-kzg-4844/v2 v2.1.1/go.mod h1:TC48kOKjJKPbN7C++qIgt0TJzZ70QznYR7Ob+WXl57E=
|
||||
github.com/ethereum/go-ethereum v1.15.11 h1:JK73WKeu0WC0O1eyX+mdQAVHUV+UR1a9VB/domDngBU=
|
||||
github.com/ethereum/go-ethereum v1.15.11/go.mod h1:mf8YiHIb0GR4x4TipcvBUPxJLw1mFdmxzoDi11sDRoI=
|
||||
github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8=
|
||||
github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
|
||||
github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
|
||||
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsMBaUOKXq6HSv655U1c=
|
||||
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk=
|
||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U=
|
||||
github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grassrootseconomics/celoutils/v3 v3.3.1 h1:ehf0eG2c8BfR2DojOm/nk8SQ44DyTFxXKISw1dHym/w=
|
||||
github.com/grassrootseconomics/celoutils/v3 v3.3.1/go.mod h1:HTHFNnWmvL6rY096xAraOMV3POYFAquoTABP6ogaF7U=
|
||||
github.com/grassrootseconomics/w3-celo v0.19.0 h1:3O5GK2os3/f9D/5oKsB0YxGyO5S3aqon/kx7ckyjQ4o=
|
||||
github.com/grassrootseconomics/w3-celo v0.19.0/go.mod h1:M3KJaj25DspF9siaqNXyamAuzC5DmWXx74tpyPp+R4Y=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grassrootseconomics/ethutils v1.4.0 h1:1QRLhOhY7GFoY27IlW9WoVoQuKDIGRjlFiPDiUWDN8Y=
|
||||
github.com/grassrootseconomics/ethutils v1.4.0/go.mod h1:7RCNwDj1wfgWt8CV4p7cQuZWPPI5fjwl/piq7NthaWg=
|
||||
github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
|
||||
github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hdevalence/ed25519consensus v0.0.0-20201207055737-7fde80a9d5ff h1:LeVKjw8pcDQj7WVVnbFvbD7ovcv+r/l15ka1NH6Lswc=
|
||||
github.com/hdevalence/ed25519consensus v0.0.0-20201207055737-7fde80a9d5ff/go.mod h1:Feit0l8NcNO4g69XNjwvsR0LGcwMMfzI1TF253rOIlQ=
|
||||
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4=
|
||||
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc=
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
|
||||
github.com/holiman/uint256 v1.3.0 h1:4wdcm/tnd0xXdu7iS3ruNvxkWwrb4aeBQv19ayYn8F4=
|
||||
github.com/holiman/uint256 v1.3.0/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA=
|
||||
github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
||||
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
|
||||
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
github.com/kamikazechaser/common v0.2.0 h1:bqi5UaMTDm/wtZlJEvQDNhsLVJP4Beg+HKWeQ+dhpss=
|
||||
github.com/kamikazechaser/common v0.2.0/go.mod h1:I1LEc8+W+g/KHZWARc1gMhuSa2STbQgfL4Hao6I/ZwY=
|
||||
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
|
||||
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs=
|
||||
github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo=
|
||||
github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
|
||||
github.com/knadh/koanf/parsers/toml v0.1.0 h1:S2hLqS4TgWZYj4/7mI5m1CQQcWurxUz6ODgOub/6LCI=
|
||||
github.com/knadh/koanf/parsers/toml v0.1.0/go.mod h1:yUprhq6eo3GbyVXFFMdbfZSo928ksS+uo0FFqNMnO18=
|
||||
github.com/knadh/koanf/providers/env v0.1.0 h1:LqKteXqfOWyx5Ab9VfGHmjY9BvRXi+clwyZozgVRiKg=
|
||||
github.com/knadh/koanf/providers/env v0.1.0/go.mod h1:RE8K9GbACJkeEnkl8L/Qcj8p4ZyPXZIQ191HJi44ZaQ=
|
||||
github.com/knadh/koanf/providers/file v1.1.0 h1:MTjA+gRrVl1zqgetEAIaXHqYje0XSosxSiMD4/7kz0o=
|
||||
github.com/knadh/koanf/providers/file v1.1.0/go.mod h1:/faSBcv2mxPVjFrXck95qeoyoZ5myJ6uxN8OOVNJJCI=
|
||||
github.com/knadh/koanf/v2 v2.1.1 h1:/R8eXqasSTsmDCsAyYj+81Wteg8AqrV9CP6gvsTsOmM=
|
||||
github.com/knadh/koanf/v2 v2.1.1/go.mod h1:4mnTRbZCK+ALuBXHZMjDfG9y714L7TykVnZkXbMU3Es=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/knadh/koanf/providers/env v1.0.0 h1:ufePaI9BnWH+ajuxGGiJ8pdTG0uLEUWC7/HDDPGLah0=
|
||||
github.com/knadh/koanf/providers/env v1.0.0/go.mod h1:mzFyRZueYhb37oPmC1HAv/oGEEuyvJDA98r3XAa8Gak=
|
||||
github.com/knadh/koanf/providers/file v1.1.2 h1:aCC36YGOgV5lTtAFz2qkgtWdeQsgfxUkxDOe+2nQY3w=
|
||||
github.com/knadh/koanf/providers/file v1.1.2/go.mod h1:/faSBcv2mxPVjFrXck95qeoyoZ5myJ6uxN8OOVNJJCI=
|
||||
github.com/knadh/koanf/v2 v2.2.0 h1:FZFwd9bUjpb8DyCWARUBy5ovuhDs1lI87dOEn2K8UVU=
|
||||
github.com/knadh/koanf/v2 v2.2.0/go.mod h1:PSFru3ufQgTsI7IF+95rf9s8XA1+aHxKuO/W+dPoHEY=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4=
|
||||
github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c=
|
||||
github.com/lmittmann/tint v1.0.4 h1:LeYihpJ9hyGvE0w+K2okPTGUdVLfng1+nDNVR4vWISc=
|
||||
github.com/lmittmann/tint v1.0.4/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
|
||||
github.com/lmittmann/w3 v0.19.5 h1:WwVRyIwhRLfIahmpB1EglsB3o1XWsgydgrxIUp5upFQ=
|
||||
github.com/lmittmann/w3 v0.19.5/go.mod h1:pN97sGGYGvsbqOYj/ms3Pd+7k/aiK/9OpNcxMmmzSOI=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||
@ -154,138 +134,101 @@ github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjU
|
||||
github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/nats-io/nats.go v1.36.0 h1:suEUPuWzTSse/XhESwqLxXGuj8vGRuPRoG7MoRN/qyU=
|
||||
github.com/nats-io/nats.go v1.36.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
|
||||
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
|
||||
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
|
||||
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
|
||||
github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
|
||||
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
|
||||
github.com/nats-io/nats.go v1.42.0 h1:ynIMupIOvf/ZWH/b2qda6WGKGNSjwOUutTpWRvAmhaM=
|
||||
github.com/nats-io/nats.go v1.42.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
|
||||
github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0=
|
||||
github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
|
||||
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo=
|
||||
github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8=
|
||||
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
|
||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
||||
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
||||
github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0=
|
||||
github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ=
|
||||
github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c=
|
||||
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
|
||||
github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM=
|
||||
github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
||||
github.com/redis/rueidis v1.0.44 h1:QfhfuovwEabcywfEXofRjPZuT29pjtpIWDJlCGHZfg8=
|
||||
github.com/redis/rueidis v1.0.44/go.mod h1:bnbkk4+CkXZgDPEbUtSos/o55i4RhFYYesJ4DS2zmq0=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8=
|
||||
github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE=
|
||||
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg=
|
||||
github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a h1:CmF68hwI0XsOQ5UwlBopMi2Ow4Pbg32akc4KIVCOm+Y=
|
||||
github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
|
||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/supranational/blst v0.3.14 h1:xNMoHRJOTwMn63ip6qoWJ2Ymgvj7E2b9jY2FAwY+qRo=
|
||||
github.com/supranational/blst v0.3.14/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||
github.com/uptrace/bunrouter v1.0.21 h1:HXarvX+N834sXyHpl+I/TuE11m19kLW/qG5u3YpHUag=
|
||||
github.com/uptrace/bunrouter v1.0.21/go.mod h1:TwT7Bc0ztF2Z2q/ZzMuSVkcb/Ig/d3MQeP2cxn3e1hI=
|
||||
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
|
||||
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
|
||||
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
|
||||
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
|
||||
github.com/uptrace/bunrouter v1.0.23 h1:Bi7NKw3uCQkcA/GUCtDNPq5LE5UdR9pe+UyWbjHB/wU=
|
||||
github.com/uptrace/bunrouter v1.0.23/go.mod h1:O3jAcl+5qgnF+ejhgkmbceEk0E/mqaK+ADOocdNpY8M=
|
||||
github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
|
||||
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
|
||||
github.com/valyala/fastrand v1.1.0 h1:f+5HkLW4rsgzdNoleUOB69hyT9IlD2ZQh9GyDMfb5G8=
|
||||
github.com/valyala/fastrand v1.1.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ=
|
||||
github.com/valyala/histogram v1.2.0 h1:wyYGAZZt3CpwUiIb9AU/Zbllg1llXyrtApRS815OLoQ=
|
||||
github.com/valyala/histogram v1.2.0/go.mod h1:Hb4kBwb4UxsaNbbbh+RRz8ZR6pdodR57tzWUS3BUzXY=
|
||||
go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0=
|
||||
go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
|
||||
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
|
||||
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
|
||||
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
|
||||
rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
|
||||
|
||||
@ -11,7 +11,6 @@ func New() *bunrouter.Router {
|
||||
router := bunrouter.New()
|
||||
|
||||
router.GET("/metrics", metricsHandler())
|
||||
|
||||
return router
|
||||
}
|
||||
|
||||
|
||||
@ -5,40 +5,41 @@ import (
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/grassrootseconomics/celo-tracker/db"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/pool"
|
||||
"github.com/grassrootseconomics/eth-tracker/db"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/pool"
|
||||
)
|
||||
|
||||
type (
|
||||
BackfillOpts struct {
|
||||
DB db.DB
|
||||
Logg *slog.Logger
|
||||
Pool *pool.Pool
|
||||
BatchSize int
|
||||
DB db.DB
|
||||
Logg *slog.Logger
|
||||
Pool *pool.Pool
|
||||
}
|
||||
|
||||
Backfill struct {
|
||||
db db.DB
|
||||
logg *slog.Logger
|
||||
pool *pool.Pool
|
||||
stopCh chan struct{}
|
||||
ticker *time.Ticker
|
||||
batchSize int
|
||||
db db.DB
|
||||
logg *slog.Logger
|
||||
pool *pool.Pool
|
||||
stopCh chan struct{}
|
||||
ticker *time.Ticker
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
idleCheckInterval = 60 * time.Second
|
||||
busyCheckInterval = 1 * time.Second
|
||||
|
||||
maxPoolSizePush = 100
|
||||
busyCheckInterval = 250 * time.Millisecond
|
||||
)
|
||||
|
||||
func New(o BackfillOpts) *Backfill {
|
||||
return &Backfill{
|
||||
db: o.DB,
|
||||
logg: o.Logg,
|
||||
pool: o.Pool,
|
||||
stopCh: make(chan struct{}),
|
||||
ticker: time.NewTicker(idleCheckInterval),
|
||||
batchSize: o.BatchSize,
|
||||
db: o.DB,
|
||||
logg: o.Logg,
|
||||
pool: o.Pool,
|
||||
stopCh: make(chan struct{}),
|
||||
ticker: time.NewTicker(idleCheckInterval),
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,13 +91,13 @@ func (b *Backfill) Run(skipLatest bool) error {
|
||||
if missingBlocksCount > 0 {
|
||||
b.logg.Info("found missing blocks", "skip_latest", skipLatest, "missing_blocks_count", missingBlocksCount)
|
||||
|
||||
buffer := make([]uint, maxPoolSizePush)
|
||||
buffer := make([]uint, b.batchSize)
|
||||
j := uint(0)
|
||||
pushedCount := 0
|
||||
j, buffer = missingBlocks.NextSetMany(j, buffer)
|
||||
for ; len(buffer) > 0; j, buffer = missingBlocks.NextSetMany(j, buffer) {
|
||||
for k := range buffer {
|
||||
if pushedCount >= maxPoolSizePush {
|
||||
if pushedCount >= b.batchSize {
|
||||
break
|
||||
}
|
||||
|
||||
@ -104,11 +105,11 @@ func (b *Backfill) Run(skipLatest bool) error {
|
||||
b.logg.Debug("pushed block from backfill", "block", buffer[k])
|
||||
pushedCount++
|
||||
}
|
||||
j += 1
|
||||
j++
|
||||
}
|
||||
}
|
||||
|
||||
if missingBlocksCount > maxPoolSizePush {
|
||||
if missingBlocksCount > uint(b.batchSize) {
|
||||
b.ticker.Reset(busyCheckInterval)
|
||||
} else {
|
||||
b.ticker.Reset(idleCheckInterval)
|
||||
|
||||
228
internal/cache/bootstrap.go
vendored
Normal file
228
internal/cache/bootstrap.go
vendored
Normal file
@ -0,0 +1,228 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/chain"
|
||||
"github.com/grassrootseconomics/ethutils"
|
||||
"github.com/lmittmann/w3"
|
||||
"github.com/lmittmann/w3/module/eth"
|
||||
)
|
||||
|
||||
func bootstrapCache(
|
||||
chain chain.Chain,
|
||||
cache Cache,
|
||||
registries []string,
|
||||
watchlist []string,
|
||||
blacklist []string,
|
||||
lo *slog.Logger,
|
||||
) error {
|
||||
var (
|
||||
tokenRegistryGetter = w3.MustNewFunc("tokenRegistry()", "address")
|
||||
quoterGetter = w3.MustNewFunc("quoter()", "address")
|
||||
systemAcccountGetter = w3.MustNewFunc("systemAccount()", "address")
|
||||
)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5)
|
||||
defer cancel()
|
||||
|
||||
for _, registry := range registries {
|
||||
registryMap, err := chain.Provider().RegistryMap(ctx, ethutils.HexToAddress(registry))
|
||||
if err != nil {
|
||||
lo.Error("could not fetch registry", "registry", registry, "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
for k, v := range registryMap {
|
||||
if v != ethutils.ZeroAddress {
|
||||
if err := cache.Add(ctx, v.Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lo.Debug("cached registry entry", "type", k, "address", v.Hex())
|
||||
}
|
||||
}
|
||||
|
||||
if custodialRegistrationProxy := registryMap[ethutils.CustodialProxy]; custodialRegistrationProxy != ethutils.ZeroAddress {
|
||||
var systemAccount common.Address
|
||||
err := chain.Provider().Client.CallCtx(
|
||||
ctx,
|
||||
eth.CallFunc(custodialRegistrationProxy, systemAcccountGetter).Returns(&systemAccount),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if systemAccount != ethutils.ZeroAddress {
|
||||
if err := cache.Add(ctx, systemAccount.Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
lo.Debug("cached custodial system account", "address", systemAccount.Hex())
|
||||
}
|
||||
}
|
||||
|
||||
if accountIndex := registryMap[ethutils.AccountIndex]; accountIndex != ethutils.ZeroAddress {
|
||||
if err := cache.Add(ctx, accountIndex.Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lo.Debug("cached account index", "address", accountIndex.Hex())
|
||||
|
||||
accountIndexIter, err := chain.Provider().NewBatchIterator(ctx, accountIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
accountIndexBatch, err := accountIndexIter.Next(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if accountIndexBatch == nil {
|
||||
break
|
||||
}
|
||||
|
||||
for _, address := range accountIndexBatch {
|
||||
if address != ethutils.ZeroAddress {
|
||||
if err := cache.Add(ctx, address.Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
lo.Debug("cached account index batch", "batch_size", len(accountIndexBatch))
|
||||
}
|
||||
}
|
||||
|
||||
if tokenIndex := registryMap[ethutils.TokenIndex]; tokenIndex != ethutils.ZeroAddress {
|
||||
if err := cache.Add(ctx, tokenIndex.Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lo.Debug("cached token index", "address", tokenIndex.Hex())
|
||||
|
||||
tokenIndexIter, err := chain.Provider().NewBatchIterator(ctx, tokenIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
tokenIndexBatch, err := tokenIndexIter.Next(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tokenIndexBatch == nil {
|
||||
break
|
||||
}
|
||||
|
||||
for _, address := range tokenIndexBatch {
|
||||
if address != ethutils.ZeroAddress {
|
||||
if err := cache.Add(ctx, address.Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
lo.Debug("cached token index batch", "batch_size", len(tokenIndexBatch))
|
||||
}
|
||||
}
|
||||
|
||||
if poolIndex := registryMap[ethutils.PoolIndex]; poolIndex != ethutils.ZeroAddress {
|
||||
if err := cache.Add(ctx, poolIndex.Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lo.Debug("cached pool index", "address", poolIndex.Hex())
|
||||
|
||||
poolIndexIter, err := chain.Provider().NewBatchIterator(ctx, poolIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
poolIndexBatch, err := poolIndexIter.Next(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if poolIndexBatch == nil {
|
||||
break
|
||||
}
|
||||
for _, address := range poolIndexBatch {
|
||||
if address != ethutils.ZeroAddress {
|
||||
if err := cache.Add(ctx, address.Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var poolTokenIndex, priceQuoter common.Address
|
||||
err := chain.Provider().Client.CallCtx(
|
||||
ctx,
|
||||
eth.CallFunc(address, tokenRegistryGetter).Returns(&poolTokenIndex),
|
||||
eth.CallFunc(address, quoterGetter).Returns(&priceQuoter),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if priceQuoter != ethutils.ZeroAddress {
|
||||
if err := cache.Add(ctx, priceQuoter.Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lo.Debug("cached pool index quoter", "pool", poolIndex.Hex(), "address", priceQuoter.Hex())
|
||||
}
|
||||
if poolTokenIndex != ethutils.ZeroAddress {
|
||||
if err := cache.Add(ctx, poolTokenIndex.Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lo.Debug("cached pool index token index", "pool", poolIndex.Hex(), "address", poolTokenIndex.Hex())
|
||||
|
||||
poolTokenIndexIter, err := chain.Provider().NewBatchIterator(ctx, poolTokenIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
poolTokenIndexBatch, err := poolTokenIndexIter.Next(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if poolTokenIndexBatch == nil {
|
||||
break
|
||||
}
|
||||
for _, address := range poolTokenIndexBatch {
|
||||
if address != ethutils.ZeroAddress {
|
||||
if err := cache.Add(ctx, address.Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
lo.Debug("cached pool token index batch", "batch_size", len(poolTokenIndexBatch))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lo.Debug("cached pool index batch", "batch_size", len(poolIndexBatch))
|
||||
}
|
||||
}
|
||||
|
||||
for _, address := range watchlist {
|
||||
if err := cache.Add(ctx, ethutils.HexToAddress(address).Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, address := range blacklist {
|
||||
if err := cache.Remove(ctx, ethutils.HexToAddress(address).Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := cache.Remove(ctx, ethutils.ZeroAddress.Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
cacheSize, err := cache.Size(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lo.Info("registry bootstrap complete", "registry", registry, "current_cache_size", cacheSize)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
52
internal/cache/cache.go
vendored
52
internal/cache/cache.go
vendored
@ -3,6 +3,8 @@ package cache
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/chain"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -10,53 +12,43 @@ type (
|
||||
Add(context.Context, string) error
|
||||
Remove(context.Context, string) error
|
||||
Exists(context.Context, string) (bool, error)
|
||||
ExistsNetwork(context.Context, string, ...string) (bool, error)
|
||||
Size(context.Context) (int64, error)
|
||||
}
|
||||
|
||||
CacheOpts struct {
|
||||
Logg *slog.Logger
|
||||
RedisDSN string
|
||||
CacheType string
|
||||
RedisDSN string
|
||||
CacheType string
|
||||
Registries []string
|
||||
Watchlist []string
|
||||
Blacklist []string
|
||||
Chain chain.Chain
|
||||
Logg *slog.Logger
|
||||
}
|
||||
)
|
||||
|
||||
func New(o CacheOpts) (Cache, error) {
|
||||
o.Logg.Info("initializing cache", "registries", o.Registries, "watchlist", o.Watchlist, "blacklist", o.Blacklist)
|
||||
var cache Cache
|
||||
|
||||
switch o.CacheType {
|
||||
case "map":
|
||||
case "internal":
|
||||
cache = NewMapCache()
|
||||
case "redis":
|
||||
redisCache, err := NewRedisCache(redisOpts{
|
||||
DSN: o.RedisDSN,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cache = redisCache
|
||||
default:
|
||||
cache = NewMapCache()
|
||||
o.Logg.Warn("invalid cache type, using default type (map)")
|
||||
}
|
||||
|
||||
// geSmartContracts, err := o.Chain.Provider().GetGESmartContracts(
|
||||
// context.Background(),
|
||||
// o.Registries,
|
||||
// )
|
||||
// if err != nil {
|
||||
// return nil, fmt.Errorf("cache could not bootstrap GE smart contracts: err %v", err)
|
||||
// }
|
||||
|
||||
// for k, v := range geSmartContracts {
|
||||
// cache.Add(k, v)
|
||||
// }
|
||||
// for _, address := range o.Watchlist {
|
||||
// cache.Add(address, false)
|
||||
// }
|
||||
// for _, address := range o.Blacklist {
|
||||
// cache.Remove(address)
|
||||
// }
|
||||
// o.Logg.Info("cache bootstrap complete", "cached_addresses", cache.Size())
|
||||
if err := bootstrapCache(
|
||||
o.Chain,
|
||||
cache,
|
||||
o.Registries,
|
||||
o.Watchlist,
|
||||
o.Blacklist,
|
||||
o.Logg,
|
||||
); err != nil {
|
||||
return cache, err
|
||||
}
|
||||
|
||||
return cache, nil
|
||||
}
|
||||
|
||||
56
internal/cache/redis.go
vendored
56
internal/cache/redis.go
vendored
@ -1,56 +0,0 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/redis/rueidis"
|
||||
)
|
||||
|
||||
type (
|
||||
redisOpts struct {
|
||||
DSN string
|
||||
}
|
||||
|
||||
redisCache struct {
|
||||
client rueidis.Client
|
||||
}
|
||||
)
|
||||
|
||||
func NewRedisCache(o redisOpts) (Cache, error) {
|
||||
client, err := rueidis.NewClient(rueidis.ClientOption{
|
||||
InitAddress: []string{o.DSN},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &redisCache{
|
||||
client: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *redisCache) Add(ctx context.Context, key string) error {
|
||||
// Without NX it will overwrite any existing KEY
|
||||
cmd := c.client.B().Set().Key(key).Value("true").Build()
|
||||
return c.client.Do(ctx, cmd).Error()
|
||||
}
|
||||
|
||||
func (c *redisCache) Remove(ctx context.Context, key string) error {
|
||||
cmd := c.client.B().Del().Key(key).Build()
|
||||
return c.client.Do(ctx, cmd).Error()
|
||||
}
|
||||
|
||||
func (c *redisCache) Exists(ctx context.Context, key string) (bool, error) {
|
||||
cmd := c.client.B().Exists().Key(key).Build()
|
||||
res, err := c.client.Do(ctx, cmd).AsBool()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (c *redisCache) Size(ctx context.Context) (int64, error) {
|
||||
cmd := c.client.B().Dbsize().Build()
|
||||
return c.client.Do(ctx, cmd).AsInt64()
|
||||
}
|
||||
26
internal/cache/xmap.go
vendored
26
internal/cache/xmap.go
vendored
@ -7,12 +7,12 @@ import (
|
||||
)
|
||||
|
||||
type mapCache struct {
|
||||
xmap *xsync.Map
|
||||
xmap *xsync.MapOf[string, bool]
|
||||
}
|
||||
|
||||
func NewMapCache() Cache {
|
||||
return &mapCache{
|
||||
xmap: xsync.NewMap(),
|
||||
xmap: xsync.NewMapOf[string, bool](),
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,7 +28,27 @@ func (c *mapCache) Remove(_ context.Context, key string) error {
|
||||
|
||||
func (c *mapCache) Exists(_ context.Context, key string) (bool, error) {
|
||||
_, ok := c.xmap.Load(key)
|
||||
return ok, nil
|
||||
if ok {
|
||||
return true, nil
|
||||
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (c *mapCache) ExistsNetwork(_ context.Context, token string, addresses ...string) (bool, error) {
|
||||
_, ok := c.xmap.Load(token)
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
for _, v := range addresses {
|
||||
_, ok := c.xmap.Load(v)
|
||||
if ok {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (c *mapCache) Size(_ context.Context) (int64, error) {
|
||||
|
||||
@ -1,121 +0,0 @@
|
||||
package chain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/celo-org/celo-blockchain/common"
|
||||
"github.com/celo-org/celo-blockchain/core/types"
|
||||
"github.com/celo-org/celo-blockchain/rpc"
|
||||
"github.com/grassrootseconomics/celoutils/v3"
|
||||
"github.com/grassrootseconomics/w3-celo"
|
||||
"github.com/grassrootseconomics/w3-celo/module/eth"
|
||||
"github.com/grassrootseconomics/w3-celo/w3types"
|
||||
)
|
||||
|
||||
type (
|
||||
CeloRPCOpts struct {
|
||||
RPCEndpoint string
|
||||
ChainID int64
|
||||
}
|
||||
|
||||
CeloRPC struct {
|
||||
provider *celoutils.Provider
|
||||
}
|
||||
)
|
||||
|
||||
func NewRPCFetcher(o CeloRPCOpts) (Chain, error) {
|
||||
customRPCClient, err := lowTimeoutRPCClient(o.RPCEndpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chainProvider := celoutils.NewProvider(
|
||||
o.RPCEndpoint,
|
||||
o.ChainID,
|
||||
celoutils.WithClient(customRPCClient),
|
||||
)
|
||||
|
||||
return &CeloRPC{
|
||||
provider: chainProvider,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func lowTimeoutRPCClient(rpcEndpoint string) (*w3.Client, error) {
|
||||
httpClient := &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
rpcClient, err := rpc.DialHTTPWithClient(
|
||||
rpcEndpoint,
|
||||
httpClient,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return w3.NewClient(rpcClient), nil
|
||||
}
|
||||
|
||||
func (c *CeloRPC) GetBlocks(ctx context.Context, blockNumbers []uint64) ([]types.Block, error) {
|
||||
blocksCount := len(blockNumbers)
|
||||
calls := make([]w3types.RPCCaller, blocksCount)
|
||||
blocks := make([]types.Block, blocksCount)
|
||||
|
||||
for i, v := range blockNumbers {
|
||||
calls[i] = eth.BlockByNumber(new(big.Int).SetUint64(v)).Returns(&blocks[i])
|
||||
}
|
||||
|
||||
if err := c.provider.Client.CallCtx(ctx, calls...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return blocks, nil
|
||||
}
|
||||
|
||||
func (c *CeloRPC) GetBlock(ctx context.Context, blockNumber uint64) (*types.Block, error) {
|
||||
var block types.Block
|
||||
blockCall := eth.BlockByNumber(new(big.Int).SetUint64(blockNumber)).Returns(&block)
|
||||
|
||||
if err := c.provider.Client.CallCtx(ctx, blockCall); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &block, nil
|
||||
}
|
||||
|
||||
func (c *CeloRPC) GetLatestBlock(ctx context.Context) (uint64, error) {
|
||||
var latestBlock big.Int
|
||||
latestBlockCall := eth.BlockNumber().Returns(&latestBlock)
|
||||
|
||||
if err := c.provider.Client.CallCtx(ctx, latestBlockCall); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return latestBlock.Uint64(), nil
|
||||
}
|
||||
|
||||
func (c *CeloRPC) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, error) {
|
||||
var transaction types.Transaction
|
||||
if err := c.provider.Client.CallCtx(ctx, eth.Tx(txHash).Returns(&transaction)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &transaction, nil
|
||||
}
|
||||
|
||||
func (c *CeloRPC) GetReceipts(ctx context.Context, blockNumber *big.Int) (types.Receipts, error) {
|
||||
var receipts types.Receipts
|
||||
|
||||
if err := c.provider.Client.CallCtx(ctx, eth.BlockReceipts(blockNumber).Returns(&receipts)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return receipts, nil
|
||||
}
|
||||
|
||||
func (c *CeloRPC) Provider() *celoutils.Provider {
|
||||
return c.provider
|
||||
}
|
||||
@ -4,17 +4,17 @@ import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/celo-org/celo-blockchain/common"
|
||||
"github.com/celo-org/celo-blockchain/core/types"
|
||||
"github.com/grassrootseconomics/celoutils/v3"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/grassrootseconomics/ethutils"
|
||||
)
|
||||
|
||||
type Chain interface {
|
||||
GetBlocks(context.Context, []uint64) ([]types.Block, error)
|
||||
GetBlocks(context.Context, []uint64) ([]*types.Block, error)
|
||||
GetBlock(context.Context, uint64) (*types.Block, error)
|
||||
GetLatestBlock(context.Context) (uint64, error)
|
||||
GetTransaction(context.Context, common.Hash) (*types.Transaction, error)
|
||||
GetReceipts(context.Context, *big.Int) (types.Receipts, error)
|
||||
// Expose provider until we eject from celoutils
|
||||
Provider() *celoutils.Provider
|
||||
Provider() *ethutils.Provider
|
||||
}
|
||||
|
||||
@ -1,3 +1,118 @@
|
||||
package chain
|
||||
|
||||
// TBA
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/grassrootseconomics/ethutils"
|
||||
"github.com/lmittmann/w3"
|
||||
"github.com/lmittmann/w3/module/eth"
|
||||
"github.com/lmittmann/w3/w3types"
|
||||
)
|
||||
|
||||
type (
|
||||
EthRPCOpts struct {
|
||||
RPCEndpoint string
|
||||
ChainID int64
|
||||
}
|
||||
|
||||
EthRPC struct {
|
||||
provider *ethutils.Provider
|
||||
}
|
||||
)
|
||||
|
||||
func NewRPCFetcher(o EthRPCOpts) (Chain, error) {
|
||||
customRPCClient, err := lowTimeoutRPCClient(o.RPCEndpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chainProvider := ethutils.NewProvider(
|
||||
o.RPCEndpoint,
|
||||
o.ChainID,
|
||||
ethutils.WithClient(customRPCClient),
|
||||
)
|
||||
|
||||
return &EthRPC{
|
||||
provider: chainProvider,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func lowTimeoutRPCClient(rpcEndpoint string) (*w3.Client, error) {
|
||||
httpClient := &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
rpcClient, err := rpc.DialOptions(context.Background(), rpcEndpoint, rpc.WithHTTPClient(httpClient))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return w3.NewClient(rpcClient), nil
|
||||
}
|
||||
|
||||
func (c *EthRPC) GetBlocks(ctx context.Context, blockNumbers []uint64) ([]*types.Block, error) {
|
||||
blocksCount := len(blockNumbers)
|
||||
calls := make([]w3types.RPCCaller, blocksCount)
|
||||
blocks := make([]*types.Block, blocksCount)
|
||||
|
||||
for i, v := range blockNumbers {
|
||||
calls[i] = eth.BlockByNumber(new(big.Int).SetUint64(v)).Returns(&blocks[i])
|
||||
}
|
||||
|
||||
if err := c.provider.Client.CallCtx(ctx, calls...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return blocks, nil
|
||||
}
|
||||
|
||||
func (c *EthRPC) GetBlock(ctx context.Context, blockNumber uint64) (*types.Block, error) {
|
||||
var block *types.Block
|
||||
blockCall := eth.BlockByNumber(new(big.Int).SetUint64(blockNumber)).Returns(&block)
|
||||
|
||||
if err := c.provider.Client.CallCtx(ctx, blockCall); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return block, nil
|
||||
}
|
||||
|
||||
func (c *EthRPC) GetLatestBlock(ctx context.Context) (uint64, error) {
|
||||
var latestBlock *big.Int
|
||||
latestBlockCall := eth.BlockNumber().Returns(&latestBlock)
|
||||
|
||||
if err := c.provider.Client.CallCtx(ctx, latestBlockCall); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return latestBlock.Uint64(), nil
|
||||
}
|
||||
|
||||
func (c *EthRPC) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, error) {
|
||||
var transaction *types.Transaction
|
||||
if err := c.provider.Client.CallCtx(ctx, eth.Tx(txHash).Returns(&transaction)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return transaction, nil
|
||||
}
|
||||
|
||||
func (c *EthRPC) GetReceipts(ctx context.Context, blockNumber *big.Int) (types.Receipts, error) {
|
||||
var receipts types.Receipts
|
||||
|
||||
if err := c.provider.Client.CallCtx(ctx, eth.BlockReceipts(blockNumber).Returns(&receipts)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return receipts, nil
|
||||
}
|
||||
|
||||
func (c *EthRPC) Provider() *ethutils.Provider {
|
||||
return c.provider
|
||||
}
|
||||
|
||||
@ -9,12 +9,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
testRPCEndpoint = "https://celo.archive.grassecon.net"
|
||||
testChainID = 42220
|
||||
testRPCEndpoint = "https://alfajores-forno.celo-testnet.org"
|
||||
testChainID = 44787
|
||||
)
|
||||
|
||||
func setupCeloRPC() (Chain, error) {
|
||||
opts := CeloRPCOpts{
|
||||
func setupEthRPC() (Chain, error) {
|
||||
opts := EthRPCOpts{
|
||||
RPCEndpoint: testRPCEndpoint,
|
||||
ChainID: testChainID,
|
||||
}
|
||||
@ -22,13 +22,13 @@ func setupCeloRPC() (Chain, error) {
|
||||
}
|
||||
|
||||
func TestRPC_GetBlocks(t *testing.T) {
|
||||
rpcFetcher, err := setupCeloRPC()
|
||||
rpcFetcher, err := setupEthRPC()
|
||||
require.NoError(t, err)
|
||||
|
||||
blockNumbers := []uint64{
|
||||
19_600_000,
|
||||
23_000_000,
|
||||
27_000_000,
|
||||
26_385_000,
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
@ -39,10 +39,10 @@ func TestRPC_GetBlocks(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRPC_GetBlock(t *testing.T) {
|
||||
rpcFetcher, err := setupCeloRPC()
|
||||
rpcFetcher, err := setupEthRPC()
|
||||
require.NoError(t, err)
|
||||
|
||||
var blockNumber uint64 = 19_900_000
|
||||
var blockNumber uint64 = 26_386_000
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@ -52,7 +52,7 @@ func TestRPC_GetBlock(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRPC_GetLatestBlock(t *testing.T) {
|
||||
rpcFetcher, err := setupCeloRPC()
|
||||
rpcFetcher, err := setupEthRPC()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
@ -64,10 +64,10 @@ func TestRPC_GetLatestBlock(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRPC_GetTransaction(t *testing.T) {
|
||||
rpcFetcher, err := setupCeloRPC()
|
||||
rpcFetcher, err := setupEthRPC()
|
||||
require.NoError(t, err)
|
||||
|
||||
var blockNumber uint64 = 19_900_000
|
||||
var blockNumber uint64 = 26_387_000
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@ -81,10 +81,10 @@ func TestRPC_GetTransaction(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRPC_GetReceipts(t *testing.T) {
|
||||
rpcFetcher, err := setupCeloRPC()
|
||||
rpcFetcher, err := setupEthRPC()
|
||||
require.NoError(t, err)
|
||||
|
||||
var blockNumber uint64 = 19_900_000
|
||||
var blockNumber uint64 = 26_388_000
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
32
internal/handler/contract_creation.go
Normal file
32
internal/handler/contract_creation.go
Normal file
@ -0,0 +1,32 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/router"
|
||||
)
|
||||
|
||||
const contractCreationEventName = "CONTRACT_CREATION"
|
||||
|
||||
func HandleContractCreation(hc *HandlerContainer) router.ContractCreationHandlerFunc {
|
||||
return func(ctx context.Context, ccp router.ContractCreationPayload, c router.Callback) error {
|
||||
contractCreationEvent := event.Event{
|
||||
Block: ccp.Block,
|
||||
ContractAddress: ccp.ContractAddress,
|
||||
Success: ccp.Success,
|
||||
Timestamp: ccp.Timestamp,
|
||||
TxHash: ccp.TxHash,
|
||||
TxType: contractCreationEventName,
|
||||
Payload: map[string]any{
|
||||
"from": ccp.From,
|
||||
},
|
||||
}
|
||||
|
||||
if err := hc.cache.Add(ctx, ccp.ContractAddress); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c(ctx, contractCreationEvent)
|
||||
}
|
||||
}
|
||||
66
internal/handler/custodial_registration.go
Normal file
66
internal/handler/custodial_registration.go
Normal file
@ -0,0 +1,66 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/router"
|
||||
"github.com/lmittmann/w3"
|
||||
)
|
||||
|
||||
const custodialRegistrationEventName = "CUSTODIAL_REGISTRATION"
|
||||
|
||||
var (
|
||||
custodialRegistrationEvent = w3.MustNewEvent("NewRegistration(address indexed subject)")
|
||||
custodialRegistrationSig = w3.MustNewFunc("register(address)", "")
|
||||
)
|
||||
|
||||
func HandleCustodialRegistrationLog() router.LogHandlerFunc {
|
||||
return func(ctx context.Context, lp router.LogPayload, c router.Callback) error {
|
||||
var account common.Address
|
||||
|
||||
if err := custodialRegistrationEvent.DecodeArgs(lp.Log, &account); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
custodialRegistrationEvent := event.Event{
|
||||
Index: lp.Log.Index,
|
||||
Block: lp.Log.BlockNumber,
|
||||
ContractAddress: lp.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: lp.Timestamp,
|
||||
TxHash: lp.Log.TxHash.Hex(),
|
||||
TxType: custodialRegistrationEventName,
|
||||
Payload: map[string]any{
|
||||
"account": account.Hex(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, custodialRegistrationEvent)
|
||||
}
|
||||
}
|
||||
|
||||
func HandleCustodialRegistrationInputData() router.InputDataHandlerFunc {
|
||||
return func(ctx context.Context, idp router.InputDataPayload, c router.Callback) error {
|
||||
var account common.Address
|
||||
|
||||
if err := custodialRegistrationSig.DecodeArgs(w3.B(idp.InputData), &account); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
custodialRegistrationEvent := event.Event{
|
||||
Block: idp.Block,
|
||||
ContractAddress: idp.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: idp.Timestamp,
|
||||
TxHash: idp.TxHash,
|
||||
TxType: custodialRegistrationEventName,
|
||||
Payload: map[string]any{
|
||||
"account": account.Hex(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, custodialRegistrationEvent)
|
||||
}
|
||||
}
|
||||
91
internal/handler/faucet_give.go
Normal file
91
internal/handler/faucet_give.go
Normal file
@ -0,0 +1,91 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/router"
|
||||
"github.com/grassrootseconomics/ethutils"
|
||||
"github.com/lmittmann/w3"
|
||||
)
|
||||
|
||||
const faucetGiveEventName = "FAUCET_GIVE"
|
||||
|
||||
var (
|
||||
faucetGiveEvent = w3.MustNewEvent("Give(address indexed _recipient, address indexed _token, uint256 _amount)")
|
||||
faucetGiveToSig = w3.MustNewFunc("giveTo(address)", "uint256")
|
||||
faucetGimmeSig = w3.MustNewFunc("gimme()", "uint256")
|
||||
)
|
||||
|
||||
func HandleFaucetGiveLog() router.LogHandlerFunc {
|
||||
return func(ctx context.Context, lp router.LogPayload, c router.Callback) error {
|
||||
var (
|
||||
recipient common.Address
|
||||
token common.Address
|
||||
amount big.Int
|
||||
)
|
||||
|
||||
if err := faucetGiveEvent.DecodeArgs(lp.Log, &recipient, &token, &amount); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
faucetGiveEvent := event.Event{
|
||||
Index: lp.Log.Index,
|
||||
Block: lp.Log.BlockNumber,
|
||||
ContractAddress: lp.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: lp.Timestamp,
|
||||
TxHash: lp.Log.TxHash.Hex(),
|
||||
TxType: faucetGiveEventName,
|
||||
Payload: map[string]any{
|
||||
"recipient": recipient.Hex(),
|
||||
"token": token.Hex(),
|
||||
"amount": amount.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, faucetGiveEvent)
|
||||
}
|
||||
}
|
||||
|
||||
func HandleFaucetGiveInputData() router.InputDataHandlerFunc {
|
||||
return func(ctx context.Context, idp router.InputDataPayload, c router.Callback) error {
|
||||
faucetGiveEvent := event.Event{
|
||||
Block: idp.Block,
|
||||
ContractAddress: idp.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: idp.Timestamp,
|
||||
TxHash: idp.TxHash,
|
||||
TxType: faucetGiveEventName,
|
||||
}
|
||||
|
||||
switch idp.InputData[:8] {
|
||||
case "63e4bff4":
|
||||
var to common.Address
|
||||
|
||||
if err := faucetGiveToSig.DecodeArgs(w3.B(idp.InputData), &to); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
faucetGiveEvent.Payload = map[string]any{
|
||||
"recipient": to.Hex(),
|
||||
"token": ethutils.ZeroAddress,
|
||||
"amount": "0",
|
||||
}
|
||||
|
||||
return c(ctx, faucetGiveEvent)
|
||||
case "de82efb4":
|
||||
faucetGiveEvent.Payload = map[string]any{
|
||||
"recipient": ethutils.ZeroAddress,
|
||||
"token": ethutils.ZeroAddress,
|
||||
"amount": "0",
|
||||
}
|
||||
|
||||
return c(ctx, faucetGiveEvent)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
13
internal/handler/handler.go
Normal file
13
internal/handler/handler.go
Normal file
@ -0,0 +1,13 @@
|
||||
package handler
|
||||
|
||||
import "github.com/grassrootseconomics/eth-tracker/internal/cache"
|
||||
|
||||
type HandlerContainer struct {
|
||||
cache cache.Cache
|
||||
}
|
||||
|
||||
func New(cacheProvider cache.Cache) *HandlerContainer {
|
||||
return &HandlerContainer{
|
||||
cache: cacheProvider,
|
||||
}
|
||||
}
|
||||
89
internal/handler/index_add.go
Normal file
89
internal/handler/index_add.go
Normal file
@ -0,0 +1,89 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/router"
|
||||
"github.com/lmittmann/w3"
|
||||
)
|
||||
|
||||
const indexAddEventName = "INDEX_ADD"
|
||||
|
||||
var (
|
||||
indexAddEvent = w3.MustNewEvent("AddressAdded(address _token)")
|
||||
indexAddSig = w3.MustNewFunc("add(address)", "bool")
|
||||
indexRegisterSig = w3.MustNewFunc("register(address)", "bool")
|
||||
)
|
||||
|
||||
func HandleIndexAddLog(hc *HandlerContainer) router.LogHandlerFunc {
|
||||
return func(ctx context.Context, lp router.LogPayload, c router.Callback) error {
|
||||
var address common.Address
|
||||
|
||||
if err := indexAddEvent.DecodeArgs(lp.Log, &address); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
indexAddEvent := event.Event{
|
||||
Index: lp.Log.Index,
|
||||
Block: lp.Log.BlockNumber,
|
||||
ContractAddress: lp.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: lp.Timestamp,
|
||||
TxHash: lp.Log.TxHash.Hex(),
|
||||
TxType: indexAddEventName,
|
||||
Payload: map[string]any{
|
||||
"address": address.Hex(),
|
||||
},
|
||||
}
|
||||
|
||||
if err := hc.cache.Add(ctx, address.Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c(ctx, indexAddEvent)
|
||||
}
|
||||
}
|
||||
|
||||
func HandleIndexAddInputData() router.InputDataHandlerFunc {
|
||||
return func(ctx context.Context, idp router.InputDataPayload, c router.Callback) error {
|
||||
indexAddEvent := event.Event{
|
||||
Block: idp.Block,
|
||||
ContractAddress: idp.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: idp.Timestamp,
|
||||
TxHash: idp.TxHash,
|
||||
TxType: indexAddEventName,
|
||||
}
|
||||
|
||||
switch idp.InputData[:8] {
|
||||
case "0a3b0a4f":
|
||||
var address common.Address
|
||||
|
||||
indexAddEvent.Payload = map[string]any{
|
||||
"address": address.Hex(),
|
||||
}
|
||||
|
||||
if err := indexAddSig.DecodeArgs(w3.B(idp.InputData), &address); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c(ctx, indexAddEvent)
|
||||
case "4420e486":
|
||||
var address common.Address
|
||||
|
||||
indexAddEvent.Payload = map[string]any{
|
||||
"address": address.Hex(),
|
||||
}
|
||||
|
||||
if err := indexRegisterSig.DecodeArgs(w3.B(idp.InputData), &address); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c(ctx, indexAddEvent)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
70
internal/handler/index_remove.go
Normal file
70
internal/handler/index_remove.go
Normal file
@ -0,0 +1,70 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/router"
|
||||
"github.com/lmittmann/w3"
|
||||
)
|
||||
|
||||
const indexRemoveEventName = "INDEX_REMOVE"
|
||||
|
||||
var (
|
||||
indexRemoveEvent = w3.MustNewEvent("AddressRemoved(address _token)")
|
||||
indexRemoveSig = w3.MustNewFunc("remove(address)", "bool")
|
||||
)
|
||||
|
||||
func HandleIndexRemoveLog(hc *HandlerContainer) router.LogHandlerFunc {
|
||||
return func(ctx context.Context, lp router.LogPayload, c router.Callback) error {
|
||||
var address common.Address
|
||||
|
||||
if err := indexRemoveEvent.DecodeArgs(lp.Log, &address); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
indexRemoveEvent := event.Event{
|
||||
Index: lp.Log.Index,
|
||||
Block: lp.Log.BlockNumber,
|
||||
ContractAddress: lp.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: lp.Timestamp,
|
||||
TxHash: lp.Log.TxHash.Hex(),
|
||||
TxType: indexRemoveEventName,
|
||||
Payload: map[string]any{
|
||||
"address": address.Hex(),
|
||||
},
|
||||
}
|
||||
|
||||
if err := hc.cache.Remove(ctx, address.Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c(ctx, indexRemoveEvent)
|
||||
}
|
||||
}
|
||||
|
||||
func HandleIndexRemoveInputData() router.InputDataHandlerFunc {
|
||||
return func(ctx context.Context, idp router.InputDataPayload, c router.Callback) error {
|
||||
var address common.Address
|
||||
|
||||
if err := indexRemoveSig.DecodeArgs(w3.B(idp.InputData), &address); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
indexRemoveEvent := event.Event{
|
||||
Block: idp.Block,
|
||||
ContractAddress: idp.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: idp.Timestamp,
|
||||
TxHash: idp.TxHash,
|
||||
TxType: indexRemoveEventName,
|
||||
Payload: map[string]any{
|
||||
"address": address.Hex(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, indexRemoveEvent)
|
||||
}
|
||||
}
|
||||
71
internal/handler/ownership.go
Normal file
71
internal/handler/ownership.go
Normal file
@ -0,0 +1,71 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/router"
|
||||
"github.com/lmittmann/w3"
|
||||
)
|
||||
|
||||
const ownershipEventName = "OWNERSHIP_TRANSFERRED"
|
||||
|
||||
var (
|
||||
ownershipEvent = w3.MustNewEvent("OwnershipTransferred(address indexed previousOwner, address indexed newOwner)")
|
||||
ownershipToSig = w3.MustNewFunc("transferOwnership(address)", "bool")
|
||||
)
|
||||
|
||||
func HandleOwnershipLog() router.LogHandlerFunc {
|
||||
return func(ctx context.Context, lp router.LogPayload, c router.Callback) error {
|
||||
var (
|
||||
previousOwner common.Address
|
||||
newOwner common.Address
|
||||
)
|
||||
|
||||
if err := ownershipEvent.DecodeArgs(lp.Log, &previousOwner, &newOwner); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ownershipEvent := event.Event{
|
||||
Index: lp.Log.Index,
|
||||
Block: lp.Log.BlockNumber,
|
||||
ContractAddress: lp.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: lp.Timestamp,
|
||||
TxHash: lp.Log.TxHash.Hex(),
|
||||
TxType: ownershipEventName,
|
||||
Payload: map[string]any{
|
||||
"previousOwner": previousOwner.Hex(),
|
||||
"newOwner": newOwner.Hex(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, ownershipEvent)
|
||||
}
|
||||
}
|
||||
|
||||
func HandleOwnershipInputData() router.InputDataHandlerFunc {
|
||||
return func(ctx context.Context, idp router.InputDataPayload, c router.Callback) error {
|
||||
var newOwner common.Address
|
||||
|
||||
if err := ownershipToSig.DecodeArgs(w3.B(idp.InputData), &newOwner); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ownershipEvent := event.Event{
|
||||
Block: idp.Block,
|
||||
ContractAddress: idp.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: idp.Timestamp,
|
||||
TxHash: idp.TxHash,
|
||||
TxType: ownershipEventName,
|
||||
Payload: map[string]any{
|
||||
"previousOwner": idp.From,
|
||||
"newOwner": newOwner.Hex(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, ownershipEvent)
|
||||
}
|
||||
}
|
||||
83
internal/handler/pool_deposit.go
Normal file
83
internal/handler/pool_deposit.go
Normal file
@ -0,0 +1,83 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/router"
|
||||
"github.com/lmittmann/w3"
|
||||
)
|
||||
|
||||
const poolDepositEventName = "POOL_DEPOSIT"
|
||||
|
||||
var (
|
||||
poolDepositEvent = w3.MustNewEvent("Deposit(address indexed initiator, address indexed tokenIn, uint256 amountIn)")
|
||||
poolDepositSig = w3.MustNewFunc("deposit(address, uint256)", "")
|
||||
)
|
||||
|
||||
func HandlePoolDepositLog() router.LogHandlerFunc {
|
||||
return func(ctx context.Context, lp router.LogPayload, c router.Callback) error {
|
||||
var (
|
||||
initiator common.Address
|
||||
tokenIn common.Address
|
||||
amountIn big.Int
|
||||
)
|
||||
|
||||
if err := poolDepositEvent.DecodeArgs(
|
||||
lp.Log,
|
||||
&initiator,
|
||||
&tokenIn,
|
||||
&amountIn,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
poolDepositEvent := event.Event{
|
||||
Index: lp.Log.Index,
|
||||
Block: lp.Log.BlockNumber,
|
||||
ContractAddress: lp.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: lp.Timestamp,
|
||||
TxHash: lp.Log.TxHash.Hex(),
|
||||
TxType: poolDepositEventName,
|
||||
Payload: map[string]any{
|
||||
"initiator": initiator.Hex(),
|
||||
"tokenIn": tokenIn.Hex(),
|
||||
"amountIn": amountIn.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, poolDepositEvent)
|
||||
}
|
||||
}
|
||||
|
||||
func HandlePoolDepositInputData() router.InputDataHandlerFunc {
|
||||
return func(ctx context.Context, idp router.InputDataPayload, c router.Callback) error {
|
||||
var (
|
||||
tokenIn common.Address
|
||||
amountIn big.Int
|
||||
)
|
||||
|
||||
if err := poolDepositSig.DecodeArgs(w3.B(idp.InputData), &tokenIn, &amountIn); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
poolDepositEvent := event.Event{
|
||||
Block: idp.Block,
|
||||
ContractAddress: idp.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: idp.Timestamp,
|
||||
TxHash: idp.TxHash,
|
||||
TxType: poolDepositEventName,
|
||||
Payload: map[string]any{
|
||||
"initiator": idp.From,
|
||||
"tokenIn": tokenIn.Hex(),
|
||||
"amountIn": amountIn.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, poolDepositEvent)
|
||||
}
|
||||
}
|
||||
96
internal/handler/pool_swap.go
Normal file
96
internal/handler/pool_swap.go
Normal file
@ -0,0 +1,96 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/router"
|
||||
"github.com/lmittmann/w3"
|
||||
)
|
||||
|
||||
const poolSwapEventName = "POOL_SWAP"
|
||||
|
||||
var (
|
||||
poolSwapEvent = w3.MustNewEvent("Swap(address indexed initiator, address indexed tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut, uint256 fee)")
|
||||
poolSwapSig = w3.MustNewFunc("withdraw(address, address, uint256)", "")
|
||||
)
|
||||
|
||||
func HandlePoolSwapLog() router.LogHandlerFunc {
|
||||
return func(ctx context.Context, lp router.LogPayload, c router.Callback) error {
|
||||
var (
|
||||
initiator common.Address
|
||||
tokenIn common.Address
|
||||
tokenOut common.Address
|
||||
amountIn big.Int
|
||||
amountOut big.Int
|
||||
fee big.Int
|
||||
)
|
||||
|
||||
if err := poolSwapEvent.DecodeArgs(
|
||||
lp.Log,
|
||||
&initiator,
|
||||
&tokenIn,
|
||||
&tokenOut,
|
||||
&amountIn,
|
||||
&amountOut,
|
||||
&fee,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
poolSwapEvent := event.Event{
|
||||
Index: lp.Log.Index,
|
||||
Block: lp.Log.BlockNumber,
|
||||
ContractAddress: lp.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: lp.Timestamp,
|
||||
TxHash: lp.Log.TxHash.Hex(),
|
||||
TxType: poolSwapEventName,
|
||||
Payload: map[string]any{
|
||||
"initiator": initiator.Hex(),
|
||||
"tokenIn": tokenIn.Hex(),
|
||||
"tokenOut": tokenOut.Hex(),
|
||||
"amountIn": amountIn.String(),
|
||||
"amountOut": amountOut.String(),
|
||||
"fee": fee.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, poolSwapEvent)
|
||||
}
|
||||
}
|
||||
|
||||
func HandlePoolSwapInputData() router.InputDataHandlerFunc {
|
||||
return func(ctx context.Context, idp router.InputDataPayload, c router.Callback) error {
|
||||
var (
|
||||
tokenOut common.Address
|
||||
tokenIn common.Address
|
||||
amountIn big.Int
|
||||
)
|
||||
|
||||
if err := poolSwapSig.DecodeArgs(w3.B(idp.InputData), &tokenOut, &tokenIn, &amountIn); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
poolSwapEvent := event.Event{
|
||||
Block: idp.Block,
|
||||
ContractAddress: idp.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: idp.Timestamp,
|
||||
TxHash: idp.TxHash,
|
||||
TxType: poolSwapEventName,
|
||||
Payload: map[string]any{
|
||||
"initiator": idp.From,
|
||||
"tokenIn": tokenIn.Hex(),
|
||||
"tokenOut": tokenOut.Hex(),
|
||||
"amountIn": amountIn.String(),
|
||||
"amountOut": "0",
|
||||
"fee": "0",
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, poolSwapEvent)
|
||||
}
|
||||
}
|
||||
75
internal/handler/quoter_price.go
Normal file
75
internal/handler/quoter_price.go
Normal file
@ -0,0 +1,75 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/router"
|
||||
"github.com/lmittmann/w3"
|
||||
)
|
||||
|
||||
const quoterPriceEventName = "QUOTER_PRICE_INDEX_UPDATED"
|
||||
|
||||
var (
|
||||
quoterPriceEvent = w3.MustNewEvent("PriceIndexUpdated(address _tokenAddress, uint256 _exchangeRate)")
|
||||
quoterPriceToSig = w3.MustNewFunc("setPriceIndexValue(address, uint256)", "uint256")
|
||||
)
|
||||
|
||||
func HandleQuoterPriceUpdateLog() router.LogHandlerFunc {
|
||||
return func(ctx context.Context, lp router.LogPayload, c router.Callback) error {
|
||||
var (
|
||||
token common.Address
|
||||
exchangeRate big.Int
|
||||
)
|
||||
|
||||
if err := quoterPriceEvent.DecodeArgs(lp.Log, &token, &exchangeRate); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
quoterPriceEvent := event.Event{
|
||||
Index: lp.Log.Index,
|
||||
Block: lp.Log.BlockNumber,
|
||||
ContractAddress: lp.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: lp.Timestamp,
|
||||
TxHash: lp.Log.TxHash.Hex(),
|
||||
TxType: quoterPriceEventName,
|
||||
Payload: map[string]any{
|
||||
"token": token.Hex(),
|
||||
"exchangeRate": exchangeRate.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, quoterPriceEvent)
|
||||
}
|
||||
}
|
||||
|
||||
func HandleQuoterPriceUpdateInputdata() router.InputDataHandlerFunc {
|
||||
return func(ctx context.Context, idp router.InputDataPayload, c router.Callback) error {
|
||||
var (
|
||||
token common.Address
|
||||
exchangeRate big.Int
|
||||
)
|
||||
|
||||
if err := quoterPriceToSig.DecodeArgs(w3.B(idp.InputData), &token, &exchangeRate); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
quoterPriceEvent := event.Event{
|
||||
Block: idp.Block,
|
||||
ContractAddress: idp.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: idp.Timestamp,
|
||||
TxHash: idp.TxHash,
|
||||
TxType: quoterPriceEventName,
|
||||
Payload: map[string]any{
|
||||
"token": token.Hex(),
|
||||
"exchangeRate": exchangeRate.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, quoterPriceEvent)
|
||||
}
|
||||
}
|
||||
66
internal/handler/quoter_updated.go
Normal file
66
internal/handler/quoter_updated.go
Normal file
@ -0,0 +1,66 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/router"
|
||||
"github.com/lmittmann/w3"
|
||||
)
|
||||
|
||||
const quoterUpdatedEventName = "QUOTER_UPDATED"
|
||||
|
||||
var (
|
||||
quoterUpdatedEvent = w3.MustNewEvent("QuoterUpdated(address indexed newQuoter)")
|
||||
quoterUpdatedSig = w3.MustNewFunc("setQuoter(address)", "")
|
||||
)
|
||||
|
||||
func HandleQuoterUpdatedLog() router.LogHandlerFunc {
|
||||
return func(ctx context.Context, lp router.LogPayload, c router.Callback) error {
|
||||
var newQuoter common.Address
|
||||
|
||||
if err := quoterUpdatedEvent.DecodeArgs(lp.Log, &newQuoter); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
quoterUpdatedEvent := event.Event{
|
||||
Index: lp.Log.Index,
|
||||
Block: lp.Log.BlockNumber,
|
||||
ContractAddress: lp.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: lp.Timestamp,
|
||||
TxHash: lp.Log.TxHash.Hex(),
|
||||
TxType: quoterUpdatedEventName,
|
||||
Payload: map[string]any{
|
||||
"newQuoter": newQuoter.Hex(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, quoterUpdatedEvent)
|
||||
}
|
||||
}
|
||||
|
||||
func HandleQuoterUpdatedInputData() router.InputDataHandlerFunc {
|
||||
return func(ctx context.Context, idp router.InputDataPayload, c router.Callback) error {
|
||||
var newQuoter common.Address
|
||||
|
||||
if err := quoterUpdatedSig.DecodeArgs(w3.B(idp.InputData), &newQuoter); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
quoterUpdatedEvent := event.Event{
|
||||
Block: idp.Block,
|
||||
ContractAddress: idp.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: idp.Timestamp,
|
||||
TxHash: idp.TxHash,
|
||||
TxType: quoterUpdatedEventName,
|
||||
Payload: map[string]any{
|
||||
"newQuoter": newQuoter.Hex(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, quoterUpdatedEvent)
|
||||
}
|
||||
}
|
||||
70
internal/handler/seal.go
Normal file
70
internal/handler/seal.go
Normal file
@ -0,0 +1,70 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/router"
|
||||
"github.com/lmittmann/w3"
|
||||
)
|
||||
|
||||
const sealEventName = "SEAL_STATE_CHANGE"
|
||||
|
||||
var (
|
||||
sealEvent = w3.MustNewEvent("SealStateChange(bool indexed _final, uint256 _sealState)")
|
||||
sealToSig = w3.MustNewFunc("seal(uint256)", "uint256")
|
||||
)
|
||||
|
||||
func HandleSealStateChangeLog() router.LogHandlerFunc {
|
||||
return func(ctx context.Context, lp router.LogPayload, c router.Callback) error {
|
||||
var (
|
||||
final bool
|
||||
sealState big.Int
|
||||
)
|
||||
|
||||
if err := sealEvent.DecodeArgs(lp.Log, &final, &sealState); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sealEvent := event.Event{
|
||||
Index: lp.Log.Index,
|
||||
Block: lp.Log.BlockNumber,
|
||||
ContractAddress: lp.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: lp.Timestamp,
|
||||
TxHash: lp.Log.TxHash.Hex(),
|
||||
TxType: sealEventName,
|
||||
Payload: map[string]any{
|
||||
"final": final,
|
||||
"sealState": sealState.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, sealEvent)
|
||||
}
|
||||
}
|
||||
|
||||
func HandleSealStateChangeInputData() router.InputDataHandlerFunc {
|
||||
return func(ctx context.Context, idp router.InputDataPayload, c router.Callback) error {
|
||||
var sealState big.Int
|
||||
|
||||
if err := sealToSig.DecodeArgs(w3.B(idp.InputData), &sealState); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sealEvent := event.Event{
|
||||
Block: idp.Block,
|
||||
ContractAddress: idp.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: idp.Timestamp,
|
||||
TxHash: idp.TxHash,
|
||||
TxType: sealEventName,
|
||||
Payload: map[string]any{
|
||||
"sealState": sealState.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, sealEvent)
|
||||
}
|
||||
}
|
||||
94
internal/handler/token_approve.go
Normal file
94
internal/handler/token_approve.go
Normal file
@ -0,0 +1,94 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/router"
|
||||
"github.com/lmittmann/w3"
|
||||
)
|
||||
|
||||
const approveEventName = "TOKEN_APPROVE"
|
||||
|
||||
var (
|
||||
tokenApproveEvent = w3.MustNewEvent("Approval(address indexed _owner, address indexed _spender, uint256 _value)")
|
||||
tokenApproveToSig = w3.MustNewFunc("approve(address, uint256)", "bool")
|
||||
)
|
||||
|
||||
func HandleTokenApproveLog(hc *HandlerContainer) router.LogHandlerFunc {
|
||||
return func(ctx context.Context, lp router.LogPayload, c router.Callback) error {
|
||||
var (
|
||||
owner common.Address
|
||||
spender common.Address
|
||||
value big.Int
|
||||
)
|
||||
|
||||
if err := tokenApproveEvent.DecodeArgs(lp.Log, &owner, &spender, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proceed, err := hc.checkWithinNetwork(ctx, lp.Log.Address.Hex(), owner.Hex(), spender.Hex())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !proceed {
|
||||
return nil
|
||||
}
|
||||
|
||||
tokenApproveEvent := event.Event{
|
||||
Index: lp.Log.Index,
|
||||
Block: lp.Log.BlockNumber,
|
||||
ContractAddress: lp.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: lp.Timestamp,
|
||||
TxHash: lp.Log.TxHash.Hex(),
|
||||
TxType: approveEventName,
|
||||
Payload: map[string]any{
|
||||
"owner": owner.Hex(),
|
||||
"spender": spender.Hex(),
|
||||
"value": value.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, tokenApproveEvent)
|
||||
}
|
||||
}
|
||||
|
||||
func HandleTokenApproveInputData(hc *HandlerContainer) router.InputDataHandlerFunc {
|
||||
return func(ctx context.Context, idp router.InputDataPayload, c router.Callback) error {
|
||||
var (
|
||||
spender common.Address
|
||||
value big.Int
|
||||
)
|
||||
|
||||
if err := tokenApproveToSig.DecodeArgs(w3.B(idp.InputData), &spender, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proceed, err := hc.checkWithinNetwork(ctx, idp.ContractAddress, idp.From, spender.Hex())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !proceed {
|
||||
return nil
|
||||
}
|
||||
|
||||
tokenApproveEvent := event.Event{
|
||||
Block: idp.Block,
|
||||
ContractAddress: idp.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: idp.Timestamp,
|
||||
TxHash: idp.TxHash,
|
||||
TxType: approveEventName,
|
||||
Payload: map[string]any{
|
||||
"owner": idp.From,
|
||||
"spender": spender.Hex(),
|
||||
"value": value.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, tokenApproveEvent)
|
||||
}
|
||||
}
|
||||
72
internal/handler/token_burn.go
Normal file
72
internal/handler/token_burn.go
Normal file
@ -0,0 +1,72 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/router"
|
||||
"github.com/lmittmann/w3"
|
||||
)
|
||||
|
||||
const burnEventName = "TOKEN_BURN"
|
||||
|
||||
var (
|
||||
tokenBurnEvent = w3.MustNewEvent("Burn(address indexed _tokenBurner, uint256 _value)")
|
||||
tokenBurnToSig = w3.MustNewFunc("burn(uint256)", "bool")
|
||||
)
|
||||
|
||||
func HandleTokenBurnLog() router.LogHandlerFunc {
|
||||
return func(ctx context.Context, lp router.LogPayload, c router.Callback) error {
|
||||
var (
|
||||
tokenBurner common.Address
|
||||
value big.Int
|
||||
)
|
||||
|
||||
if err := tokenBurnEvent.DecodeArgs(lp.Log, &tokenBurner, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tokenBurnEvent := event.Event{
|
||||
Index: lp.Log.Index,
|
||||
Block: lp.Log.BlockNumber,
|
||||
ContractAddress: lp.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: lp.Timestamp,
|
||||
TxHash: lp.Log.TxHash.Hex(),
|
||||
TxType: burnEventName,
|
||||
Payload: map[string]any{
|
||||
"tokenBurner": tokenBurner.Hex(),
|
||||
"value": value.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, tokenBurnEvent)
|
||||
}
|
||||
}
|
||||
|
||||
func HandleTokenBurnInputData() router.InputDataHandlerFunc {
|
||||
return func(ctx context.Context, idp router.InputDataPayload, c router.Callback) error {
|
||||
var value big.Int
|
||||
|
||||
if err := tokenBurnToSig.DecodeArgs(w3.B(idp.InputData), &value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tokenBurnEvent := event.Event{
|
||||
Block: idp.Block,
|
||||
ContractAddress: idp.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: idp.Timestamp,
|
||||
TxHash: idp.TxHash,
|
||||
TxType: burnEventName,
|
||||
Payload: map[string]any{
|
||||
"tokenBurner": idp.From,
|
||||
"value": value.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, tokenBurnEvent)
|
||||
}
|
||||
}
|
||||
78
internal/handler/token_mint.go
Normal file
78
internal/handler/token_mint.go
Normal file
@ -0,0 +1,78 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/router"
|
||||
"github.com/lmittmann/w3"
|
||||
)
|
||||
|
||||
const mintEventName = "TOKEN_MINT"
|
||||
|
||||
var (
|
||||
tokenMintEvent = w3.MustNewEvent("Mint(address indexed _tokenMinter, address indexed _beneficiary, uint256 _value)")
|
||||
tokenMintToSig = w3.MustNewFunc("mintTo(address, uint256)", "bool")
|
||||
)
|
||||
|
||||
func HandleTokenMintLog() router.LogHandlerFunc {
|
||||
return func(ctx context.Context, lp router.LogPayload, c router.Callback) error {
|
||||
var (
|
||||
tokenMinter common.Address
|
||||
to common.Address
|
||||
value big.Int
|
||||
)
|
||||
|
||||
if err := tokenMintEvent.DecodeArgs(lp.Log, &tokenMinter, &to, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tokenMintEvent := event.Event{
|
||||
Index: lp.Log.Index,
|
||||
Block: lp.Log.BlockNumber,
|
||||
ContractAddress: lp.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: lp.Timestamp,
|
||||
TxHash: lp.Log.TxHash.Hex(),
|
||||
TxType: mintEventName,
|
||||
Payload: map[string]any{
|
||||
"tokenMinter": tokenMinter.Hex(),
|
||||
"to": to.Hex(),
|
||||
"value": value.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, tokenMintEvent)
|
||||
}
|
||||
}
|
||||
|
||||
func HandleTokenMintInputData() router.InputDataHandlerFunc {
|
||||
return func(ctx context.Context, idp router.InputDataPayload, c router.Callback) error {
|
||||
var (
|
||||
to common.Address
|
||||
value big.Int
|
||||
)
|
||||
|
||||
if err := tokenMintToSig.DecodeArgs(w3.B(idp.InputData), &to, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tokenMintEvent := event.Event{
|
||||
Block: idp.Block,
|
||||
ContractAddress: idp.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: idp.Timestamp,
|
||||
TxHash: idp.TxHash,
|
||||
TxType: mintEventName,
|
||||
Payload: map[string]any{
|
||||
"tokenMinter": idp.From,
|
||||
"to": to.Hex(),
|
||||
"value": value.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, tokenMintEvent)
|
||||
}
|
||||
}
|
||||
170
internal/handler/token_transfer.go
Normal file
170
internal/handler/token_transfer.go
Normal file
@ -0,0 +1,170 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/router"
|
||||
"github.com/lmittmann/w3"
|
||||
)
|
||||
|
||||
const transferEventName = "TOKEN_TRANSFER"
|
||||
|
||||
var (
|
||||
tokenTransferEvent = w3.MustNewEvent("Transfer(address indexed _from, address indexed _to, uint256 _value)")
|
||||
tokenTransferFromEvent = w3.MustNewEvent("TransferFrom(address indexed _from, address indexed _to, address indexed _spender, uint256 _value)")
|
||||
|
||||
tokenTransferSig = w3.MustNewFunc("transfer(address, uint256)", "bool")
|
||||
tokenTransferFromSig = w3.MustNewFunc("transferFrom(address, address, uint256)", "bool")
|
||||
)
|
||||
|
||||
func HandleTokenTransferLog(hc *HandlerContainer) router.LogHandlerFunc {
|
||||
return func(ctx context.Context, lp router.LogPayload, c router.Callback) error {
|
||||
var (
|
||||
from common.Address
|
||||
to common.Address
|
||||
value big.Int
|
||||
)
|
||||
|
||||
if err := tokenTransferEvent.DecodeArgs(lp.Log, &from, &to, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proceed, err := hc.checkWithinNetwork(ctx, lp.Log.Address.Hex(), from.Hex(), to.Hex())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !proceed {
|
||||
return nil
|
||||
}
|
||||
|
||||
tokenTransferEvent := event.Event{
|
||||
Index: lp.Log.Index,
|
||||
Block: lp.Log.BlockNumber,
|
||||
ContractAddress: lp.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: lp.Timestamp,
|
||||
TxHash: lp.Log.TxHash.Hex(),
|
||||
TxType: transferEventName,
|
||||
Payload: map[string]any{
|
||||
"from": from.Hex(),
|
||||
"to": to.Hex(),
|
||||
"value": value.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, tokenTransferEvent)
|
||||
}
|
||||
}
|
||||
|
||||
func HandleTokenTransferInputData(hc *HandlerContainer) router.InputDataHandlerFunc {
|
||||
return func(ctx context.Context, idp router.InputDataPayload, c router.Callback) error {
|
||||
tokenTransferEvent := event.Event{
|
||||
Block: idp.Block,
|
||||
ContractAddress: idp.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: idp.Timestamp,
|
||||
TxHash: idp.TxHash,
|
||||
TxType: transferEventName,
|
||||
}
|
||||
|
||||
switch idp.InputData[:8] {
|
||||
case "a9059cbb":
|
||||
var (
|
||||
to common.Address
|
||||
value big.Int
|
||||
)
|
||||
|
||||
if err := tokenTransferSig.DecodeArgs(w3.B(idp.InputData), &to, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proceed, err := hc.checkWithinNetwork(ctx, idp.ContractAddress, idp.From, to.Hex())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !proceed {
|
||||
return nil
|
||||
}
|
||||
|
||||
tokenTransferEvent.Payload = map[string]any{
|
||||
"from": idp.From,
|
||||
"to": to.Hex(),
|
||||
"value": value.String(),
|
||||
}
|
||||
|
||||
return c(ctx, tokenTransferEvent)
|
||||
case "23b872dd":
|
||||
var (
|
||||
from common.Address
|
||||
to common.Address
|
||||
value big.Int
|
||||
)
|
||||
|
||||
if err := tokenTransferFromSig.DecodeArgs(w3.B(idp.InputData), &from, &to, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proceed, err := hc.checkWithinNetwork(ctx, idp.ContractAddress, from.Hex(), to.Hex())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !proceed {
|
||||
return nil
|
||||
}
|
||||
|
||||
tokenTransferEvent.Payload = map[string]any{
|
||||
"from": from.Hex(),
|
||||
"to": to.Hex(),
|
||||
"value": value.String(),
|
||||
}
|
||||
|
||||
return c(ctx, tokenTransferEvent)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func HandleTokenTransferFromLog(hc *HandlerContainer) router.LogHandlerFunc {
|
||||
return func(ctx context.Context, lp router.LogPayload, c router.Callback) error {
|
||||
var (
|
||||
from common.Address
|
||||
to common.Address
|
||||
spender common.Address
|
||||
value big.Int
|
||||
)
|
||||
|
||||
if err := tokenTransferFromEvent.DecodeArgs(lp.Log, &from, &to, &spender, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proceed, err := hc.checkWithinNetwork(ctx, lp.Log.Address.Hex(), from.Hex(), to.Hex())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !proceed {
|
||||
return nil
|
||||
}
|
||||
|
||||
tokenTransferFromEvent := event.Event{
|
||||
Index: lp.Log.Index,
|
||||
Block: lp.Log.BlockNumber,
|
||||
ContractAddress: lp.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: lp.Timestamp,
|
||||
TxHash: lp.Log.TxHash.Hex(),
|
||||
TxType: transferEventName,
|
||||
Payload: map[string]any{
|
||||
"from": from.Hex(),
|
||||
"to": to.Hex(),
|
||||
"spender": spender.Hex(),
|
||||
"value": value.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return c(ctx, tokenTransferFromEvent)
|
||||
}
|
||||
}
|
||||
12
internal/handler/within_network.go
Normal file
12
internal/handler/within_network.go
Normal file
@ -0,0 +1,12 @@
|
||||
package handler
|
||||
|
||||
import "context"
|
||||
|
||||
func (hc *HandlerContainer) checkWithinNetwork(ctx context.Context, contractAddress string, from string, to string) (bool, error) {
|
||||
exists, err := hc.cache.ExistsNetwork(ctx, contractAddress, from, to)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return exists, nil
|
||||
}
|
||||
@ -3,10 +3,9 @@ package pool
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/alitto/pond"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/processor"
|
||||
"github.com/alitto/pond/v2"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/processor"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -18,21 +17,16 @@ type (
|
||||
|
||||
Pool struct {
|
||||
logg *slog.Logger
|
||||
workerPool *pond.WorkerPool
|
||||
workerPool pond.Pool
|
||||
processor *processor.Processor
|
||||
}
|
||||
)
|
||||
|
||||
const blocksBuffer = 100
|
||||
|
||||
func New(o PoolOpts) *Pool {
|
||||
return &Pool{
|
||||
logg: o.Logg,
|
||||
workerPool: pond.New(
|
||||
workerPool: pond.NewPool(
|
||||
o.WorkerCount,
|
||||
blocksBuffer,
|
||||
pond.Strategy(pond.Balanced()),
|
||||
pond.PanicHandler(panicHandler(o.Logg)),
|
||||
),
|
||||
processor: o.Processor,
|
||||
}
|
||||
@ -42,6 +36,7 @@ func (p *Pool) Stop() {
|
||||
p.workerPool.StopAndWait()
|
||||
}
|
||||
|
||||
// non-blocking
|
||||
func (p *Pool) Push(block uint64) {
|
||||
p.workerPool.Submit(func() {
|
||||
err := p.processor.ProcessBlock(context.Background(), block)
|
||||
@ -55,12 +50,6 @@ func (p *Pool) Size() uint64 {
|
||||
return p.workerPool.WaitingTasks()
|
||||
}
|
||||
|
||||
func (p *Pool) ActiveWorkers() int {
|
||||
func (p *Pool) ActiveWorkers() int64 {
|
||||
return p.workerPool.RunningWorkers()
|
||||
}
|
||||
|
||||
func panicHandler(logg *slog.Logger) func(interface{}) {
|
||||
return func(panic interface{}) {
|
||||
logg.Error("block processor goroutine exited from a panic", "error", panic, "stack_trace", string(debug.Stack()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,12 +6,12 @@ import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/celo-org/celo-blockchain/common"
|
||||
"github.com/celo-org/celo-blockchain/core/types"
|
||||
"github.com/grassrootseconomics/celo-tracker/db"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/cache"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/chain"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/router"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/grassrootseconomics/eth-tracker/db"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/cache"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/chain"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/router"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -54,31 +54,90 @@ func (p *Processor) ProcessBlock(ctx context.Context, blockNumber uint64) error
|
||||
}
|
||||
|
||||
for _, receipt := range receipts {
|
||||
if receipt.Status > 0 {
|
||||
if receipt.Status == 1 {
|
||||
for _, log := range receipt.Logs {
|
||||
exists, err := p.cache.Exists(ctx, log.Address.Hex())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
if err := p.router.RouteSuccessTx(
|
||||
if err := p.router.ProcessLog(
|
||||
ctx,
|
||||
router.SuccessTx{
|
||||
router.LogPayload{
|
||||
Log: log,
|
||||
Timestamp: block.Time(),
|
||||
},
|
||||
); err != nil && !errors.Is(err, context.Canceled) {
|
||||
return err
|
||||
return fmt.Errorf("route success transaction error: tx %s: %v", receipt.TxHash.Hex(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
if receipt.ContractAddress != (common.Address{}) {
|
||||
tx, err := p.chain.GetTransaction(ctx, receipt.TxHash)
|
||||
if err != nil && !errors.Is(err, context.Canceled) {
|
||||
return fmt.Errorf("get transaction error: tx %s: %v", receipt.TxHash.Hex(), err)
|
||||
}
|
||||
|
||||
from, err := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("transaction decode error: tx %s: %v", receipt.TxHash.Hex(), err)
|
||||
}
|
||||
|
||||
exists, err := p.cache.Exists(ctx, from.Hex())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
if err := p.router.ProcessContractCreation(
|
||||
ctx,
|
||||
router.ContractCreationPayload{
|
||||
From: from.Hex(),
|
||||
Block: blockNumber,
|
||||
ContractAddress: receipt.ContractAddress.Hex(),
|
||||
Timestamp: block.Time(),
|
||||
TxHash: receipt.TxHash.Hex(),
|
||||
Success: true,
|
||||
},
|
||||
); err != nil && !errors.Is(err, context.Canceled) {
|
||||
return fmt.Errorf("route success contract creation error: tx %s: %v", receipt.TxHash.Hex(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if receipt.Status == 0 {
|
||||
tx, err := p.chain.GetTransaction(ctx, receipt.TxHash)
|
||||
if err != nil && !errors.Is(err, context.Canceled) {
|
||||
return fmt.Errorf("get transaction error: tx %s: %v", receipt.TxHash.Hex(), err)
|
||||
}
|
||||
if tx.To() == nil {
|
||||
from, err := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("transaction decode error: tx %s: %v", receipt.TxHash.Hex(), err)
|
||||
}
|
||||
|
||||
if tx.To() != nil {
|
||||
exists, err := p.cache.Exists(ctx, from.Hex())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exists {
|
||||
if err := p.router.ProcessContractCreation(
|
||||
ctx,
|
||||
router.ContractCreationPayload{
|
||||
From: from.Hex(),
|
||||
Block: blockNumber,
|
||||
ContractAddress: receipt.ContractAddress.Hex(),
|
||||
Timestamp: block.Time(),
|
||||
TxHash: receipt.TxHash.Hex(),
|
||||
Success: false,
|
||||
},
|
||||
); err != nil && !errors.Is(err, context.Canceled) {
|
||||
return fmt.Errorf("route reverted contract creation error: tx %s: %v", receipt.TxHash.Hex(), err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
exists, err := p.cache.Exists(ctx, tx.To().Hex())
|
||||
if err != nil {
|
||||
return err
|
||||
@ -89,9 +148,9 @@ func (p *Processor) ProcessBlock(ctx context.Context, blockNumber uint64) error
|
||||
return fmt.Errorf("transaction decode error: tx %s: %v", receipt.TxHash.Hex(), err)
|
||||
}
|
||||
|
||||
if err := p.router.RouteRevertTx(
|
||||
if err := p.router.ProcessInputData(
|
||||
ctx,
|
||||
router.RevertTx{
|
||||
router.InputDataPayload{
|
||||
From: from.Hex(),
|
||||
InputData: common.Bytes2Hex(tx.Data()),
|
||||
Block: blockNumber,
|
||||
@ -100,7 +159,7 @@ func (p *Processor) ProcessBlock(ctx context.Context, blockNumber uint64) error
|
||||
TxHash: receipt.TxHash.Hex(),
|
||||
},
|
||||
); err != nil && !errors.Is(err, context.Canceled) {
|
||||
return err
|
||||
return fmt.Errorf("route revert transaction error: tx %s: %v", receipt.TxHash.Hex(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,26 +2,25 @@ package pub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/grassrootseconomics/celo-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
)
|
||||
|
||||
type (
|
||||
JetStreamOpts struct {
|
||||
Logg *slog.Logger
|
||||
Endpoint string
|
||||
DedupDuration time.Duration
|
||||
PersistDuration time.Duration
|
||||
Logg *slog.Logger
|
||||
}
|
||||
|
||||
jetStreamPub struct {
|
||||
js jetstream.JetStream
|
||||
natsConn *nats.Conn
|
||||
jsCtx nats.JetStreamContext
|
||||
}
|
||||
)
|
||||
|
||||
@ -37,33 +36,25 @@ func NewJetStreamPub(o JetStreamOpts) (Pub, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
js, err := natsConn.JetStream()
|
||||
js, err := jetstream.New(natsConn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o.Logg.Info("successfully connected to NATS server")
|
||||
|
||||
stream, err := js.StreamInfo(streamName)
|
||||
if err != nil && !errors.Is(err, nats.ErrStreamNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
if stream == nil {
|
||||
_, err := js.AddStream(&nats.StreamConfig{
|
||||
Name: streamName,
|
||||
MaxAge: o.PersistDuration,
|
||||
Storage: nats.FileStorage,
|
||||
Subjects: streamSubjects,
|
||||
Duplicates: o.DedupDuration,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o.Logg.Info("successfully created NATS JetStream stream", "stream_name", streamName)
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
js.CreateStream(ctx, jetstream.StreamConfig{
|
||||
Name: streamName,
|
||||
Subjects: streamSubjects,
|
||||
MaxAge: o.PersistDuration,
|
||||
Storage: jetstream.FileStorage,
|
||||
Duplicates: time.Minute * 20,
|
||||
})
|
||||
|
||||
return &jetStreamPub{
|
||||
natsConn: natsConn,
|
||||
jsCtx: js,
|
||||
js: js,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -73,16 +64,17 @@ func (p *jetStreamPub) Close() {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *jetStreamPub) Send(_ context.Context, payload event.Event) error {
|
||||
func (p *jetStreamPub) Send(ctx context.Context, payload event.Event) error {
|
||||
data, err := payload.Serialize()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = p.jsCtx.Publish(
|
||||
_, err = p.js.Publish(
|
||||
ctx,
|
||||
fmt.Sprintf("%s.%s", streamName, payload.TxType),
|
||||
data,
|
||||
nats.MsgId(fmt.Sprintf("%s:%d", payload.TxHash, payload.Index)),
|
||||
jetstream.WithMsgID(fmt.Sprintf("%s:%d", payload.TxHash, payload.Index)),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@ -3,7 +3,7 @@ package pub
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grassrootseconomics/celo-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
)
|
||||
|
||||
type Pub interface {
|
||||
|
||||
@ -1,73 +0,0 @@
|
||||
package queue
|
||||
|
||||
//
|
||||
// import (
|
||||
// "context"
|
||||
// "log/slog"
|
||||
|
||||
// "github.com/alitto/pond"
|
||||
// "github.com/grassrootseconomics/celo-tracker/internal/processor"
|
||||
// )
|
||||
|
||||
// type (
|
||||
// QueueOpts struct {
|
||||
// QueueSize int
|
||||
// Logg *slog.Logger
|
||||
// Processor *processor.Processor
|
||||
// Pool *pond.WorkerPool
|
||||
// }
|
||||
|
||||
// Queue struct {
|
||||
// logg *slog.Logger
|
||||
// processChan chan uint64
|
||||
// stopSignal chan interface{}
|
||||
// processor *processor.Processor
|
||||
// pool *pond.WorkerPool
|
||||
// }
|
||||
// )
|
||||
|
||||
// func New(o QueueOpts) *Queue {
|
||||
// return &Queue{
|
||||
// logg: o.Logg,
|
||||
// processChan: make(chan uint64, o.QueueSize),
|
||||
// stopSignal: make(chan interface{}),
|
||||
// processor: o.Processor,
|
||||
// pool: o.Pool,
|
||||
// }
|
||||
// }
|
||||
|
||||
// func (q *Queue) Stop() {
|
||||
// q.stopSignal <- struct{}{}
|
||||
// }
|
||||
|
||||
// func (q *Queue) Process() {
|
||||
// for {
|
||||
// select {
|
||||
// case <-q.stopSignal:
|
||||
// q.logg.Info("shutdown signal received stopping queue processing")
|
||||
// return
|
||||
// case block, ok := <-q.processChan:
|
||||
// if !ok {
|
||||
// return
|
||||
// }
|
||||
// q.pool.Submit(func() {
|
||||
// err := q.processor.ProcessBlock(context.Background(), block)
|
||||
// if err != nil {
|
||||
// q.logg.Error("block processor error", "block_number", block, "error", err)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// func (q *Queue) Push(block uint64) {
|
||||
// q.processChan <- block
|
||||
// }
|
||||
|
||||
// func (q *Queue) Size() int {
|
||||
// return len(q.processChan)
|
||||
// }
|
||||
|
||||
// func (q *Queue) WaitingSize() uint64 {
|
||||
// return q.pool.WaitingTasks()
|
||||
// }
|
||||
@ -1,94 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/celo-org/celo-blockchain/common"
|
||||
"github.com/grassrootseconomics/celo-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/celoutils/v3"
|
||||
"github.com/grassrootseconomics/w3-celo"
|
||||
)
|
||||
|
||||
type faucetGiveHandler struct{}
|
||||
|
||||
const faucetGiveEventName = "FAUCET_GIVE"
|
||||
|
||||
var (
|
||||
_ Handler = (*faucetGiveHandler)(nil)
|
||||
|
||||
faucetGiveEvent = w3.MustNewEvent("Give(address indexed _recipient, address indexed _token, uint256 _amount)")
|
||||
faucetGiveToSig = w3.MustNewFunc("giveTo(address)", "uint256")
|
||||
faucetGimmeSig = w3.MustNewFunc("gimme()", "uint256")
|
||||
)
|
||||
|
||||
func (h *faucetGiveHandler) Name() string {
|
||||
return faucetGiveEventName
|
||||
}
|
||||
|
||||
func (h *faucetGiveHandler) SuccessTx(ctx context.Context, tx SuccessTx, pubCB PubCallback) error {
|
||||
var (
|
||||
recipient common.Address
|
||||
token common.Address
|
||||
amount big.Int
|
||||
)
|
||||
|
||||
if err := faucetGiveEvent.DecodeArgs(tx.Log, &recipient, &token, &amount); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
faucetGiveEvent := event.Event{
|
||||
Index: tx.Log.Index,
|
||||
Block: tx.Log.BlockNumber,
|
||||
ContractAddress: tx.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.Log.TxHash.Hex(),
|
||||
TxType: faucetGiveEventName,
|
||||
Payload: map[string]any{
|
||||
"recipient": recipient.Hex(),
|
||||
"token": token.Hex(),
|
||||
"amount": amount.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return pubCB(ctx, faucetGiveEvent)
|
||||
}
|
||||
|
||||
func (h *faucetGiveHandler) RevertTx(ctx context.Context, tx RevertTx, pubCB PubCallback) error {
|
||||
faucetGiveEvent := event.Event{
|
||||
Block: tx.Block,
|
||||
ContractAddress: tx.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.TxHash,
|
||||
TxType: faucetGiveEventName,
|
||||
}
|
||||
|
||||
switch tx.InputData[:8] {
|
||||
case "63e4bff4":
|
||||
var to common.Address
|
||||
|
||||
if err := faucetGiveToSig.DecodeArgs(w3.B(tx.InputData), &to); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
faucetGiveEvent.Payload = map[string]any{
|
||||
"recipient": to.Hex(),
|
||||
"token": celoutils.ZeroAddress,
|
||||
"amount": "0",
|
||||
}
|
||||
|
||||
return pubCB(ctx, faucetGiveEvent)
|
||||
case "de82efb4":
|
||||
faucetGiveEvent.Payload = map[string]any{
|
||||
"recipient": celoutils.ZeroAddress,
|
||||
"token": celoutils.ZeroAddress,
|
||||
"amount": "0",
|
||||
}
|
||||
|
||||
return pubCB(ctx, faucetGiveEvent)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -1,95 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/celo-org/celo-blockchain/common"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/cache"
|
||||
"github.com/grassrootseconomics/celo-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/w3-celo"
|
||||
)
|
||||
|
||||
type indexAddHandler struct {
|
||||
cache cache.Cache
|
||||
}
|
||||
|
||||
const indexAddEventName = "INDEX_ADD"
|
||||
|
||||
var (
|
||||
_ Handler = (*indexAddHandler)(nil)
|
||||
|
||||
indexAddEvent = w3.MustNewEvent("AddressAdded(address _token)")
|
||||
indexAddSig = w3.MustNewFunc("add(address)", "bool")
|
||||
indexRegisterSig = w3.MustNewFunc("register(address)", "bool")
|
||||
)
|
||||
|
||||
func (h *indexAddHandler) Name() string {
|
||||
return indexAddEventName
|
||||
}
|
||||
|
||||
func (h *indexAddHandler) SuccessTx(ctx context.Context, tx SuccessTx, pubCB PubCallback) error {
|
||||
var address common.Address
|
||||
|
||||
if err := indexAddEvent.DecodeArgs(tx.Log, &address); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
indexAddEvent := event.Event{
|
||||
Index: tx.Log.Index,
|
||||
Block: tx.Log.BlockNumber,
|
||||
ContractAddress: tx.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.Log.TxHash.Hex(),
|
||||
TxType: indexAddEventName,
|
||||
Payload: map[string]any{
|
||||
"address": address.Hex(),
|
||||
},
|
||||
}
|
||||
|
||||
if err := h.cache.Add(ctx, address.Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return pubCB(ctx, indexAddEvent)
|
||||
}
|
||||
|
||||
func (h *indexAddHandler) RevertTx(ctx context.Context, tx RevertTx, pubCB PubCallback) error {
|
||||
indexAddEvent := event.Event{
|
||||
Block: tx.Block,
|
||||
ContractAddress: tx.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.TxHash,
|
||||
TxType: indexAddEventName,
|
||||
}
|
||||
|
||||
switch tx.InputData[:8] {
|
||||
case "0a3b0a4f":
|
||||
var address common.Address
|
||||
|
||||
indexAddEvent.Payload = map[string]any{
|
||||
"address": address.Hex(),
|
||||
}
|
||||
|
||||
if err := indexAddSig.DecodeArgs(w3.B(tx.InputData), &address); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return pubCB(ctx, indexAddEvent)
|
||||
case "4420e486":
|
||||
var address common.Address
|
||||
|
||||
indexAddEvent.Payload = map[string]any{
|
||||
"address": address.Hex(),
|
||||
}
|
||||
|
||||
if err := indexRegisterSig.DecodeArgs(w3.B(tx.InputData), &address); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return pubCB(ctx, indexAddEvent)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -1,77 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/celo-org/celo-blockchain/common"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/cache"
|
||||
"github.com/grassrootseconomics/celo-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/w3-celo"
|
||||
)
|
||||
|
||||
type indexRemoveHandler struct {
|
||||
cache cache.Cache
|
||||
}
|
||||
|
||||
const indexRemoveEventName = "INDEX_REMOVE"
|
||||
|
||||
var (
|
||||
_ Handler = (*indexRemoveHandler)(nil)
|
||||
|
||||
indexRemoveEvent = w3.MustNewEvent("AddressRemoved(address _token)")
|
||||
indexRemoveSig = w3.MustNewFunc("remove(address)", "bool")
|
||||
)
|
||||
|
||||
func (h *indexRemoveHandler) Name() string {
|
||||
return indexRemoveEventName
|
||||
}
|
||||
|
||||
func (h *indexRemoveHandler) SuccessTx(ctx context.Context, tx SuccessTx, pubCB PubCallback) error {
|
||||
var address common.Address
|
||||
|
||||
if err := indexRemoveEvent.DecodeArgs(tx.Log, &address); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
indexRemoveEvent := event.Event{
|
||||
Index: tx.Log.Index,
|
||||
Block: tx.Log.BlockNumber,
|
||||
ContractAddress: tx.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.Log.TxHash.Hex(),
|
||||
TxType: indexRemoveEventName,
|
||||
Payload: map[string]any{
|
||||
"address": address.Hex(),
|
||||
},
|
||||
}
|
||||
|
||||
if err := h.cache.Remove(ctx, address.Hex()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return pubCB(ctx, indexRemoveEvent)
|
||||
|
||||
}
|
||||
|
||||
func (h *indexRemoveHandler) RevertTx(ctx context.Context, tx RevertTx, pubCB PubCallback) error {
|
||||
var address common.Address
|
||||
|
||||
if err := indexRemoveSig.DecodeArgs(w3.B(tx.InputData), &address); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
indexRemoveEvent := event.Event{
|
||||
Block: tx.Block,
|
||||
ContractAddress: tx.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.TxHash,
|
||||
TxType: indexRemoveEventName,
|
||||
Payload: map[string]any{
|
||||
"address": address.Hex(),
|
||||
},
|
||||
}
|
||||
|
||||
return pubCB(ctx, indexRemoveEvent)
|
||||
}
|
||||
@ -1,77 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/celo-org/celo-blockchain/common"
|
||||
"github.com/grassrootseconomics/celo-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/w3-celo"
|
||||
)
|
||||
|
||||
type ownershipHandler struct{}
|
||||
|
||||
const (
|
||||
ownershipEventName = "OWNERSHIP_TRANSFERRED"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Handler = (*ownershipHandler)(nil)
|
||||
|
||||
ownershipEvent = w3.MustNewEvent("OwnershipTransferred(address indexed previousOwner, address indexed newOwner)")
|
||||
ownershipToSig = w3.MustNewFunc("transferOwnership(address)", "bool")
|
||||
)
|
||||
|
||||
func (h *ownershipHandler) Name() string {
|
||||
return ownershipEventName
|
||||
}
|
||||
|
||||
func (h *ownershipHandler) SuccessTx(ctx context.Context, tx SuccessTx, pubCB PubCallback) error {
|
||||
var (
|
||||
previousOwner common.Address
|
||||
newOwner common.Address
|
||||
)
|
||||
|
||||
if err := ownershipEvent.DecodeArgs(tx.Log, &previousOwner, &newOwner); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ownershipEvent := event.Event{
|
||||
Index: tx.Log.Index,
|
||||
Block: tx.Log.BlockNumber,
|
||||
ContractAddress: tx.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.Log.TxHash.Hex(),
|
||||
TxType: ownershipEventName,
|
||||
Payload: map[string]any{
|
||||
"previousOwner": previousOwner.Hex(),
|
||||
"newOwner": newOwner.Hex(),
|
||||
},
|
||||
}
|
||||
|
||||
return pubCB(ctx, ownershipEvent)
|
||||
}
|
||||
|
||||
func (h *ownershipHandler) RevertTx(ctx context.Context, tx RevertTx, pubCB PubCallback) error {
|
||||
|
||||
var newOwner common.Address
|
||||
|
||||
if err := ownershipToSig.DecodeArgs(w3.B(tx.InputData), &newOwner); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ownershipEvent := event.Event{
|
||||
Block: tx.Block,
|
||||
ContractAddress: tx.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.TxHash,
|
||||
TxType: ownershipEventName,
|
||||
Payload: map[string]any{
|
||||
"previousOwner": tx.From,
|
||||
"newOwner": newOwner.Hex(),
|
||||
},
|
||||
}
|
||||
|
||||
return pubCB(ctx, ownershipEvent)
|
||||
}
|
||||
@ -1,86 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/celo-org/celo-blockchain/common"
|
||||
"github.com/grassrootseconomics/celo-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/w3-celo"
|
||||
)
|
||||
|
||||
type poolDepositHandler struct{}
|
||||
|
||||
const poolDepositEventName = "POOL_DEPOSIT"
|
||||
|
||||
var (
|
||||
_ Handler = (*poolDepositHandler)(nil)
|
||||
|
||||
poolDepositEvent = w3.MustNewEvent("Deposit(address indexed initiator, address indexed tokenIn, uint256 amountIn)")
|
||||
poolDepositSig = w3.MustNewFunc("deposit(address, uint256)", "")
|
||||
)
|
||||
|
||||
func (h *poolDepositHandler) Name() string {
|
||||
return poolDepositEventName
|
||||
}
|
||||
|
||||
func (h *poolDepositHandler) SuccessTx(ctx context.Context, tx SuccessTx, pubCB PubCallback) error {
|
||||
var (
|
||||
initiator common.Address
|
||||
tokenIn common.Address
|
||||
amountIn big.Int
|
||||
)
|
||||
|
||||
if err := poolDepositEvent.DecodeArgs(
|
||||
tx.Log,
|
||||
&initiator,
|
||||
&tokenIn,
|
||||
&amountIn,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
poolDepositEvent := event.Event{
|
||||
Index: tx.Log.Index,
|
||||
Block: tx.Log.BlockNumber,
|
||||
ContractAddress: tx.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.Log.TxHash.Hex(),
|
||||
TxType: poolDepositEventName,
|
||||
Payload: map[string]any{
|
||||
"initiator": initiator.Hex(),
|
||||
"tokenIn": tokenIn.Hex(),
|
||||
"amountIn": amountIn.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return pubCB(ctx, poolDepositEvent)
|
||||
}
|
||||
|
||||
func (h *poolDepositHandler) RevertTx(ctx context.Context, tx RevertTx, pubCB PubCallback) error {
|
||||
var (
|
||||
tokenIn common.Address
|
||||
amountIn big.Int
|
||||
)
|
||||
|
||||
if err := poolDepositSig.DecodeArgs(w3.B(tx.InputData), &tokenIn, &amountIn); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
poolDepositEvent := event.Event{
|
||||
Block: tx.Block,
|
||||
ContractAddress: tx.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.TxHash,
|
||||
TxType: poolDepositEventName,
|
||||
Payload: map[string]any{
|
||||
"initiator": tx.From,
|
||||
"tokenIn": tokenIn.Hex(),
|
||||
"amountIn": amountIn.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return pubCB(ctx, poolDepositEvent)
|
||||
}
|
||||
@ -1,99 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/celo-org/celo-blockchain/common"
|
||||
"github.com/grassrootseconomics/celo-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/w3-celo"
|
||||
)
|
||||
|
||||
type poolSwapHandler struct{}
|
||||
|
||||
const poolSwapEventName = "POOL_SWAP"
|
||||
|
||||
var (
|
||||
_ Handler = (*poolSwapHandler)(nil)
|
||||
|
||||
poolSwapEvent = w3.MustNewEvent("Swap(address indexed initiator, address indexed tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut, uint256 fee)")
|
||||
poolSwapSig = w3.MustNewFunc("withdraw(address, address, uint256)", "")
|
||||
)
|
||||
|
||||
func (h *poolSwapHandler) Name() string {
|
||||
return poolSwapEventName
|
||||
}
|
||||
|
||||
func (h *poolSwapHandler) SuccessTx(ctx context.Context, tx SuccessTx, pubCB PubCallback) error {
|
||||
var (
|
||||
initiator common.Address
|
||||
tokenIn common.Address
|
||||
tokenOut common.Address
|
||||
amountIn big.Int
|
||||
amountOut big.Int
|
||||
fee big.Int
|
||||
)
|
||||
|
||||
if err := poolSwapEvent.DecodeArgs(
|
||||
tx.Log,
|
||||
&initiator,
|
||||
&tokenIn,
|
||||
&tokenOut,
|
||||
&amountIn,
|
||||
&amountOut,
|
||||
&fee,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
poolSwapEvent := event.Event{
|
||||
Index: tx.Log.Index,
|
||||
Block: tx.Log.BlockNumber,
|
||||
ContractAddress: tx.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.Log.TxHash.Hex(),
|
||||
TxType: poolSwapEventName,
|
||||
Payload: map[string]any{
|
||||
"initiator": initiator.Hex(),
|
||||
"tokenIn": tokenIn.Hex(),
|
||||
"tokenOut": tokenOut.Hex(),
|
||||
"amountIn": amountIn.String(),
|
||||
"amountOut": amountOut.String(),
|
||||
"fee": fee.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return pubCB(ctx, poolSwapEvent)
|
||||
}
|
||||
|
||||
func (h *poolSwapHandler) RevertTx(ctx context.Context, tx RevertTx, pubCB PubCallback) error {
|
||||
var (
|
||||
tokenOut common.Address
|
||||
tokenIn common.Address
|
||||
amountIn big.Int
|
||||
)
|
||||
|
||||
if err := poolSwapSig.DecodeArgs(w3.B(tx.InputData), &tokenOut, &tokenIn, &amountIn); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
poolSwapEvent := event.Event{
|
||||
Block: tx.Block,
|
||||
ContractAddress: tx.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.TxHash,
|
||||
TxType: poolSwapEventName,
|
||||
Payload: map[string]any{
|
||||
"initiator": tx.From,
|
||||
"tokenIn": tokenIn.Hex(),
|
||||
"tokenOut": tokenOut.Hex(),
|
||||
"amountIn": amountIn.String(),
|
||||
"amountOut": "0",
|
||||
"fee": "0",
|
||||
},
|
||||
}
|
||||
|
||||
return pubCB(ctx, poolSwapEvent)
|
||||
}
|
||||
@ -1,78 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/celo-org/celo-blockchain/common"
|
||||
"github.com/grassrootseconomics/celo-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/w3-celo"
|
||||
)
|
||||
|
||||
type quoterPriceHandler struct{}
|
||||
|
||||
const quoterPriceEventName = "QUOTER_PRICE_INDEX_UPDATED"
|
||||
|
||||
var (
|
||||
_ Handler = (*quoterPriceHandler)(nil)
|
||||
|
||||
quoterPriceEvent = w3.MustNewEvent("PriceIndexUpdated(address _tokenAddress, uint256 _exchangeRate)")
|
||||
quoterPriceToSig = w3.MustNewFunc("setPriceIndexValue(address, uint256)", "uint256")
|
||||
)
|
||||
|
||||
func (h *quoterPriceHandler) Name() string {
|
||||
return quoterPriceEventName
|
||||
}
|
||||
|
||||
func (h *quoterPriceHandler) SuccessTx(ctx context.Context, tx SuccessTx, pubCB PubCallback) error {
|
||||
var (
|
||||
token common.Address
|
||||
exchangeRate big.Int
|
||||
)
|
||||
|
||||
if err := quoterPriceEvent.DecodeArgs(tx.Log, &token, &exchangeRate); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
quoterPriceEvent := event.Event{
|
||||
Index: tx.Log.Index,
|
||||
Block: tx.Log.BlockNumber,
|
||||
ContractAddress: tx.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.Log.TxHash.Hex(),
|
||||
TxType: quoterPriceEventName,
|
||||
Payload: map[string]any{
|
||||
"token": token.Hex(),
|
||||
"exchangeRate": exchangeRate.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return pubCB(ctx, quoterPriceEvent)
|
||||
}
|
||||
|
||||
func (h *quoterPriceHandler) RevertTx(ctx context.Context, tx RevertTx, pubCB PubCallback) error {
|
||||
var (
|
||||
token common.Address
|
||||
exchangeRate big.Int
|
||||
)
|
||||
|
||||
if err := quoterPriceToSig.DecodeArgs(w3.B(tx.InputData), &token, &exchangeRate); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
quoterPriceEvent := event.Event{
|
||||
Block: tx.Block,
|
||||
ContractAddress: tx.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.TxHash,
|
||||
TxType: quoterPriceEventName,
|
||||
Payload: map[string]any{
|
||||
"token": token.Hex(),
|
||||
"exchangeRate": exchangeRate.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return pubCB(ctx, quoterPriceEvent)
|
||||
}
|
||||
@ -1,123 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/celo-org/celo-blockchain/common"
|
||||
"github.com/celo-org/celo-blockchain/core/types"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/cache"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/pub"
|
||||
"github.com/grassrootseconomics/celo-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/w3-celo"
|
||||
)
|
||||
|
||||
type (
|
||||
PubCallback func(context.Context, event.Event) error
|
||||
|
||||
SuccessTx struct {
|
||||
Log *types.Log
|
||||
Timestamp uint64
|
||||
}
|
||||
|
||||
RevertTx struct {
|
||||
From string
|
||||
InputData string
|
||||
Block uint64
|
||||
ContractAddress string
|
||||
Timestamp uint64
|
||||
TxHash string
|
||||
}
|
||||
|
||||
Handler interface {
|
||||
Name() string
|
||||
SuccessTx(context.Context, SuccessTx, PubCallback) error
|
||||
RevertTx(context.Context, RevertTx, PubCallback) error
|
||||
}
|
||||
|
||||
RouterOpts struct {
|
||||
Pub pub.Pub
|
||||
Cache cache.Cache
|
||||
}
|
||||
|
||||
Router struct {
|
||||
pub pub.Pub
|
||||
cache cache.Cache
|
||||
logHandlers map[common.Hash]Handler
|
||||
inputDataHandlers map[string]Handler
|
||||
}
|
||||
)
|
||||
|
||||
func New(o RouterOpts) *Router {
|
||||
var (
|
||||
indexAddHandler *indexAddHandler = &indexAddHandler{cache: o.Cache}
|
||||
indexRemoveHandler *indexRemoveHandler = &indexRemoveHandler{cache: o.Cache}
|
||||
tokenTransferHandler *tokenTransferHandler = &tokenTransferHandler{cache: o.Cache}
|
||||
faucetGiveHandler *faucetGiveHandler = &faucetGiveHandler{}
|
||||
ownershipHandler *ownershipHandler = &ownershipHandler{}
|
||||
poolDepositHandler *poolDepositHandler = &poolDepositHandler{}
|
||||
poolSwapHandler *poolSwapHandler = &poolSwapHandler{}
|
||||
quoterPriceHandler *quoterPriceHandler = "erPriceHandler{}
|
||||
sealHandler *sealHandler = &sealHandler{}
|
||||
tokenBurnHandler *tokenBurnHandler = &tokenBurnHandler{}
|
||||
tokenMintHandler *tokenMintHandler = &tokenMintHandler{}
|
||||
)
|
||||
|
||||
logHandlers := map[common.Hash]Handler{
|
||||
w3.H("0x26162814817e23ec5035d6a2edc6c422da2da2119e27cfca6be65cc2dc55ca4c"): faucetGiveHandler,
|
||||
w3.H("0xa226db3f664042183ee0281230bba26cbf7b5057e50aee7f25a175ff45ce4d7f"): indexAddHandler,
|
||||
w3.H("0x24a12366c02e13fe4a9e03d86a8952e85bb74a456c16e4a18b6d8295700b74bb"): indexRemoveHandler,
|
||||
w3.H("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0"): ownershipHandler,
|
||||
w3.H("0x5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62"): poolDepositHandler,
|
||||
w3.H("0xd6d34547c69c5ee3d2667625c188acf1006abb93e0ee7cf03925c67cf7760413"): poolSwapHandler,
|
||||
w3.H("0xdb9ce1a76955721ca61ac50cd1b87f9ab8620325c8619a62192c2dc7871d56b1"): quoterPriceHandler,
|
||||
w3.H("0x6b7e2e653f93b645d4ed7292d6429f96637084363e477c8aaea1a43ed13c284e"): sealHandler,
|
||||
w3.H("0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5"): tokenBurnHandler,
|
||||
w3.H("0xab8530f87dc9b59234c4623bf917212bb2536d647574c8e7e5da92c2ede0c9f8"): tokenMintHandler,
|
||||
w3.H("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"): tokenTransferHandler,
|
||||
}
|
||||
|
||||
inputDataHandlers := map[string]Handler{
|
||||
"63e4bff4": faucetGiveHandler,
|
||||
"de82efb4": faucetGiveHandler,
|
||||
"0a3b0a4f": indexAddHandler,
|
||||
"4420e486": indexAddHandler,
|
||||
"29092d0e": indexRemoveHandler,
|
||||
"f2fde38b": ownershipHandler,
|
||||
"47e7ef24": poolDepositHandler,
|
||||
"d9caed12": poolSwapHandler,
|
||||
"ebc59dff": quoterPriceHandler,
|
||||
"86fe212d": sealHandler,
|
||||
"42966c68": tokenBurnHandler,
|
||||
"449a52f8": tokenMintHandler,
|
||||
"a9059cbb": tokenTransferHandler,
|
||||
"23b872dd": tokenTransferHandler,
|
||||
}
|
||||
|
||||
return &Router{
|
||||
pub: o.Pub,
|
||||
logHandlers: logHandlers,
|
||||
inputDataHandlers: inputDataHandlers,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Router) RouteSuccessTx(ctx context.Context, msg SuccessTx) error {
|
||||
handler, ok := r.logHandlers[msg.Log.Topics[0]]
|
||||
if ok {
|
||||
return handler.SuccessTx(ctx, msg, r.pub.Send)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) RouteRevertTx(ctx context.Context, msg RevertTx) error {
|
||||
if len(msg.InputData) < 8 {
|
||||
return nil
|
||||
}
|
||||
|
||||
handler, ok := r.inputDataHandlers[msg.InputData[:8]]
|
||||
if ok {
|
||||
return handler.RevertTx(ctx, msg, r.pub.Send)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -1,73 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/grassrootseconomics/celo-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/w3-celo"
|
||||
)
|
||||
|
||||
type sealHandler struct{}
|
||||
|
||||
const sealEventName = "SEAL_STATE_CHANGE"
|
||||
|
||||
var (
|
||||
_ Handler = (*sealHandler)(nil)
|
||||
|
||||
sealEvent = w3.MustNewEvent("SealStateChange(bool indexed _final, uint256 _sealState)")
|
||||
sealToSig = w3.MustNewFunc("seal(uint256)", "uint256")
|
||||
)
|
||||
|
||||
func (h *sealHandler) Name() string {
|
||||
return sealEventName
|
||||
}
|
||||
|
||||
func (h *sealHandler) SuccessTx(ctx context.Context, tx SuccessTx, pubCB PubCallback) error {
|
||||
var (
|
||||
final bool
|
||||
sealState big.Int
|
||||
)
|
||||
|
||||
if err := sealEvent.DecodeArgs(tx.Log, &final, &sealState); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sealEvent := event.Event{
|
||||
Index: tx.Log.Index,
|
||||
Block: tx.Log.BlockNumber,
|
||||
ContractAddress: tx.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.Log.TxHash.Hex(),
|
||||
TxType: sealEventName,
|
||||
Payload: map[string]any{
|
||||
"final": final,
|
||||
"sealState": sealState.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return pubCB(ctx, sealEvent)
|
||||
}
|
||||
|
||||
func (h *sealHandler) RevertTx(ctx context.Context, tx RevertTx, pubCB PubCallback) error {
|
||||
var sealState big.Int
|
||||
|
||||
if err := sealToSig.DecodeArgs(w3.B(tx.InputData), &sealState); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sealEvent := event.Event{
|
||||
Block: tx.Block,
|
||||
ContractAddress: tx.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.TxHash,
|
||||
TxType: sealEventName,
|
||||
Payload: map[string]any{
|
||||
"sealState": sealState.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return pubCB(ctx, sealEvent)
|
||||
}
|
||||
@ -1,75 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/celo-org/celo-blockchain/common"
|
||||
"github.com/grassrootseconomics/celo-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/w3-celo"
|
||||
)
|
||||
|
||||
type tokenBurnHandler struct{}
|
||||
|
||||
const burnEventName = "TOKEN_BURN"
|
||||
|
||||
var (
|
||||
_ Handler = (*tokenBurnHandler)(nil)
|
||||
|
||||
tokenBurnEvent = w3.MustNewEvent("Burn(address indexed _tokenBurner, uint256 _value)")
|
||||
tokenBurnToSig = w3.MustNewFunc("Burn(uint256)", "bool")
|
||||
)
|
||||
|
||||
func (h *tokenBurnHandler) Name() string {
|
||||
return burnEventName
|
||||
}
|
||||
|
||||
func (h *tokenBurnHandler) SuccessTx(ctx context.Context, tx SuccessTx, pubCB PubCallback) error {
|
||||
var (
|
||||
tokenBurner common.Address
|
||||
value big.Int
|
||||
)
|
||||
|
||||
if err := tokenBurnEvent.DecodeArgs(tx.Log, &tokenBurner, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tokenBurnEvent := event.Event{
|
||||
Index: tx.Log.Index,
|
||||
Block: tx.Log.BlockNumber,
|
||||
ContractAddress: tx.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.Log.TxHash.Hex(),
|
||||
TxType: burnEventName,
|
||||
Payload: map[string]any{
|
||||
"tokenBurner": tokenBurner.Hex(),
|
||||
"value": value.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return pubCB(ctx, tokenBurnEvent)
|
||||
}
|
||||
|
||||
func (h *tokenBurnHandler) RevertTx(ctx context.Context, tx RevertTx, pubCB PubCallback) error {
|
||||
var value big.Int
|
||||
|
||||
if err := tokenBurnToSig.DecodeArgs(w3.B(tx.InputData), &value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tokenBurnEvent := event.Event{
|
||||
Block: tx.Block,
|
||||
ContractAddress: tx.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.TxHash,
|
||||
TxType: burnEventName,
|
||||
Payload: map[string]any{
|
||||
"tokenBurner": tx.From,
|
||||
"value": value.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return pubCB(ctx, tokenBurnEvent)
|
||||
}
|
||||
@ -1,82 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/celo-org/celo-blockchain/common"
|
||||
"github.com/grassrootseconomics/celo-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/w3-celo"
|
||||
)
|
||||
|
||||
type tokenMintHandler struct{}
|
||||
|
||||
const mintEventName = "TOKEN_MINT"
|
||||
|
||||
var (
|
||||
_ Handler = (*tokenMintHandler)(nil)
|
||||
|
||||
tokenMintEvent = w3.MustNewEvent("Mint(address indexed _tokenMinter, address indexed _beneficiary, uint256 _value)")
|
||||
tokenMintToSig = w3.MustNewFunc("MintTo(address, uint256)", "bool")
|
||||
)
|
||||
|
||||
func (h *tokenMintHandler) Name() string {
|
||||
return mintEventName
|
||||
}
|
||||
|
||||
func (h *tokenMintHandler) SuccessTx(ctx context.Context, tx SuccessTx, pubCB PubCallback) error {
|
||||
var (
|
||||
tokenMinter common.Address
|
||||
to common.Address
|
||||
value big.Int
|
||||
)
|
||||
|
||||
if err := tokenMintEvent.DecodeArgs(tx.Log, &tokenMinter, &to, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tokenMintEvent := event.Event{
|
||||
Index: tx.Log.Index,
|
||||
Block: tx.Log.BlockNumber,
|
||||
ContractAddress: tx.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.Log.TxHash.Hex(),
|
||||
TxType: mintEventName,
|
||||
Payload: map[string]any{
|
||||
"tokenMinter": tokenMinter.Hex(),
|
||||
"to": to.Hex(),
|
||||
"value": value.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return pubCB(ctx, tokenMintEvent)
|
||||
}
|
||||
|
||||
func (h *tokenMintHandler) RevertTx(ctx context.Context, tx RevertTx, pubCB PubCallback) error {
|
||||
|
||||
var (
|
||||
to common.Address
|
||||
value big.Int
|
||||
)
|
||||
|
||||
if err := tokenMintToSig.DecodeArgs(w3.B(tx.InputData), &to, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tokenMintEvent := event.Event{
|
||||
Block: tx.Block,
|
||||
ContractAddress: tx.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.TxHash,
|
||||
TxType: mintEventName,
|
||||
Payload: map[string]any{
|
||||
"tokenMinter": tx.From,
|
||||
"to": to.Hex(),
|
||||
"value": value.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return pubCB(ctx, tokenMintEvent)
|
||||
}
|
||||
@ -1,161 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/celo-org/celo-blockchain/common"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/cache"
|
||||
"github.com/grassrootseconomics/celo-tracker/pkg/event"
|
||||
"github.com/grassrootseconomics/celoutils/v3"
|
||||
"github.com/grassrootseconomics/w3-celo"
|
||||
)
|
||||
|
||||
type tokenTransferHandler struct {
|
||||
cache cache.Cache
|
||||
}
|
||||
|
||||
const transferEventName = "TOKEN_TRANSFER"
|
||||
|
||||
var (
|
||||
_ Handler = (*tokenTransferHandler)(nil)
|
||||
|
||||
tokenTransferEvent = w3.MustNewEvent("Transfer(address indexed _from, address indexed _to, uint256 _value)")
|
||||
tokenTransferSig = w3.MustNewFunc("transfer(address, uint256)", "bool")
|
||||
tokenTransferFromSig = w3.MustNewFunc("transferFrom(address, address, uint256)", "bool")
|
||||
|
||||
stables = map[string]bool{
|
||||
celoutils.CUSDContractMainnet: true,
|
||||
celoutils.CKESContractMainnet: true,
|
||||
celoutils.USDTContractMainnet: true,
|
||||
celoutils.USDCContractMainnet: true,
|
||||
}
|
||||
)
|
||||
|
||||
func (h *tokenTransferHandler) Name() string {
|
||||
return transferEventName
|
||||
}
|
||||
|
||||
func (h *tokenTransferHandler) SuccessTx(ctx context.Context, tx SuccessTx, pubCB PubCallback) error {
|
||||
var (
|
||||
from common.Address
|
||||
to common.Address
|
||||
value big.Int
|
||||
)
|
||||
|
||||
if err := tokenTransferEvent.DecodeArgs(tx.Log, &from, &to, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proceed, err := h.checkStables(ctx, from.Hex(), to.Hex(), tx.Log.Address.Hex())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !proceed {
|
||||
return nil
|
||||
}
|
||||
|
||||
tokenTransferEvent := event.Event{
|
||||
Index: tx.Log.Index,
|
||||
Block: tx.Log.BlockNumber,
|
||||
ContractAddress: tx.Log.Address.Hex(),
|
||||
Success: true,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.Log.TxHash.Hex(),
|
||||
TxType: transferEventName,
|
||||
Payload: map[string]any{
|
||||
"from": from.Hex(),
|
||||
"to": to.Hex(),
|
||||
"value": value.String(),
|
||||
},
|
||||
}
|
||||
|
||||
return pubCB(ctx, tokenTransferEvent)
|
||||
}
|
||||
|
||||
func (h *tokenTransferHandler) RevertTx(ctx context.Context, tx RevertTx, pubCB PubCallback) error {
|
||||
tokenTransferEvent := event.Event{
|
||||
Block: tx.Block,
|
||||
ContractAddress: tx.ContractAddress,
|
||||
Success: false,
|
||||
Timestamp: tx.Timestamp,
|
||||
TxHash: tx.TxHash,
|
||||
TxType: transferEventName,
|
||||
}
|
||||
|
||||
switch tx.InputData[:8] {
|
||||
case "a9059cbb":
|
||||
var (
|
||||
to common.Address
|
||||
value big.Int
|
||||
)
|
||||
|
||||
if err := tokenTransferSig.DecodeArgs(w3.B(tx.InputData), &to, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proceed, err := h.checkStables(ctx, tx.From, to.Hex(), tx.ContractAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !proceed {
|
||||
return nil
|
||||
}
|
||||
|
||||
tokenTransferEvent.Payload = map[string]any{
|
||||
"from": tx.From,
|
||||
"to": to.Hex(),
|
||||
"value": value.String(),
|
||||
}
|
||||
|
||||
return pubCB(ctx, tokenTransferEvent)
|
||||
case "23b872dd":
|
||||
var (
|
||||
from common.Address
|
||||
to common.Address
|
||||
value big.Int
|
||||
)
|
||||
|
||||
if err := tokenTransferFromSig.DecodeArgs(w3.B(tx.InputData), &from, &to, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proceed, err := h.checkStables(ctx, from.Hex(), to.Hex(), tx.ContractAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !proceed {
|
||||
return nil
|
||||
}
|
||||
|
||||
tokenTransferEvent.Payload = map[string]any{
|
||||
"from": from.Hex(),
|
||||
"to": to.Hex(),
|
||||
"value": value.String(),
|
||||
}
|
||||
|
||||
return pubCB(ctx, tokenTransferEvent)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *tokenTransferHandler) checkStables(ctx context.Context, from string, to string, contractAddress string) (bool, error) {
|
||||
_, ok := stables[contractAddress]
|
||||
if !ok {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// TODO: Pipeline this check on Redis with a new method
|
||||
fromExists, err := h.cache.Exists(ctx, from)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
toExists, err := h.cache.Exists(ctx, to)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return fromExists || toExists, nil
|
||||
}
|
||||
@ -6,8 +6,8 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/cache"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/pool"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/cache"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/pool"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
@ -4,9 +4,9 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/celo-org/celo-blockchain"
|
||||
"github.com/celo-org/celo-blockchain/core/types"
|
||||
"github.com/celo-org/celo-blockchain/event"
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
)
|
||||
|
||||
type BlockQueueFn func(uint64) error
|
||||
@ -23,7 +23,7 @@ func (s *Syncer) Start() {
|
||||
s.realtimeSub = event.ResubscribeErr(resubscribeInterval, s.resubscribeFn())
|
||||
}
|
||||
|
||||
func (s *Syncer) receiveRealtimeBlocks(ctx context.Context, fn BlockQueueFn) (celo.Subscription, error) {
|
||||
func (s *Syncer) receiveRealtimeBlocks(ctx context.Context, fn BlockQueueFn) (ethereum.Subscription, error) {
|
||||
newHeadersReceiver := make(chan *types.Header, 1)
|
||||
sub, err := s.ethClient.SubscribeNewHead(ctx, newHeadersReceiver)
|
||||
s.logg.Info("realtime syncer connected to ws endpoint")
|
||||
|
||||
@ -4,12 +4,12 @@ import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"github.com/celo-org/celo-blockchain"
|
||||
"github.com/celo-org/celo-blockchain/ethclient"
|
||||
"github.com/grassrootseconomics/celo-tracker/db"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/chain"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/pool"
|
||||
"github.com/grassrootseconomics/celo-tracker/internal/stats"
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/grassrootseconomics/eth-tracker/db"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/chain"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/pool"
|
||||
"github.com/grassrootseconomics/eth-tracker/internal/stats"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -27,7 +27,7 @@ type (
|
||||
db db.DB
|
||||
ethClient *ethclient.Client
|
||||
logg *slog.Logger
|
||||
realtimeSub celo.Subscription
|
||||
realtimeSub ethereum.Subscription
|
||||
pool *pool.Pool
|
||||
stats *stats.Stats
|
||||
stopCh chan struct{}
|
||||
|
||||
@ -41,13 +41,22 @@ func InitConfig(lo *slog.Logger, confFilePath string) *koanf.Koanf {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if err := ko.Load(env.Provider("TRACKER_", ".", func(s string) string {
|
||||
return strings.ReplaceAll(strings.ToLower(
|
||||
strings.TrimPrefix(s, "TRACKER_")), "__", ".")
|
||||
}), nil); err != nil {
|
||||
err := ko.Load(env.ProviderWithValue("TRACKER_", ".", func(s string, v string) (string, interface{}) {
|
||||
key := strings.ReplaceAll(strings.ToLower(strings.TrimPrefix(s, "TRACKER_")), "__", ".")
|
||||
if strings.Contains(v, " ") {
|
||||
return key, strings.Split(v, " ")
|
||||
}
|
||||
return key, v
|
||||
}), nil)
|
||||
|
||||
if err != nil {
|
||||
lo.Error("could not override config from env vars", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if os.Getenv("DEBUG") != "" {
|
||||
ko.Print()
|
||||
}
|
||||
|
||||
return ko
|
||||
}
|
||||
|
||||
110
pkg/router/router.go
Normal file
110
pkg/router/router.go
Normal file
@ -0,0 +1,110 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/grassrootseconomics/eth-tracker/pkg/event"
|
||||
)
|
||||
|
||||
type (
|
||||
Callback func(context.Context, event.Event) error
|
||||
|
||||
LogPayload struct {
|
||||
Log *types.Log
|
||||
Timestamp uint64
|
||||
}
|
||||
|
||||
InputDataPayload struct {
|
||||
From string
|
||||
InputData string
|
||||
Block uint64
|
||||
ContractAddress string
|
||||
Timestamp uint64
|
||||
TxHash string
|
||||
}
|
||||
|
||||
ContractCreationPayload struct {
|
||||
From string
|
||||
ContractAddress string
|
||||
Block uint64
|
||||
Timestamp uint64
|
||||
TxHash string
|
||||
Success bool
|
||||
}
|
||||
|
||||
LogHandlerFunc func(context.Context, LogPayload, Callback) error
|
||||
InputDataHandlerFunc func(context.Context, InputDataPayload, Callback) error
|
||||
ContractCreationHandlerFunc func(context.Context, ContractCreationPayload, Callback) error
|
||||
|
||||
LogRouteEntry struct {
|
||||
Signature common.Hash
|
||||
HandlerFunc LogHandlerFunc
|
||||
}
|
||||
|
||||
InputDataEntry struct {
|
||||
Signature string
|
||||
HandlerFunc InputDataHandlerFunc
|
||||
}
|
||||
|
||||
Router struct {
|
||||
callbackFn Callback
|
||||
logHandlers map[common.Hash]LogRouteEntry
|
||||
inputDataHandlers map[string]InputDataEntry
|
||||
contractCreationHandler ContractCreationHandlerFunc
|
||||
}
|
||||
)
|
||||
|
||||
func New(callbackFn Callback) *Router {
|
||||
return &Router{
|
||||
callbackFn: callbackFn,
|
||||
logHandlers: make(map[common.Hash]LogRouteEntry),
|
||||
inputDataHandlers: make(map[string]InputDataEntry),
|
||||
contractCreationHandler: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Router) RegisterLogRoute(signature common.Hash, handlerFunc LogHandlerFunc) {
|
||||
r.logHandlers[signature] = LogRouteEntry{
|
||||
Signature: signature,
|
||||
HandlerFunc: handlerFunc,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Router) RegisterInputDataRoute(signature string, handlerFunc InputDataHandlerFunc) {
|
||||
r.inputDataHandlers[signature] = InputDataEntry{
|
||||
Signature: signature,
|
||||
HandlerFunc: handlerFunc,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Router) RegisterContractCreationHandler(handlerFunc ContractCreationHandlerFunc) {
|
||||
r.contractCreationHandler = handlerFunc
|
||||
}
|
||||
|
||||
func (r *Router) ProcessLog(ctx context.Context, payload LogPayload) error {
|
||||
handler, ok := r.logHandlers[payload.Log.Topics[0]]
|
||||
if ok {
|
||||
return handler.HandlerFunc(ctx, payload, r.callbackFn)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) ProcessInputData(ctx context.Context, payload InputDataPayload) error {
|
||||
if len(payload.InputData) < 8 {
|
||||
return nil
|
||||
}
|
||||
|
||||
handler, ok := r.inputDataHandlers[payload.InputData[:8]]
|
||||
if ok {
|
||||
return handler.HandlerFunc(ctx, payload, r.callbackFn)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) ProcessContractCreation(ctx context.Context, payload ContractCreationPayload) error {
|
||||
return r.contractCreationHandler(ctx, payload, r.callbackFn)
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user