diff --git a/.github/workflows/eventindexer.yml b/.github/workflows/eventindexer.yml index 6c2288eaa0e..4ea96f31e93 100644 --- a/.github/workflows/eventindexer.yml +++ b/.github/workflows/eventindexer.yml @@ -2,7 +2,7 @@ name: Eventindexer on: push: - branches: [main, alpha-2] + branches: [main] paths: - "packages/eventindexer/**" pull_request: @@ -16,7 +16,7 @@ jobs: steps: - uses: actions/setup-go@v3 with: - go-version: 1.20.5 + go-version: 1.21.0 - uses: actions/checkout@v3 - name: golangci-lint uses: golangci/golangci-lint-action@v3 @@ -40,7 +40,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: ">=1.20.5" + go-version: ">=1.21.0" - name: eventindexer - Unit Tests working-directory: ./packages/eventindexer @@ -96,4 +96,4 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-args: | - PACKAGE=eventindexer \ No newline at end of file + PACKAGE=eventindexer diff --git a/.github/workflows/relayer.yml b/.github/workflows/relayer.yml index 642f03703ca..8bf582e8fab 100644 --- a/.github/workflows/relayer.yml +++ b/.github/workflows/relayer.yml @@ -2,7 +2,7 @@ name: Relayer on: push: - branches: [main, alpha-2] + branches: [main] paths: - "packages/relayer/**" pull_request: @@ -16,7 +16,7 @@ jobs: steps: - uses: actions/setup-go@v3 with: - go-version: 1.20.5 + go-version: 1.21.0 - uses: actions/checkout@v3 - name: golangci-lint uses: golangci/golangci-lint-action@v3 @@ -26,7 +26,7 @@ jobs: # Optional: working directory, useful for monorepos working-directory: ./packages/relayer - args: --config=.golangci.yml + args: --config=.golangci.yml --timeout=4m test: runs-on: ubuntu-latest @@ -40,7 +40,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: "1.20.5" + go-version: "1.21.0" - name: relayer - Unit Tests working-directory: ./packages/relayer diff --git a/Dockerfile b/Dockerfile index 547fe6bfc51..67e3abdafea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.19.3 as builder +FROM golang:1.21.0 as builder ARG PACKAGE=eventindexer diff --git a/go.mod b/go.mod index eab611ffb99..6b88e30583f 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/taikoxyz/taiko-mono -go 1.19 +go 1.21 require ( github.com/buildkite/terminal-to-html/v3 v3.8.0 diff --git a/go.sum b/go.sum index bc08cc048e6..8efaa6b12e1 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8 h1:V8krnnfGj4pV65YLUm3C0/8bl7V5Nry2Pwvy3ru/wLc= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= @@ -7,15 +8,18 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= +github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/hcsshim v0.9.7 h1:mKNHW/Xvv1aFH87Jb6ERDzXTJTLPlmzfZ28VBFD/bfg= +github.com/Microsoft/hcsshim v0.9.7/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 h1:ZK3C5DtzV2nVAQTx5S5jQvMeDqWtD1By5mOoyY/xJek= github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= +github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= @@ -23,8 +27,11 @@ github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHG github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/appleboy/gofight/v2 v2.1.2 h1:VOy3jow4vIK8BRQJoC/I9muxyYlJ2yb9ht2hZoS3rf4= +github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -32,6 +39,7 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/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/buildkite/terminal-to-html/v3 v3.8.0 h1:S7ImMS8W+2yS/9D4ugrXzB95C4AuNaKcaw/eR/95bFU= github.com/buildkite/terminal-to-html/v3 v3.8.0/go.mod h1:j3XxsnYElte/Bo7Pft+U5eQWWbcx3j51uQ8fo43VrjM= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= @@ -39,6 +47,7 @@ github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+M github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= +github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= @@ -51,9 +60,13 @@ github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUK github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= +github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= 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 v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= +github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lgvnQ2+oGlE/EyZy4+2/CxRh9KfvCXnag1vtpxVM= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= +github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/containerd v1.6.19 h1:F0qgQPrG0P2JPgwpxWxYavrVeXAG0ezUIB9Z/4FTUAU= github.com/containerd/containerd v1.6.19/go.mod h1:HZCDMn4v/Xl2579/MvtOC2M206i+JJ6VxFWU/NetrGY= @@ -64,9 +77,11 @@ github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoY github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 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/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyberhorsey/errors v0.0.0-20220929234051-087d6d8bb841 h1:FaPua89k9KmkkiptlTAmYzcTsn1IFdQsqneuFO6IAu8= github.com/cyberhorsey/errors v0.0.0-20220929234051-087d6d8bb841/go.mod h1:qSH/IvpdArCjfny4ODMko/7U0z4JoNIWctgCnUrapnI= github.com/cyberhorsey/webutils v0.0.0-20230314183728-56890c6ddbe7 h1:KYOh2RfWAltxYsfD/Ar5D3zB4+AuNQejXW5BvMlGor4= @@ -78,10 +93,12 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= github.com/deckarep/golang-set/v2 v2.1.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.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU= github.com/denisenkom/go-mssqldb v0.12.2 h1:1OcPn5GBIobjWNd+8yjfHNIaFX14B1pWI3F9HZy5KXw= +github.com/denisenkom/go-mssqldb v0.12.2/go.mod h1:lnIw1mZukFRZDJYQ0Pb833QS2IaC3l5HkEfra2LJ+sk= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= @@ -94,7 +111,9 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0= +github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -103,17 +122,22 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/ethereum/go-ethereum v1.11.4 h1:KG81SnUHXWk8LJB3mBcHg/E2yLvXoiPmRMCIRxgx3cE= github.com/ethereum/go-ethereum v1.11.4/go.mod h1:it7x0DWnTDMfVFdXcU6Ti4KEFQynLHVRarcSlPr0HBo= 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/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 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.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= +github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= +github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4= github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= github.com/go-git/go-git/v5 v5.7.0 h1:t9AudWVLmqzlo+4bqdf7GY+46SUuRsx59SboFxkq2aE= github.com/go-git/go-git/v5 v5.7.0/go.mod h1:coJHKEOk5kUClpsNlXrUvPrDxY3w3gjHvhcZd8Fodw8= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -136,6 +160,7 @@ github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -148,6 +173,7 @@ github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0kt github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -160,6 +186,7 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomarkdown/markdown v0.0.0-20230322041520-c84983bdbf2a h1:AWZzzFrqyjYlRloN6edwTLTUbKxf5flLXNuTBDm3Ews= github.com/gomarkdown/markdown v0.0.0-20230322041520-c84983bdbf2a/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -175,9 +202,13 @@ github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 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/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.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= +github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= +github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/iancoleman/strcase v0.1.3/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= @@ -196,6 +227,7 @@ github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8 github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgconn v1.11.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= +github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -213,6 +245,7 @@ github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwX github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= +github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= @@ -221,17 +254,20 @@ github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrU github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= github.com/jackc/pgtype v1.10.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= +github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= github.com/jackc/pgx/v4 v4.15.0/go.mod h1:D/zyOyXiaM1TmVWnOM18p0xdDtdakRBa0RsVGI3U3bw= github.com/jackc/pgx/v4 v4.17.0 h1:Hsx+baY8/zU2WtPLQyZi8WbecgcsWEeyoK1jvg/WgIo= +github.com/jackc/pgx/v4 v4.17.0/go.mod h1:Gd6RmOhtFLTu8cp/Fhq4kP195KrshxYJH3oW8AWJ1pw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 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/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -243,6 +279,7 @@ github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/ github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -257,12 +294,14 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 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/labstack/echo-contrib v0.13.0 h1:bzSG0SpuZZd7BmJLvsWtPfU23W0Enh3K0tok3aENVKA= github.com/labstack/echo-contrib v0.13.0/go.mod h1:IF9+MJu22ADOZEHD+bAV67XMIO3vNXUy7Naz/ABPHEs= github.com/labstack/echo/v4 v4.0.0/go.mod h1:tZv7nai5buKSg5h/8E6zz4LsD/Dqh9/91Mvs7Z5Zyno= @@ -300,6 +339,7 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k 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 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0= @@ -310,7 +350,9 @@ github.com/microcosm-cc/bluemonday v1.0.4/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvza github.com/microcosm-cc/bluemonday v1.0.20 h1:flpzsq4KU3QIYAYGV/szUat7H+GPOXR0B2JU5A1Wp8Y= github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= +github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo= github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= @@ -330,6 +372,7 @@ github.com/neko-neko/echo-logrus/v2 v2.0.1 h1:BX2U6uv2N3UiUY75y+SntQak5S1AJIel9j github.com/neko-neko/echo-logrus/v2 v2.0.1/go.mod h1:GDYWo9CY4VXk/vn5ac5reoutYEkZEexlFI01MzHXVG0= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 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/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= @@ -362,15 +405,19 @@ github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NX github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 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/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 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/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= @@ -392,6 +439,7 @@ github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs github.com/skeema/knownhosts v1.1.1 h1:MTk78x9FPgDFVFkDLTrsnnfCJl7g1C/nnKvePgrIngE= github.com/skeema/knownhosts v1.1.1/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo= 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/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -405,6 +453,7 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= 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/testcontainers/testcontainers-go v0.21.0 h1:syePAxdeTzfkap+RrJaQZpJQ/s/fsUgn11xIvHrOE9U= github.com/testcontainers/testcontainers-go v0.21.0/go.mod h1:c1ez3WVRHq7T/Aj+X3TIipFBwkBaNT5iNCY8+1b83Ng= github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= @@ -412,9 +461,11 @@ github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITn github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= 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/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= +github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.22.0/go.mod h1:0mw2RjXGOzxf4NL2jni3gUQ7LfjjUSiG5sskOUUSEpU= @@ -432,6 +483,7 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17 github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= 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= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= @@ -558,6 +610,7 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= 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= @@ -654,16 +707,27 @@ gorm.io/gorm v1.24.6/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.36.1 h1:CICrjwr/1M4+6OQ4HJZ/AHxjcwe67r5vPUF518MkO8A= +modernc.org/cc/v3 v3.36.1/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/ccgo/v3 v3.16.8 h1:G0QNlTqI5uVgczBWfGKs7B++EPwCfXPWGD2MdeKloDs= +modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= modernc.org/libc v1.16.19 h1:S8flPn5ZeXx6iw/8yNa986hwTQDrY8RXU7tObZuAozo= +modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/memory v1.1.1 h1:bDOL0DIDLQv7bWhP3gMvIrnoFw+Eo6F7a2QK9HPDiFU= +modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sqlite v1.18.1 h1:ko32eKt3jf7eqIkCgPAeHMBXw3riNSLhl2f3loEF7o8= +modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= modernc.org/strutil v1.1.2 h1:iFBDH6j1Z0bN/Q9udJnnFoFpENA4252qe/7/5woE5MI= +modernc.org/strutil v1.1.2/go.mod h1:OYajnUAcI/MX+XD/Wx7v1bbdvcQSvxgtb0gC+u3d3eg= modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/packages/eventindexer/.golangci.yml b/packages/eventindexer/.golangci.yml index 521b5c4b4fd..4d07f36217d 100644 --- a/packages/eventindexer/.golangci.yml +++ b/packages/eventindexer/.golangci.yml @@ -18,7 +18,7 @@ linters: - gocognit - gocritic - gofmt - - golint + # - revive - gosec - gosimple - lll @@ -44,3 +44,6 @@ issues: - path: contracts\.go linters: - lll + - path: / + linters: + - typecheck diff --git a/packages/eventindexer/cli/cli.go b/packages/eventindexer/cli/cli.go index 3bb3c0cf676..b5c7e3fba3e 100644 --- a/packages/eventindexer/cli/cli.go +++ b/packages/eventindexer/cli/cli.go @@ -3,6 +3,7 @@ package cli import ( "context" "fmt" + "log" "os" "strconv" "strings" @@ -15,7 +16,6 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/joho/godotenv" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/eventindexer" "github.com/taikoxyz/taiko-mono/packages/eventindexer/db" "github.com/taikoxyz/taiko-mono/packages/eventindexer/http" @@ -45,13 +45,12 @@ func Run( mode eventindexer.Mode, watchMode eventindexer.WatchMode, httpOnly eventindexer.HTTPOnly, + indexNfts eventindexer.IndexNFTS, ) { if err := loadAndValidateEnv(); err != nil { log.Fatal(err) } - log.SetFormatter(&log.JSONFormatter{}) - db, err := openDBConnection(eventindexer.DBConnectionOpts{ Name: os.Getenv("MYSQL_USER"), Password: os.Getenv("MYSQL_PASSWORD"), @@ -126,10 +125,20 @@ func Run( log.Fatal(err) } + var nftBalanceRepo eventindexer.NFTBalanceRepository + + if indexNfts { + nftBalanceRepo, err = repo.NewNFTBalanceRepository(db) + if err != nil { + log.Fatal(err) + } + } + i, err := indexer.NewService(indexer.NewServiceOpts{ EventRepo: eventRepository, BlockRepo: blockRepository, StatRepo: statRepository, + NFTBalanceRepo: nftBalanceRepo, EthClient: ethClient, RPCClient: rpcClient, SrcTaikoAddress: common.HexToAddress(os.Getenv("L1_TAIKO_ADDRESS")), @@ -138,6 +147,7 @@ func Run( SrcSwapAddresses: stringsToAddresses(strings.Split(os.Getenv("SWAP_ADDRESSES"), ",")), BlockBatchSize: uint64(blockBatchSize), SubscriptionBackoff: subscriptionBackoff, + IndexNFTs: bool(indexNfts), }) if err != nil { log.Fatal(err) @@ -267,9 +277,15 @@ func newHTTPServer(db eventindexer.DB, l1EthClient *ethclient.Client) (*http.Ser return nil, err } + nftBalanceRepo, err := repo.NewNFTBalanceRepository(db) + if err != nil { + return nil, err + } + srv, err := http.NewServer(http.NewServerOpts{ EventRepo: eventRepo, StatRepo: statRepo, + NFTBalanceRepo: nftBalanceRepo, Echo: echo.New(), CorsOrigins: strings.Split(os.Getenv("CORS_ORIGINS"), ","), EthClient: l1EthClient, diff --git a/packages/eventindexer/cmd/main.go b/packages/eventindexer/cmd/main.go index 9056e9d5d48..a43520605e0 100644 --- a/packages/eventindexer/cmd/main.go +++ b/packages/eventindexer/cmd/main.go @@ -28,11 +28,18 @@ func main() { false: run an http server and index blocks `) + indexNfts := flag.Bool("index-nfts", false, `index nft transfer events. + options: + true: index + false: dont index + `) + flag.Parse() cli.Run( eventindexer.Mode(*modePtr), eventindexer.WatchMode(*watchModePtr), eventindexer.HTTPOnly(*httpOnlyPtr), + eventindexer.IndexNFTS(*indexNfts), ) } diff --git a/packages/eventindexer/contracts/erc1155/abi.go b/packages/eventindexer/contracts/erc1155/abi.go new file mode 100644 index 00000000000..73069984244 --- /dev/null +++ b/packages/eventindexer/contracts/erc1155/abi.go @@ -0,0 +1,318 @@ +package erc1155 + +var ( + ABI = `[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + } + ], + "name": "TransferBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "TransferSingle", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "value", + "type": "string" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "URI", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "accounts", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + } + ], + "name": "balanceOfBatch", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeBatchTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "uri", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } + ]` +) diff --git a/packages/eventindexer/errors.go b/packages/eventindexer/errors.go index 5bce12912e5..73e8b651300 100644 --- a/packages/eventindexer/errors.go +++ b/packages/eventindexer/errors.go @@ -4,8 +4,18 @@ import "github.com/cyberhorsey/errors" var ( ErrNoEthClient = errors.Validation.NewWithKeyAndDetail("ERR_NO_ETH_CLIENT", "EthClient is required") - ErrNoEventRepository = errors.Validation.NewWithKeyAndDetail("ERR_NO_EVENT_REPOSITORY", "EventRepository is required") - ErrNoStatRepository = errors.Validation.NewWithKeyAndDetail("ERR_NO_STAT_REPOSITORY", "StatRepository is required") + ErrNoEventRepository = errors.Validation.NewWithKeyAndDetail( + "ERR_NO_EVENT_REPOSITORY", + "EventRepository is required", + ) + ErrNoNFTBalanceRepository = errors.Validation.NewWithKeyAndDetail( + "ERR_NO_NFT_BALANCE_REPOSITORY", + "NFTBalanceRepository is required", + ) + ErrNoStatRepository = errors.Validation.NewWithKeyAndDetail( + "ERR_NO_STAT_REPOSITORY", + "StatRepository is required", + ) ErrNoBlockRepository = errors.Validation.NewWithKeyAndDetail( "ERR_NO_BLOCK_REPOSITORY", "BlockRepository is required", diff --git a/packages/eventindexer/event.go b/packages/eventindexer/event.go index 826024d7fa0..fa75cb5698a 100644 --- a/packages/eventindexer/event.go +++ b/packages/eventindexer/event.go @@ -22,33 +22,40 @@ var ( EventNameExited = "Exited" EventNameWithdrawn = "Withdrawn" EventNameMint = "Mint" + EventNameNFTTransfer = "Transfer" ) // Event represents a stored EVM event. The fields will be serialized // into the Data field to be unmarshalled into a concrete struct // dependant on the name of the event type Event struct { - ID int `json:"id"` - Name string `json:"name"` - Data datatypes.JSON `json:"data"` - ChainID int64 `json:"chainID"` - Event string `json:"event"` - Address string `json:"address"` - BlockID sql.NullInt64 `json:"blockID"` - Amount decimal.NullDecimal `json:"amount"` - AssignedProver string `json:"assignedProver"` + ID int `json:"id"` + Name string `json:"name"` + Data datatypes.JSON `json:"data"` + ChainID int64 `json:"chainID"` + Event string `json:"event"` + Address string `json:"address"` + BlockID sql.NullInt64 `json:"blockID"` + Amount decimal.NullDecimal `json:"amount"` + AssignedProver string `json:"assignedProver"` + To string `json:"to"` + TokenID sql.NullInt64 `json:"tokenID"` + ContractAddress string `json:"contractAddress"` } // SaveEventOpts type SaveEventOpts struct { - Name string - Data string - ChainID *big.Int - Event string - Address string - BlockID *int64 - Amount *big.Int - AssignedProver *string + Name string + Data string + ChainID *big.Int + Event string + Address string + BlockID *int64 + Amount *big.Int + AssignedProver *string + To *string + TokenID *int64 + ContractAddress *string } type UniqueProversResponse struct { diff --git a/packages/eventindexer/flags.go b/packages/eventindexer/flags.go index 523f62f7dcc..76db6b018ef 100644 --- a/packages/eventindexer/flags.go +++ b/packages/eventindexer/flags.go @@ -18,3 +18,5 @@ var ( ) type HTTPOnly bool + +type IndexNFTS bool diff --git a/packages/eventindexer/http/get_nft_balances_by_address_and_chain_id.go b/packages/eventindexer/http/get_nft_balances_by_address_and_chain_id.go new file mode 100644 index 00000000000..cb757173956 --- /dev/null +++ b/packages/eventindexer/http/get_nft_balances_by_address_and_chain_id.go @@ -0,0 +1,22 @@ +package http + +import ( + "net/http" + + "github.com/cyberhorsey/webutils" + "github.com/labstack/echo/v4" +) + +func (srv *Server) GetNFTBalancesByAddessAndChainID(c echo.Context) error { + page, err := srv.nftBalanceRepo.FindByAddress( + c.Request().Context(), + c.Request(), + c.QueryParam("address"), + c.QueryParam("chainID"), + ) + if err != nil { + return webutils.LogAndRenderErrors(c, http.StatusUnprocessableEntity, err) + } + + return c.JSON(http.StatusOK, page) +} diff --git a/packages/eventindexer/http/get_pos_stats.go b/packages/eventindexer/http/get_pos_stats.go index 439d1e0ef57..cdb6fc3e0ef 100644 --- a/packages/eventindexer/http/get_pos_stats.go +++ b/packages/eventindexer/http/get_pos_stats.go @@ -4,10 +4,11 @@ import ( "context" "net/http" + "log/slog" + "github.com/cyberhorsey/webutils" "github.com/labstack/echo/v4" "github.com/patrickmn/go-cache" - log "github.com/sirupsen/logrus" ) type posStatsResponse struct { @@ -48,10 +49,10 @@ func (srv *Server) getPosStats(ctx context.Context) (*posStatsResponse, error) { return nil, err } - log.Infof( - "pos stats, slashedTokens: %v, capacity: %v", - totalSlashedTokens.String(), - capacity.String(), + slog.Info( + "pos stats", + "totalSlashedTokens", totalSlashedTokens.String(), + "capacity", capacity.String(), ) resp := &posStatsResponse{ diff --git a/packages/eventindexer/http/routes.go b/packages/eventindexer/http/routes.go index 8e00f1f0c99..193ec75f0b6 100644 --- a/packages/eventindexer/http/routes.go +++ b/packages/eventindexer/http/routes.go @@ -12,6 +12,7 @@ func (srv *Server) configureRoutes() { srv.echo.GET("/posStats", srv.GetPOSStats) srv.echo.GET("/currentProvers", srv.GetCurrentProvers) srv.echo.GET("/assignedBlocks", srv.GetAssignedBlocksByProverAddress) + srv.echo.GET("/nftsByAddress", srv.GetNFTBalancesByAddessAndChainID) galaxeAPI := srv.echo.Group("/api") diff --git a/packages/eventindexer/http/server.go b/packages/eventindexer/http/server.go index ffa3fcf4cb2..2e5048a1976 100644 --- a/packages/eventindexer/http/server.go +++ b/packages/eventindexer/http/server.go @@ -19,17 +19,19 @@ import ( ) type Server struct { - echo *echo.Echo - eventRepo eventindexer.EventRepository - statRepo eventindexer.StatRepository - cache *cache.Cache - proverPool *proverpool.ProverPool + echo *echo.Echo + eventRepo eventindexer.EventRepository + statRepo eventindexer.StatRepository + nftBalanceRepo eventindexer.NFTBalanceRepository + cache *cache.Cache + proverPool *proverpool.ProverPool } type NewServerOpts struct { Echo *echo.Echo EventRepo eventindexer.EventRepository StatRepo eventindexer.StatRepository + NFTBalanceRepo eventindexer.NFTBalanceRepository ProverPoolAddress common.Address EthClient *ethclient.Client CorsOrigins []string @@ -52,6 +54,10 @@ func (opts NewServerOpts) Validate() error { return eventindexer.ErrNoCORSOrigins } + if opts.NFTBalanceRepo == nil { + return eventindexer.ErrNoNFTBalanceRepository + } + // proverpooladdress is optional return nil @@ -76,11 +82,12 @@ func NewServer(opts NewServerOpts) (*Server, error) { } srv := &Server{ - echo: opts.Echo, - eventRepo: opts.EventRepo, - statRepo: opts.StatRepo, - cache: cache, - proverPool: proverPool, + echo: opts.Echo, + eventRepo: opts.EventRepo, + statRepo: opts.StatRepo, + nftBalanceRepo: opts.NFTBalanceRepo, + cache: cache, + proverPool: proverPool, } corsOrigins := opts.CorsOrigins diff --git a/packages/eventindexer/http/server_test.go b/packages/eventindexer/http/server_test.go index 9395dd2f66f..0ef682716ff 100644 --- a/packages/eventindexer/http/server_test.go +++ b/packages/eventindexer/http/server_test.go @@ -20,10 +20,11 @@ func newTestServer(url string) *Server { _ = godotenv.Load("../.test.env") srv := &Server{ - cache: cache.New(5*time.Second, 6*time.Second), - echo: echo.New(), - eventRepo: mock.NewEventRepository(), - statRepo: mock.NewStatRepository(), + cache: cache.New(5*time.Second, 6*time.Second), + echo: echo.New(), + eventRepo: mock.NewEventRepository(), + statRepo: mock.NewStatRepository(), + nftBalanceRepo: mock.NewNFTBalanceRepository(), } srv.configureMiddleware([]string{"*"}) @@ -41,47 +42,62 @@ func Test_NewServer(t *testing.T) { }{ { "success", + NewServerOpts{ + Echo: echo.New(), + EventRepo: &repo.EventRepository{}, + CorsOrigins: make([]string, 0), + StatRepo: &repo.StatRepository{}, + NFTBalanceRepo: &repo.NFTBalanceRepository{}, + }, + nil, + }, + { + "noNftBalanceRepo", NewServerOpts{ Echo: echo.New(), EventRepo: &repo.EventRepository{}, CorsOrigins: make([]string, 0), StatRepo: &repo.StatRepository{}, }, - nil, + eventindexer.ErrNoNFTBalanceRepository, }, { "noStatRepo", NewServerOpts{ - Echo: echo.New(), - EventRepo: &repo.EventRepository{}, - CorsOrigins: make([]string, 0), + Echo: echo.New(), + EventRepo: &repo.EventRepository{}, + CorsOrigins: make([]string, 0), + NFTBalanceRepo: &repo.NFTBalanceRepository{}, }, eventindexer.ErrNoStatRepository, }, { "noEventRepo", NewServerOpts{ - Echo: echo.New(), - CorsOrigins: make([]string, 0), - StatRepo: &repo.StatRepository{}, + Echo: echo.New(), + CorsOrigins: make([]string, 0), + StatRepo: &repo.StatRepository{}, + NFTBalanceRepo: &repo.NFTBalanceRepository{}, }, eventindexer.ErrNoEventRepository, }, { "noCorsOrigins", NewServerOpts{ - Echo: echo.New(), - EventRepo: &repo.EventRepository{}, - StatRepo: &repo.StatRepository{}, + Echo: echo.New(), + EventRepo: &repo.EventRepository{}, + StatRepo: &repo.StatRepository{}, + NFTBalanceRepo: &repo.NFTBalanceRepository{}, }, eventindexer.ErrNoCORSOrigins, }, { "noHttpFramework", NewServerOpts{ - EventRepo: &repo.EventRepository{}, - CorsOrigins: make([]string, 0), - StatRepo: &repo.StatRepository{}, + EventRepo: &repo.EventRepository{}, + CorsOrigins: make([]string, 0), + StatRepo: &repo.StatRepository{}, + NFTBalanceRepo: &repo.NFTBalanceRepository{}, }, ErrNoHTTPFramework, }, diff --git a/packages/eventindexer/indexer/filter.go b/packages/eventindexer/indexer/filter.go index 22698c614e6..66ddc8e4103 100644 --- a/packages/eventindexer/indexer/filter.go +++ b/packages/eventindexer/indexer/filter.go @@ -4,9 +4,10 @@ import ( "context" "math/big" + "log/slog" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "golang.org/x/sync/errgroup" ) @@ -143,11 +144,20 @@ func L1FilterFunc( }) } + if svc.indexNfts { + wg.Go(func() error { + if err := svc.indexNFTTransfers(ctx, chainID, filterOpts.Start, *filterOpts.End); err != nil { + return errors.Wrap(err, "svc.indexNFTTransfers") + } + return nil + }) + } + err := wg.Wait() if err != nil { if errors.Is(err, context.Canceled) { - log.Error("context cancelled") + slog.Error("context cancelled") return err } @@ -202,10 +212,19 @@ func L2FilterFunc( }) } + if svc.indexNfts { + wg.Go(func() error { + if err := svc.indexNFTTransfers(ctx, chainID, filterOpts.Start, *filterOpts.End); err != nil { + return errors.Wrap(err, "svc.indexNFTTransfers") + } + return nil + }) + } + err := wg.Wait() if err != nil { if errors.Is(err, context.Canceled) { - log.Error("context cancelled") + slog.Error("context cancelled") return err } diff --git a/packages/eventindexer/indexer/filter_then_subscribe.go b/packages/eventindexer/indexer/filter_then_subscribe.go index 1eb27b8b0e2..c2d4552f6c6 100644 --- a/packages/eventindexer/indexer/filter_then_subscribe.go +++ b/packages/eventindexer/indexer/filter_then_subscribe.go @@ -5,9 +5,10 @@ import ( "fmt" "math/big" + "log/slog" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/eventindexer" ) @@ -36,15 +37,15 @@ func (svc *Service) FilterThenSubscribe( } if svc.processingBlockHeight == header.Number.Uint64() { - log.Infof("chain ID %v caught up, subscribing to new incoming events", chainID.Uint64()) + slog.Info("indexing caught up subscribing to new incoming events", "chainID", chainID.Uint64()) return svc.subscribe(ctx, chainID) } - log.Infof("chain ID %v getting events between %v and %v in batches of %v", - chainID.Uint64(), - svc.processingBlockHeight, - header.Number.Int64(), - svc.blockBatchSize, + slog.Info("getting batch of events", + "chainID", chainID.Uint64(), + "startBlock", svc.processingBlockHeight, + "endBlock", header.Number.Int64(), + "batchSize", svc.blockBatchSize, ) for i := svc.processingBlockHeight; i < header.Number.Uint64(); i += svc.blockBatchSize { @@ -78,7 +79,7 @@ func (svc *Service) FilterThenSubscribe( return errors.Wrap(err, "svc.ethClient.HeaderByNumber") } - log.Infof("setting last processed block to height: %v, hash: %v", end, header.Hash().Hex()) + slog.Info("setting last processed block", "height", end, "hash", header.Hash().Hex()) if err := svc.blockRepo.Save(eventindexer.SaveBlockOpts{ Height: uint64(end), @@ -93,9 +94,9 @@ func (svc *Service) FilterThenSubscribe( svc.processingBlockHeight = uint64(end) } - log.Infof( - "chain id %v indexer fully caught up, checking latest block number to see if it's advanced", - chainID.Uint64(), + slog.Info( + "fully caught up, checking blockNumber to see if advanced", + "chainID", chainID.Uint64(), ) latestBlock, err := svc.ethClient.HeaderByNumber(ctx, nil) diff --git a/packages/eventindexer/indexer/index_nft_transfers.go b/packages/eventindexer/indexer/index_nft_transfers.go new file mode 100644 index 00000000000..8ca16608689 --- /dev/null +++ b/packages/eventindexer/indexer/index_nft_transfers.go @@ -0,0 +1,244 @@ +package indexer + +import ( + "context" + "fmt" + "math/big" + "strings" + + "log/slog" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/pkg/errors" + "github.com/taikoxyz/taiko-mono/packages/eventindexer" + "github.com/taikoxyz/taiko-mono/packages/eventindexer/contracts/erc1155" +) + +var ( + logTransferSignature = []byte("Transfer(address,address,uint256)") + logTransferSigHash = crypto.Keccak256Hash(logTransferSignature) + transferSingleSignature = []byte("TransferSingle(address,address,address,uint256,uint256)") + transferSingleSignatureHash = crypto.Keccak256Hash(transferSingleSignature) + transferBatchSignature = []byte("TransferBatch(address,address,address,uint256[],uint256[])") + transferBatchSignatureHash = crypto.Keccak256Hash(transferBatchSignature) +) + +// indexNFTTransfers indexes from a given starting block to a given end block and parses all event logs +// to find ERC721 or ERC1155 transfer events +func (svc *Service) indexNFTTransfers( + ctx context.Context, + chainID *big.Int, + start uint64, + end uint64, +) error { + query := ethereum.FilterQuery{ + FromBlock: big.NewInt(int64(start)), + ToBlock: big.NewInt(int64(end)), + } + + logs, err := svc.ethClient.FilterLogs(ctx, query) + if err != nil { + return err + } + + for _, vLog := range logs { + if !svc.isERC721Transfer(ctx, vLog) && !svc.isERC1155Transfer(ctx, vLog) { + continue + } + + if err := svc.saveNFTTransfer(ctx, chainID, vLog); err != nil { + return err + } + } + + return nil +} + +// isERC1155Transfer determines whether a given log is a valid ERC1155 transfer event +func (svc *Service) isERC1155Transfer(ctx context.Context, vLog types.Log) bool { + // malformed event + if len(vLog.Topics) == 0 { + return false + } + + // the first topic is ALWAYS the hash of the event signature. + // this is how people are expected to look up which event is which. + if vLog.Topics[0].Hex() != transferSingleSignatureHash.Hex() && + vLog.Topics[0].Hex() != transferBatchSignatureHash.Hex() { + return false + } + + return true +} + +// isERC721Transfer determines whether a given log is a valid ERC721 transfer event +func (svc *Service) isERC721Transfer(ctx context.Context, vLog types.Log) bool { + // malformed event + if len(vLog.Topics) == 0 { + return false + } + + // the first topic is ALWAYS the hash of the event signature. + // this is how people are expected to look up which event is which. + if vLog.Topics[0].Hex() != logTransferSigHash.Hex() { + return false + } + + // erc20 transfer length will be 3, nft will be 4, only way to + // differentiate them + if len(vLog.Topics) != 4 { + return false + } + + return true +} + +// saveNFTTrasnfer parses the event logs and saves either an ERC721 or ERC1155 event, updating +// users balances +func (svc *Service) saveNFTTransfer(ctx context.Context, chainID *big.Int, vLog types.Log) error { + if svc.isERC721Transfer(ctx, vLog) { + return svc.saveERC721Transfer(ctx, chainID, vLog) + } + + if svc.isERC1155Transfer(ctx, vLog) { + return svc.saveERC1155Transfer(ctx, chainID, vLog) + } + + return errors.New("nftTransferVlog not ERC721 or ERC1155") +} + +// saveERC721Transfer updates the user's balances on the from and to of a ERC721 transfer event +func (svc *Service) saveERC721Transfer(ctx context.Context, chainID *big.Int, vLog types.Log) error { + from := fmt.Sprintf("0x%v", common.Bytes2Hex(vLog.Topics[1].Bytes()[12:])) + + to := fmt.Sprintf("0x%v", common.Bytes2Hex(vLog.Topics[2].Bytes()[12:])) + + tokenID := vLog.Topics[3].Big().Int64() + + slog.Info( + "erc721 transfer found", + "from", from, + "to", to, + "tokenID", tokenID, + "contractAddress", vLog.Address.Hex(), + ) + + // increment To address's balance + + _, err := svc.nftBalanceRepo.IncreaseBalance(ctx, eventindexer.UpdateNFTBalanceOpts{ + ChainID: chainID.Int64(), + Address: to, + TokenID: tokenID, + ContractAddress: vLog.Address.Hex(), + ContractType: "ERC721", + Amount: 1, // ERC721 is always 1 + }) + if err != nil { + return err + } + + // decrement From address's balance + // ignore zero address since that is usually the "mint" + if from != ZeroAddress.Hex() { + _, err = svc.nftBalanceRepo.SubtractBalance(ctx, eventindexer.UpdateNFTBalanceOpts{ + ChainID: chainID.Int64(), + Address: from, + TokenID: tokenID, + ContractAddress: vLog.Address.Hex(), + ContractType: "ERC721", + Amount: 1, // ERC721 is always 1 + }) + if err != nil { + return err + } + } + + return nil +} + +// saveERC1155Transfer parses and saves either a TransferSingle or TransferBatch event to +// the database and updates the user's balances +func (svc *Service) saveERC1155Transfer(ctx context.Context, chainID *big.Int, vLog types.Log) error { + from := fmt.Sprintf("0x%v", common.Bytes2Hex(vLog.Topics[2].Bytes()[12:])) + + to := fmt.Sprintf("0x%v", common.Bytes2Hex(vLog.Topics[3].Bytes()[12:])) + + slog.Info("erc1155 found") + + type transfer struct { + ID *big.Int `abi:"id"` + Amount *big.Int `abi:"value"` + } + + var transfers []transfer + + erc1155ABI, err := abi.JSON(strings.NewReader(erc1155.ABI)) + if err != nil { + return err + } + + if vLog.Topics[0].Hex() == transferSingleSignatureHash.Hex() { + var t transfer + + err = erc1155ABI.UnpackIntoInterface(&t, "TransferSingle", []byte(vLog.Data)) + if err != nil { + return err + } + + transfers = append(transfers, t) + } else if vLog.Topics[0].Hex() != transferBatchSignatureHash.Hex() { + var t []transfer + + err = erc1155ABI.UnpackIntoInterface(&t, "TransferBatch", []byte(vLog.Data)) + if err != nil { + return err + } + + transfers = t + } + + slog.Info( + "erc1155 transfer found", + "from", from, + "to", to, + "transfers", transfers, + "contractAddress", vLog.Address.Hex(), + ) + + // increment To address's balance + + for _, transfer := range transfers { + _, err = svc.nftBalanceRepo.IncreaseBalance(ctx, eventindexer.UpdateNFTBalanceOpts{ + ChainID: chainID.Int64(), + Address: to, + TokenID: transfer.ID.Int64(), + ContractAddress: vLog.Address.Hex(), + ContractType: "ERC1155", + Amount: transfer.Amount.Int64(), + }) + if err != nil { + return err + } + + if from != ZeroAddress.Hex() { + // decrement From address's balance + _, err = svc.nftBalanceRepo.SubtractBalance(ctx, eventindexer.UpdateNFTBalanceOpts{ + ChainID: chainID.Int64(), + Address: from, + TokenID: transfer.ID.Int64(), + ContractAddress: vLog.Address.Hex(), + ContractType: "ERC1155", + Amount: transfer.Amount.Int64(), + }) + if err != nil { + return err + } + } + } + + return nil +} diff --git a/packages/eventindexer/indexer/save_block_proposed_event.go b/packages/eventindexer/indexer/save_block_proposed_event.go index 49a844861d0..a34e36ebab9 100644 --- a/packages/eventindexer/indexer/save_block_proposed_event.go +++ b/packages/eventindexer/indexer/save_block_proposed_event.go @@ -5,9 +5,10 @@ import ( "encoding/json" "math/big" + "log/slog" + "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/eventindexer" "github.com/taikoxyz/taiko-mono/packages/eventindexer/contracts/taikol1" ) @@ -18,7 +19,7 @@ func (svc *Service) saveBlockProposedEvents( events *taikol1.TaikoL1BlockProposedIterator, ) error { if !events.Next() || events.Event == nil { - log.Infof("no blockProposed events") + slog.Info("no blockProposed events") return nil } @@ -39,8 +40,6 @@ func (svc *Service) saveBlockProposedEvents( return errors.Wrap(err, "svc.ethClient.TransactionSender") } - log.Infof("blockProposed by: %v", sender.Hex()) - if err := svc.saveBlockProposedEvent(ctx, chainID, event, sender); err != nil { eventindexer.BlockProposedEventsProcessedError.Inc() @@ -59,7 +58,7 @@ func (svc *Service) saveBlockProposedEvent( event *taikol1.TaikoL1BlockProposed, sender common.Address, ) error { - log.Info("blockProposed event found") + slog.Info("blockProposed", "proposer", sender.Hex()) marshaled, err := json.Marshal(event) if err != nil { diff --git a/packages/eventindexer/indexer/save_block_proven_event.go b/packages/eventindexer/indexer/save_block_proven_event.go index b95e93e96a3..40c5d93ea61 100644 --- a/packages/eventindexer/indexer/save_block_proven_event.go +++ b/packages/eventindexer/indexer/save_block_proven_event.go @@ -5,9 +5,10 @@ import ( "encoding/json" "math/big" + "log/slog" + "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/eventindexer" "github.com/taikoxyz/taiko-mono/packages/eventindexer/contracts/taikol1" ) @@ -23,7 +24,7 @@ func (svc *Service) saveBlockProvenEvents( events *taikol1.TaikoL1BlockProvenIterator, ) error { if !events.Next() || events.Event == nil { - log.Infof("no blockProven events") + slog.Info("no blockProven events") return nil } @@ -34,8 +35,6 @@ func (svc *Service) saveBlockProvenEvents( return errors.Wrap(err, "svc.detectAndHandleReorg") } - log.Infof("blockProven by: %v", event.Prover.Hex()) - if err := svc.saveBlockProvenEvent(ctx, chainID, event); err != nil { eventindexer.BlockProvenEventsProcessedError.Inc() @@ -53,7 +52,9 @@ func (svc *Service) saveBlockProvenEvent( chainID *big.Int, event *taikol1.TaikoL1BlockProven, ) error { - log.Infof("blockProven event found, id: %v", event.BlockId.Int64()) + slog.Info("blockProven event found", + "blockID", event.BlockId.Int64(), + "prover", event.Prover.Hex()) marshaled, err := json.Marshal(event) if err != nil { @@ -120,19 +121,20 @@ func (svc *Service) updateAverageProofTime(ctx context.Context, event *taikol1.T new(big.Int).SetUint64(proofTime), ) - log.Infof(`avgProofWindow update: id: %v, - prover: %v, - proposedAt: %v, - provenAt: %v, - proofTime: %v, - avg: %v, - newAvg: %v`, + slog.Info("avgProofWindow update", + "id", event.BlockId.Int64(), + "prover", event.Prover.Hex(), + "proposedAt", proposedAt, + "provenAt", provenAt, + "proofTime", proofTime, + "avg", avg.String(), + "newAvg", newAverageProofTime.String(), ) diff --git a/packages/eventindexer/indexer/save_block_verified_event.go b/packages/eventindexer/indexer/save_block_verified_event.go index 6c0dd34e7f8..eaec389feb6 100644 --- a/packages/eventindexer/indexer/save_block_verified_event.go +++ b/packages/eventindexer/indexer/save_block_verified_event.go @@ -5,6 +5,8 @@ import ( "encoding/json" "math/big" + "log/slog" + "github.com/pkg/errors" log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/eventindexer" @@ -17,15 +19,13 @@ func (svc *Service) saveBlockVerifiedEvents( events *taikol1.TaikoL1BlockVerifiedIterator, ) error { if !events.Next() || events.Event == nil { - log.Infof("no BlockVerified events") + slog.Info("no BlockVerified events") return nil } for { event := events.Event - log.Infof("new blockVerified event, blockId: %v", event.BlockId.Int64()) - if err := svc.detectAndHandleReorg(ctx, eventindexer.EventNameBlockVerified, event.BlockId.Int64()); err != nil { return errors.Wrap(err, "svc.detectAndHandleReorg") } @@ -47,6 +47,8 @@ func (svc *Service) saveBlockVerifiedEvent( chainID *big.Int, event *taikol1.TaikoL1BlockVerified, ) error { + slog.Info("new blockVerified event", "blockID", event.BlockId.Int64()) + marshaled, err := json.Marshal(event) if err != nil { return errors.Wrap(err, "json.Marshal(event)") diff --git a/packages/eventindexer/indexer/save_exited_event.go b/packages/eventindexer/indexer/save_exited_event.go index 7aa1df32874..7de130828d0 100644 --- a/packages/eventindexer/indexer/save_exited_event.go +++ b/packages/eventindexer/indexer/save_exited_event.go @@ -4,9 +4,11 @@ import ( "context" "encoding/json" "math/big" + "strconv" + + "log/slog" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/eventindexer" "github.com/taikoxyz/taiko-mono/packages/eventindexer/contracts/proverpool" ) @@ -17,14 +19,19 @@ func (svc *Service) saveExitedEvents( events *proverpool.ProverPoolExitedIterator, ) error { if !events.Next() || events.Event == nil { - log.Infof("no Exited events") + slog.Info("no Exited events") return nil } for { event := events.Event - log.Infof("new Exited event, addr: %v, amt: %v", event.Addr.Hex(), event.Amount) + slog.Info("new Exited event", + "address", + event.Addr.Hex(), + "amount", + strconv.FormatUint(event.Amount, 10), + ) if err := svc.saveExitedEvent(ctx, chainID, event); err != nil { eventindexer.ExitedEventsProcessedError.Inc() diff --git a/packages/eventindexer/indexer/save_liquidity_added_event.go b/packages/eventindexer/indexer/save_liquidity_added_event.go index 87f01f56b84..8dd0dacf16a 100644 --- a/packages/eventindexer/indexer/save_liquidity_added_event.go +++ b/packages/eventindexer/indexer/save_liquidity_added_event.go @@ -5,9 +5,10 @@ import ( "encoding/json" "math/big" + "log/slog" + "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/eventindexer" "github.com/taikoxyz/taiko-mono/packages/eventindexer/contracts/swap" ) @@ -22,7 +23,7 @@ func (svc *Service) saveLiquidityAddedEvents( events *swap.SwapMintIterator, ) error { if !events.Next() || events.Event == nil { - log.Infof("no LiquidityAdded events") + slog.Info("no LiquidityAdded events") return nil } @@ -56,17 +57,17 @@ func (svc *Service) saveLiquidityAddedEvent( return err } - log.Infof("liquidityAdded event for sender %v, amount0: %v, amount1: %v", - from.Hex(), - event.Amount0.String(), - event.Amount1.String(), + slog.Info("liquidityAdded event for", + "sender", from.Hex(), + "amount0", event.Amount0.String(), + "amount1", event.Amount1.String(), ) // we only want events with > 0.1 ETH swap if event.Amount0.Cmp(minLiquidityAddedAmount) <= 0 && event.Amount1.Cmp(minLiquidityAddedAmount) <= 0 { - log.Infof("skipping liquidityAdded event, min trade too low. amountIn: %v, amountOut: %v", - event.Amount0.String(), - event.Amount1.String(), + slog.Info("skipping liquidityAdded event, min trade too low", + "amount0", event.Amount0.String(), + "amount1", event.Amount1.String(), ) return nil diff --git a/packages/eventindexer/indexer/save_message_sent_event.go b/packages/eventindexer/indexer/save_message_sent_event.go index 2d9eb2d6fd8..dd0b76d486b 100644 --- a/packages/eventindexer/indexer/save_message_sent_event.go +++ b/packages/eventindexer/indexer/save_message_sent_event.go @@ -5,9 +5,10 @@ import ( "encoding/json" "math/big" + "log/slog" + "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/eventindexer" "github.com/taikoxyz/taiko-mono/packages/eventindexer/contracts/bridge" ) @@ -23,14 +24,14 @@ func (svc *Service) saveMessageSentEvents( events *bridge.BridgeMessageSentIterator, ) error { if !events.Next() || events.Event == nil { - log.Infof("no MessageSent events") + slog.Info("no MessageSent events") return nil } for { event := events.Event - log.Infof("new messageSent event for owner: %v", event.Message.Owner.Hex()) + slog.Info("new messageSent event", "owner", event.Message.Owner.Hex()) if err := svc.saveMessageSentEvent(ctx, chainID, event); err != nil { eventindexer.MessageSentEventsProcessedError.Inc() @@ -51,14 +52,16 @@ func (svc *Service) saveMessageSentEvent( ) error { // only save eth transfers if event.Message.Data != nil && common.BytesToHash(event.Message.Data) != zeroHash { - log.Info("skipping message sent event, is not eth transfer") + slog.Info("skipping message sent event, is not eth transfer") return nil } // amount must be >= 0.15 eth if event.Message.DepositValue.Cmp(minEthAmount) < 0 { - log.Infof("skipping message sent event, value: %v, requiredValue: %v", + slog.Info("skipping message sent event", + "value", event.Message.DepositValue.String(), + "requiredValue", minEthAmount.String(), ) diff --git a/packages/eventindexer/indexer/save_slashed_event.go b/packages/eventindexer/indexer/save_slashed_event.go index a3775039341..c45acf7a746 100644 --- a/packages/eventindexer/indexer/save_slashed_event.go +++ b/packages/eventindexer/indexer/save_slashed_event.go @@ -4,9 +4,11 @@ import ( "context" "encoding/json" "math/big" + "strconv" + + "log/slog" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/eventindexer" "github.com/taikoxyz/taiko-mono/packages/eventindexer/contracts/proverpool" ) @@ -17,14 +19,17 @@ func (svc *Service) saveSlashedEvents( events *proverpool.ProverPoolSlashedIterator, ) error { if !events.Next() || events.Event == nil { - log.Infof("no Slashed events") + slog.Info("no Slashed events") return nil } for { event := events.Event - log.Infof("new slashed event, addr: %v, amt: %v", event.Addr.Hex(), event.Amount) + slog.Info("new slashed event", + "address", event.Addr.Hex(), + "amount", strconv.FormatUint(event.Amount, 10), + ) if err := svc.saveSlashedEvent(ctx, chainID, event); err != nil { eventindexer.SlashedEventsProcessedError.Inc() diff --git a/packages/eventindexer/indexer/save_staked_event.go b/packages/eventindexer/indexer/save_staked_event.go index db7ef0935e2..70956d4a092 100644 --- a/packages/eventindexer/indexer/save_staked_event.go +++ b/packages/eventindexer/indexer/save_staked_event.go @@ -4,9 +4,11 @@ import ( "context" "encoding/json" "math/big" + "strconv" + + "log/slog" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/eventindexer" "github.com/taikoxyz/taiko-mono/packages/eventindexer/contracts/proverpool" ) @@ -17,14 +19,17 @@ func (svc *Service) saveStakedEvents( events *proverpool.ProverPoolStakedIterator, ) error { if !events.Next() || events.Event == nil { - log.Infof("no Staked events") + slog.Info("no Staked events") return nil } for { event := events.Event - log.Infof("new Staked event, addr: %v, amt: %v", event.Addr.Hex(), event.Amount) + slog.Info("new Staked event", + "address", event.Addr.Hex(), + "amount", strconv.FormatUint(event.Amount, 10), + ) if err := svc.saveStakedEvent(ctx, chainID, event); err != nil { eventindexer.StakedEventsProcessedError.Inc() diff --git a/packages/eventindexer/indexer/save_swap_event.go b/packages/eventindexer/indexer/save_swap_event.go index bc994b79d26..621b830c3a6 100644 --- a/packages/eventindexer/indexer/save_swap_event.go +++ b/packages/eventindexer/indexer/save_swap_event.go @@ -6,9 +6,10 @@ import ( "fmt" "math/big" + "log/slog" + "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/eventindexer" "github.com/taikoxyz/taiko-mono/packages/eventindexer/contracts/swap" ) @@ -23,7 +24,7 @@ func (svc *Service) saveSwapEvents( events *swap.SwapSwapIterator, ) error { if !events.Next() || events.Event == nil { - log.Infof("no Swap events") + slog.Info("no Swap events") return nil } @@ -47,16 +48,16 @@ func (svc *Service) saveSwapEvent( chainID *big.Int, event *swap.SwapSwap, ) error { - log.Infof("swap event for sender 0x%v, amount: %v", - common.Bytes2Hex(event.Raw.Topics[2].Bytes()[12:]), - event.Amount0In.String(), + slog.Info("swap event", + "sender", fmt.Sprintf("0x%v", common.Bytes2Hex(event.Raw.Topics[2].Bytes()[12:])), + "amount", event.Amount0In.String(), ) // we only want events with > 0.1 ETH swap if event.Amount0In.Cmp(minTradeAmount) <= 0 && event.Amount1Out.Cmp(minTradeAmount) <= 0 { - log.Infof("skipping skip event, min trade too low. amountIn: %v, amountOut: %v", - event.Amount0In.String(), - event.Amount1Out.String(), + slog.Info("skipping skip event, min trade too low", + "amount0", event.Amount0In.String(), + "amount1", event.Amount1Out.String(), ) return nil diff --git a/packages/eventindexer/indexer/save_withdrawn_event.go b/packages/eventindexer/indexer/save_withdrawn_event.go index 99e556e9480..df2db547b9a 100644 --- a/packages/eventindexer/indexer/save_withdrawn_event.go +++ b/packages/eventindexer/indexer/save_withdrawn_event.go @@ -3,10 +3,11 @@ package indexer import ( "context" "encoding/json" + "log/slog" "math/big" + "strconv" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/eventindexer" "github.com/taikoxyz/taiko-mono/packages/eventindexer/contracts/proverpool" ) @@ -17,14 +18,17 @@ func (svc *Service) saveWithdrawnEvents( events *proverpool.ProverPoolWithdrawnIterator, ) error { if !events.Next() || events.Event == nil { - log.Infof("no Withdrawn events") + slog.Info("no Withdrawn events") return nil } for { event := events.Event - log.Infof("new Withdrawn event, addr: %v, amt: %v", event.Addr.Hex(), event.Amount) + slog.Info("new Withdrawn event", + "address", event.Addr.Hex(), + "amount", strconv.FormatUint(event.Amount, 10), + ) if err := svc.saveWithdrawnEvent(ctx, chainID, event); err != nil { eventindexer.WithdrawnEventsProcessedError.Inc() diff --git a/packages/eventindexer/indexer/service.go b/packages/eventindexer/indexer/service.go index 7e106946daa..7a908ae4219 100644 --- a/packages/eventindexer/indexer/service.go +++ b/packages/eventindexer/indexer/service.go @@ -19,10 +19,11 @@ var ( ) type Service struct { - eventRepo eventindexer.EventRepository - blockRepo eventindexer.BlockRepository - statRepo eventindexer.StatRepository - ethClient *ethclient.Client + eventRepo eventindexer.EventRepository + blockRepo eventindexer.BlockRepository + statRepo eventindexer.StatRepository + nftBalanceRepo eventindexer.NFTBalanceRepository + ethClient *ethclient.Client processingBlockHeight uint64 @@ -33,12 +34,15 @@ type Service struct { proverPool *proverpool.ProverPool bridge *bridge.Bridge swaps []*swap.Swap + + indexNfts bool } type NewServiceOpts struct { EventRepo eventindexer.EventRepository BlockRepo eventindexer.BlockRepository StatRepo eventindexer.StatRepository + NFTBalanceRepo eventindexer.NFTBalanceRepository EthClient *ethclient.Client RPCClient *rpc.Client SrcTaikoAddress common.Address @@ -47,6 +51,7 @@ type NewServiceOpts struct { SrcSwapAddresses []common.Address BlockBatchSize uint64 SubscriptionBackoff time.Duration + IndexNFTs bool } func NewService(opts NewServiceOpts) (*Service, error) { @@ -54,6 +59,10 @@ func NewService(opts NewServiceOpts) (*Service, error) { return nil, eventindexer.ErrNoEventRepository } + if opts.IndexNFTs && opts.NFTBalanceRepo == nil { + return nil, eventindexer.ErrNoNFTBalanceRepository + } + if opts.EthClient == nil { return nil, eventindexer.ErrNoEthClient } @@ -104,16 +113,19 @@ func NewService(opts NewServiceOpts) (*Service, error) { } return &Service{ - eventRepo: opts.EventRepo, - blockRepo: opts.BlockRepo, - statRepo: opts.StatRepo, - ethClient: opts.EthClient, - taikol1: taikoL1, - bridge: bridgeContract, - proverPool: proverPool, - swaps: swapContracts, + eventRepo: opts.EventRepo, + blockRepo: opts.BlockRepo, + statRepo: opts.StatRepo, + nftBalanceRepo: opts.NFTBalanceRepo, + ethClient: opts.EthClient, + taikol1: taikoL1, + bridge: bridgeContract, + proverPool: proverPool, + swaps: swapContracts, blockBatchSize: opts.BlockBatchSize, subscriptionBackoff: opts.SubscriptionBackoff, + + indexNfts: opts.IndexNFTs, }, nil } diff --git a/packages/eventindexer/indexer/set_initial_processing_block_height.go b/packages/eventindexer/indexer/set_initial_processing_block_height.go index c44e5ec73e1..709241f177a 100644 --- a/packages/eventindexer/indexer/set_initial_processing_block_height.go +++ b/packages/eventindexer/indexer/set_initial_processing_block_height.go @@ -2,10 +2,10 @@ package indexer import ( "context" + "log/slog" "math/big" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/eventindexer" ) @@ -38,7 +38,7 @@ func (svc *Service) setInitialProcessingBlockByMode( startingBlock = latestProcessedBlock.Height } - log.Infof("starting block: %v", startingBlock) + slog.Info("set processingBlockHeight", "startingBlock", startingBlock) svc.processingBlockHeight = startingBlock diff --git a/packages/eventindexer/indexer/subscribe.go b/packages/eventindexer/indexer/subscribe.go index 0db55b0a712..5b09d1a22ff 100644 --- a/packages/eventindexer/indexer/subscribe.go +++ b/packages/eventindexer/indexer/subscribe.go @@ -3,11 +3,15 @@ package indexer import ( "context" "math/big" + "strconv" + + "log/slog" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" + "github.com/labstack/gommon/log" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/eventindexer" "github.com/taikoxyz/taiko-mono/packages/eventindexer/contracts/bridge" "github.com/taikoxyz/taiko-mono/packages/eventindexer/contracts/proverpool" @@ -17,7 +21,7 @@ import ( // subscribe subscribes to latest events func (svc *Service) subscribe(ctx context.Context, chainID *big.Int) error { - log.Info("subscribing to new events") + slog.Info("subscribing to new events") errChan := make(chan error) @@ -45,11 +49,15 @@ func (svc *Service) subscribe(ctx context.Context, chainID *big.Int) error { } } + if svc.indexNfts { + go svc.subscribeNftTransfers(ctx, chainID, errChan) + } + // nolint: gosimple for { select { case <-ctx.Done(): - log.Info("context finished") + slog.Info("context finished") return nil case err := <-errChan: eventindexer.ErrorsEncounteredDuringSubscription.Inc() @@ -59,6 +67,40 @@ func (svc *Service) subscribe(ctx context.Context, chainID *big.Int) error { } } +func (svc *Service) subscribeNftTransfers( + ctx context.Context, + chainID *big.Int, + errChan chan error, +) { + headers := make(chan *types.Header) + + sub := event.ResubscribeErr(svc.subscriptionBackoff, func(ctx context.Context, err error) (event.Subscription, error) { + if err != nil { + slog.Error("svc.SubscribeNewHead", "error", err) + } + slog.Info("resubscribing to NewHead events for nft trasnfers") + + return svc.ethClient.SubscribeNewHead(ctx, headers) + }) + + for { + select { + case <-ctx.Done(): + slog.Info("context finished") + return + case err := <-sub.Err(): + slog.Error("sub.Err()", "error", err) + errChan <- errors.Wrap(err, "sub.Err()") + case header := <-headers: + go func() { + if err := svc.indexNFTTransfers(ctx, chainID, header.Number.Uint64(), header.Number.Uint64()); err != nil { + slog.Error("svc.indexNFTTransfers", "error", err) + } + }() + } + } +} + func (svc *Service) subscribeSlashed( ctx context.Context, chainID *big.Int, @@ -68,9 +110,9 @@ func (svc *Service) subscribeSlashed( sub := event.ResubscribeErr(svc.subscriptionBackoff, func(ctx context.Context, err error) (event.Subscription, error) { if err != nil { - log.Errorf("svc.taikoL1.WatchSlashed: %v", err) + slog.Error("svc.taikoL1.WatchSlashed", "error", err) } - log.Info("resubscribing to Slashed events") + slog.Info("resubscribing to Slashed events") return svc.proverPool.WatchSlashed(&bind.WatchOpts{ Context: ctx, @@ -82,26 +124,29 @@ func (svc *Service) subscribeSlashed( for { select { case <-ctx.Done(): - log.Info("context finished") + slog.Info("context finished") return case err := <-sub.Err(): - log.Errorf("sub.Err(): %v", err) + slog.Error("sub.Err()", "error", err) errChan <- errors.Wrap(err, "sub.Err()") case event := <-sink: go func() { - log.Infof("slashedEvent for address %v, amount %v", event.Addr.Hex(), event.Amount) + slog.Info("slashedEvent", + "address", event.Addr.Hex(), + "amount", strconv.FormatUint(event.Amount, 10), + ) if err := svc.saveSlashedEvent(ctx, chainID, event); err != nil { eventindexer.SlashedEventsProcessedError.Inc() - log.Errorf("svc.subscribe, svc.saveSlashedEvent: %v", err) + slog.Error("svc.subscribe, svc.saveSlashedEvent", "error", err) return } block, err := svc.blockRepo.GetLatestBlockProcessed(chainID) if err != nil { - log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessed: %v", err) + slog.Error("svc.subscribe, svc.blockRepo.GetLatestBlockProcessed", "error", err) return } @@ -112,7 +157,7 @@ func (svc *Service) subscribeSlashed( ChainID: chainID, }) if err != nil { - log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + slog.Error("svc.subscribe, blockRepo.save", "error", err) return } @@ -132,9 +177,9 @@ func (svc *Service) subscribeStaked( sub := event.ResubscribeErr(svc.subscriptionBackoff, func(ctx context.Context, err error) (event.Subscription, error) { if err != nil { - log.Errorf("svc.taikoL1.WatchStaked: %v", err) + slog.Error("svc.taikoL1.WatchStaked", "error", err) } - log.Info("resubscribing to Staked events") + slog.Info("resubscribing to Staked events") return svc.proverPool.WatchStaked(&bind.WatchOpts{ Context: ctx, @@ -146,26 +191,28 @@ func (svc *Service) subscribeStaked( for { select { case <-ctx.Done(): - log.Info("context finished") + slog.Info("context finished") return case err := <-sub.Err(): - log.Errorf("sub.Err(): %v", err) + slog.Error("sub.Err()", "error", err) errChan <- errors.Wrap(err, "sub.Err()") case event := <-sink: go func() { - log.Infof("stakedEvent for address %v, amount %v", event.Addr.Hex(), event.Amount) + slog.Info("stakedEvent", + "address", event.Addr.Hex(), + "amount", event.Amount) if err := svc.saveStakedEvent(ctx, chainID, event); err != nil { eventindexer.StakedEventsProcessedError.Inc() - log.Errorf("svc.subscribe, svc.saveStakedEvent: %v", err) + slog.Error("svc.subscribe, svc.saveStakedEvent", "error", err) return } block, err := svc.blockRepo.GetLatestBlockProcessed(chainID) if err != nil { - log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessed: %v", err) + slog.Error("svc.subscribe, svc.blockRepo.GetLatestBlockProcessed", "error", err) return } @@ -176,7 +223,7 @@ func (svc *Service) subscribeStaked( ChainID: chainID, }) if err != nil { - log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + slog.Error("svc.subscribe, blockRepo.save", "error", err) return } @@ -196,9 +243,9 @@ func (svc *Service) subscribeExited( sub := event.ResubscribeErr(svc.subscriptionBackoff, func(ctx context.Context, err error) (event.Subscription, error) { if err != nil { - log.Errorf("svc.taikoL1.WatchExited: %v", err) + slog.Error("svc.taikoL1.WatchExited", "error", err) } - log.Info("resubscribing to Exited events") + slog.Info("resubscribing to Exited events") return svc.proverPool.WatchExited(&bind.WatchOpts{ Context: ctx, @@ -210,26 +257,26 @@ func (svc *Service) subscribeExited( for { select { case <-ctx.Done(): - log.Info("context finished") + slog.Info("context finished") return case err := <-sub.Err(): - log.Errorf("sub.Err(): %v", err) + slog.Error("sub.Err()", "error", err) errChan <- errors.Wrap(err, "sub.Err()") case event := <-sink: go func() { - log.Infof("exitedEvent for address %v, amount %v", event.Addr.Hex(), event.Amount) + slog.Info("exitedEvent", "address", event.Addr.Hex(), "amount", event.Amount) if err := svc.saveExitedEvent(ctx, chainID, event); err != nil { eventindexer.ExitedEventsProcessedError.Inc() - log.Errorf("svc.subscribe, svc.saveExitedEvent: %v", err) + slog.Error("svc.subscribe, svc.saveExitedEvent", "error", err) return } block, err := svc.blockRepo.GetLatestBlockProcessed(chainID) if err != nil { - log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessed: %v", err) + slog.Error("svc.subscribe, svc.blockRepo.GetLatestBlockProcessed", "error", err) return } @@ -240,7 +287,7 @@ func (svc *Service) subscribeExited( ChainID: chainID, }) if err != nil { - log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + slog.Error("svc.subscribe, blockRepo.save", "error", err) return } @@ -260,9 +307,9 @@ func (svc *Service) subscribeWithdrawn( sub := event.ResubscribeErr(svc.subscriptionBackoff, func(ctx context.Context, err error) (event.Subscription, error) { if err != nil { - log.Errorf("svc.taikoL1.WatchWithdrawn: %v", err) + slog.Error("svc.taikoL1.WatchWithdrawn", "error", err) } - log.Info("resubscribing to Withdrawn events") + slog.Info("resubscribing to Withdrawn events") return svc.proverPool.WatchWithdrawn(&bind.WatchOpts{ Context: ctx, @@ -274,26 +321,26 @@ func (svc *Service) subscribeWithdrawn( for { select { case <-ctx.Done(): - log.Info("context finished") + slog.Info("context finished") return case err := <-sub.Err(): - log.Errorf("sub.Err(): %v", err) + slog.Error("sub.Err()", "error", err) errChan <- errors.Wrap(err, "sub.Err()") case event := <-sink: go func() { - log.Infof("withdrawnEvent for address %v, amount %v", event.Addr.Hex(), event.Amount) + slog.Info("withdrawnEvent", "address", event.Addr.Hex(), "amount", event.Amount) if err := svc.saveWithdrawnEvent(ctx, chainID, event); err != nil { eventindexer.WithdrawnEventsProcessedError.Inc() - log.Errorf("svc.subscribe, svc.saveWithdrawnEvent: %v", err) + log.Error("svc.subscribe, svc.saveWithdrawnEvent", "error", err) return } block, err := svc.blockRepo.GetLatestBlockProcessed(chainID) if err != nil { - log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessed: %v", err) + slog.Error("svc.subscribe, svc.blockRepo.GetLatestBlockProcessed", "error", err) return } @@ -304,7 +351,7 @@ func (svc *Service) subscribeWithdrawn( ChainID: chainID, }) if err != nil { - log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + slog.Error("svc.subscribe, blockRepo.save", "error", err) return } @@ -320,7 +367,7 @@ func (svc *Service) subscribeBlockProven(ctx context.Context, chainID *big.Int, sub := event.ResubscribeErr(svc.subscriptionBackoff, func(ctx context.Context, err error) (event.Subscription, error) { if err != nil { - log.Errorf("svc.taikoL1.WatchBlockProven: %v", err) + log.Error("svc.taikoL1.WatchBlockProven", "error", err) } log.Info("resubscribing to BlockProven events") @@ -334,26 +381,28 @@ func (svc *Service) subscribeBlockProven(ctx context.Context, chainID *big.Int, for { select { case <-ctx.Done(): - log.Info("context finished") + slog.Info("context finished") return case err := <-sub.Err(): - log.Errorf("sub.Err(): %v", err) + slog.Error("sub.Err()", "error", err) errChan <- errors.Wrap(err, "sub.Err()") case event := <-sink: go func() { - log.Infof("blockProvenEvent from subscription for prover %v", event.Prover.Hex()) + log.Info("blockProvenEvent from subscription for prover", + "prover", event.Prover.Hex(), + ) if err := svc.saveBlockProvenEvent(ctx, chainID, event); err != nil { eventindexer.BlockProvenEventsProcessedError.Inc() - log.Errorf("svc.subscribe, svc.saveBlockProvenEvent: %v", err) + log.Error("svc.subscribe, svc.saveBlockProvenEvent", "error", err) return } block, err := svc.blockRepo.GetLatestBlockProcessed(chainID) if err != nil { - log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessed: %v", err) + slog.Error("svc.subscribe, svc.blockRepo.GetLatestBlockProcessed", "error", err) return } @@ -364,7 +413,7 @@ func (svc *Service) subscribeBlockProven(ctx context.Context, chainID *big.Int, ChainID: chainID, }) if err != nil { - log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + slog.Error("svc.subscribe, blockRepo.save", "error", err) return } @@ -380,7 +429,7 @@ func (svc *Service) subscribeBlockProposed(ctx context.Context, chainID *big.Int sub := event.ResubscribeErr(svc.subscriptionBackoff, func(ctx context.Context, err error) (event.Subscription, error) { if err != nil { - log.Errorf("svc.taikoL1.WatchBlockProposed: %v", err) + log.Error("svc.taikoL1.WatchBlockProposed", "error", err) } log.Info("resubscribing to BlockProposed events") @@ -394,42 +443,42 @@ func (svc *Service) subscribeBlockProposed(ctx context.Context, chainID *big.Int for { select { case <-ctx.Done(): - log.Info("context finished") + slog.Info("context finished") return case err := <-sub.Err(): - log.Errorf("sub.Err(): %v", err) + slog.Error("sub.Err()", "error", err) errChan <- errors.Wrap(err, "sub.Err()") case event := <-sink: go func() { - log.Infof("blockProposedEvent from subscription") + slog.Info("blockProposedEvent from subscription") tx, _, err := svc.ethClient.TransactionByHash(ctx, event.Raw.TxHash) if err != nil { - log.Errorf("svc.ethClient.TransactionByHash: %v", err) + slog.Error("svc.ethClient.TransactionByHash", "error", err) return } sender, err := svc.ethClient.TransactionSender(ctx, tx, event.Raw.BlockHash, event.Raw.TxIndex) if err != nil { - log.Errorf("svc.ethClient.TransactionSender: %v", err) + slog.Error("svc.ethClient.TransactionSender", "error", err) return } - log.Infof("blockProposed by: %v", sender.Hex()) + slog.Info("blockProposed", "proposer", sender.Hex(), "blockID", event.BlockId.Uint64()) if err := svc.saveBlockProposedEvent(ctx, chainID, event, sender); err != nil { eventindexer.BlockProposedEventsProcessedError.Inc() - log.Errorf("svc.subscribe, svc.saveBlockProposedEvent: %v", err) + slog.Error("svc.subscribe, svc.saveBlockProposedEvent", "error", err) return } block, err := svc.blockRepo.GetLatestBlockProcessed(chainID) if err != nil { - log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessed: %v", err) + slog.Error("svc.subscribe, svc.blockRepo.GetLatestBlockProcessed", "error", err) return } @@ -441,7 +490,7 @@ func (svc *Service) subscribeBlockProposed(ctx context.Context, chainID *big.Int ChainID: chainID, }) if err != nil { - log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + slog.Error("svc.subscribe, blockRepo.save", "error", err) return } @@ -458,10 +507,10 @@ func (svc *Service) subscribeBlockVerified(ctx context.Context, chainID *big.Int sub := event.ResubscribeErr(svc.subscriptionBackoff, func(ctx context.Context, err error) (event.Subscription, error) { if err != nil { - log.Errorf("svc.taikoL1.WatchBlockVerified: %v", err) + slog.Error("svc.taikoL1.WatchBlockVerified", "error", err) } - log.Info("resubscribing to BlockVerified events") + slog.Info("resubscribing to BlockVerified events") return svc.taikol1.WatchBlockVerified(&bind.WatchOpts{ Context: ctx, @@ -473,25 +522,25 @@ func (svc *Service) subscribeBlockVerified(ctx context.Context, chainID *big.Int for { select { case <-ctx.Done(): - log.Info("context finished") + slog.Info("context finished") return case err := <-sub.Err(): - log.Errorf("sub.Err(): %v", err) + slog.Error("sub.Err()", "error", err) errChan <- errors.Wrap(err, "sub.Err()") case event := <-sink: go func() { - log.Infof("blockVerifiedEvent from subscription") + slog.Info("blockVerifiedEvent from subscription", "prover", event.Prover.Hex()) if err := svc.saveBlockVerifiedEvent(ctx, chainID, event); err != nil { eventindexer.BlockVerifiedEventsProcessedError.Inc() - log.Errorf("svc.subscribe, svc.saveBlockVerifiedEvent: %v", err) + slog.Error("svc.subscribe, svc.saveBlockVerifiedEvent", "error", err) return } block, err := svc.blockRepo.GetLatestBlockProcessed(chainID) if err != nil { - log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessed: %v", err) + slog.Error("svc.subscribe, svc.blockRepo.GetLatestBlockProcessed", "error", err) return } @@ -502,7 +551,7 @@ func (svc *Service) subscribeBlockVerified(ctx context.Context, chainID *big.Int ChainID: chainID, }) if err != nil { - log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + slog.Error("svc.subscribe, blockRepo.save", "error", err) return } @@ -518,9 +567,10 @@ func (svc *Service) subscribeMessageSent(ctx context.Context, chainID *big.Int, sub := event.ResubscribeErr(svc.subscriptionBackoff, func(ctx context.Context, err error) (event.Subscription, error) { if err != nil { - log.Errorf("svc.taikoL1.WatchMessageSent: %v", err) + slog.Error("svc.taikoL1.WatchMessageSent", "error", err) } - log.Info("resubscribing to MessageSent events") + + slog.Info("resubscribing to MessageSent events") return svc.bridge.WatchMessageSent(&bind.WatchOpts{ Context: ctx, @@ -532,26 +582,26 @@ func (svc *Service) subscribeMessageSent(ctx context.Context, chainID *big.Int, for { select { case <-ctx.Done(): - log.Info("context finished") + slog.Info("context finished") return case err := <-sub.Err(): - log.Errorf("sub.Err(): %v", err) + slog.Error("sub.Err()", "error", err) errChan <- errors.Wrap(err, "sub.Err()") case event := <-sink: go func() { - log.Infof("messageSentEvent for owner: %v", event.Message.Owner.Hex()) + slog.Info("messageSentEvent", "owner", event.Message.Owner.Hex()) if err := svc.saveMessageSentEvent(ctx, chainID, event); err != nil { eventindexer.MessageSentEventsProcessedError.Inc() - log.Errorf("svc.subscribe, svc.saveMessageSentEvent: %v", err) + slog.Error("svc.subscribe, svc.saveMessageSentEvent", "error", err) return } block, err := svc.blockRepo.GetLatestBlockProcessed(chainID) if err != nil { - log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessed: %v", err) + slog.Error("svc.subscribe, svc.blockRepo.GetLatestBlockProcessed", "error", err) return } @@ -562,7 +612,7 @@ func (svc *Service) subscribeMessageSent(ctx context.Context, chainID *big.Int, ChainID: chainID, }) if err != nil { - log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + slog.Error("svc.subscribe, blockRepo.save", "error", err) return } @@ -578,9 +628,9 @@ func (svc *Service) subscribeSwap(ctx context.Context, s *swap.Swap, chainID *bi sub := event.ResubscribeErr(svc.subscriptionBackoff, func(ctx context.Context, err error) (event.Subscription, error) { if err != nil { - log.Errorf("s.WatchSwap: %v", err) + slog.Error("s.WatchSwap", "error", err) } - log.Info("resubscribing to Swap events") + slog.Info("resubscribing to Swap events") return s.WatchSwap(&bind.WatchOpts{ Context: ctx, @@ -592,24 +642,24 @@ func (svc *Service) subscribeSwap(ctx context.Context, s *swap.Swap, chainID *bi for { select { case <-ctx.Done(): - log.Info("context finished") + slog.Info("context finished") return case err := <-sub.Err(): - log.Errorf("sub.Err(): %v", err) + slog.Error("sub.Err()", "error", err) errChan <- errors.Wrap(err, "sub.Err()") case event := <-sink: go func() { if err := svc.saveSwapEvent(ctx, chainID, event); err != nil { eventindexer.SwapEventsProcessedError.Inc() - log.Errorf("svc.subscribe, svc.saveSwapEvent: %v", err) + slog.Error("svc.subscribe, svc.saveSwapEvent", "error", err) return } block, err := svc.blockRepo.GetLatestBlockProcessed(chainID) if err != nil { - log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessed: %v", err) + slog.Error("svc.subscribe, svc.blockRepo.GetLatestBlockProcessed", "error", err) return } @@ -620,7 +670,7 @@ func (svc *Service) subscribeSwap(ctx context.Context, s *swap.Swap, chainID *bi ChainID: chainID, }) if err != nil { - log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + slog.Error("svc.subscribe, blockRepo.save", "error", err) return } @@ -636,9 +686,9 @@ func (svc *Service) subscribeLiquidityAdded(ctx context.Context, s *swap.Swap, c sub := event.ResubscribeErr(svc.subscriptionBackoff, func(ctx context.Context, err error) (event.Subscription, error) { if err != nil { - log.Errorf("s.WatchMint: %v", err) + slog.Error("s.WatchMint", "error", err) } - log.Info("resubscribing to Swap events") + slog.Info("resubscribing to Swap events") return s.WatchMint(&bind.WatchOpts{ Context: ctx, @@ -650,24 +700,24 @@ func (svc *Service) subscribeLiquidityAdded(ctx context.Context, s *swap.Swap, c for { select { case <-ctx.Done(): - log.Info("context finished") + slog.Info("context finished") return case err := <-sub.Err(): - log.Errorf("sub.Err(): %v", err) + slog.Error("sub.Err()", "error", err) errChan <- errors.Wrap(err, "sub.Err()") case event := <-sink: go func() { if err := svc.saveLiquidityAddedEvent(ctx, chainID, event); err != nil { eventindexer.SwapEventsProcessedError.Inc() - log.Errorf("svc.subscribe, svc.saveLiquidityAddedEvent: %v", err) + slog.Error("svc.subscribe, svc.saveLiquidityAddedEvent", "error", err) return } block, err := svc.blockRepo.GetLatestBlockProcessed(chainID) if err != nil { - log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessed: %v", err) + slog.Error("svc.subscribe, blockRepo.GetLatestBlockProcessed", "error", err) return } @@ -678,7 +728,7 @@ func (svc *Service) subscribeLiquidityAdded(ctx context.Context, s *swap.Swap, c ChainID: chainID, }) if err != nil { - log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + slog.Error("svc.subscribe, svc.blockRepo.Save", "error", err) return } diff --git a/packages/eventindexer/migrations/1666650706_alter_events_table_add_token_id.sql b/packages/eventindexer/migrations/1666650706_alter_events_table_add_token_id.sql new file mode 100644 index 00000000000..e2921251873 --- /dev/null +++ b/packages/eventindexer/migrations/1666650706_alter_events_table_add_token_id.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +ALTER TABLE `events` ADD COLUMN token_id int DEFAULT NULL; + +-- +goose StatementEnd +-- +goose Down +-- +goose StatementBegin +ALTER TABLE `events` DROP COLUMN token_id; +-- +goose StatementEnd \ No newline at end of file diff --git a/packages/eventindexer/migrations/1666650707_alter_events_table_add_to.sql b/packages/eventindexer/migrations/1666650707_alter_events_table_add_to.sql new file mode 100644 index 00000000000..561b11ff2c3 --- /dev/null +++ b/packages/eventindexer/migrations/1666650707_alter_events_table_add_to.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +ALTER TABLE `events` ADD COLUMN `to` VARCHAR(42) DEFAULT ""; + +-- +goose StatementEnd +-- +goose Down +-- +goose StatementBegin +ALTER TABLE `events` DROP COLUMN `to`; +-- +goose StatementEnd \ No newline at end of file diff --git a/packages/eventindexer/migrations/1666650708_alter_events_table_add_contract_address.sql b/packages/eventindexer/migrations/1666650708_alter_events_table_add_contract_address.sql new file mode 100644 index 00000000000..6079d3423f4 --- /dev/null +++ b/packages/eventindexer/migrations/1666650708_alter_events_table_add_contract_address.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +ALTER TABLE `events` ADD COLUMN contract_address VARCHAR(42) DEFAULT ""; + +-- +goose StatementEnd +-- +goose Down +-- +goose StatementBegin +ALTER TABLE `events` DROP COLUMN contract_address; +-- +goose StatementEnd \ No newline at end of file diff --git a/packages/eventindexer/migrations/1666650709_create_nft_balances_table.sql b/packages/eventindexer/migrations/1666650709_create_nft_balances_table.sql new file mode 100644 index 00000000000..af766f2db46 --- /dev/null +++ b/packages/eventindexer/migrations/1666650709_create_nft_balances_table.sql @@ -0,0 +1,19 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE IF NOT EXISTS nft_balances ( + id int NOT NULL PRIMARY KEY AUTO_INCREMENT, + chain_id int NOT NULL, + address VARCHAR(42) NOT NULL DEFAULT "", + amount DECIMAL(65, 0) DEFAULT NULL, + contract_address VARCHAR(42) NOT NULL DEFAULT "", + contract_type VARCHAR(7) NOT NULL DEFAULT "ERC721", + token_id DECIMAL(65, 0) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP , + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +); + +-- +goose StatementEnd +-- +goose Down +-- +goose StatementBegin +DROP TABLE nft_balances; +-- +goose StatementEnd diff --git a/packages/eventindexer/migrations/1666650710_alter_nft_balances_table_add_address_and_chain_id_index.sql b/packages/eventindexer/migrations/1666650710_alter_nft_balances_table_add_address_and_chain_id_index.sql new file mode 100644 index 00000000000..2bdff460540 --- /dev/null +++ b/packages/eventindexer/migrations/1666650710_alter_nft_balances_table_add_address_and_chain_id_index.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +ALTER TABLE `nft_balances` ADD INDEX `address_and_chain_id_index` (`address`, `chain_id`); + +-- +goose StatementEnd +-- +goose Down +-- +goose StatementBegin +DROP INDEX address_and_chain_id_index on nft_balances; +-- +goose StatementEnd diff --git a/packages/eventindexer/migrations/1666650711_alter_nft_balances_table_add_address_contract_address_token_id_and_chain_id_index.sql b/packages/eventindexer/migrations/1666650711_alter_nft_balances_table_add_address_contract_address_token_id_and_chain_id_index.sql new file mode 100644 index 00000000000..0abc3615882 --- /dev/null +++ b/packages/eventindexer/migrations/1666650711_alter_nft_balances_table_add_address_contract_address_token_id_and_chain_id_index.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +ALTER TABLE `nft_balances` ADD INDEX `address_contract_address_token_id_and_chain_id_index` (`address`, `contract_address`, `token_id`, `chain_id`); + +-- +goose StatementEnd +-- +goose Down +-- +goose StatementBegin +DROP INDEX address_contract_address_token_id_and_chain_id_index on nft_balances; +-- +goose StatementEnd diff --git a/packages/eventindexer/mock/nft_balance_repository.go b/packages/eventindexer/mock/nft_balance_repository.go new file mode 100644 index 00000000000..4b55cae4b70 --- /dev/null +++ b/packages/eventindexer/mock/nft_balance_repository.go @@ -0,0 +1,49 @@ +package mock + +import ( + "context" + "net/http" + + "github.com/morkid/paginate" + "github.com/taikoxyz/taiko-mono/packages/eventindexer" +) + +type NFTBalanceRepository struct { + nftBalances []*eventindexer.NFTBalance +} + +func NewNFTBalanceRepository() *NFTBalanceRepository { + return &NFTBalanceRepository{} +} + +func (r *NFTBalanceRepository) SubtractBalance( + ctx context.Context, + opts eventindexer.UpdateNFTBalanceOpts, +) (*eventindexer.NFTBalance, error) { + return nil, nil +} + +func (r *NFTBalanceRepository) IncreaseBalance( + ctx context.Context, + opts eventindexer.UpdateNFTBalanceOpts, +) (*eventindexer.NFTBalance, error) { + return nil, nil +} + +func (r *NFTBalanceRepository) FindByAddress(ctx context.Context, + req *http.Request, + address string, + chainID string, +) (paginate.Page, error) { + var balances []*eventindexer.NFTBalance + + for _, b := range r.nftBalances { + if b.Address == address { + balances = append(balances, b) + } + } + + return paginate.Page{ + Items: balances, + }, nil +} diff --git a/packages/eventindexer/nft_balance.go b/packages/eventindexer/nft_balance.go new file mode 100644 index 00000000000..9b1651a49b1 --- /dev/null +++ b/packages/eventindexer/nft_balance.go @@ -0,0 +1,40 @@ +package eventindexer + +import ( + "context" + "net/http" + + "github.com/morkid/paginate" +) + +// NFTBalance represents a single contractAddress/tokenId pairing for a given holder +// address +type NFTBalance struct { + ID int `json:"id"` + ChainID int64 `json:"chainID"` + Address string `json:"address"` + Amount int64 `json:"amount"` + TokenID int64 `json:"tokenID"` + ContractAddress string `json:"contractAddress"` + ContractType string `json:"contractType"` +} + +type UpdateNFTBalanceOpts struct { + ChainID int64 + Address string + TokenID int64 + ContractAddress string + ContractType string + Amount int64 +} + +// NFTBalanceRepository is used to interact with nft balances in the store +type NFTBalanceRepository interface { + SubtractBalance(ctx context.Context, opts UpdateNFTBalanceOpts) (*NFTBalance, error) + IncreaseBalance(ctx context.Context, opts UpdateNFTBalanceOpts) (*NFTBalance, error) + FindByAddress(ctx context.Context, + req *http.Request, + address string, + chainID string, + ) (paginate.Page, error) +} diff --git a/packages/eventindexer/repo/event.go b/packages/eventindexer/repo/event.go index 0cfb71053c2..515bfa20ed3 100644 --- a/packages/eventindexer/repo/event.go +++ b/packages/eventindexer/repo/event.go @@ -60,6 +60,21 @@ func (r *EventRepository) Save(ctx context.Context, opts eventindexer.SaveEventO e.AssignedProver = *opts.AssignedProver } + if opts.TokenID != nil { + e.TokenID = sql.NullInt64{ + Valid: true, + Int64: *opts.TokenID, + } + } + + if opts.To != nil { + e.To = *opts.To + } + + if opts.ContractAddress != nil { + e.ContractAddress = *opts.ContractAddress + } + if err := r.db.GormDB().Create(e).Error; err != nil { return nil, errors.Wrap(err, "r.db.Create") } diff --git a/packages/eventindexer/repo/nft_balance.go b/packages/eventindexer/repo/nft_balance.go new file mode 100644 index 00000000000..5ecf134ef12 --- /dev/null +++ b/packages/eventindexer/repo/nft_balance.go @@ -0,0 +1,127 @@ +package repo + +import ( + "context" + "net/http" + + "github.com/morkid/paginate" + "github.com/pkg/errors" + "github.com/taikoxyz/taiko-mono/packages/eventindexer" + "gorm.io/gorm" +) + +type NFTBalanceRepository struct { + db eventindexer.DB +} + +func NewNFTBalanceRepository(db eventindexer.DB) (*NFTBalanceRepository, error) { + if db == nil { + return nil, eventindexer.ErrNoDB + } + + return &NFTBalanceRepository{ + db: db, + }, nil +} + +func (r *NFTBalanceRepository) IncreaseBalance( + ctx context.Context, + opts eventindexer.UpdateNFTBalanceOpts, +) (*eventindexer.NFTBalance, error) { + b := &eventindexer.NFTBalance{ + ContractAddress: opts.ContractAddress, + TokenID: opts.TokenID, + Address: opts.Address, + ContractType: opts.ContractType, + ChainID: opts.ChainID, + Amount: 0, + } + + err := r.db. + GormDB(). + Where("contract_address = ?", opts.ContractAddress). + Where("token_id = ?", opts.TokenID). + Where("address = ?", opts.Address). + Where("chain_id = ?", opts.ChainID). + First(b). + Error + if err != nil { + // allow to be not found, it may be first time this user has this NFT + if err != gorm.ErrRecordNotFound { + // should always be found, since we are subtracting a balance. + // that should be indexed as a positive balance before. + return nil, errors.Wrap(err, "r.db.gormDB.First") + } + } + + b.Amount += opts.Amount + + // update the row to reflect new balance + if err := r.db.GormDB().Save(b).Error; err != nil { + return nil, errors.Wrap(err, "r.db.Save") + } + + return b, nil +} + +func (r *NFTBalanceRepository) SubtractBalance( + ctx context.Context, + opts eventindexer.UpdateNFTBalanceOpts, +) (*eventindexer.NFTBalance, error) { + b := &eventindexer.NFTBalance{ + ContractAddress: opts.ContractAddress, + TokenID: opts.TokenID, + Address: opts.Address, + ContractType: opts.ContractType, + ChainID: opts.ChainID, + } + + err := r.db. + GormDB(). + Where("contract_address = ?", opts.ContractAddress). + Where("token_id = ?", opts.TokenID). + Where("address = ?", opts.Address). + Where("chain_id = ?", opts.ChainID). + First(b). + Error + if err != nil { + // should always be found, since we are subtracting a balance. + // that should be indexed as a positive balance before. + return nil, errors.Wrap(err, "r.db.gormDB.First") + } + + b.Amount -= opts.Amount + + // we can just delete the row, this user has no more of this NFT + if b.Amount == 0 { + if err := r.db.GormDB().Delete(b).Error; err != nil { + return nil, errors.Wrap(err, "r.db.Delete") + } + } else { + // update the row instead to reflect new balance + if err := r.db.GormDB().Save(b).Error; err != nil { + return nil, errors.Wrap(err, "r.db.Save") + } + } + + return b, nil +} + +func (r *NFTBalanceRepository) FindByAddress(ctx context.Context, + req *http.Request, + address string, + chainID string, +) (paginate.Page, error) { + pg := paginate.New(&paginate.Config{ + DefaultSize: 100, + }) + + q := r.db.GormDB(). + Raw("SELECT * FROM nft_balances WHERE address = ? AND chain_id = ? AND amount > 0", address, chainID) + + reqCtx := pg.With(q) + + page := reqCtx.Request(req).Response(&[]eventindexer.NFTBalance{}) + + return page, nil +} diff --git a/packages/relayer/.golangci.yml b/packages/relayer/.golangci.yml index cd7bacf64a3..c2dca06411c 100644 --- a/packages/relayer/.golangci.yml +++ b/packages/relayer/.golangci.yml @@ -18,7 +18,7 @@ linters: - gocognit - gocritic - gofmt - - golint + # - revive - gosec - gosimple - lll @@ -39,6 +39,9 @@ issues: - path: _test\.go linters: - funlen + - path: / + linters: + - typecheck run: skip-dirs: diff --git a/packages/relayer/cli/cli.go b/packages/relayer/cli/cli.go index 08a79a5b90c..507ca109db1 100644 --- a/packages/relayer/cli/cli.go +++ b/packages/relayer/cli/cli.go @@ -3,6 +3,7 @@ package cli import ( "context" "fmt" + "log" "os" "strconv" "strings" @@ -15,7 +16,6 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/joho/godotenv" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/relayer" "github.com/taikoxyz/taiko-mono/packages/relayer/db" "github.com/taikoxyz/taiko-mono/packages/relayer/http" @@ -63,8 +63,6 @@ func Run( log.Fatal(err) } - log.SetFormatter(&log.JSONFormatter{}) - db, err := openDBConnection(relayer.DBConnectionOpts{ Name: os.Getenv("MYSQL_USER"), Password: os.Getenv("MYSQL_PASSWORD"), diff --git a/packages/relayer/indexer/detect_and_handle_reorg.go b/packages/relayer/indexer/detect_and_handle_reorg.go index b50cb07f5c4..6ad827c3030 100644 --- a/packages/relayer/indexer/detect_and_handle_reorg.go +++ b/packages/relayer/indexer/detect_and_handle_reorg.go @@ -5,7 +5,7 @@ import ( "github.com/pkg/errors" - log "github.com/sirupsen/logrus" + "log/slog" ) func (svc *Service) detectAndHandleReorg(ctx context.Context, eventType string, msgHash string) error { @@ -19,7 +19,7 @@ func (svc *Service) detectAndHandleReorg(ctx context.Context, eventType string, } // reorg detected - log.Infof("reorg detected for msgHash %v and eventType %v", msgHash, eventType) + slog.Info("reorg detected", "msgHash", msgHash, "eventType", eventType) err = svc.eventRepo.Delete(ctx, e.ID) if err != nil { diff --git a/packages/relayer/indexer/filter_then_subscribe.go b/packages/relayer/indexer/filter_then_subscribe.go index 98988962e40..2292bfc75d6 100644 --- a/packages/relayer/indexer/filter_then_subscribe.go +++ b/packages/relayer/indexer/filter_then_subscribe.go @@ -4,9 +4,11 @@ import ( "context" "fmt" + "log/slog" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/labstack/gommon/log" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/relayer" "golang.org/x/sync/errgroup" ) @@ -45,15 +47,15 @@ func (svc *Service) FilterThenSubscribe( } if svc.processingBlockHeight == header.Number.Uint64() { - log.Infof("chain ID %v caught up, subscribing to new incoming events", chainID.Uint64()) + slog.Info("indexing caught up, subscribing to new incoming events", "chainID", chainID.Uint64()) return svc.subscribe(ctx, chainID) } - log.Infof("chain ID %v getting events between %v and %v in batches of %v", - chainID.Uint64(), - svc.processingBlockHeight, - header.Number.Int64(), - svc.blockBatchSize, + slog.Info("fetching batch block events", + "chainID", chainID.Uint64(), + "startblock", svc.processingBlockHeight, + "endblock", header.Number.Int64(), + "batchsize", svc.blockBatchSize, ) for i := svc.processingBlockHeight; i < header.Number.Uint64(); i += svc.blockBatchSize { diff --git a/packages/relayer/indexer/handle_event.go b/packages/relayer/indexer/handle_event.go index aad5552363d..236249267f3 100644 --- a/packages/relayer/indexer/handle_event.go +++ b/packages/relayer/indexer/handle_event.go @@ -5,9 +5,10 @@ import ( "encoding/json" "math/big" + "log/slog" + "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/relayer" "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" ) @@ -18,14 +19,14 @@ func (svc *Service) handleEvent( chainID *big.Int, event *bridge.BridgeMessageSent, ) error { - log.Infof("event found for msgHash: %v, txHash: %v", common.Hash(event.MsgHash).Hex(), event.Raw.TxHash.Hex()) + slog.Info("event found for msgHash", "msgHash", common.Hash(event.MsgHash).Hex(), "txHash", event.Raw.TxHash.Hex()) if err := svc.detectAndHandleReorg(ctx, relayer.EventNameMessageSent, common.Hash(event.MsgHash).Hex()); err != nil { return errors.Wrap(err, "svc.detectAndHandleReorg") } if event.MsgHash == relayer.ZeroHash { - log.Warn("Zero msgHash found. This is unexpected. Returning early") + slog.Warn("Zero msgHash found. This is unexpected. Returning early") return nil } @@ -64,7 +65,7 @@ func (svc *Service) handleEvent( } if !canProcessMessage(ctx, eventStatus, event.Message.Owner, svc.relayerAddr) { - log.Warnf("cant process msgHash: %v, eventStatus: %v", common.Hash(event.MsgHash).Hex(), eventStatus) + slog.Warn("cant process message", "msgHash", common.Hash(event.MsgHash).Hex(), "eventStatus", eventStatus) return nil } @@ -85,7 +86,7 @@ func canProcessMessage( // we can not process, exit early if eventStatus == relayer.EventStatusNewOnlyOwner { if messageOwner != relayerAddress { - log.Infof("gasLimit == 0 and owner is not the current relayer key, can not process. continuing loop") + slog.Info("gasLimit == 0 and owner is not the current relayer key, can not process. continuing loop") return false } diff --git a/packages/relayer/indexer/handle_no_events_in_batch.go b/packages/relayer/indexer/handle_no_events_in_batch.go index bac69757830..71ef151c203 100644 --- a/packages/relayer/indexer/handle_no_events_in_batch.go +++ b/packages/relayer/indexer/handle_no_events_in_batch.go @@ -4,8 +4,9 @@ import ( "context" "math/big" + "log/slog" + "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/relayer" ) @@ -21,7 +22,7 @@ func (svc *Service) handleNoEventsInBatch( return errors.Wrap(err, "svc.ethClient.HeaderByNumber") } - log.Infof("setting last processed block to height: %v, hash: %v", blockNumber, header.Hash().Hex()) + slog.Info("setting last processed block", "blockNum", blockNumber, "headerHash", header.Hash().Hex()) if err := svc.blockRepo.Save(relayer.SaveBlockOpts{ Height: uint64(blockNumber), diff --git a/packages/relayer/indexer/save_message_status_changed_events.go b/packages/relayer/indexer/save_message_status_changed_events.go index ce56b07be85..9d9aa3843b1 100644 --- a/packages/relayer/indexer/save_message_status_changed_events.go +++ b/packages/relayer/indexer/save_message_status_changed_events.go @@ -5,9 +5,10 @@ import ( "encoding/json" "math/big" + "log/slog" + "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/relayer" "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" ) @@ -18,14 +19,14 @@ func (svc *Service) saveMessageStatusChangedEvents( events *bridge.BridgeMessageStatusChangedIterator, ) error { if !events.Next() || events.Event == nil { - log.Infof("no messageStatusChanged events") + slog.Info("no messageStatusChanged events") return nil } for { event := events.Event - log.Infof("messageStatusChanged: %v", common.Hash(event.MsgHash).Hex()) + slog.Info("messageStatusChanged", "msgHash", common.Hash(event.MsgHash).Hex()) if err := svc.detectAndHandleReorg( ctx, diff --git a/packages/relayer/indexer/subscribe.go b/packages/relayer/indexer/subscribe.go index 33351b68c0c..decd325d7dd 100644 --- a/packages/relayer/indexer/subscribe.go +++ b/packages/relayer/indexer/subscribe.go @@ -4,18 +4,19 @@ import ( "context" "math/big" + "log/slog" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/event" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/relayer" "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" ) // subscribe subscribes to latest events func (svc *Service) subscribe(ctx context.Context, chainID *big.Int) error { - log.Info("subscribing to new events") + slog.Info("subscribing to new events") errChan := make(chan error) @@ -27,7 +28,7 @@ func (svc *Service) subscribe(ctx context.Context, chainID *big.Int) error { for { select { case <-ctx.Done(): - log.Info("context finished") + slog.Info("context finished") return nil case err := <-errChan: relayer.ErrorsEncounteredDuringSubscription.Inc() @@ -42,10 +43,10 @@ func (svc *Service) subscribeMessageSent(ctx context.Context, chainID *big.Int, sub := event.ResubscribeErr(svc.subscriptionBackoff, func(ctx context.Context, err error) (event.Subscription, error) { if err != nil { - log.Errorf("svc.bridge.WatchMessageSent: %v", err) + slog.Error("svc.bridge.WatchMessageSent", "error", err) } - log.Info("resubscribing to WatchMessageSent events") + slog.Info("resubscribing to WatchMessageSent events") return svc.bridge.WatchMessageSent(&bind.WatchOpts{ Context: ctx, @@ -57,23 +58,23 @@ func (svc *Service) subscribeMessageSent(ctx context.Context, chainID *big.Int, for { select { case <-ctx.Done(): - log.Info("context finished") + slog.Info("context finished") return case err := <-sub.Err(): errChan <- errors.Wrap(err, "sub.Err()") case event := <-sink: go func() { - log.Infof("new message sent event %v from chainID %v", common.Hash(event.MsgHash).Hex(), chainID.String()) + slog.Info("new message sent event", "msgHash", common.Hash(event.MsgHash).Hex(), "chainID", chainID.String()) err := svc.handleEvent(ctx, chainID, event) if err != nil { - log.Errorf("svc.subscribe, svc.handleEvent: %v", err) + slog.Error("svc.subscribe, svc.handleEvent", "error", err) return } block, err := svc.blockRepo.GetLatestBlockProcessedForEvent(relayer.EventNameMessageSent, chainID) if err != nil { - log.Errorf("svc.subscribe, blockRepo.GetLatestBlockProcessedForEvent: %v", err) + slog.Error("svc.subscribe, blockRepo.GetLatestBlockProcessedForEvent", "error", err) return } @@ -85,7 +86,7 @@ func (svc *Service) subscribeMessageSent(ctx context.Context, chainID *big.Int, EventName: relayer.EventNameMessageSent, }) if err != nil { - log.Errorf("svc.subscribe, svc.blockRepo.Save: %v", err) + slog.Error("svc.subscribe, svc.blockRepo.Save", "error", err) return } @@ -101,9 +102,9 @@ func (svc *Service) subscribeMessageStatusChanged(ctx context.Context, chainID * sub := event.ResubscribeErr(svc.subscriptionBackoff, func(ctx context.Context, err error) (event.Subscription, error) { if err != nil { - log.Errorf("svc.bridge.WatchMessageStatusChanged: %v", err) + slog.Error("svc.bridge.WatchMessageStatusChanged", "error", err) } - log.Info("resubscribing to WatchMessageStatusChanged events") + slog.Info("resubscribing to WatchMessageStatusChanged events") return svc.bridge.WatchMessageStatusChanged(&bind.WatchOpts{ Context: ctx, @@ -115,15 +116,18 @@ func (svc *Service) subscribeMessageStatusChanged(ctx context.Context, chainID * for { select { case <-ctx.Done(): - log.Info("context finished") + slog.Info("context finished") return case err := <-sub.Err(): errChan <- errors.Wrap(err, "sub.Err()") case event := <-sink: - log.Infof("new message status changed event %v from chainID %v", common.Hash(event.MsgHash).Hex(), chainID.String()) + slog.Info("new message status changed event", + "msgHash", common.Hash(event.MsgHash).Hex(), + "chainID", chainID.String(), + ) if err := svc.saveMessageStatusChangedEvent(ctx, chainID, event); err != nil { - log.Errorf("svc.subscribe, svc.saveMessageStatusChangedEvent: %v", err) + slog.Error("svc.subscribe, svc.saveMessageStatusChangedEvent", "error", err) } } } diff --git a/packages/relayer/message/is_profitable.go b/packages/relayer/message/is_profitable.go index 6728fa3ac63..b4732d6d2af 100644 --- a/packages/relayer/message/is_profitable.go +++ b/packages/relayer/message/is_profitable.go @@ -4,7 +4,8 @@ import ( "context" "math/big" - log "github.com/sirupsen/logrus" + "log/slog" + "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" ) @@ -18,11 +19,10 @@ func (p *Processor) isProfitable( shouldProcess := processingFee.Cmp(cost) == 1 - log.Infof( - "processingFee: %v, cost: %v, process: %v", - processingFee.Uint64(), - cost, - shouldProcess, + slog.Info("isProfitable", + "processingFee", processingFee.Uint64(), + "cost", cost, + "shouldProcess", shouldProcess, ) if !shouldProcess { diff --git a/packages/relayer/message/process_message.go b/packages/relayer/message/process_message.go index b6b426fcb55..467c48e3bdc 100644 --- a/packages/relayer/message/process_message.go +++ b/packages/relayer/message/process_message.go @@ -4,6 +4,7 @@ import ( "context" "encoding/hex" "fmt" + "log/slog" "math/big" "strings" "time" @@ -14,7 +15,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/relayer" "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" ) @@ -57,9 +57,9 @@ func (p *Processor) ProcessMessage( encodedSignalProof, err := p.prover.EncodedSignalProof(ctx, p.rpc, p.srcSignalServiceAddress, key, latestSyncedHeader) if err != nil { - log.Errorf("srcChainID: %v, destChainID: %v, txHash: %v: msgHash: %v, from: %v encountered signalProofError %v", - event.Message.SrcChainId, - event.Message.DestChainId, + slog.Error("srcChainID: %v, destChainID: %v, txHash: %v: msgHash: %v, from: %v encountered signalProofError %v", + event.Message.SrcChainId.String(), + event.Message.DestChainId.String(), event.Raw.TxHash.Hex(), common.Hash(event.MsgHash).Hex(), event.Message.Owner.Hex(), @@ -81,11 +81,9 @@ func (p *Processor) ProcessMessage( // message will fail when we try to process it if !received { - log.Warnf( - "msgHash: %v, srcChainId: %v, encodedSignalProof: %v not received on dest chain", - common.Hash(event.MsgHash).Hex(), - event.Message.SrcChainId, - hex.EncodeToString(encodedSignalProof), + slog.Warn("Message not received on dest chain", + "msgHash", common.Hash(event.MsgHash).Hex(), + "srcChainId", event.Message.SrcChainId.String(), ) relayer.MessagesNotReceivedOnDestChain.Inc() @@ -113,18 +111,18 @@ func (p *Processor) ProcessMessage( return errors.Wrap(err, "p.saveMEssageStatusChangedEvent") } - log.Infof("Mined tx %s", hex.EncodeToString(tx.Hash().Bytes())) + slog.Info("Mined tx", "txHash", hex.EncodeToString(tx.Hash().Bytes())) messageStatus, err := p.destBridge.GetMessageStatus(&bind.CallOpts{}, event.MsgHash) if err != nil { return errors.Wrap(err, "p.destBridge.GetMessageStatus") } - log.Infof( - "updating message status to: %v for txHash: %v, processed in txHash: %v", - relayer.EventStatus(messageStatus).String(), - event.Raw.TxHash.Hex(), - hex.EncodeToString(tx.Hash().Bytes()), + slog.Info( + "updating message status", + "status", relayer.EventStatus(messageStatus).String(), + "occuredtxHash", event.Raw.TxHash.Hex(), + "processedTxHash", hex.EncodeToString(tx.Hash().Bytes()), ) if messageStatus == uint8(relayer.EventStatusRetriable) { diff --git a/packages/relayer/message/wait_header_synced.go b/packages/relayer/message/wait_header_synced.go index ca4d15b1c3b..1478b160920 100644 --- a/packages/relayer/message/wait_header_synced.go +++ b/packages/relayer/message/wait_header_synced.go @@ -2,13 +2,13 @@ package message import ( "context" + "log/slog" "math/big" "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" ) @@ -21,11 +21,10 @@ func (p *Processor) waitHeaderSynced(ctx context.Context, event *bridge.BridgeMe case <-ctx.Done(): return ctx.Err() case <-ticker.C: - log.Infof( - "msgHash: %v, txHash: %v is waiting to be processable. occurred in block %v", - common.Hash(event.MsgHash).Hex(), - event.Raw.TxHash.Hex(), - event.Raw.BlockNumber, + slog.Info("waitHeaderSynced checking if tx is processable", + "msgHash", common.Hash(event.MsgHash).Hex(), + "txHash", event.Raw.TxHash.Hex(), + "blockNumber", event.Raw.BlockNumber, ) // get latest synced header since not every header is synced from L1 => L2, // and later blocks still have the storage trie proof from previous blocks. @@ -41,23 +40,21 @@ func (p *Processor) waitHeaderSynced(ctx context.Context, event *bridge.BridgeMe // header is caught up and processible if header.Number.Uint64() >= event.Raw.BlockNumber { - log.Infof( - "msgHash: %v, txHash: %v is processable. occurred in block %v, latestSynced is block %v", - common.Hash(event.MsgHash).Hex(), - event.Raw.TxHash.Hex(), - event.Raw.BlockNumber, - header.Number.Uint64(), + slog.Info("waitHeaderSynced processable", + "msgHash", common.Hash(event.MsgHash).Hex(), + "txHash", event.Raw.TxHash.Hex(), + "eventBlockNum", event.Raw.BlockNumber, + "latestSyncedBlockNum", header.Number.Uint64(), ) return nil } - log.Infof( - "msgHash: %v, txHash: %v is waiting to be processable. occurred in block %v, latestSynced is block %v", - common.Hash(event.MsgHash).Hex(), - event.Raw.TxHash.Hex(), - event.Raw.BlockNumber, - header.Number.Uint64(), + slog.Info("waitHeaderSynced waiting to be processable", + "msgHash", common.Hash(event.MsgHash).Hex(), + "txHash", event.Raw.TxHash.Hex(), + "eventBlockNum", event.Raw.BlockNumber, + "latestSyncedBlockNum", header.Number.Uint64(), ) } } diff --git a/packages/relayer/types.go b/packages/relayer/types.go index 1157cf8f4a5..d7d050938e2 100644 --- a/packages/relayer/types.go +++ b/packages/relayer/types.go @@ -6,12 +6,13 @@ import ( "math/big" "time" + "log/slog" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/tokenvault" ) @@ -43,7 +44,7 @@ func WaitReceipt(ctx context.Context, confirmer confirmer, txHash common.Hash) ( ticker := time.NewTicker(time.Second) defer ticker.Stop() - log.Infof("waiting for transaction receipt for txHash %v", txHash.Hex()) + slog.Info("waiting for transaction receipt", "txHash", txHash.Hex()) for { select { @@ -59,7 +60,7 @@ func WaitReceipt(ctx context.Context, confirmer confirmer, txHash common.Hash) ( return nil, fmt.Errorf("transaction reverted, hash: %s", txHash) } - log.Infof("transaction receipt found for txHash %v", txHash.Hex()) + slog.Info("transaction receipt found", "txHash", txHash.Hex()) return receipt, nil } @@ -69,7 +70,7 @@ func WaitReceipt(ctx context.Context, confirmer confirmer, txHash common.Hash) ( // WaitConfirmations won't return before N blocks confirmations have been seen // on destination chain. func WaitConfirmations(ctx context.Context, confirmer confirmer, confirmations uint64, txHash common.Hash) error { - log.Infof("txHash %v beginning waiting for confirmations", txHash.Hex()) + slog.Info("beginning waiting for confirmations", "txHash", txHash.Hex()) ticker := time.NewTicker(10 * time.Second) @@ -86,7 +87,7 @@ func WaitConfirmations(ctx context.Context, confirmer confirmer, confirmations u continue } - log.Errorf("txHash: %v encountered error getting receipt: %v", txHash.Hex(), err) + slog.Error("encountered error getting receipt", "txHash", txHash.Hex(), "error", err) return err } @@ -97,19 +98,19 @@ func WaitConfirmations(ctx context.Context, confirmer confirmer, confirmations u } want := receipt.BlockNumber.Uint64() + confirmations - log.Infof( - "txHash: %v waiting for %v confirmations which will happen in block number: %v, latestBlockNumber: %v", - txHash.Hex(), - confirmations, - want, - latest, + slog.Info( + "waiting for confirmations", + "txHash", txHash.Hex(), + "confirmations", confirmations, + "blockNumWillbeConfirmed", want, + "latestBlockNum", latest, ) if latest < receipt.BlockNumber.Uint64()+confirmations { continue } - log.Infof("txHash %v received %v confirmations, done", txHash.Hex(), confirmations) + slog.Info("done waiting for confirmations", "txHash", txHash.Hex(), "confirmations", confirmations) return nil }