Compare commits

..

29 Commits

Author SHA1 Message Date
679d7f9927
feat: cache contracts created by other cached accounts for instant indexing 2025-07-03 11:52:35 +03:00
ef28ec1298
feat: add quoter updated handler 2025-07-03 10:55:44 +03:00
5cf5f9894c
feat: cache systemSigner account to index custodial contract deployments 2025-07-02 13:12:40 +03:00
20ba62f313
feat-testing: raise duplicates window to 20 minutes 2025-05-30 08:21:03 +03:00
e370d7eae5
fix: wrong config pos 2025-05-29 14:28:30 +03:00
574b42f75e
config: restore batch size 2025-05-29 14:21:43 +03:00
8417a43277
ci/cd: bump go version in Dockerfile 2025-05-26 13:01:33 +03:00
f90cc75323
deps: upgrade, deprecate redis, upgrade pond worker 2025-05-26 13:00:34 +03:00
20434beb17
Merge branch 'feat/tranfer-from-event' 2025-05-26 10:53:09 +03:00
838810dc14
fix: correct keccak signature 2025-05-26 10:50:55 +03:00
0efd01e058
feat: add TransferFrom event 2025-05-13 18:57:28 +03:00
cf23978621
feat: update op-geth 2025-03-13 12:25:59 +03:00
2d30901aa3
fix: load multiple registries via env
Signed-off-by: Mohammed Sohail <sohailsameja@gmail.com>
2025-03-13 12:25:22 +03:00
9c97ce2d2f
fix: load multiple registries via env 2025-03-13 12:20:10 +03:00
414b14a92e
docs: update README 2024-11-21 18:18:02 +03:00
4470095769
feat: add within network check for approve events
Merge commit '5962c26' from cel2
2024-11-20 11:25:55 +03:00
e503ecff5c
feat: restore geth library, bump deps, remove all celo refs 2024-11-20 11:25:26 +03:00
23a7561edc
release: disable cgo, bump to min go version 1.23.3 2024-11-20 11:14:52 +03:00
5962c26659
feat: add within network check for approve events 2024-11-20 10:57:51 +03:00
0b5af2f938
Merge branch 'cel2' of https://github.com/grassrootseconomics/eth-tracker into cel2 2024-11-20 09:59:57 +03:00
cf263c7d15
feat: change transfer event lookup to enforce both token AND address existence before emitting event
* Add ExistsNetwork cache lookup
* Exists now only accepts a single param
2024-11-20 09:56:38 +03:00
faa428c583
fix: load registries 2024-11-20 09:56:38 +03:00
f912f6835a
fix: temp patch to load a single registry
* We seem to have an issue loading a slice from env
2024-11-20 09:56:38 +03:00
fd1cced053
fix: load registries 2024-11-12 10:48:47 +03:00
dca3b4d211
fix: temp patch to load a single registry
* We seem to have an issue loading a slice from env
2024-11-12 10:36:29 +03:00
513912f361
Merge branch 'master' into cel2 2024-11-12 09:10:49 +03:00
90cc1563ec
feat: reduce busyCheckInterval -> 250ms 2024-11-12 09:10:27 +03:00
d4d3763732
Merge branch 'master' into cel2 2024-11-12 09:02:59 +03:00
115f6817e6
fix: remove required redis configs 2024-11-04 08:33:14 +03:00
25 changed files with 380 additions and 522 deletions

View File

@ -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

View File

@ -1,7 +1,7 @@
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,7 +14,6 @@ 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/*.go
run-bootstrap:

View File

@ -6,6 +6,9 @@ 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.
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.
@ -36,8 +39,7 @@ The cache will auto-update based on any additions/removals from all indexes.
- Git
- Docker
- NATS server
- Redis server (Optional)
- Access to a Celo RPC node
- 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.
@ -55,7 +57,7 @@ docker buildx build --build-arg BUILD=$(git rev-parse --short HEAD) --tag eth-tr
docker images
```
### 2. Run NATS and Redis
### 2. Run NATS
For an example, see `dev/docker-compose.yaml`.

View File

@ -44,11 +44,11 @@ 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()
@ -60,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,
@ -69,10 +70,11 @@ func main() {
lo.Error("could not initialize blocks db", "error", err)
os.Exit(1)
}
lo.Debug("loaded blocks db")
cacheOpts := cache.CacheOpts{
Chain: chain,
Registries: ko.Strings("bootstrap.ge_registries"),
Registries: ko.MustStrings("bootstrap.ge_registry"),
Watchlist: ko.Strings("bootstrap.watchlist"),
Blacklist: ko.Strings("bootstrap.blacklist"),
CacheType: ko.MustString("core.cache_type"),
@ -86,6 +88,7 @@ func main() {
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"),
@ -96,8 +99,10 @@ func main() {
lo.Error("could not initialize jetstream pub", "error", err)
os.Exit(1)
}
lo.Debug("loaded jetstream publisher")
router := bootstrapEventRouter(cache, jetStreamPub.Send)
lo.Debug("bootstrapped event router")
blockProcessor := processor.NewProcessor(processor.ProcessorOpts{
Cache: cache,
@ -106,23 +111,25 @@ func main() {
Router: router,
Logg: lo,
})
lo.Debug("bootstrapped processor")
poolOpts := pool.PoolOpts{
Logg: lo,
WorkerCount: ko.Int("core.pool_size"),
BatchSize: ko.MustInt("core.batch_size"),
Processor: blockProcessor,
}
if ko.Int("core.pool_size") <= 0 {
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,
@ -137,6 +144,7 @@ func main() {
lo.Error("could not initialize chain syncer", "error", err)
os.Exit(1)
}
lo.Debug("bootstrapped realtime syncer")
backfill := backfill.New(backfill.BackfillOpts{
BatchSize: ko.MustInt("core.batch_size"),
@ -144,16 +152,20 @@ func main() {
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)
@ -162,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)

View File

@ -11,7 +11,7 @@ func bootstrapEventRouter(cacheProvider cache.Cache, pubCB router.Callback) *rou
handlerContainer := handler.New(cacheProvider)
router := router.New(pubCB)
router.RegisterContractCreationHandler(handler.HandleContractCreation())
router.RegisterContractCreationHandler(handler.HandleContractCreation(handlerContainer))
router.RegisterLogRoute(w3.H("0x26162814817e23ec5035d6a2edc6c422da2da2119e27cfca6be65cc2dc55ca4c"), handler.HandleFaucetGiveLog())
router.RegisterLogRoute(w3.H("0xa226db3f664042183ee0281230bba26cbf7b5057e50aee7f25a175ff45ce4d7f"), handler.HandleIndexAddLog(handlerContainer))
@ -25,7 +25,9 @@ func bootstrapEventRouter(cacheProvider cache.Cache, pubCB router.Callback) *rou
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())
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())
@ -42,7 +44,8 @@ func bootstrapEventRouter(cacheProvider cache.Cache, pubCB router.Callback) *rou
router.RegisterInputDataRoute("4420e486", handler.HandleCustodialRegistrationInputData())
router.RegisterInputDataRoute("a9059cbb", handler.HandleTokenTransferInputData(handlerContainer))
router.RegisterInputDataRoute("23b872dd", handler.HandleTokenTransferInputData(handlerContainer))
router.RegisterInputDataRoute("095ea7b3", handler.HandleTokenApproveInputData())
router.RegisterInputDataRoute("095ea7b3", handler.HandleTokenApproveInputData(handlerContainer))
router.RegisterInputDataRoute("f912c64b", handler.HandleQuoterUpdatedInputData())
return router
}

View File

@ -10,9 +10,9 @@ 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"
@ -27,7 +27,7 @@ start_block = 0
[bootstrap]
# This will bootstrap the cache on which addresses to track
ge_registries = ["0xE979a64D375F5D363d7cecF3c93B9aFD40Ba9f55"]
ge_registry = ["0x0f8E97ef2d6A42CF62549D4924FCBdcE83A1C6A5"]
watchlist = [""]
blacklist = [""]

View File

@ -1 +0,0 @@
package db

78
go.mod
View File

@ -1,70 +1,64 @@
module github.com/grassrootseconomics/eth-tracker
go 1.23.0
replace github.com/ethereum/go-ethereum => github.com/celo-org/op-geth v1.101408.1-0.20241003173630-fd593f27afa2
go 1.24
require (
github.com/VictoriaMetrics/metrics v1.35.1
github.com/alitto/pond v1.9.2
github.com/bits-and-blooms/bitset v1.14.3
github.com/ethereum/go-ethereum v1.14.8
github.com/grassrootseconomics/ethutils v1.3.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 v1.0.0
github.com/knadh/koanf/providers/file v1.1.2
github.com/knadh/koanf/v2 v2.1.1
github.com/lmittmann/w3 v0.17.1
github.com/nats-io/nats.go v1.36.0
github.com/puzpuzpuz/xsync/v3 v3.4.0
github.com/redis/rueidis v1.0.48
github.com/stretchr/testify v1.9.0
github.com/uptrace/bunrouter v1.0.22
go.etcd.io/bbolt v1.3.11
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 (
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect
github.com/consensys/bavard v0.1.13 // indirect
github.com/consensys/gnark-crypto v0.12.1 // indirect
github.com/crate-crypto/go-kzg-4844 v1.0.0 // 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.6.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240821192748-42bd03ba8313 // indirect
github.com/ethereum/c-kzg-4844 v1.0.0 // 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-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/holiman/uint256 v1.3.1 // 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/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/nats-io/nkeys v0.4.7 // indirect
github.com/nats-io/nkeys v0.4.11 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
github.com/supranational/blst v0.3.11 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // 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.26.0 // 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/mod v0.20.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/time v0.7.0 // 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
)

224
go.sum
View File

@ -1,27 +1,17 @@
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/DataDog/zstd v1.5.6-0.20230824185856-869dae002e5e h1:ZIWapoIRN1VqT8GR8jAwb1Ie9GyehWjVcGh32Y2MznE=
github.com/DataDog/zstd v1.5.6-0.20230824185856-869dae002e5e/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
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/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
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/alitto/pond v1.9.2 h1:9Qb75z/scEZVCoSU+osVmQ0I0JOeLfdTDafrbcJ8CLs=
github.com/alitto/pond v1.9.2/go.mod h1:xQn3P/sHTYcU/1BR3i86IGIrilcrGC2LiS+E2+CJWsI=
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.14.3 h1:Gd2c8lSNf9pKXom5JtD7AaKO8o7fGQ2LtFj1436qilA=
github.com/bits-and-blooms/bitset v1.14.3/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ=
github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
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/celo-org/op-geth v1.101408.1-0.20241003173630-fd593f27afa2 h1:uNjQB6rkdWDza/dfkvBW35MAVnfXaNmE67BFr3rVR7g=
github.com/celo-org/op-geth v1.101408.1-0.20241003173630-fd593f27afa2/go.mod h1:Mk8AhvlqFbjI9oW2ymThSSoqc6kiEH0/tCmHGMEu6ac=
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/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I=
@ -36,106 +26,104 @@ github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwP
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.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ=
github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M=
github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c h1:uQYC5Z1mdLRPrZhHjHxufI8+2UG/i25QG92j0Er9p6I=
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs=
github.com/crate-crypto/go-kzg-4844 v1.0.0 h1:TsSgHwrkTKecKJ4kadtHi4b3xHW5dCFUDFnUp1TsawI=
github.com/crate-crypto/go-kzg-4844 v1.0.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc=
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.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM=
github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
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/ethereum-optimism/superchain-registry/superchain v0.0.0-20240821192748-42bd03ba8313 h1:SVSFg8ccdRBJxOdRS1pK8oIHvMufiPAQz1gkQsEPnZc=
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240821192748-42bd03ba8313/go.mod h1:XaVXL9jg8BcyOeugECgIUGa9Y3DjYJj71RHmb5qon6M=
github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA=
github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 h1:KrE8I4reeVvf7C1tm8elRjj4BdscTYzz/WAbYyf/JI4=
github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w=
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/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/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.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
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-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/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.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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/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/ethutils v1.3.0 h1:0uX9HG7EujqoNyueYN2gB40zki50AIdxuNLmU0FZroU=
github.com/grassrootseconomics/ethutils v1.3.0/go.mod h1:Wuv1VEZrkLIXqTSEYI3Nh9HG/ZHOUQ+U+xvWJ8QtjgQ=
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/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.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs=
github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
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 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.1.1 h1:/R8eXqasSTsmDCsAyYj+81Wteg8AqrV9CP6gvsTsOmM=
github.com/knadh/koanf/v2 v2.1.1/go.mod h1:4mnTRbZCK+ALuBXHZMjDfG9y714L7TykVnZkXbMU3Es=
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.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
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.17.1 h1:zdXIimmNmYfqOFur+Jqc9Yqwtq6jwnsQufbTOnSAtW4=
github.com/lmittmann/w3 v0.17.1/go.mod h1:WVUGMbL83WYBu4Sge3SVlW3qIG4VaHe+S8+UUnwz9Eg=
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.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.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
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=
@ -149,18 +137,26 @@ github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx
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.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/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/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
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/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.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
@ -173,66 +169,56 @@ github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuI
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.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4=
github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
github.com/redis/rueidis v1.0.48 h1:ggZHjEtc/echUmPkGTfssRisnc3p/mIUEwrpbNsZ1mQ=
github.com/redis/rueidis v1.0.48/go.mod h1:by+34b0cFXndxtYmPAHpoTHO5NkosDlBvhexoTURIxM=
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.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
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/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.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/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA=
github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg=
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/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4=
github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
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/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
github.com/uptrace/bunrouter v1.0.22 h1:634bRGogHxjMaSqc5a3MjM/sisS/MkfXhWJ/WZXrktc=
github.com/uptrace/bunrouter v1.0.22/go.mod h1:O3jAcl+5qgnF+ejhgkmbceEk0E/mqaK+ADOocdNpY8M=
github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
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=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
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/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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.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.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
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=

View File

@ -11,7 +11,6 @@ func New() *bunrouter.Router {
router := bunrouter.New()
router.GET("/metrics", metricsHandler())
return router
}

View File

@ -29,7 +29,7 @@ type (
const (
idleCheckInterval = 60 * time.Second
busyCheckInterval = 1 * time.Second
busyCheckInterval = 250 * time.Millisecond
)
func New(o BackfillOpts) *Backfill {

View File

@ -22,8 +22,9 @@ func bootstrapCache(
lo *slog.Logger,
) error {
var (
tokenRegistryGetter = w3.MustNewFunc("tokenRegistry()", "address")
quoterGetter = w3.MustNewFunc("quoter()", "address")
tokenRegistryGetter = w3.MustNewFunc("tokenRegistry()", "address")
quoterGetter = w3.MustNewFunc("quoter()", "address")
systemAcccountGetter = w3.MustNewFunc("systemAccount()", "address")
)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5)
@ -46,6 +47,23 @@ func bootstrapCache(
}
}
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
@ -103,7 +121,6 @@ func bootstrapCache(
if err := cache.Add(ctx, address.Hex()); err != nil {
return err
}
}
}
lo.Debug("cached token index batch", "batch_size", len(tokenIndexBatch))

View File

@ -11,7 +11,8 @@ type (
Cache interface {
Add(context.Context, string) error
Remove(context.Context, string) error
Exists(context.Context, ...string) (bool, error)
Exists(context.Context, string) (bool, error)
ExistsNetwork(context.Context, string, ...string) (bool, error)
Size(context.Context) (int64, error)
}
@ -27,19 +28,12 @@ type (
)
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 "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)")

View File

@ -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, keys ...string) (bool, error) {
cmd := c.client.B().Exists().Key(keys...).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()
}

View File

@ -26,8 +26,23 @@ func (c *mapCache) Remove(_ context.Context, key string) error {
return nil
}
func (c *mapCache) Exists(_ context.Context, key ...string) (bool, error) {
for _, v := range key {
func (c *mapCache) Exists(_ context.Context, key string) (bool, error) {
_, ok := c.xmap.Load(key)
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

View File

@ -1,121 +0,0 @@
package chain
// 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 (
// CeloRPCOpts struct {
// RPCEndpoint string
// ChainID int64
// }
// CeloRPC struct {
// provider *ethutils.Provider
// }
// )
// func NewRPCFetcher(o CeloRPCOpts) (Chain, error) {
// customRPCClient, err := lowTimeoutRPCClient(o.RPCEndpoint)
// if err != nil {
// return nil, err
// }
// chainProvider := ethutils.NewProvider(
// o.RPCEndpoint,
// o.ChainID,
// ethutils.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() *ethutils.Provider {
// return c.provider
// }

View File

@ -1,98 +0,0 @@
package chain
// import (
// "context"
// "testing"
// "time"
// "github.com/stretchr/testify/require"
// )
// const (
// testRPCEndpoint = "https://celo.archive.grassecon.net"
// testChainID = 42220
// )
// func setupCeloRPC() (Chain, error) {
// opts := CeloRPCOpts{
// RPCEndpoint: testRPCEndpoint,
// ChainID: testChainID,
// }
// return NewRPCFetcher(opts)
// }
// func TestRPC_GetBlocks(t *testing.T) {
// rpcFetcher, err := setupCeloRPC()
// require.NoError(t, err)
// blockNumbers := []uint64{
// 19_600_000,
// 23_000_000,
// 27_000_000,
// }
// ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// defer cancel()
// blocks, err := rpcFetcher.GetBlocks(ctx, blockNumbers)
// require.NoError(t, err)
// t.Logf("blocks %+v\n", blocks)
// }
// func TestRPC_GetBlock(t *testing.T) {
// rpcFetcher, err := setupCeloRPC()
// require.NoError(t, err)
// var blockNumber uint64 = 19_900_000
// ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// defer cancel()
// block, err := rpcFetcher.GetBlock(ctx, blockNumber)
// require.NoError(t, err)
// t.Logf("block %+v\n", block)
// }
// func TestRPC_GetLatestBlock(t *testing.T) {
// rpcFetcher, err := setupCeloRPC()
// require.NoError(t, err)
// ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// defer cancel()
// block, err := rpcFetcher.GetLatestBlock(ctx)
// require.NoError(t, err)
// t.Logf("block %+v\n", block)
// }
// func TestRPC_GetTransaction(t *testing.T) {
// rpcFetcher, err := setupCeloRPC()
// require.NoError(t, err)
// var blockNumber uint64 = 19_900_000
// ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// defer cancel()
// block, err := rpcFetcher.GetBlock(ctx, blockNumber)
// require.NoError(t, err)
// require.NotNil(t, block)
// transaction, err := rpcFetcher.GetTransaction(ctx, block.Transactions()[0].Hash())
// require.NoError(t, err)
// t.Logf("transaction %+v\n", transaction)
// }
// func TestRPC_GetReceipts(t *testing.T) {
// rpcFetcher, err := setupCeloRPC()
// require.NoError(t, err)
// var blockNumber uint64 = 19_900_000
// ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// defer cancel()
// block, err := rpcFetcher.GetBlock(ctx, blockNumber)
// require.NoError(t, err)
// require.NotNil(t, block)
// receipts, err := rpcFetcher.GetReceipts(ctx, block.Number())
// require.NoError(t, err)
// t.Logf("receipts %+v\n", receipts)
// }

View File

@ -9,7 +9,7 @@ import (
const contractCreationEventName = "CONTRACT_CREATION"
func HandleContractCreation() router.ContractCreationHandlerFunc {
func HandleContractCreation(hc *HandlerContainer) router.ContractCreationHandlerFunc {
return func(ctx context.Context, ccp router.ContractCreationPayload, c router.Callback) error {
contractCreationEvent := event.Event{
Block: ccp.Block,
@ -23,6 +23,10 @@ func HandleContractCreation() router.ContractCreationHandlerFunc {
},
}
if err := hc.cache.Add(ctx, ccp.ContractAddress); err != nil {
return err
}
return c(ctx, contractCreationEvent)
}
}

View 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)
}
}

View File

@ -17,7 +17,7 @@ var (
tokenApproveToSig = w3.MustNewFunc("approve(address, uint256)", "bool")
)
func HandleTokenApproveLog() router.LogHandlerFunc {
func HandleTokenApproveLog(hc *HandlerContainer) router.LogHandlerFunc {
return func(ctx context.Context, lp router.LogPayload, c router.Callback) error {
var (
owner common.Address
@ -29,6 +29,14 @@ func HandleTokenApproveLog() router.LogHandlerFunc {
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,
@ -48,7 +56,7 @@ func HandleTokenApproveLog() router.LogHandlerFunc {
}
}
func HandleTokenApproveInputData() router.InputDataHandlerFunc {
func HandleTokenApproveInputData(hc *HandlerContainer) router.InputDataHandlerFunc {
return func(ctx context.Context, idp router.InputDataPayload, c router.Callback) error {
var (
spender common.Address
@ -59,6 +67,14 @@ func HandleTokenApproveInputData() router.InputDataHandlerFunc {
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,

View File

@ -10,27 +10,14 @@ import (
"github.com/lmittmann/w3"
)
const (
transferEventName = "TOKEN_TRANSFER"
CUSDContractMainnet = "0x765DE816845861e75A25fCA122bb6898B8B1282a"
CKESContractMainnet = "0x456a3D042C0DbD3db53D5489e98dFb038553B0d0"
CEURContractmainnet = "0xD8763CBa276a3738E6DE85b4b3bF5FDed6D6cA73"
USDCContractMainnet = "0xcebA9300f2b948710d2653dD7B07f33A8B32118C"
USDTContractMainnet = "0x617f3112bf5397D0467D315cC709EF968D9ba546"
)
const transferEventName = "TOKEN_TRANSFER"
var (
tokenTransferEvent = w3.MustNewEvent("Transfer(address indexed _from, address indexed _to, uint256 _value)")
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")
stables = map[string]bool{
CUSDContractMainnet: true,
CKESContractMainnet: true,
USDTContractMainnet: true,
USDCContractMainnet: true,
}
)
func HandleTokenTransferLog(hc *HandlerContainer) router.LogHandlerFunc {
@ -45,7 +32,7 @@ func HandleTokenTransferLog(hc *HandlerContainer) router.LogHandlerFunc {
return err
}
proceed, err := hc.checkStables(ctx, from.Hex(), to.Hex(), lp.Log.Address.Hex())
proceed, err := hc.checkWithinNetwork(ctx, lp.Log.Address.Hex(), from.Hex(), to.Hex())
if err != nil {
return err
}
@ -94,7 +81,7 @@ func HandleTokenTransferInputData(hc *HandlerContainer) router.InputDataHandlerF
return err
}
proceed, err := hc.checkStables(ctx, idp.From, to.Hex(), idp.ContractAddress)
proceed, err := hc.checkWithinNetwork(ctx, idp.ContractAddress, idp.From, to.Hex())
if err != nil {
return err
}
@ -120,7 +107,7 @@ func HandleTokenTransferInputData(hc *HandlerContainer) router.InputDataHandlerF
return err
}
proceed, err := hc.checkStables(ctx, from.Hex(), to.Hex(), idp.ContractAddress)
proceed, err := hc.checkWithinNetwork(ctx, idp.ContractAddress, from.Hex(), to.Hex())
if err != nil {
return err
}
@ -141,16 +128,43 @@ func HandleTokenTransferInputData(hc *HandlerContainer) router.InputDataHandlerF
}
}
func (hc *HandlerContainer) checkStables(ctx context.Context, from string, to string, contractAddress string) (bool, error) {
_, ok := stables[contractAddress]
if !ok {
return true, 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
)
exists, err := hc.cache.Exists(ctx, from, to)
if err != nil {
return false, err
}
if err := tokenTransferFromEvent.DecodeArgs(lp.Log, &from, &to, &spender, &value); err != nil {
return err
}
return exists, nil
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)
}
}

View 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
}

View File

@ -3,15 +3,13 @@ package pool
import (
"context"
"log/slog"
"runtime/debug"
"github.com/alitto/pond"
"github.com/alitto/pond/v2"
"github.com/grassrootseconomics/eth-tracker/internal/processor"
)
type (
PoolOpts struct {
BatchSize int
Logg *slog.Logger
WorkerCount int
Processor *processor.Processor
@ -19,7 +17,7 @@ type (
Pool struct {
logg *slog.Logger
workerPool *pond.WorkerPool
workerPool pond.Pool
processor *processor.Processor
}
)
@ -27,11 +25,8 @@ type (
func New(o PoolOpts) *Pool {
return &Pool{
logg: o.Logg,
workerPool: pond.New(
workerPool: pond.NewPool(
o.WorkerCount,
o.BatchSize,
pond.Strategy(pond.Balanced()),
pond.PanicHandler(panicHandler(o.Logg)),
),
processor: o.Processor,
}
@ -41,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)
@ -54,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()))
}
}

View File

@ -49,7 +49,7 @@ func NewJetStreamPub(o JetStreamOpts) (Pub, error) {
Subjects: streamSubjects,
MaxAge: o.PersistDuration,
Storage: jetstream.FileStorage,
Duplicates: time.Minute,
Duplicates: time.Minute * 20,
})
return &jetStreamPub{

View File

@ -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
}