Skip to content

Commit a39adb3

Browse files
feat: add initial tokens bootstrapper
1 parent e9308ba commit a39adb3

File tree

7 files changed

+481
-12
lines changed

7 files changed

+481
-12
lines changed

cmd/bootstrap/main.go

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"flag"
6+
"log/slog"
7+
"os"
8+
"time"
9+
10+
"github.com/celo-org/celo-blockchain/common"
11+
"github.com/grassrootseconomics/celo-indexer/internal/util"
12+
"github.com/grassrootseconomics/celoutils/v3"
13+
"github.com/grassrootseconomics/w3-celo"
14+
"github.com/grassrootseconomics/w3-celo/module/eth"
15+
"github.com/jackc/pgx/v5/pgxpool"
16+
"github.com/knadh/koanf/v2"
17+
)
18+
19+
type TokenArgs struct {
20+
ContractAddress string
21+
TokenName string
22+
TokenSymbol string
23+
TokenDecimals uint8
24+
}
25+
26+
const (
27+
insertTokenQuery = `INSERT INTO tokens(
28+
contract_address,
29+
token_name,
30+
token_symbol,
31+
token_decimals
32+
) VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING`
33+
)
34+
35+
var (
36+
build = "dev"
37+
38+
confFlag string
39+
40+
lo *slog.Logger
41+
ko *koanf.Koanf
42+
43+
dbPool *pgxpool.Pool
44+
)
45+
46+
func init() {
47+
flag.StringVar(&confFlag, "config", "config.toml", "Config file location")
48+
flag.Parse()
49+
50+
lo = util.InitLogger()
51+
ko = util.InitConfig(lo, confFlag)
52+
53+
lo.Info("starting GE indexer token bootstrapper", "build", build)
54+
}
55+
56+
func main() {
57+
var (
58+
tokenRegistryGetter = w3.MustNewFunc("tokenRegistry()", "address")
59+
nameGetter = w3.MustNewFunc("name()", "string")
60+
symbolGetter = w3.MustNewFunc("symbol()", "string")
61+
decimalsGetter = w3.MustNewFunc("decimals()", "uint8")
62+
)
63+
64+
chainProvider := celoutils.NewProvider(ko.MustString("chain.rpc_endpoint"), ko.MustInt64("chain.chainid"))
65+
66+
var err error
67+
dbPool, err = newPgStore()
68+
if err != nil {
69+
lo.Error("could not initialize postgres store", "error", err)
70+
os.Exit(1)
71+
}
72+
73+
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5)
74+
defer cancel()
75+
76+
for _, registry := range ko.MustStrings("bootstrap.ge_registries") {
77+
registryMap, err := chainProvider.RegistryMap(ctx, celoutils.HexToAddress(registry))
78+
if err != nil {
79+
lo.Error("could not fetch registry", "error", err)
80+
os.Exit(1)
81+
}
82+
83+
if tokenIndex := registryMap[celoutils.TokenIndex]; tokenIndex != celoutils.ZeroAddress {
84+
tokenIndexIter, err := chainProvider.NewBatchIterator(ctx, tokenIndex)
85+
if err != nil {
86+
lo.Error("could not create token index iter", "error", err)
87+
os.Exit(1)
88+
}
89+
90+
for {
91+
batch, err := tokenIndexIter.Next(ctx)
92+
if err != nil {
93+
lo.Error("error fetching next token index batch", "error", err)
94+
os.Exit(1)
95+
}
96+
if batch == nil {
97+
break
98+
}
99+
lo.Debug("index batch", "index", tokenIndex.Hex(), "size", len(batch))
100+
for _, address := range batch {
101+
if address != celoutils.ZeroAddress {
102+
var (
103+
tokenName string
104+
tokenSymbol string
105+
tokenDecimals uint8
106+
)
107+
108+
err := chainProvider.Client.CallCtx(
109+
ctx,
110+
eth.CallFunc(address, nameGetter).Returns(&tokenName),
111+
eth.CallFunc(address, symbolGetter).Returns(&tokenSymbol),
112+
eth.CallFunc(address, decimalsGetter).Returns(&tokenDecimals),
113+
)
114+
if err != nil {
115+
lo.Error("error fetching token details", "error", err)
116+
os.Exit(1)
117+
}
118+
119+
if err := insertToken(ctx, TokenArgs{
120+
ContractAddress: address.Hex(),
121+
TokenName: tokenName,
122+
TokenSymbol: tokenSymbol,
123+
TokenDecimals: tokenDecimals,
124+
}); err != nil {
125+
lo.Error("pg insert error", "error", err)
126+
os.Exit(1)
127+
}
128+
}
129+
}
130+
}
131+
}
132+
133+
if poolIndex := registryMap[celoutils.PoolIndex]; poolIndex != celoutils.ZeroAddress {
134+
poolIndexIter, err := chainProvider.NewBatchIterator(ctx, poolIndex)
135+
if err != nil {
136+
lo.Error("cache could create pool index iter", "error", err)
137+
os.Exit(1)
138+
}
139+
140+
for {
141+
batch, err := poolIndexIter.Next(ctx)
142+
if err != nil {
143+
lo.Error("error fetching next pool index batch", "error", err)
144+
os.Exit(1)
145+
}
146+
if batch == nil {
147+
break
148+
}
149+
lo.Debug("index batch", "index", poolIndex.Hex(), "size", len(batch))
150+
for _, address := range batch {
151+
var poolTokenIndex common.Address
152+
err := chainProvider.Client.CallCtx(
153+
ctx,
154+
eth.CallFunc(address, tokenRegistryGetter).Returns(&poolTokenIndex),
155+
)
156+
if err != nil {
157+
lo.Error("error fetching pool token index and/or quoter", "error", err)
158+
os.Exit(1)
159+
}
160+
if poolTokenIndex != celoutils.ZeroAddress {
161+
poolTokenIndexIter, err := chainProvider.NewBatchIterator(ctx, poolTokenIndex)
162+
if err != nil {
163+
lo.Error("error creating pool token index iter", "error", err)
164+
os.Exit(1)
165+
}
166+
167+
for {
168+
batch, err := poolTokenIndexIter.Next(ctx)
169+
if err != nil {
170+
lo.Error("error fetching next pool token index batch", "error", err)
171+
os.Exit(1)
172+
}
173+
if batch == nil {
174+
break
175+
}
176+
lo.Debug("index batch", "index", poolTokenIndex.Hex(), "size", len(batch))
177+
for _, address := range batch {
178+
if address != celoutils.ZeroAddress {
179+
var (
180+
tokenName string
181+
tokenSymbol string
182+
tokenDecimals uint8
183+
)
184+
185+
err := chainProvider.Client.CallCtx(
186+
ctx,
187+
eth.CallFunc(address, nameGetter).Returns(&tokenName),
188+
eth.CallFunc(address, symbolGetter).Returns(&tokenSymbol),
189+
eth.CallFunc(address, decimalsGetter).Returns(&tokenDecimals),
190+
)
191+
if err != nil {
192+
lo.Error("error fetching token details", "error", err)
193+
os.Exit(1)
194+
}
195+
196+
if err := insertToken(ctx, TokenArgs{
197+
ContractAddress: address.Hex(),
198+
TokenName: tokenName,
199+
TokenSymbol: tokenSymbol,
200+
TokenDecimals: tokenDecimals,
201+
}); err != nil {
202+
lo.Error("pg insert error", "error", err)
203+
os.Exit(1)
204+
}
205+
}
206+
}
207+
}
208+
}
209+
}
210+
}
211+
}
212+
}
213+
lo.Info("tokens bootstrap complete")
214+
}
215+
216+
func newPgStore() (*pgxpool.Pool, error) {
217+
parsedConfig, err := pgxpool.ParseConfig(ko.MustString("postgres.dsn"))
218+
if err != nil {
219+
return nil, err
220+
}
221+
222+
dbPool, err := pgxpool.NewWithConfig(context.Background(), parsedConfig)
223+
if err != nil {
224+
return nil, err
225+
}
226+
227+
return dbPool, nil
228+
}
229+
230+
func insertToken(ctx context.Context, insertArgs TokenArgs) error {
231+
_, err := dbPool.Exec(
232+
ctx,
233+
insertTokenQuery,
234+
insertArgs.ContractAddress,
235+
insertArgs.TokenName,
236+
insertArgs.TokenSymbol,
237+
insertArgs.TokenDecimals,
238+
)
239+
if err != nil {
240+
return err
241+
}
242+
243+
return nil
244+
}

cmd/main.go renamed to cmd/service/main.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/grassrootseconomics/celo-indexer/internal/handler"
1717
"github.com/grassrootseconomics/celo-indexer/internal/store"
1818
"github.com/grassrootseconomics/celo-indexer/internal/sub"
19+
"github.com/grassrootseconomics/celo-indexer/internal/util"
1920
"github.com/knadh/koanf/v2"
2021
)
2122

@@ -38,8 +39,8 @@ func init() {
3839
flag.StringVar(&queriesFlag, "queries", "queries.sql", "Queries file location")
3940
flag.Parse()
4041

41-
lo = initLogger()
42-
ko = initConfig()
42+
lo = util.InitLogger()
43+
ko = util.InitConfig(lo, confFlag)
4344

4445
lo.Info("starting celo indexer", "build", build)
4546
}

config.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,15 @@ dsn = "postgres://postgres:postgres@127.0.0.1:5432/ge_celo_data"
1010
[jetstream]
1111
endpoint = "nats://127.0.0.1:4222"
1212
id = "celo-indexer-1"
13+
14+
[chain]
15+
rpc_endpoint = "https://celo.grassecon.net"
16+
chainid = 42220
17+
18+
[bootstrap]
19+
# This will bootstrap the cache on which addresses to track
20+
# Grassroots Economics specific registries that autoload all other smart contracts
21+
ge_registries = [
22+
"0xd1FB944748aca327a1ba036B082993D9dd9Bfa0C",
23+
"0x0cc9f4fff962def35bb34a53691180b13e653030",
24+
]

go.mod

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ go 1.22.3
44

55
require (
66
github.com/VictoriaMetrics/metrics v1.33.1
7+
github.com/celo-org/celo-blockchain v1.8.4
78
github.com/grassrootseconomics/celo-tracker v1.0.2-beta
9+
github.com/grassrootseconomics/celoutils/v3 v3.3.1
10+
github.com/grassrootseconomics/w3-celo v0.19.0
811
github.com/jackc/pgx/v5 v5.6.0
912
github.com/jackc/tern/v2 v2.1.1
1013
github.com/kamikazechaser/common v0.2.0
@@ -18,35 +21,71 @@ require (
1821
)
1922

2023
require (
24+
filippo.io/edwards25519 v1.0.0-alpha.2 // indirect
2125
github.com/Masterminds/goutils v1.1.1 // indirect
2226
github.com/Masterminds/semver/v3 v3.2.0 // indirect
2327
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
28+
github.com/StackExchange/wmi v1.2.1 // indirect
29+
github.com/VictoriaMetrics/fastcache v1.12.1 // indirect
30+
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
31+
github.com/celo-org/celo-bls-go v0.3.4 // indirect
32+
github.com/celo-org/celo-bls-go-android v0.3.3 // indirect
33+
github.com/celo-org/celo-bls-go-ios v0.3.3 // indirect
34+
github.com/celo-org/celo-bls-go-linux v0.3.3 // indirect
35+
github.com/celo-org/celo-bls-go-macos v0.3.3 // indirect
36+
github.com/celo-org/celo-bls-go-other v0.3.3 // indirect
37+
github.com/celo-org/celo-bls-go-windows v0.3.3 // indirect
38+
github.com/cespare/xxhash/v2 v2.2.0 // indirect
39+
github.com/deckarep/golang-set v1.8.0 // indirect
40+
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
2441
github.com/fsnotify/fsnotify v1.6.0 // indirect
42+
github.com/go-ole/go-ole v1.3.0 // indirect
43+
github.com/go-stack/stack v1.8.1 // indirect
2544
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect
26-
github.com/google/go-cmp v0.6.0 // indirect
45+
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
2746
github.com/google/uuid v1.3.0 // indirect
47+
github.com/gorilla/websocket v1.5.0 // indirect
48+
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
49+
github.com/hdevalence/ed25519consensus v0.0.0-20201207055737-7fde80a9d5ff // indirect
50+
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
51+
github.com/holiman/uint256 v1.2.4 // indirect
2852
github.com/huandu/xstrings v1.4.0 // indirect
53+
github.com/huin/goupnp v1.3.0 // indirect
2954
github.com/imdario/mergo v0.3.13 // indirect
3055
github.com/jackc/pgpassfile v1.0.0 // indirect
3156
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
3257
github.com/jackc/puddle/v2 v2.2.1 // indirect
58+
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
3359
github.com/klauspost/compress v1.17.2 // indirect
3460
github.com/knadh/koanf/maps v0.1.1 // indirect
35-
github.com/kr/pretty v0.3.1 // indirect
3661
github.com/lmittmann/tint v1.0.4 // indirect
62+
github.com/mattn/go-runewidth v0.0.14 // indirect
3763
github.com/mitchellh/copystructure v1.2.0 // indirect
3864
github.com/mitchellh/reflectwalk v1.0.2 // indirect
3965
github.com/nats-io/nkeys v0.4.7 // indirect
4066
github.com/nats-io/nuid v1.0.1 // indirect
67+
github.com/olekukonko/tablewriter v0.0.5 // indirect
68+
github.com/onsi/gomega v1.10.1 // indirect
4169
github.com/pelletier/go-toml v1.9.5 // indirect
42-
github.com/rogpeppe/go-internal v1.12.0 // indirect
70+
github.com/pkg/errors v0.9.1 // indirect
71+
github.com/prometheus/tsdb v0.7.1 // indirect
72+
github.com/rivo/uniseg v0.4.2 // indirect
73+
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
4374
github.com/shopspring/decimal v1.3.1 // indirect
4475
github.com/spf13/cast v1.5.0 // indirect
4576
github.com/stretchr/testify v1.9.0 // indirect
77+
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
78+
github.com/tklauser/go-sysconf v0.3.12 // indirect
79+
github.com/tklauser/numcpus v0.6.1 // indirect
4680
github.com/valyala/fastrand v1.1.0 // indirect
4781
github.com/valyala/histogram v1.2.0 // indirect
4882
golang.org/x/crypto v0.21.0 // indirect
83+
golang.org/x/net v0.23.0 // indirect
4984
golang.org/x/sync v0.7.0 // indirect
5085
golang.org/x/sys v0.20.0 // indirect
5186
golang.org/x/text v0.15.0 // indirect
87+
golang.org/x/time v0.5.0 // indirect
88+
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
89+
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
90+
gopkg.in/yaml.v2 v2.4.0 // indirect
5291
)

0 commit comments

Comments
 (0)