mirror of
https://github.com/grassrootseconomics/cic-custodial.git
synced 2025-04-19 15:01:01 +02:00
Compare commits
63 Commits
v0.2.4-alp
...
master
Author | SHA1 | Date | |
---|---|---|---|
cb40a6482a | |||
b244fc7dca | |||
5d0099f136 | |||
|
8b116f8a0f | ||
|
888fb4ce11 | ||
|
27b300db93 | ||
|
788cf66fc7 | ||
|
d2cb0796c8 | ||
9e1d62a014 | |||
98ff897049 | |||
8dc0dcf12d | |||
|
f84b90f411 | ||
|
83113c8411 | ||
|
6ccc27685c | ||
|
e821da13d4 | ||
|
2b42da206b | ||
b9d3c219c8 | |||
8ef2311d8e | |||
e91f82c08a | |||
|
223656b2bc | ||
|
0218831bd9 | ||
|
b2df62f0df | ||
|
d9acaa9583 | ||
d51e74883d | |||
0e5db7f06f | |||
b137088d38 | |||
21a17d2735 | |||
eba329eefa | |||
82294b96f8 | |||
e67a42ede3 | |||
a98fe958a3 | |||
e203c49049 | |||
448b142f7c | |||
750fdd9c1f | |||
5f5678e25b | |||
ef5bd1860f | |||
ac5567bc56 | |||
2d5e41eb81 | |||
|
fc49f2387d | ||
|
81a3bb7e3c | ||
0235f25f81 | |||
04e5d3c20f | |||
ea53214e2b | |||
ee07e61457 | |||
fe9d217b60 | |||
bbd4b57fa8 | |||
b1572cfba7 | |||
0fd35f9668 | |||
5a94a38805 | |||
0ef18b4e3e | |||
341a760f02 | |||
ec14328d49 | |||
70419a9b19 | |||
a47e44f262 | |||
a1b6cb08d8 | |||
1ddff06502 | |||
|
885163e48a | ||
|
d9806ca02c | ||
|
4dac0e8413 | ||
4dfc1725cb | |||
4372b9dbf1 | |||
010ba8c2cb | |||
add7f2a442 |
10
.dockerignore
Normal file
10
.dockerignore
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
.github
|
||||||
|
.deepsource.toml
|
||||||
|
.goreleaser.yaml
|
||||||
|
|
||||||
|
**/.env
|
||||||
|
**/.git
|
||||||
|
**/.gitignore
|
||||||
|
|
||||||
|
**/docker-compose*
|
||||||
|
**/Dockerfile*
|
13
.env.example
13
.env.example
@ -1,3 +1,10 @@
|
|||||||
POSTGRES_DSN=postgres://postgres:postgres@postgres:5432/cic_custodial
|
CUSTODIAL_CHAIN__RPC_ENDPOINT=
|
||||||
REDIS_DSN=redis://redis:6379/1
|
CUSTODIAL_SYSTEM__GAS_FAUCET_ADDRESS=
|
||||||
ASYNQ_DSN=redis://redis:6379/0
|
CUSTODIAL_SYSTEM__GIFTABLE_TOKEN_ADDRESS=
|
||||||
|
CUSTODIAL_SYSTEM__PRIVATE_KEY=
|
||||||
|
CUSTODIAL_SYSTEM__PUBLIC_KEY=
|
||||||
|
CUSTODIAL_SYSTEM__ACCOUNT_INDEX_ADDRESS=
|
||||||
|
CUSTODIAL_POSTGRES__DSN=
|
||||||
|
CUSTODIAL_REDIS__DSN=
|
||||||
|
CUSTODIAL_ASYNQ__DSN=
|
||||||
|
CUSTODIAL_JETSTREAM__ENDPOINT=
|
37
.github/workflows/binary_release.yaml
vendored
37
.github/workflows/binary_release.yaml
vendored
@ -1,37 +0,0 @@
|
|||||||
name: binary_release
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "v*"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
goreleaser:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: goreleaser/goreleaser-cross
|
|
||||||
environment: build
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Workaround Git Security Warning
|
|
||||||
run: |
|
|
||||||
# Workaround a bug in github actions:
|
|
||||||
# https://github.com/actions/runner-images/issues/6775.
|
|
||||||
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
|
||||||
|
|
||||||
- name: Set up Go
|
|
||||||
uses: actions/setup-go@v2
|
|
||||||
with:
|
|
||||||
go-version: 1.19
|
|
||||||
|
|
||||||
- name: Run GoReleaser
|
|
||||||
uses: goreleaser/goreleaser-action@v2
|
|
||||||
with:
|
|
||||||
version: latest
|
|
||||||
args: release --rm-dist
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
29
.github/workflows/docker_release.yaml
vendored
29
.github/workflows/docker_release.yaml
vendored
@ -1,29 +0,0 @@
|
|||||||
name: docker_release
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "v*"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-publish:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: docker/login-action@v1.14.1
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: docker compose build push
|
|
||||||
env:
|
|
||||||
DOCKER_BUILDKIT: 1
|
|
||||||
COMPOSE_DOCKER_CLI_BUILD: 1
|
|
||||||
run: |
|
|
||||||
export TAG=$GITHUB_REF_NAME
|
|
||||||
docker-compose -f docker-compose.build.yaml build --progress plain
|
|
||||||
docker-compose -f docker-compose.build.yaml push
|
|
||||||
export TAG=latest
|
|
||||||
docker-compose -f docker-compose.build.yaml build --progress plain
|
|
||||||
docker-compose -f docker-compose.build.yaml push
|
|
100
.github/workflows/release.yaml
vendored
Normal file
100
.github/workflows/release.yaml
vendored
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
name: release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
|
- name: Check out repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Cache Docker layers
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: /tmp/.buildx-cache
|
||||||
|
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-buildx-
|
||||||
|
|
||||||
|
- name: Login to GHCR Docker registry
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Set outputs
|
||||||
|
run: |
|
||||||
|
echo "RELEASE_TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV \
|
||||||
|
&& echo "RELEASE_SHORT_COMMIT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build and push image
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: ./
|
||||||
|
file: ./Dockerfile
|
||||||
|
platforms: linux/amd64
|
||||||
|
push: true
|
||||||
|
build-args: |
|
||||||
|
BUILD_COMMIT=${{ env.RELEASE_SHORT_COMMIT }}
|
||||||
|
cache-from: type=local,src=/tmp/.buildx-cache
|
||||||
|
cache-to: type=local,dest=/tmp/.buildx-cache
|
||||||
|
tags: |
|
||||||
|
ghcr.io/grassrootseconomics/cic-custodial/cic-custodial:latest
|
||||||
|
ghcr.io/grassrootseconomics/cic-custodial/cic-custodial:${{ env.RELEASE_TAG }}
|
||||||
|
|
||||||
|
goreleaser:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: goreleaser/goreleaser-cross
|
||||||
|
environment: build
|
||||||
|
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/go/pkg/mod
|
||||||
|
~/.cache/go-build
|
||||||
|
~/Library/Caches/go-build
|
||||||
|
%LocalAppData%\go-build
|
||||||
|
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-go-
|
||||||
|
|
||||||
|
- name: Workaround Git Security Warning
|
||||||
|
run: |
|
||||||
|
# Workaround a bug in github actions:
|
||||||
|
# https://github.com/actions/runner-images/issues/6775.
|
||||||
|
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v3
|
||||||
|
with:
|
||||||
|
go-version: 'stable'
|
||||||
|
|
||||||
|
- name: Run GoReleaser
|
||||||
|
uses: goreleaser/goreleaser-action@v2
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
args: release --rm-dist
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,4 @@
|
|||||||
cic-custodial
|
cic-custodial
|
||||||
dist
|
dist
|
||||||
.env
|
**/*.env
|
||||||
covprofile
|
covprofile
|
@ -10,12 +10,12 @@ builds:
|
|||||||
- amd64
|
- amd64
|
||||||
main: ./cmd/service
|
main: ./cmd/service
|
||||||
ldflags:
|
ldflags:
|
||||||
- -s -w
|
- -X main.build={{.ShortCommit}} -s -w
|
||||||
|
|
||||||
archives:
|
archives:
|
||||||
- format: tar.gz
|
- format: tar.gz
|
||||||
files:
|
files:
|
||||||
- LICENSE
|
- LICENSE
|
||||||
- config.toml
|
- config.toml
|
||||||
- queries
|
- queries.sql
|
||||||
- migrations
|
- migrations
|
||||||
|
28
Dockerfile
28
Dockerfile
@ -1,23 +1,33 @@
|
|||||||
FROM golang:1.19-bullseye as build
|
FROM golang:1-bullseye as build
|
||||||
|
|
||||||
|
ENV CGO_ENABLED=1
|
||||||
|
ENV GOOS=linux
|
||||||
|
ENV GOARCH=amd64
|
||||||
|
|
||||||
|
ENV BUILD_COMMIT=${BUILD_COMMIT}
|
||||||
|
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
|
COPY go.* .
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o cic-custodial -ldflags="-s -w" cmd/service/*.go
|
RUN go build -o cic-custodial -ldflags="-X main.build=${BUILD_COMMIT} -s -w" cmd/service/*
|
||||||
|
|
||||||
|
|
||||||
FROM debian:bullseye-slim
|
FROM debian:bullseye-slim
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
RUN set -x && \
|
|
||||||
apt-get update && \
|
|
||||||
apt-get install -y ca-certificates && \
|
|
||||||
rm -rf /var/cache/apt/archives /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
WORKDIR /service
|
WORKDIR /service
|
||||||
|
|
||||||
|
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||||
COPY --from=build /build/cic-custodial .
|
COPY --from=build /build/cic-custodial .
|
||||||
|
COPY migrations migrations/
|
||||||
COPY config.toml .
|
COPY config.toml .
|
||||||
COPY queries .
|
COPY queries.sql .
|
||||||
|
COPY LICENSE .
|
||||||
CMD ["./cic-custodial"]
|
|
||||||
|
|
||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
|
|
||||||
|
CMD ["./cic-custodial"]
|
||||||
|
21
Makefile
Normal file
21
Makefile
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
BIN := cic-custodial
|
||||||
|
BUILD_CONF := CGO_ENABLED=1 GOOS=linux GOARCH=amd64
|
||||||
|
BUILD_COMMIT := $(shell git rev-parse --short HEAD 2> /dev/null)
|
||||||
|
|
||||||
|
.PHONY: build run run-debug docs
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm ${BIN}
|
||||||
|
|
||||||
|
build:
|
||||||
|
${BUILD_CONF} go build -ldflags="-X main.build=${BUILD_COMMIT} -s -w" -o ${BIN} cmd/service/*
|
||||||
|
|
||||||
|
docs:
|
||||||
|
swag fmt --dir internal/api/
|
||||||
|
swag init --dir internal/api/ -g swagger.go
|
||||||
|
|
||||||
|
run:
|
||||||
|
${BUILD_CONF} go run cmd/service/*
|
||||||
|
|
||||||
|
run-debug:
|
||||||
|
${BUILD_CONF} go run cmd/service/* -debug
|
17
README.md
Normal file
17
README.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# cic-custodial
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
[](https://goreportcard.com/report/github.com/grassrootseconomics/cic-custodial)
|
||||||
|
|
||||||
|
> CIC Custodial
|
||||||
|
|
||||||
|
Experimental custodial API.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
- [Usage](docs/usage.md)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[AGPL-3.0](LICENSE).
|
@ -1,53 +1,38 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/VictoriaMetrics/metrics"
|
"github.com/VictoriaMetrics/metrics"
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
|
_ "github.com/grassrootseconomics/cic-custodial/docs"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/api"
|
"github.com/grassrootseconomics/cic-custodial/internal/api"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
||||||
"github.com/hibiken/asynq"
|
"github.com/grassrootseconomics/cic-custodial/pkg/util"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/labstack/echo/v4/middleware"
|
||||||
|
echoSwagger "github.com/swaggo/echo-swagger"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
systemGlobalLockKey = "system:global_lock"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Bootstrap API server.
|
// Bootstrap API server.
|
||||||
func initApiServer(custodialContainer *custodial.Custodial) *echo.Echo {
|
func initApiServer(custodialContainer *custodial.Custodial) *echo.Echo {
|
||||||
lo.Debug("api: bootstrapping api server")
|
customValidator := validator.New()
|
||||||
|
|
||||||
server := echo.New()
|
server := echo.New()
|
||||||
server.HideBanner = true
|
server.HideBanner = true
|
||||||
server.HidePort = true
|
server.HidePort = true
|
||||||
|
server.Validator = &api.Validator{
|
||||||
server.HTTPErrorHandler = func(err error, c echo.Context) {
|
ValidatorProvider: customValidator,
|
||||||
// Handle asynq duplication errors across all api handlers.
|
|
||||||
if errors.Is(err, asynq.ErrTaskIDConflict) {
|
|
||||||
c.JSON(http.StatusForbidden, api.ErrResp{
|
|
||||||
Ok: false,
|
|
||||||
Code: api.DUPLICATE_ERROR,
|
|
||||||
Message: "Request with duplicate tracking id submitted.",
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := err.(validator.ValidationErrors); ok {
|
|
||||||
c.JSON(http.StatusForbidden, api.ErrResp{
|
|
||||||
Ok: false,
|
|
||||||
Code: api.VALIDATION_ERROR,
|
|
||||||
Message: err.(validator.ValidationErrors).Error(),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log internal server error for further investigation.
|
|
||||||
lo.Error("api:", "path", c.Path(), "err", err)
|
|
||||||
|
|
||||||
c.JSON(http.StatusInternalServerError, api.ErrResp{
|
|
||||||
Ok: false,
|
|
||||||
Code: api.INTERNAL_ERROR,
|
|
||||||
Message: "Internal server error.",
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
server.HTTPErrorHandler = customHTTPErrorHandler
|
||||||
|
|
||||||
|
server.Use(middleware.Recover())
|
||||||
|
server.Use(middleware.BodyLimit("1M"))
|
||||||
|
server.Use(middleware.ContextTimeout(util.SLATimeout))
|
||||||
|
|
||||||
if ko.Bool("service.metrics") {
|
if ko.Bool("service.metrics") {
|
||||||
server.GET("/metrics", func(c echo.Context) error {
|
server.GET("/metrics", func(c echo.Context) error {
|
||||||
@ -56,17 +41,65 @@ func initApiServer(custodialContainer *custodial.Custodial) *echo.Echo {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
customValidator := validator.New()
|
if ko.Bool("service.docs") {
|
||||||
customValidator.RegisterValidation("eth_checksum", api.EthChecksumValidator)
|
server.GET("/docs/*", echoSwagger.WrapHandler)
|
||||||
|
|
||||||
server.Validator = &api.Validator{
|
|
||||||
ValidatorProvider: customValidator,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apiRoute := server.Group("/api")
|
apiRoute := server.Group("/api", systemGlobalLock(custodialContainer))
|
||||||
apiRoute.POST("/account/create", api.CreateAccountHandler(custodialContainer))
|
|
||||||
apiRoute.POST("/sign/transfer", api.SignTransferHandler(custodialContainer))
|
apiRoute.POST("/account/create", api.HandleAccountCreate(custodialContainer))
|
||||||
apiRoute.GET("/track/:trackingId", api.TxStatus(custodialContainer.PgStore))
|
apiRoute.GET("/account/status/:address", api.HandleNetworkAccountStatus(custodialContainer))
|
||||||
|
apiRoute.POST("/sign/transfer", api.HandleSignTransfer(custodialContainer))
|
||||||
|
apiRoute.POST("/sign/transferAuth", api.HandleSignTranserAuthorization(custodialContainer))
|
||||||
|
apiRoute.GET("/track/:trackingId", api.HandleTrackTx(custodialContainer))
|
||||||
|
|
||||||
return server
|
return server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func customHTTPErrorHandler(err error, c echo.Context) {
|
||||||
|
if c.Response().Committed {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if he, ok := err.(*echo.HTTPError); ok {
|
||||||
|
var errorMsg string
|
||||||
|
|
||||||
|
if m, ok := he.Message.(error); ok {
|
||||||
|
errorMsg = m.Error()
|
||||||
|
} else if m, ok := he.Message.(string); ok {
|
||||||
|
errorMsg = m
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(he.Code, api.ErrResp{
|
||||||
|
Ok: false,
|
||||||
|
Message: errorMsg,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lo.Error("api: echo error", "path", c.Path(), "err", err)
|
||||||
|
c.JSON(http.StatusInternalServerError, api.ErrResp{
|
||||||
|
Ok: false,
|
||||||
|
Message: "Internal server error.",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func systemGlobalLock(cu *custodial.Custodial) echo.MiddlewareFunc {
|
||||||
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
|
return func(c echo.Context) error {
|
||||||
|
locked, err := cu.RedisClient.Get(c.Request().Context(), systemGlobalLockKey).Bool()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if locked {
|
||||||
|
return c.JSON(http.StatusServiceUnavailable, api.ErrResp{
|
||||||
|
Ok: false,
|
||||||
|
Message: "System manually locked.",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return next(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"math/big"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
eth_crypto "github.com/celo-org/celo-blockchain/crypto"
|
|
||||||
"github.com/go-redis/redis/v8"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/nonce"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
|
||||||
"github.com/grassrootseconomics/w3-celo-patch"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Define common smart contrcat ABI's that can be injected into the system container.
|
|
||||||
// Any relevant function signature that will be used by the custodial system can be defined here.
|
|
||||||
func initAbis() map[string]*w3.Func {
|
|
||||||
return map[string]*w3.Func{
|
|
||||||
// Keccak hash -> 0x449a52f8
|
|
||||||
"mintTo": w3.MustNewFunc("mintTo(address, uint256)", "bool"),
|
|
||||||
// Keccak hash -> 0xa9059cbb
|
|
||||||
"transfer": w3.MustNewFunc("transfer(address,uint256)", "bool"),
|
|
||||||
// Keccak hash -> 0x23b872dd
|
|
||||||
"transferFrom": w3.MustNewFunc("transferFrom(address, address, uint256)", "bool"),
|
|
||||||
// Add to account index
|
|
||||||
"add": w3.MustNewFunc("add(address)", "bool"),
|
|
||||||
// giveTo gas refill
|
|
||||||
"giveTo": w3.MustNewFunc("giveTo(address)", "uint256"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bootstrap the internal custodial system configs and system signer key.
|
|
||||||
// This container is passed down to individual tasker and API handlers.
|
|
||||||
func initSystemContainer(ctx context.Context, noncestore nonce.Noncestore) (*tasker.SystemContainer, error) {
|
|
||||||
// Some custodial system defaults loaded from the config file.
|
|
||||||
systemContainer := &tasker.SystemContainer{
|
|
||||||
Abis: initAbis(),
|
|
||||||
AccountIndexContract: w3.A(ko.MustString("system.account_index")),
|
|
||||||
GasFaucetContract: w3.A(ko.MustString("system.gas_faucet")),
|
|
||||||
GasRefillThreshold: big.NewInt(ko.MustInt64("system.gas_refill_threshold")),
|
|
||||||
GasRefillValue: big.NewInt(ko.MustInt64("system.gas_refill_value")),
|
|
||||||
GiftableGasValue: big.NewInt(ko.MustInt64("system.giftable_gas_value")),
|
|
||||||
GiftableToken: w3.A(ko.MustString("system.giftable_token_address")),
|
|
||||||
GiftableTokenValue: big.NewInt(ko.MustInt64("system.giftable_token_value")),
|
|
||||||
LockPrefix: ko.MustString("system.lock_prefix"),
|
|
||||||
LockTimeout: 1 * time.Second,
|
|
||||||
PublicKey: ko.MustString("system.public_key"),
|
|
||||||
TokenDecimals: ko.MustInt("system.token_decimals"),
|
|
||||||
TokenTransferGasLimit: uint64(ko.MustInt64("system.token_transfer_gas_limit")),
|
|
||||||
}
|
|
||||||
// Check if system signer account nonce is present.
|
|
||||||
// If not (first boot), we bootstrap it from the network.
|
|
||||||
currentSystemNonce, err := noncestore.Peek(ctx, ko.MustString("system.public_key"))
|
|
||||||
lo.Info("custodial: loaded (noncestore) system nonce", "nonce", currentSystemNonce)
|
|
||||||
if err == redis.Nil {
|
|
||||||
nonce, err := noncestore.SyncNetworkNonce(ctx, ko.MustString("system.public_key"))
|
|
||||||
lo.Info("custodial: syncing system nonce", "nonce", nonce)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadedPrivateKey, err := eth_crypto.HexToECDSA(ko.MustString("system.private_key"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
systemContainer.PrivateKey = loadedPrivateKey
|
|
||||||
|
|
||||||
return systemContainer, nil
|
|
||||||
}
|
|
@ -1,36 +1,32 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/bsm/redislock"
|
"github.com/bsm/redislock"
|
||||||
"github.com/grassrootseconomics/celoutils"
|
"github.com/grassrootseconomics/celoutils"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/events"
|
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/keystore"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/nonce"
|
"github.com/grassrootseconomics/cic-custodial/internal/nonce"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/queries"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/internal/sub"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
||||||
"github.com/grassrootseconomics/cic-custodial/pkg/logg"
|
"github.com/grassrootseconomics/cic-custodial/pkg/logg"
|
||||||
"github.com/grassrootseconomics/cic-custodial/pkg/postgres"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/pkg/redis"
|
"github.com/grassrootseconomics/cic-custodial/pkg/redis"
|
||||||
"github.com/jackc/pgx/v5/pgxpool"
|
|
||||||
"github.com/knadh/goyesql/v2"
|
|
||||||
"github.com/knadh/koanf"
|
|
||||||
"github.com/knadh/koanf/parsers/toml"
|
"github.com/knadh/koanf/parsers/toml"
|
||||||
"github.com/knadh/koanf/providers/env"
|
"github.com/knadh/koanf/providers/env"
|
||||||
"github.com/knadh/koanf/providers/file"
|
"github.com/knadh/koanf/providers/file"
|
||||||
|
"github.com/knadh/koanf/v2"
|
||||||
|
"github.com/nats-io/nats.go"
|
||||||
"github.com/zerodha/logf"
|
"github.com/zerodha/logf"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Load logger.
|
// Load logger.
|
||||||
func initLogger(debug bool) logf.Logger {
|
func initLogger() logf.Logger {
|
||||||
loggOpts := logg.LoggOpts{
|
loggOpts := logg.LoggOpts{}
|
||||||
Color: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
if debug {
|
if debugFlag {
|
||||||
|
loggOpts.Color = true
|
||||||
loggOpts.Caller = true
|
loggOpts.Caller = true
|
||||||
loggOpts.Debug = true
|
loggOpts.Debug = true
|
||||||
}
|
}
|
||||||
@ -39,28 +35,32 @@ func initLogger(debug bool) logf.Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load config file.
|
// Load config file.
|
||||||
func initConfig(configFilePath string) *koanf.Koanf {
|
func initConfig() *koanf.Koanf {
|
||||||
var (
|
var (
|
||||||
ko = koanf.New(".")
|
ko = koanf.New(".")
|
||||||
)
|
)
|
||||||
|
|
||||||
confFile := file.Provider(configFilePath)
|
confFile := file.Provider(confFlag)
|
||||||
if err := ko.Load(confFile, toml.Parser()); err != nil {
|
if err := ko.Load(confFile, toml.Parser()); err != nil {
|
||||||
lo.Fatal("Could not load config file", "error", err)
|
lo.Fatal("init: could not load config file", "error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ko.Load(env.Provider("", ".", func(s string) string {
|
if err := ko.Load(env.Provider("CUSTODIAL_", ".", func(s string) string {
|
||||||
return strings.ReplaceAll(strings.ToLower(
|
return strings.ReplaceAll(strings.ToLower(
|
||||||
strings.TrimPrefix(s, "")), "_", ".")
|
strings.TrimPrefix(s, "CUSTODIAL_")), "__", ".")
|
||||||
}), nil); err != nil {
|
}), nil); err != nil {
|
||||||
lo.Fatal("Could not override config from env vars", "error", err)
|
lo.Fatal("init: could not override config from env vars", "error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if debugFlag {
|
||||||
|
ko.Print()
|
||||||
}
|
}
|
||||||
|
|
||||||
return ko
|
return ko
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load Celo chain provider.
|
// Load Celo chain provider.
|
||||||
func initCeloProvider() (*celoutils.Provider, error) {
|
func initCeloProvider() *celoutils.Provider {
|
||||||
providerOpts := celoutils.ProviderOpts{
|
providerOpts := celoutils.ProviderOpts{
|
||||||
RpcEndpoint: ko.MustString("chain.rpc_endpoint"),
|
RpcEndpoint: ko.MustString("chain.rpc_endpoint"),
|
||||||
}
|
}
|
||||||
@ -73,86 +73,48 @@ func initCeloProvider() (*celoutils.Provider, error) {
|
|||||||
|
|
||||||
provider, err := celoutils.NewProvider(providerOpts)
|
provider, err := celoutils.NewProvider(providerOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
lo.Fatal("init: critical error loading chain provider", "error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return provider, nil
|
return provider
|
||||||
}
|
|
||||||
|
|
||||||
// Load postgres pool.
|
|
||||||
func initPostgresPool() (*pgxpool.Pool, error) {
|
|
||||||
poolOpts := postgres.PostgresPoolOpts{
|
|
||||||
DSN: ko.MustString("postgres.dsn"),
|
|
||||||
}
|
|
||||||
|
|
||||||
pool, err := postgres.NewPostgresPool(poolOpts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return pool, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load separate redis connection for the tasker on a reserved db namespace.
|
// Load separate redis connection for the tasker on a reserved db namespace.
|
||||||
func initAsynqRedisPool() (*redis.RedisPool, error) {
|
func initAsynqRedisPool() *redis.RedisPool {
|
||||||
poolOpts := redis.RedisPoolOpts{
|
poolOpts := redis.RedisPoolOpts{
|
||||||
DSN: ko.MustString("asynq.dsn"),
|
DSN: ko.MustString("asynq.dsn"),
|
||||||
MinIdleConns: ko.MustInt("redis.min_idle_conn"),
|
MinIdleConns: ko.MustInt("redis.min_idle_conn"),
|
||||||
}
|
}
|
||||||
|
|
||||||
pool, err := redis.NewRedisPool(poolOpts)
|
pool, err := redis.NewRedisPool(context.Background(), poolOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
lo.Fatal("init: critical error connecting to asynq redis db", "error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pool, nil
|
return pool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Common redis connection on a different db namespace from the takser.
|
// Common redis connection on a different db namespace from the takser.
|
||||||
func initCommonRedisPool() (*redis.RedisPool, error) {
|
func initCommonRedisPool() *redis.RedisPool {
|
||||||
poolOpts := redis.RedisPoolOpts{
|
poolOpts := redis.RedisPoolOpts{
|
||||||
DSN: ko.MustString("redis.dsn"),
|
DSN: ko.MustString("redis.dsn"),
|
||||||
MinIdleConns: ko.MustInt("redis.min_idle_conn"),
|
MinIdleConns: ko.MustInt("redis.min_idle_conn"),
|
||||||
}
|
}
|
||||||
|
|
||||||
pool, err := redis.NewRedisPool(poolOpts)
|
pool, err := redis.NewRedisPool(context.Background(), poolOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
lo.Fatal("init: critical error connecting to common redis db", "error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pool, nil
|
return pool
|
||||||
}
|
|
||||||
|
|
||||||
// Load SQL statements into struct.
|
|
||||||
func initQueries(queriesPath string) (*queries.Queries, error) {
|
|
||||||
parsedQueries, err := goyesql.ParseFile(queriesPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
loadedQueries, err := queries.LoadQueries(parsedQueries)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return loadedQueries, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load postgres based keystore.
|
|
||||||
func initPostgresKeystore(postgresPool *pgxpool.Pool, queries *queries.Queries) (keystore.Keystore, error) {
|
|
||||||
keystore := keystore.NewPostgresKeytore(keystore.Opts{
|
|
||||||
PostgresPool: postgresPool,
|
|
||||||
Queries: queries,
|
|
||||||
})
|
|
||||||
|
|
||||||
return keystore, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load redis backed noncestore.
|
// Load redis backed noncestore.
|
||||||
func initRedisNoncestore(redisPool *redis.RedisPool, celoProvider *celoutils.Provider) nonce.Noncestore {
|
func initRedisNoncestore(redisPool *redis.RedisPool, chainProvider *celoutils.Provider, store store.Store) nonce.Noncestore {
|
||||||
return nonce.NewRedisNoncestore(nonce.Opts{
|
return nonce.NewRedisNoncestore(nonce.Opts{
|
||||||
RedisPool: redisPool,
|
ChainProvider: chainProvider,
|
||||||
CeloProvider: celoProvider,
|
RedisPool: redisPool,
|
||||||
|
Store: store,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,30 +126,50 @@ func initLockProvider(redisPool redislock.RedisClient) *redislock.Client {
|
|||||||
// Load tasker client.
|
// Load tasker client.
|
||||||
func initTaskerClient(redisPool *redis.RedisPool) *tasker.TaskerClient {
|
func initTaskerClient(redisPool *redis.RedisPool) *tasker.TaskerClient {
|
||||||
return tasker.NewTaskerClient(tasker.TaskerClientOpts{
|
return tasker.NewTaskerClient(tasker.TaskerClientOpts{
|
||||||
RedisPool: redisPool,
|
RedisPool: redisPool,
|
||||||
TaskRetention: time.Duration(ko.MustInt64("asynq.task_retention_hrs")) * time.Hour,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load Postgres store
|
// Load Postgres store.
|
||||||
func initPostgresStore(postgresPool *pgxpool.Pool, queries *queries.Queries) store.Store {
|
func initPgStore() store.Store {
|
||||||
return store.NewPostgresStore(store.Opts{
|
store, err := store.NewPgStore(store.Opts{
|
||||||
PostgresPool: postgresPool,
|
DSN: ko.MustString("postgres.dsn"),
|
||||||
Queries: queries,
|
MigrationsFolderPath: migrationsFolderFlag,
|
||||||
|
QueriesFolderPath: queriesFlag,
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// Init JetStream context for tasker events.
|
|
||||||
func initJetStream() (events.EventEmitter, error) {
|
|
||||||
jsEmitter, err := events.NewJetStreamEventEmitter(events.JetStreamOpts{
|
|
||||||
ServerUrl: ko.MustString("jetstream.endpoint"),
|
|
||||||
PersistDuration: time.Duration(ko.MustInt("jetstream.persist_duration_hours")) * time.Hour,
|
|
||||||
DedupDuration: time.Duration(ko.MustInt("jetstream.dedup_duration_hours")) * time.Hour,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
lo.Fatal("init: critical error loading Postgres store", "error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return jsEmitter, nil
|
return store
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init JetStream context for both pub/sub.
|
||||||
|
func initJetStream() (*nats.Conn, nats.JetStreamContext) {
|
||||||
|
natsConn, err := nats.Connect(ko.MustString("jetstream.endpoint"))
|
||||||
|
if err != nil {
|
||||||
|
lo.Fatal("init: critical error connecting to NATS", "error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
js, err := natsConn.JetStream()
|
||||||
|
if err != nil {
|
||||||
|
lo.Fatal("init: bad JetStream opts", "error", err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return natsConn, js
|
||||||
|
}
|
||||||
|
|
||||||
|
func initSub(natsConn *nats.Conn, jsCtx nats.JetStreamContext, cu *custodial.Custodial) *sub.Sub {
|
||||||
|
sub, err := sub.NewSub(sub.SubOpts{
|
||||||
|
CustodialContainer: cu,
|
||||||
|
JsCtx: jsCtx,
|
||||||
|
Logg: lo,
|
||||||
|
NatsConn: natsConn,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
lo.Fatal("init: critical error bootstrapping sub", "error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return sub
|
||||||
}
|
}
|
||||||
|
@ -3,23 +3,30 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/internal/sub"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
||||||
"github.com/knadh/koanf"
|
"github.com/knadh/koanf/v2"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/zerodha/logf"
|
"github.com/zerodha/logf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type internalServicesContainer struct {
|
||||||
|
apiService *echo.Echo
|
||||||
|
jetstreamSub *sub.Sub
|
||||||
|
taskerService *tasker.TaskerServer
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
confFlag string
|
build string
|
||||||
debugFlag bool
|
|
||||||
queriesFlag string
|
confFlag string
|
||||||
|
debugFlag bool
|
||||||
|
migrationsFolderFlag string
|
||||||
|
queriesFlag string
|
||||||
|
|
||||||
lo logf.Logger
|
lo logf.Logger
|
||||||
ko *koanf.Koanf
|
ko *koanf.Koanf
|
||||||
@ -27,88 +34,59 @@ var (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flag.StringVar(&confFlag, "config", "config.toml", "Config file location")
|
flag.StringVar(&confFlag, "config", "config.toml", "Config file location")
|
||||||
flag.BoolVar(&debugFlag, "log", false, "Enable debug logging")
|
flag.BoolVar(&debugFlag, "debug", false, "Enable debug logging")
|
||||||
flag.StringVar(&queriesFlag, "queries", "queries/queries.sql", "Queries file location")
|
flag.StringVar(&migrationsFolderFlag, "migrations", "migrations/", "Migrations folder location")
|
||||||
|
flag.StringVar(&queriesFlag, "queries", "queries.sql", "Queries file location")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
lo = initLogger(debugFlag)
|
lo = initLogger()
|
||||||
ko = initConfig(confFlag)
|
ko = initConfig()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var (
|
lo.Info("main: starting cic-custodial", "build", build)
|
||||||
tasker *tasker.TaskerServer
|
|
||||||
apiServer *echo.Echo
|
|
||||||
)
|
|
||||||
|
|
||||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
celoProvider := initCeloProvider()
|
||||||
defer stop()
|
asynqRedisPool := initAsynqRedisPool()
|
||||||
|
redisPool := initCommonRedisPool()
|
||||||
|
|
||||||
queries, err := initQueries(queriesFlag)
|
store := initPgStore()
|
||||||
if err != nil {
|
redisNoncestore := initRedisNoncestore(redisPool, celoProvider, store)
|
||||||
lo.Fatal("main: critical error loading SQL queries", "error", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
celoProvider, err := initCeloProvider()
|
|
||||||
if err != nil {
|
|
||||||
lo.Fatal("main: critical error loading chain provider", "error", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
postgresPool, err := initPostgresPool()
|
|
||||||
if err != nil {
|
|
||||||
lo.Fatal("main: critical error connecting to postgres", "error", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
asynqRedisPool, err := initAsynqRedisPool()
|
|
||||||
if err != nil {
|
|
||||||
lo.Fatal("main: critical error connecting to asynq redis db", "error", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
redisPool, err := initCommonRedisPool()
|
|
||||||
if err != nil {
|
|
||||||
lo.Fatal("main: critical error connecting to common redis db", "error", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
postgresKeystore, err := initPostgresKeystore(postgresPool, queries)
|
|
||||||
if err != nil {
|
|
||||||
lo.Fatal("main: critical error loading keystore")
|
|
||||||
}
|
|
||||||
|
|
||||||
jsEventEmitter, err := initJetStream()
|
|
||||||
if err != nil {
|
|
||||||
lo.Fatal("main: critical error loading jetstream event emitter")
|
|
||||||
}
|
|
||||||
|
|
||||||
pgStore := initPostgresStore(postgresPool, queries)
|
|
||||||
redisNoncestore := initRedisNoncestore(redisPool, celoProvider)
|
|
||||||
lockProvider := initLockProvider(redisPool.Client)
|
lockProvider := initLockProvider(redisPool.Client)
|
||||||
taskerClient := initTaskerClient(asynqRedisPool)
|
taskerClient := initTaskerClient(asynqRedisPool)
|
||||||
|
|
||||||
systemContainer, err := initSystemContainer(context.Background(), redisNoncestore)
|
natsConn, jsCtx := initJetStream()
|
||||||
|
|
||||||
|
custodial, err := custodial.NewCustodial(custodial.Opts{
|
||||||
|
ApprovalTimeout: ko.MustDuration("system.approve_timeout"),
|
||||||
|
CeloProvider: celoProvider,
|
||||||
|
LockProvider: lockProvider,
|
||||||
|
Logg: lo,
|
||||||
|
Noncestore: redisNoncestore,
|
||||||
|
Store: store,
|
||||||
|
RedisClient: redisPool.Client,
|
||||||
|
RegistryAddress: ko.MustString("chain.registry_address"),
|
||||||
|
SystemPrivateKey: ko.MustString("system.private_key"),
|
||||||
|
SystemPublicKey: ko.MustString("system.public_key"),
|
||||||
|
TaskerClient: taskerClient,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lo.Fatal("main: critical error bootstrapping system container", "error", err)
|
lo.Fatal("main: crtical error loading custodial container", "error", err)
|
||||||
}
|
|
||||||
|
|
||||||
custodial := &custodial.Custodial{
|
|
||||||
CeloProvider: celoProvider,
|
|
||||||
EventEmitter: jsEventEmitter,
|
|
||||||
Keystore: postgresKeystore,
|
|
||||||
LockProvider: lockProvider,
|
|
||||||
Noncestore: redisNoncestore,
|
|
||||||
PgStore: pgStore,
|
|
||||||
SystemContainer: systemContainer,
|
|
||||||
TaskerClient: taskerClient,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internalServices := &internalServicesContainer{}
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
|
|
||||||
apiServer = initApiServer(custodial)
|
signalCh, closeCh := createSigChannel()
|
||||||
|
defer closeCh()
|
||||||
|
|
||||||
|
internalServices.apiService = initApiServer(custodial)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
lo.Info("main: starting API server")
|
host := ko.MustString("service.address")
|
||||||
if err := apiServer.Start(ko.MustString("service.address")); err != nil {
|
lo.Info("main: starting API server", "host", host)
|
||||||
|
if err := internalServices.apiService.Start(host); err != nil {
|
||||||
if strings.Contains(err.Error(), "Server closed") {
|
if strings.Contains(err.Error(), "Server closed") {
|
||||||
lo.Info("main: shutting down server")
|
lo.Info("main: shutting down server")
|
||||||
} else {
|
} else {
|
||||||
@ -117,25 +95,28 @@ func main() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
tasker = initTasker(custodial, asynqRedisPool)
|
internalServices.taskerService = initTasker(custodial, asynqRedisPool)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
lo.Info("Starting tasker")
|
lo.Info("main: starting tasker")
|
||||||
if err := tasker.Start(); err != nil {
|
if err := internalServices.taskerService.Start(); err != nil {
|
||||||
lo.Fatal("main: could not start task server", "err", err)
|
lo.Fatal("main: could not start task server", "err", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
<-ctx.Done()
|
internalServices.jetstreamSub = initSub(natsConn, jsCtx, custodial)
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
lo.Info("main: starting jetstream sub")
|
||||||
|
if err := internalServices.jetstreamSub.Process(); err != nil {
|
||||||
|
lo.Fatal("main: error running jetstream sub", "err", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
lo.Info("main: stopping tasker")
|
lo.Info("main: graceful shutdown triggered", "signal", <-signalCh)
|
||||||
tasker.Stop()
|
startGracefulShutdown(context.Background(), internalServices)
|
||||||
|
|
||||||
lo.Info("main: stopping api server")
|
|
||||||
if err := apiServer.Shutdown(ctx); err != nil {
|
|
||||||
lo.Error("Could not gracefully shutdown api server", "err", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bsm/redislock"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/tasker/task"
|
"github.com/grassrootseconomics/cic-custodial/internal/tasker/task"
|
||||||
@ -8,26 +12,70 @@ import (
|
|||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
fixedRetryCount = 25
|
||||||
|
fixedRetryPeriod = time.Second * 1
|
||||||
|
)
|
||||||
|
|
||||||
// Load tasker handlers, injecting any necessary handler dependencies from the system container.
|
// Load tasker handlers, injecting any necessary handler dependencies from the system container.
|
||||||
func initTasker(custodialContainer *custodial.Custodial, redisPool *redis.RedisPool) *tasker.TaskerServer {
|
func initTasker(custodialContainer *custodial.Custodial, redisPool *redis.RedisPool) *tasker.TaskerServer {
|
||||||
lo.Debug("Bootstrapping tasker")
|
|
||||||
|
|
||||||
taskerServerOpts := tasker.TaskerServerOpts{
|
taskerServerOpts := tasker.TaskerServerOpts{
|
||||||
Concurrency: ko.MustInt("asynq.worker_count"),
|
Concurrency: ko.MustInt("asynq.worker_count"),
|
||||||
Logg: lo,
|
IsFailureHandler: isFailureHandler,
|
||||||
LogLevel: asynq.InfoLevel,
|
Logg: lo,
|
||||||
RedisPool: redisPool,
|
LogLevel: asynq.InfoLevel,
|
||||||
|
RedisPool: redisPool,
|
||||||
|
RetryHandler: retryHandler,
|
||||||
}
|
}
|
||||||
|
|
||||||
taskerServer := tasker.NewTaskerServer(taskerServerOpts)
|
taskerServer := tasker.NewTaskerServer(taskerServerOpts)
|
||||||
|
|
||||||
taskerServer.RegisterHandlers(tasker.AccountPrepareTask, task.AccountPrepare(custodialContainer))
|
taskerServer.RegisterMiddlewareStack([]asynq.MiddlewareFunc{
|
||||||
|
observibilityMiddleware(),
|
||||||
|
})
|
||||||
|
|
||||||
taskerServer.RegisterHandlers(tasker.AccountRegisterTask, task.AccountRegisterOnChainProcessor(custodialContainer))
|
taskerServer.RegisterHandlers(tasker.AccountRegisterTask, task.AccountRegisterOnChainProcessor(custodialContainer))
|
||||||
taskerServer.RegisterHandlers(tasker.AccountGiftGasTask, task.AccountGiftGasProcessor(custodialContainer))
|
|
||||||
taskerServer.RegisterHandlers(tasker.AccountGiftVoucherTask, task.GiftVoucherProcessor(custodialContainer))
|
|
||||||
taskerServer.RegisterHandlers(tasker.AccountRefillGasTask, task.AccountRefillGasProcessor(custodialContainer))
|
taskerServer.RegisterHandlers(tasker.AccountRefillGasTask, task.AccountRefillGasProcessor(custodialContainer))
|
||||||
taskerServer.RegisterHandlers(tasker.SignTransferTask, task.SignTransfer(custodialContainer))
|
taskerServer.RegisterHandlers(tasker.SignTransferTask, task.SignTransfer(custodialContainer))
|
||||||
|
taskerServer.RegisterHandlers(tasker.SignTransferTaskAuth, task.SignTransferAuthorizationProcessor(custodialContainer))
|
||||||
taskerServer.RegisterHandlers(tasker.DispatchTxTask, task.DispatchTx(custodialContainer))
|
taskerServer.RegisterHandlers(tasker.DispatchTxTask, task.DispatchTx(custodialContainer))
|
||||||
|
|
||||||
return taskerServer
|
return taskerServer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isFailureHandler(err error) bool {
|
||||||
|
switch err {
|
||||||
|
// Ignore lock contention errors; retry until lock obtain.
|
||||||
|
case redislock.ErrNotObtained:
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func retryHandler(count int, err error, task *asynq.Task) time.Duration {
|
||||||
|
if count < fixedRetryCount {
|
||||||
|
return fixedRetryPeriod
|
||||||
|
} else {
|
||||||
|
return asynq.DefaultRetryDelayFunc(count, err, task)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func observibilityMiddleware() asynq.MiddlewareFunc {
|
||||||
|
return func(handler asynq.Handler) asynq.Handler {
|
||||||
|
return asynq.HandlerFunc(func(ctx context.Context, task *asynq.Task) error {
|
||||||
|
taskId, _ := asynq.GetTaskID(ctx)
|
||||||
|
|
||||||
|
err := handler.ProcessTask(ctx, task)
|
||||||
|
if err != nil && isFailureHandler(err) {
|
||||||
|
lo.Error("tasker: handler error", "err", err, "task_type", task.Type(), "task_id", taskId)
|
||||||
|
} else if asynq.IsPanicError(err) {
|
||||||
|
lo.Error("tasker: handler panic", "err", err, "task_type", task.Type(), "task_id", taskId)
|
||||||
|
} else {
|
||||||
|
lo.Info("tasker: process task", "task_type", task.Type(), "task_id", taskId)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
31
cmd/service/utils.go
Normal file
31
cmd/service/utils.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func createSigChannel() (chan os.Signal, func()) {
|
||||||
|
signalCh := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
|
||||||
|
|
||||||
|
return signalCh, func() {
|
||||||
|
close(signalCh)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func startGracefulShutdown(ctx context.Context, internalServices *internalServicesContainer) {
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
internalServices.jetstreamSub.Close()
|
||||||
|
|
||||||
|
if err := internalServices.apiService.Shutdown(ctx); err != nil {
|
||||||
|
lo.Fatal("Could not gracefully shutdown api server", "err", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
internalServices.taskerService.Stop()
|
||||||
|
}
|
54
config.toml
54
config.toml
@ -1,53 +1,35 @@
|
|||||||
[service]
|
[service]
|
||||||
address = ":5005"
|
address = ":5000"
|
||||||
# Exposes Prometheus metrics
|
# Exposes Go process Prometheus metrics
|
||||||
# /metrics endpoint
|
# /metrics endpoint
|
||||||
metrics = true
|
metrics = true
|
||||||
|
docs = false
|
||||||
|
|
||||||
[chain]
|
[chain]
|
||||||
rpc_endpoint = "https://rpc.alfajores.celo.grassecon.net"
|
rpc_endpoint = ""
|
||||||
testnet = true
|
testnet = true
|
||||||
|
registry_address = ""
|
||||||
|
|
||||||
# System default values
|
|
||||||
# Valus are in wei unless otherwise stated
|
|
||||||
[system]
|
[system]
|
||||||
# The giftable token is a training voucher
|
private_key = ""
|
||||||
# Every new user is given 5 DGFT
|
public_key = ""
|
||||||
gas_faucet = "0xf2a1fc19Ad275A0EAe3445798761FeD1Eea725d5"
|
approve_timeout = "30m"
|
||||||
giftable_token_address = "0xB92463E2262E700e29c16416270c9Fdfa17934D7"
|
|
||||||
giftable_token_value = 5000000
|
|
||||||
gas_refill_threshold = 20000000000000000
|
|
||||||
gas_refill_value = 10000000000000000
|
|
||||||
# Every custodial account is given 2 KES worth of CELO
|
|
||||||
giftable_gas_value = 10000000000000000
|
|
||||||
# System private key
|
|
||||||
# Should always be toped up
|
|
||||||
private_key = "95f04bc8321cbf693db9cc2bc063411bbd8bee0e4a03dea096c755d8bcca42c6"
|
|
||||||
lock_prefix = "lock:"
|
|
||||||
public_key = "0x0577AE5A3547AC753aC499E282557CE0275a4942"
|
|
||||||
token_decimals = 6
|
|
||||||
token_transfer_gas_limit = 200000
|
|
||||||
account_index = "0x1e041282695C66944BfC53cabce947cf35CEaf87"
|
|
||||||
|
|
||||||
[postgres]
|
[postgres]
|
||||||
debug = false
|
dsn = ""
|
||||||
dsn = "postgres://postgres:postgres@localhost:5432/cic_custodial"
|
|
||||||
|
|
||||||
[redis]
|
[redis]
|
||||||
debug = false
|
# Used for locks and the Noncestore
|
||||||
dsn = "redis://localhost:6379/1"
|
# Ideally use DB 1
|
||||||
|
dsn = ""
|
||||||
min_idle_conn = 5
|
min_idle_conn = 5
|
||||||
|
|
||||||
[asynq]
|
[asynq]
|
||||||
worker_count = 15
|
# Exclusively used by the asynq tasker
|
||||||
debug = false
|
# Ideally use DB 0
|
||||||
dsn = "redis://localhost:6379/0"
|
dsn = ""
|
||||||
task_retention_hrs = 24
|
task_retention_hrs = 24
|
||||||
|
worker_count = 15
|
||||||
|
|
||||||
# https://docs.nats.io/
|
|
||||||
[jetstream]
|
[jetstream]
|
||||||
endpoint = "nats://localhost:4222"
|
endpoint = ""
|
||||||
# Duration JetStream should keep the message before remocing it from the persistent store
|
|
||||||
persist_duration_hours = 48
|
|
||||||
# Duration to ignore duplicate transactions (e.g. due to restart)
|
|
||||||
dedup_duration_hours = 6
|
|
@ -1,7 +1,7 @@
|
|||||||
version: "3.9"
|
version: "3.9"
|
||||||
services:
|
services:
|
||||||
redis:
|
redis:
|
||||||
image: redis:6-alpine
|
image: redis:7-alpine
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: redis-server --save 60 1 --loglevel warning
|
command: redis-server --save 60 1 --loglevel warning
|
||||||
volumes:
|
volumes:
|
||||||
@ -20,9 +20,9 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
- POSTGRES_PASSWORD=postgres
|
- POSTGRES_PASSWORD=postgres
|
||||||
- POSTGRES_USER=postgres
|
- POSTGRES_USER=postgres
|
||||||
- POSTGRES_DB=cic_custodial
|
|
||||||
volumes:
|
volumes:
|
||||||
- cic-custodial-pg:/var/lib/postgresql/data
|
- cic-custodial-pg:/var/lib/postgresql/data
|
||||||
|
- ./init_db.sql:/docker-entrypoint-initdb.d/init_db.sql
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:5432:5432"
|
- "127.0.0.1:5432:5432"
|
||||||
healthcheck:
|
healthcheck:
|
||||||
@ -37,8 +37,8 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- cic-custodial-nats:/nats/data
|
- cic-custodial-nats:/nats/data
|
||||||
ports:
|
ports:
|
||||||
- "4222:4222"
|
- "127.0.0.1:4222:4222"
|
||||||
- "8222:8222"
|
- "127.0.0.1:8222:8222"
|
||||||
asynqmon:
|
asynqmon:
|
||||||
image: hibiken/asynqmon
|
image: hibiken/asynqmon
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@ -49,6 +49,16 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
cic-chain-events:
|
||||||
|
image: ghcr.io/grassrootseconomics/cic-chain-events/cic-chain-events:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file:
|
||||||
|
- events.env
|
||||||
|
ports:
|
||||||
|
- '127.0.0.1:5001:5000'
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
cic-custodial-pg:
|
cic-custodial-pg:
|
||||||
driver: local
|
driver: local
|
2
dev/init_db.sql
Normal file
2
dev/init_db.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
CREATE DATABASE cic_custodial;
|
||||||
|
CREATE DATABASE cic_chain_events;
|
@ -1,10 +0,0 @@
|
|||||||
version: '3.9'
|
|
||||||
services:
|
|
||||||
cic-custodial:
|
|
||||||
image: ${IMAGE_BASE_URL:-ghcr.io/grassrootseconomics/cic-custodial}/cic-custodial:${TAG:-latest}
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
cache_from:
|
|
||||||
- ${IMAGE_BASE_URL:-ghcr.io/grassrootseconomics/cic-custodial}/cic-custodial:latest
|
|
||||||
|
|
312
docs/docs.go
Normal file
312
docs/docs.go
Normal file
@ -0,0 +1,312 @@
|
|||||||
|
// Code generated by swaggo/swag. DO NOT EDIT.
|
||||||
|
|
||||||
|
package docs
|
||||||
|
|
||||||
|
import "github.com/swaggo/swag"
|
||||||
|
|
||||||
|
const docTemplate = `{
|
||||||
|
"schemes": {{ marshal .Schemes }},
|
||||||
|
"swagger": "2.0",
|
||||||
|
"info": {
|
||||||
|
"description": "{{escape .Description}}",
|
||||||
|
"title": "{{.Title}}",
|
||||||
|
"termsOfService": "https://grassecon.org/pages/terms-and-conditions.html",
|
||||||
|
"contact": {
|
||||||
|
"name": "API Support",
|
||||||
|
"url": "https://grassecon.org/pages/contact-us",
|
||||||
|
"email": "devops@grassecon.org"
|
||||||
|
},
|
||||||
|
"license": {
|
||||||
|
"name": "AGPL-3.0",
|
||||||
|
"url": "https://www.gnu.org/licenses/agpl-3.0.en.html"
|
||||||
|
},
|
||||||
|
"version": "{{.Version}}"
|
||||||
|
},
|
||||||
|
"host": "{{.Host}}",
|
||||||
|
"basePath": "{{.BasePath}}",
|
||||||
|
"paths": {
|
||||||
|
"/account/create": {
|
||||||
|
"post": {
|
||||||
|
"description": "Create a new custodial account.",
|
||||||
|
"consumes": [
|
||||||
|
"*/*"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"account"
|
||||||
|
],
|
||||||
|
"summary": "Create a new custodial account.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.OkResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/account/status/{address}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Return network balance and nonce.",
|
||||||
|
"consumes": [
|
||||||
|
"*/*"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"network"
|
||||||
|
],
|
||||||
|
"summary": "Get an address's network balance and nonce.",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Account Public Key",
|
||||||
|
"name": "address",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.OkResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/sign/transfer": {
|
||||||
|
"post": {
|
||||||
|
"description": "Sign and dispatch a transfer request.",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"network"
|
||||||
|
],
|
||||||
|
"summary": "Sign and dispatch transfer request.",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Sign Transfer Request",
|
||||||
|
"name": "signTransferRequest",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"amount": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"from": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"voucherAddress": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.OkResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/sign/transferAuth": {
|
||||||
|
"post": {
|
||||||
|
"description": "Sign and dispatch a transfer authorization (approve) request.",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"network"
|
||||||
|
],
|
||||||
|
"summary": "Sign and dispatch a transfer authorization (approve) request.",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Sign Transfer Authorization (approve) Request",
|
||||||
|
"name": "signTransferAuthorzationRequest",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"amount": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"authorizedAddress": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"authorizer": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"voucherAddress": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.OkResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/track/{trackingId}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Track an OTX (Origin transaction) status.",
|
||||||
|
"consumes": [
|
||||||
|
"*/*"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"track"
|
||||||
|
],
|
||||||
|
"summary": "Track an OTX (Origin transaction) status.",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Tracking Id",
|
||||||
|
"name": "trackingId",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.OkResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"api.ErrResp": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"ok": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"api.H": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {}
|
||||||
|
},
|
||||||
|
"api.OkResp": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"ok": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"$ref": "#/definitions/api.H"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||||
|
var SwaggerInfo = &swag.Spec{
|
||||||
|
Version: "1.0",
|
||||||
|
Host: "",
|
||||||
|
BasePath: "/api",
|
||||||
|
Schemes: []string{},
|
||||||
|
Title: "CIC Custodial API",
|
||||||
|
Description: "Interact with CIC Custodial API",
|
||||||
|
InfoInstanceName: "swagger",
|
||||||
|
SwaggerTemplate: docTemplate,
|
||||||
|
LeftDelim: "{{",
|
||||||
|
RightDelim: "}}",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
|
||||||
|
}
|
286
docs/swagger.json
Normal file
286
docs/swagger.json
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
{
|
||||||
|
"swagger": "2.0",
|
||||||
|
"info": {
|
||||||
|
"description": "Interact with CIC Custodial API",
|
||||||
|
"title": "CIC Custodial API",
|
||||||
|
"termsOfService": "https://grassecon.org/pages/terms-and-conditions.html",
|
||||||
|
"contact": {
|
||||||
|
"name": "API Support",
|
||||||
|
"url": "https://grassecon.org/pages/contact-us",
|
||||||
|
"email": "devops@grassecon.org"
|
||||||
|
},
|
||||||
|
"license": {
|
||||||
|
"name": "AGPL-3.0",
|
||||||
|
"url": "https://www.gnu.org/licenses/agpl-3.0.en.html"
|
||||||
|
},
|
||||||
|
"version": "1.0"
|
||||||
|
},
|
||||||
|
"basePath": "/api",
|
||||||
|
"paths": {
|
||||||
|
"/account/create": {
|
||||||
|
"post": {
|
||||||
|
"description": "Create a new custodial account.",
|
||||||
|
"consumes": [
|
||||||
|
"*/*"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"account"
|
||||||
|
],
|
||||||
|
"summary": "Create a new custodial account.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.OkResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/account/status/{address}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Return network balance and nonce.",
|
||||||
|
"consumes": [
|
||||||
|
"*/*"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"network"
|
||||||
|
],
|
||||||
|
"summary": "Get an address's network balance and nonce.",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Account Public Key",
|
||||||
|
"name": "address",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.OkResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/sign/transfer": {
|
||||||
|
"post": {
|
||||||
|
"description": "Sign and dispatch a transfer request.",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"network"
|
||||||
|
],
|
||||||
|
"summary": "Sign and dispatch transfer request.",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Sign Transfer Request",
|
||||||
|
"name": "signTransferRequest",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"amount": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"from": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"voucherAddress": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.OkResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/sign/transferAuth": {
|
||||||
|
"post": {
|
||||||
|
"description": "Sign and dispatch a transfer authorization (approve) request.",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"network"
|
||||||
|
],
|
||||||
|
"summary": "Sign and dispatch a transfer authorization (approve) request.",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Sign Transfer Authorization (approve) Request",
|
||||||
|
"name": "signTransferAuthorzationRequest",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"amount": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"authorizedAddress": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"authorizer": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"voucherAddress": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.OkResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/track/{trackingId}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Track an OTX (Origin transaction) status.",
|
||||||
|
"consumes": [
|
||||||
|
"*/*"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"track"
|
||||||
|
],
|
||||||
|
"summary": "Track an OTX (Origin transaction) status.",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Tracking Id",
|
||||||
|
"name": "trackingId",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.OkResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/api.ErrResp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"api.ErrResp": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"ok": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"api.H": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {}
|
||||||
|
},
|
||||||
|
"api.OkResp": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"ok": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"$ref": "#/definitions/api.H"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
188
docs/swagger.yaml
Normal file
188
docs/swagger.yaml
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
basePath: /api
|
||||||
|
definitions:
|
||||||
|
api.ErrResp:
|
||||||
|
properties:
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
ok:
|
||||||
|
type: boolean
|
||||||
|
type: object
|
||||||
|
api.H:
|
||||||
|
additionalProperties: {}
|
||||||
|
type: object
|
||||||
|
api.OkResp:
|
||||||
|
properties:
|
||||||
|
ok:
|
||||||
|
type: boolean
|
||||||
|
result:
|
||||||
|
$ref: '#/definitions/api.H'
|
||||||
|
type: object
|
||||||
|
info:
|
||||||
|
contact:
|
||||||
|
email: devops@grassecon.org
|
||||||
|
name: API Support
|
||||||
|
url: https://grassecon.org/pages/contact-us
|
||||||
|
description: Interact with CIC Custodial API
|
||||||
|
license:
|
||||||
|
name: AGPL-3.0
|
||||||
|
url: https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||||
|
termsOfService: https://grassecon.org/pages/terms-and-conditions.html
|
||||||
|
title: CIC Custodial API
|
||||||
|
version: "1.0"
|
||||||
|
paths:
|
||||||
|
/account/create:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- '*/*'
|
||||||
|
description: Create a new custodial account.
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/api.OkResp'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/api.ErrResp'
|
||||||
|
summary: Create a new custodial account.
|
||||||
|
tags:
|
||||||
|
- account
|
||||||
|
/account/status/{address}:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- '*/*'
|
||||||
|
description: Return network balance and nonce.
|
||||||
|
parameters:
|
||||||
|
- description: Account Public Key
|
||||||
|
in: path
|
||||||
|
name: address
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/api.OkResp'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/api.ErrResp'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/api.ErrResp'
|
||||||
|
summary: Get an address's network balance and nonce.
|
||||||
|
tags:
|
||||||
|
- network
|
||||||
|
/sign/transfer:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Sign and dispatch a transfer request.
|
||||||
|
parameters:
|
||||||
|
- description: Sign Transfer Request
|
||||||
|
in: body
|
||||||
|
name: signTransferRequest
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
amount:
|
||||||
|
type: integer
|
||||||
|
from:
|
||||||
|
type: string
|
||||||
|
to:
|
||||||
|
type: string
|
||||||
|
voucherAddress:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/api.OkResp'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/api.ErrResp'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/api.ErrResp'
|
||||||
|
summary: Sign and dispatch transfer request.
|
||||||
|
tags:
|
||||||
|
- network
|
||||||
|
/sign/transferAuth:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Sign and dispatch a transfer authorization (approve) request.
|
||||||
|
parameters:
|
||||||
|
- description: Sign Transfer Authorization (approve) Request
|
||||||
|
in: body
|
||||||
|
name: signTransferAuthorzationRequest
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
amount:
|
||||||
|
type: integer
|
||||||
|
authorizedAddress:
|
||||||
|
type: string
|
||||||
|
authorizer:
|
||||||
|
type: string
|
||||||
|
voucherAddress:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/api.OkResp'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/api.ErrResp'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/api.ErrResp'
|
||||||
|
summary: Sign and dispatch a transfer authorization (approve) request.
|
||||||
|
tags:
|
||||||
|
- network
|
||||||
|
/track/{trackingId}:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- '*/*'
|
||||||
|
description: Track an OTX (Origin transaction) status.
|
||||||
|
parameters:
|
||||||
|
- description: Tracking Id
|
||||||
|
in: path
|
||||||
|
name: trackingId
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/api.OkResp'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/api.ErrResp'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/api.ErrResp'
|
||||||
|
summary: Track an OTX (Origin transaction) status.
|
||||||
|
tags:
|
||||||
|
- track
|
||||||
|
swagger: "2.0"
|
71
go.mod
71
go.mod
@ -1,28 +1,42 @@
|
|||||||
module github.com/grassrootseconomics/cic-custodial
|
module github.com/grassrootseconomics/cic-custodial
|
||||||
|
|
||||||
go 1.19
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/VictoriaMetrics/metrics v1.23.1
|
github.com/VictoriaMetrics/metrics v1.24.0
|
||||||
github.com/bsm/redislock v0.7.2
|
github.com/bsm/redislock v0.9.3
|
||||||
github.com/celo-org/celo-blockchain v1.7.2
|
github.com/celo-org/celo-blockchain v1.7.2
|
||||||
github.com/georgysavva/scany/v2 v2.0.0
|
github.com/georgysavva/scany/v2 v2.0.0
|
||||||
github.com/go-playground/validator/v10 v10.11.2
|
github.com/go-playground/validator/v10 v10.14.1
|
||||||
github.com/go-redis/redis/v8 v8.11.5
|
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/grassrootseconomics/celoutils v1.0.0
|
github.com/grassrootseconomics/celoutils v1.4.1-0.20250221123515-f25baeeb2f8c
|
||||||
github.com/grassrootseconomics/w3-celo-patch v0.2.0
|
github.com/grassrootseconomics/w3-celo-patch v0.2.0
|
||||||
github.com/hibiken/asynq v0.24.0
|
github.com/hibiken/asynq v0.24.0
|
||||||
github.com/jackc/pgx/v5 v5.3.0
|
github.com/jackc/pgx/v5 v5.4.0
|
||||||
|
github.com/jackc/tern/v2 v2.1.1
|
||||||
github.com/knadh/goyesql/v2 v2.2.0
|
github.com/knadh/goyesql/v2 v2.2.0
|
||||||
github.com/knadh/koanf v1.5.0
|
github.com/knadh/koanf/parsers/toml v0.1.0
|
||||||
github.com/labstack/echo/v4 v4.10.1
|
github.com/knadh/koanf/providers/env v0.1.0
|
||||||
github.com/nats-io/nats.go v1.23.0
|
github.com/knadh/koanf/providers/file v0.1.0
|
||||||
|
github.com/knadh/koanf/v2 v2.0.1
|
||||||
|
github.com/labstack/echo/v4 v4.10.2
|
||||||
|
github.com/nats-io/nats.go v1.27.1
|
||||||
|
github.com/redis/go-redis/v9 v9.0.5
|
||||||
|
github.com/swaggo/echo-swagger v1.4.0
|
||||||
|
github.com/swaggo/swag v1.16.1
|
||||||
github.com/zerodha/logf v0.5.5
|
github.com/zerodha/logf v0.5.5
|
||||||
)
|
)
|
||||||
|
|
||||||
|
replace github.com/hibiken/asynq => github.com/grassrootseconomics/asynq v0.25.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
filippo.io/edwards25519 v1.0.0 // indirect
|
filippo.io/edwards25519 v1.0.0 // indirect
|
||||||
|
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||||
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
|
github.com/Masterminds/semver/v3 v3.2.0 // indirect
|
||||||
|
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||||
|
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||||
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||||
github.com/VictoriaMetrics/fastcache v1.12.0 // indirect
|
github.com/VictoriaMetrics/fastcache v1.12.0 // indirect
|
||||||
github.com/btcsuite/btcd v0.20.1-beta // indirect
|
github.com/btcsuite/btcd v0.20.1-beta // indirect
|
||||||
github.com/celo-org/celo-bls-go v0.6.4 // indirect
|
github.com/celo-org/celo-bls-go v0.6.4 // indirect
|
||||||
@ -32,14 +46,20 @@ require (
|
|||||||
github.com/celo-org/celo-bls-go-macos v0.6.3 // indirect
|
github.com/celo-org/celo-bls-go-macos v0.6.3 // indirect
|
||||||
github.com/celo-org/celo-bls-go-other v0.6.3 // indirect
|
github.com/celo-org/celo-bls-go-other v0.6.3 // indirect
|
||||||
github.com/celo-org/celo-bls-go-windows v0.6.3 // indirect
|
github.com/celo-org/celo-bls-go-windows v0.6.3 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
github.com/deckarep/golang-set v1.8.0 // indirect
|
github.com/deckarep/golang-set v1.8.0 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||||
|
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||||
|
github.com/go-openapi/spec v0.20.4 // indirect
|
||||||
|
github.com/go-openapi/swag v0.19.15 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-stack/stack v1.8.1 // indirect
|
github.com/go-stack/stack v1.8.1 // indirect
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
@ -48,13 +68,19 @@ require (
|
|||||||
github.com/hdevalence/ed25519consensus v0.1.0 // indirect
|
github.com/hdevalence/ed25519consensus v0.1.0 // indirect
|
||||||
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
||||||
github.com/holiman/uint256 v1.2.1 // indirect
|
github.com/holiman/uint256 v1.2.1 // indirect
|
||||||
|
github.com/huandu/xstrings v1.4.0 // indirect
|
||||||
github.com/huin/goupnp v1.0.3 // indirect
|
github.com/huin/goupnp v1.0.3 // indirect
|
||||||
|
github.com/imdario/mergo v0.3.13 // indirect
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||||
github.com/jackc/puddle/v2 v2.2.0 // indirect
|
github.com/jackc/puddle/v2 v2.2.0 // indirect
|
||||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||||
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
|
github.com/klauspost/compress v1.16.5 // indirect
|
||||||
|
github.com/knadh/koanf/maps v0.1.1 // indirect
|
||||||
github.com/labstack/gommon v0.4.0 // indirect
|
github.com/labstack/gommon v0.4.0 // indirect
|
||||||
github.com/leodido/go-urn v1.2.1 // indirect
|
github.com/leodido/go-urn v1.2.4 // indirect
|
||||||
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||||
@ -62,17 +88,20 @@ require (
|
|||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||||
github.com/nats-io/nats-server/v2 v2.9.14 // indirect
|
github.com/nats-io/nats-server/v2 v2.9.14 // indirect
|
||||||
github.com/nats-io/nkeys v0.3.0 // indirect
|
github.com/nats-io/nkeys v0.4.4 // indirect
|
||||||
github.com/nats-io/nuid v1.0.1 // indirect
|
github.com/nats-io/nuid v1.0.1 // indirect
|
||||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||||
|
github.com/onsi/ginkgo v1.16.4 // indirect
|
||||||
github.com/onsi/gomega v1.24.1 // indirect
|
github.com/onsi/gomega v1.24.1 // indirect
|
||||||
github.com/pelletier/go-toml v1.7.0 // indirect
|
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/prometheus/tsdb v0.10.0 // indirect
|
github.com/prometheus/tsdb v0.10.0 // indirect
|
||||||
github.com/rivo/uniseg v0.4.3 // indirect
|
github.com/rivo/uniseg v0.4.3 // indirect
|
||||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||||
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
||||||
github.com/spf13/cast v1.3.1 // indirect
|
github.com/shopspring/decimal v1.3.1 // indirect
|
||||||
|
github.com/spf13/cast v1.5.0 // indirect
|
||||||
|
github.com/swaggo/files/v2 v2.0.0 // indirect
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
|
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
||||||
github.com/tklauser/numcpus v0.6.0 // indirect
|
github.com/tklauser/numcpus v0.6.0 // indirect
|
||||||
@ -81,13 +110,15 @@ require (
|
|||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
github.com/valyala/histogram v1.2.0 // indirect
|
github.com/valyala/histogram v1.2.0 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||||
golang.org/x/crypto v0.6.0 // indirect
|
golang.org/x/crypto v0.10.0 // indirect
|
||||||
golang.org/x/net v0.7.0 // indirect
|
golang.org/x/net v0.10.0 // indirect
|
||||||
golang.org/x/sync v0.1.0 // indirect
|
golang.org/x/sync v0.1.0 // indirect
|
||||||
golang.org/x/sys v0.5.0 // indirect
|
golang.org/x/sys v0.9.0 // indirect
|
||||||
golang.org/x/text v0.7.0 // indirect
|
golang.org/x/text v0.10.0 // indirect
|
||||||
golang.org/x/time v0.3.0 // indirect
|
golang.org/x/time v0.3.0 // indirect
|
||||||
|
golang.org/x/tools v0.7.0 // indirect
|
||||||
google.golang.org/protobuf v1.28.0 // indirect
|
google.golang.org/protobuf v1.28.0 // indirect
|
||||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
390
go.sum
390
go.sum
@ -34,60 +34,55 @@ github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxB
|
|||||||
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
|
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
|
||||||
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
||||||
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||||
|
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||||
|
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||||
|
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||||
|
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||||
|
github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
|
||||||
|
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||||
|
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
|
||||||
|
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
|
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||||
|
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||||
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||||
github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw=
|
github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw=
|
||||||
github.com/VictoriaMetrics/fastcache v1.12.0 h1:vnVi/y9yKDcD9akmc4NqAoqgQhJrOwUF+j9LTgn4QDE=
|
github.com/VictoriaMetrics/fastcache v1.12.0 h1:vnVi/y9yKDcD9akmc4NqAoqgQhJrOwUF+j9LTgn4QDE=
|
||||||
github.com/VictoriaMetrics/fastcache v1.12.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8=
|
github.com/VictoriaMetrics/fastcache v1.12.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8=
|
||||||
github.com/VictoriaMetrics/metrics v1.23.1 h1:/j8DzeJBxSpL2qSIdqnRFLvQQhbJyJbbEi22yMm7oL0=
|
github.com/VictoriaMetrics/metrics v1.24.0 h1:ILavebReOjYctAGY5QU2F9X0MYvkcrG3aEn2RKa1Zkw=
|
||||||
github.com/VictoriaMetrics/metrics v1.23.1/go.mod h1:rAr/llLpEnAdTehiNlUxKgnjcOuROSzpw0GvjpEbvFc=
|
github.com/VictoriaMetrics/metrics v1.24.0/go.mod h1:eFT25kvsTidQFHb6U0oa0rTrDRdz4xTYjpL8+UPohys=
|
||||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||||
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
|
||||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
|
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
|
||||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
|
||||||
github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=
|
github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=
|
||||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
|
||||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
|
||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
|
||||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
|
||||||
github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo=
|
github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
|
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y=
|
github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.8.3/go.mod h1:4AEiLtAb8kLs7vgw2ZV3p2VZ1+hBavOc84hqxVNpCyw=
|
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo=
|
github.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.4.3/go.mod h1:FNNC6nQZQUuyhq5aE5c7ata8o9e4ECGmS4lAXC7o1mQ=
|
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2/go.mod h1:3hGg3PpiEjHnrkrlasTfxFqUsZ2GCk/fMUn4CbKgSkM=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2/go.mod h1:3hGg3PpiEjHnrkrlasTfxFqUsZ2GCk/fMUn4CbKgSkM=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.6.0/go.mod h1:gqlclDEZp4aqJOancXK6TN24aKhT0W0Ae9MHk3wzTMM=
|
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.2.4/go.mod h1:ZcBrrI3zBKlhGFNYWvju0I3TR93I7YIgAfy82Fh4lcQ=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/appconfig v1.4.2/go.mod h1:FZ3HkCe+b10uFZZkFdvf98LHW21k49W8o8J366lqVKY=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2/go.mod h1:45MfaXZ0cNbeuT0KQ1XJylq8A6+OpVV2E5kvY/Kq+u8=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2/go.mod h1:45MfaXZ0cNbeuT0KQ1XJylq8A6+OpVV2E5kvY/Kq+u8=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.2/go.mod h1:72HRZDLMtmVQiLG2tLfQcaWLCssELvGl+Zf2WVxMmR8=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7NkwbjlijluLsrIbu/iyl35RO4=
|
github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7NkwbjlijluLsrIbu/iyl35RO4=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.4.2/go.mod h1:NBvT9R1MEF+Ud6ApJKM0G+IkPchKS7p7c2YPKwHmBOk=
|
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.7.2/go.mod h1:8EzeIqfWt2wWT4rJVu3f21TfrhJ8AEMzVybRNSb/b4g=
|
|
||||||
github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw=
|
github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw=
|
||||||
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
|
||||||
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=
|
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=
|
||||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||||
github.com/bsm/redislock v0.7.2 h1:jggqOio8JyX9FJBKIfjF3fTxAu/v7zC5mAID9LveqG4=
|
github.com/bsm/ginkgo/v2 v2.5.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w=
|
||||||
github.com/bsm/redislock v0.7.2/go.mod h1:kS2g0Yvlymc9Dz8V3iVYAtLAaSVruYbAFdYBDrmC5WU=
|
github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao=
|
||||||
|
github.com/bsm/gomega v1.20.0/go.mod h1:JifAceMQ4crZIWYUKrlGcmbN3bqHogVTADMD2ATsbwk=
|
||||||
|
github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y=
|
||||||
|
github.com/bsm/redislock v0.9.3 h1:osmvugkXGiLDEhzUPdM0EUtKpTEgLLuli4Ky2Z4vx38=
|
||||||
|
github.com/bsm/redislock v0.9.3/go.mod h1:Epf7AJLiSFwLCiZcfi6pWFO/8eAYrYpQXFxEDPoDeAk=
|
||||||
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
|
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
|
||||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||||
@ -127,21 +122,19 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
|
|||||||
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
|
||||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304=
|
github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
|
||||||
github.com/cockroachdb/cockroach-go/v2 v2.2.0 h1:/5znzg5n373N/3ESjHF5SMLxiW4RKB05Ql//KWfeTFs=
|
github.com/cockroachdb/cockroach-go/v2 v2.2.0 h1:/5znzg5n373N/3ESjHF5SMLxiW4RKB05Ql//KWfeTFs=
|
||||||
github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ=
|
github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ=
|
||||||
github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q=
|
github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q=
|
||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
|
||||||
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.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
||||||
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
|
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
|
||||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@ -161,21 +154,19 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8
|
|||||||
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||||
github.com/docker/docker v1.6.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v1.6.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
|
github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
|
||||||
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
|
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
|
||||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
|
||||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
|
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
|
||||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||||
|
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||||
|
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||||
github.com/georgysavva/scany/v2 v2.0.0 h1:RGXqxDv4row7/FYoK8MRXAZXqoWF/NM+NP0q50k3DKU=
|
github.com/georgysavva/scany/v2 v2.0.0 h1:RGXqxDv4row7/FYoK8MRXAZXqoWF/NM+NP0q50k3DKU=
|
||||||
github.com/georgysavva/scany/v2 v2.0.0/go.mod h1:sigOdh+0qb/+aOs3TVhehVT10p8qJL7K/Zhyz8vWo38=
|
github.com/georgysavva/scany/v2 v2.0.0/go.mod h1:sigOdh+0qb/+aOs3TVhehVT10p8qJL7K/Zhyz8vWo38=
|
||||||
github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
|
github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
|
||||||
@ -186,32 +177,32 @@ github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1T
|
|||||||
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
|
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
|
github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk=
|
|
||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
|
||||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
|
||||||
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
|
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=
|
|
||||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
|
||||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||||
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
|
github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
|
||||||
|
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
|
||||||
|
github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=
|
||||||
|
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
|
||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||||
|
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
|
||||||
|
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU=
|
github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
|
||||||
github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s=
|
github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||||
github.com/go-redis/redis/v8 v8.11.2/go.mod h1:DLomh7y2e3ggQXQLd1YgmvIfecPJoFl7WU5SOQ/r06M=
|
|
||||||
github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
|
|
||||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
|
||||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
|
||||||
github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
|
github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
|
||||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
@ -219,13 +210,12 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
|
|||||||
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
|
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
|
||||||
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
|
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
|
||||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||||
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||||
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
@ -237,13 +227,11 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU
|
|||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
@ -263,21 +251,18 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
|||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
|
||||||
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
@ -290,67 +275,41 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
|
|||||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
|
github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
|
||||||
github.com/grassrootseconomics/celoutils v1.0.0 h1:+pfiNZA+PJczmpN7RsZ/sr9PM0jKQQHxB6y/Ix3AFwA=
|
github.com/grassrootseconomics/asynq v0.25.0 h1:2zSz5YwNLu/oCTm/xfNixn86i9aw4zth9Dl0dc2kFEs=
|
||||||
github.com/grassrootseconomics/celoutils v1.0.0/go.mod h1:Uo5YRy6AGLAHDZj9jaOI+AWoQ1H3L0v79728pPMkm9Q=
|
github.com/grassrootseconomics/asynq v0.25.0/go.mod h1:pe2XOdK1eIbTgTmRFHIYl75lvVuTPJxZq2T9Ocz/+2s=
|
||||||
|
github.com/grassrootseconomics/celoutils v1.4.0 h1:AJNKiOpfnQqZ3kRxeUlhWH/zlDDjhtbs/OzAMb5zU4A=
|
||||||
|
github.com/grassrootseconomics/celoutils v1.4.0/go.mod h1:Uo5YRy6AGLAHDZj9jaOI+AWoQ1H3L0v79728pPMkm9Q=
|
||||||
|
github.com/grassrootseconomics/celoutils v1.4.1-0.20240824053735-9873e8ac0473 h1:caDCYYMKi7TEl00mlV7Vl2lTcsrD7hoFcQwXCec9Ztc=
|
||||||
|
github.com/grassrootseconomics/celoutils v1.4.1-0.20240824053735-9873e8ac0473/go.mod h1:Uo5YRy6AGLAHDZj9jaOI+AWoQ1H3L0v79728pPMkm9Q=
|
||||||
|
github.com/grassrootseconomics/celoutils v1.4.1-0.20250221123515-f25baeeb2f8c h1:HrCc3I59rA9wha2QkJe+vs9vF1r+uKDbxUrM/EFCJdk=
|
||||||
|
github.com/grassrootseconomics/celoutils v1.4.1-0.20250221123515-f25baeeb2f8c/go.mod h1:Uo5YRy6AGLAHDZj9jaOI+AWoQ1H3L0v79728pPMkm9Q=
|
||||||
github.com/grassrootseconomics/w3-celo-patch v0.2.0 h1:YqibbPzX0tQKmxU1nUGzThPKk/fiYeYZY6Aif3eyu8U=
|
github.com/grassrootseconomics/w3-celo-patch v0.2.0 h1:YqibbPzX0tQKmxU1nUGzThPKk/fiYeYZY6Aif3eyu8U=
|
||||||
github.com/grassrootseconomics/w3-celo-patch v0.2.0/go.mod h1:WhBXNzNIvHmS6B2hAeShs56oa9Azb4jQSrOMKuMdBWw=
|
github.com/grassrootseconomics/w3-celo-patch v0.2.0/go.mod h1:WhBXNzNIvHmS6B2hAeShs56oa9Azb4jQSrOMKuMdBWw=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
|
||||||
github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ=
|
|
||||||
github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
|
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
|
||||||
github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=
|
github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
|
||||||
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
|
|
||||||
github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
|
||||||
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
|
||||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
|
||||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
|
||||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
|
||||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
|
||||||
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
|
|
||||||
github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
|
||||||
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
|
||||||
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
|
||||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
|
||||||
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
|
|
||||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
|
||||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
|
||||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
|
||||||
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
|
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
|
||||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
|
||||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
|
||||||
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
|
|
||||||
github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
|
||||||
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
|
|
||||||
github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q=
|
|
||||||
github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M=
|
|
||||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
|
||||||
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
|
||||||
github.com/hdevalence/ed25519consensus v0.0.0-20201207055737-7fde80a9d5ff/go.mod h1:Feit0l8NcNO4g69XNjwvsR0LGcwMMfzI1TF253rOIlQ=
|
github.com/hdevalence/ed25519consensus v0.0.0-20201207055737-7fde80a9d5ff/go.mod h1:Feit0l8NcNO4g69XNjwvsR0LGcwMMfzI1TF253rOIlQ=
|
||||||
github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7HsjsjeEZ6auqU=
|
github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7HsjsjeEZ6auqU=
|
||||||
github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo=
|
github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo=
|
||||||
github.com/hibiken/asynq v0.24.0 h1:r1CiSVYCy1vGq9REKGI/wdB2D5n/QmtzihYHHXOuBUs=
|
|
||||||
github.com/hibiken/asynq v0.24.0/go.mod h1:FVnRfUTm6gcoDkM/EjF4OIh5/06ergCPUO6pS2B2y+w=
|
|
||||||
github.com/hjson/hjson-go/v4 v4.0.0 h1:wlm6IYYqHjOdXH1gHev4VoXCaW20HdQAGCxdOEEg2cs=
|
|
||||||
github.com/hjson/hjson-go/v4 v4.0.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E=
|
|
||||||
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
|
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/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
|
||||||
github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
|
github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
|
||||||
github.com/holiman/uint256 v1.2.1 h1:XRtyuda/zw2l+Bq/38n5XUoEF72aSOu/77Thd9pPp2o=
|
github.com/holiman/uint256 v1.2.1 h1:XRtyuda/zw2l+Bq/38n5XUoEF72aSOu/77Thd9pPp2o=
|
||||||
github.com/holiman/uint256 v1.2.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
|
github.com/holiman/uint256 v1.2.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
|
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
|
||||||
|
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM=
|
github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM=
|
||||||
github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
|
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/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y=
|
||||||
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
|
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
|
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
|
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
|
||||||
|
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY=
|
github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY=
|
||||||
github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI=
|
github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI=
|
||||||
@ -367,10 +326,12 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
|
|||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
github.com/jackc/pgx/v5 v5.3.0 h1:/NQi8KHMpKWHInxXesC8yD4DhkXPrVhmnwYkjp9AmBA=
|
github.com/jackc/pgx/v5 v5.4.0 h1:BSr+GCm4N6QcgIwv0DyTFHK9ugfEFF9DzSbbzxOiXU0=
|
||||||
github.com/jackc/pgx/v5 v5.3.0/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
|
github.com/jackc/pgx/v5 v5.4.0/go.mod h1:q6iHT8uDNXWiFNOlRqJzBTaSH3+2xCXkokxHZC5qWFY=
|
||||||
github.com/jackc/puddle/v2 v2.2.0 h1:RdcDk92EJBuBS55nQMMYFXTxwstHug4jkhT5pq8VxPk=
|
github.com/jackc/puddle/v2 v2.2.0 h1:RdcDk92EJBuBS55nQMMYFXTxwstHug4jkhT5pq8VxPk=
|
||||||
github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
|
github.com/jackc/tern/v2 v2.1.1 h1:qDo41wTtDHrTgkN7lhcoMQ6oiAWqiD8xKgslxyoKHNQ=
|
||||||
|
github.com/jackc/tern/v2 v2.1.1/go.mod h1:xnRalAguscgir18eW/wscn/QTEoWwFqrpW+5S+CREWM=
|
||||||
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
|
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/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||||
@ -379,64 +340,69 @@ github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M
|
|||||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
|
||||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
|
||||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o=
|
github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
|
||||||
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||||
github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=
|
github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=
|
||||||
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
||||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||||
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
|
github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
|
||||||
|
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=
|
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=
|
||||||
github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||||
github.com/knadh/goyesql/v2 v2.2.0 h1:DNQIzgITmMTXA+z+jDzbXCpgr7fGD6Hp0AJ7ZLEAem4=
|
github.com/knadh/goyesql/v2 v2.2.0 h1:DNQIzgITmMTXA+z+jDzbXCpgr7fGD6Hp0AJ7ZLEAem4=
|
||||||
github.com/knadh/goyesql/v2 v2.2.0/go.mod h1:is+wK/XQBukYK3DdKfpJRyDH9U/ZTMyX2u6DFijjRnI=
|
github.com/knadh/goyesql/v2 v2.2.0/go.mod h1:is+wK/XQBukYK3DdKfpJRyDH9U/ZTMyX2u6DFijjRnI=
|
||||||
github.com/knadh/koanf v1.5.0 h1:q2TSd/3Pyc/5yP9ldIrSdIz26MCcyNQzW0pEAugLPNs=
|
github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs=
|
||||||
github.com/knadh/koanf v1.5.0/go.mod h1:Hgyjp4y8v44hpZtPzs7JZfRAW5AhN7KfZcwv1RYggDs=
|
github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
|
||||||
|
github.com/knadh/koanf/parsers/toml v0.1.0 h1:S2hLqS4TgWZYj4/7mI5m1CQQcWurxUz6ODgOub/6LCI=
|
||||||
|
github.com/knadh/koanf/parsers/toml v0.1.0/go.mod h1:yUprhq6eo3GbyVXFFMdbfZSo928ksS+uo0FFqNMnO18=
|
||||||
|
github.com/knadh/koanf/providers/env v0.1.0 h1:LqKteXqfOWyx5Ab9VfGHmjY9BvRXi+clwyZozgVRiKg=
|
||||||
|
github.com/knadh/koanf/providers/env v0.1.0/go.mod h1:RE8K9GbACJkeEnkl8L/Qcj8p4ZyPXZIQ191HJi44ZaQ=
|
||||||
|
github.com/knadh/koanf/providers/file v0.1.0 h1:fs6U7nrV58d3CFAFh8VTde8TM262ObYf3ODrc//Lp+c=
|
||||||
|
github.com/knadh/koanf/providers/file v0.1.0/go.mod h1:rjJ/nHQl64iYCtAW2QQnF0eSmDEX/YZ/eNFj5yR6BvA=
|
||||||
|
github.com/knadh/koanf/v2 v2.0.1 h1:1dYGITt1I23x8cfx8ZnldtezdyaZtfAuRtIFOiRzK7g=
|
||||||
|
github.com/knadh/koanf/v2 v2.0.1/go.mod h1:ZeiIlIDXTE7w1lMT6UVcNiRAS2/rCeLn/GdLNvY1Dus=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
|
||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
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/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg=
|
github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg=
|
||||||
github.com/labstack/echo/v4 v4.10.1 h1:rB+D8In9PWjsp1OpHaqK+t04nQv/SBD1IoIcXCg0lpY=
|
github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
|
||||||
github.com/labstack/echo/v4 v4.10.1/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
|
github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
|
||||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||||
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
|
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
|
||||||
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
||||||
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
|
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
|
||||||
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E=
|
github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E=
|
||||||
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
|
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
|
||||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
|
||||||
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
@ -444,12 +410,9 @@ github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxec
|
|||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||||
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
|
||||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
|
||||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
@ -463,20 +426,10 @@ github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOq
|
|||||||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
|
||||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
|
||||||
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
|
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
|
||||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
|
||||||
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
|
||||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
|
||||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
|
||||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
|
||||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
|
||||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
|
||||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
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/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
@ -484,29 +437,25 @@ github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8oh
|
|||||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
|
||||||
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
|
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
|
||||||
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
|
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
|
||||||
github.com/nats-io/jwt/v2 v2.3.0 h1:z2mA1a7tIf5ShggOFlR1oBPgd6hGqcDYsISxZByUzdI=
|
github.com/nats-io/jwt/v2 v2.3.0 h1:z2mA1a7tIf5ShggOFlR1oBPgd6hGqcDYsISxZByUzdI=
|
||||||
github.com/nats-io/nats-server/v2 v2.9.14 h1:n2GscWVgXpA14vQSRP/MM1SGi4wyazR9l19/gWxqgXQ=
|
github.com/nats-io/nats-server/v2 v2.9.14 h1:n2GscWVgXpA14vQSRP/MM1SGi4wyazR9l19/gWxqgXQ=
|
||||||
github.com/nats-io/nats-server/v2 v2.9.14/go.mod h1:40ZwFm4npKdFBhOdY7rkh3YyI1oI91FzLvlYyB7HfzM=
|
github.com/nats-io/nats-server/v2 v2.9.14/go.mod h1:40ZwFm4npKdFBhOdY7rkh3YyI1oI91FzLvlYyB7HfzM=
|
||||||
github.com/nats-io/nats.go v1.23.0 h1:lR28r7IX44WjYgdiKz9GmUeW0uh/m33uD3yEjLZ2cOE=
|
github.com/nats-io/nats.go v1.27.1 h1:OuYnal9aKVSnOzLQIzf7554OXMCG7KbaTkCSBHRcSoo=
|
||||||
github.com/nats-io/nats.go v1.23.0/go.mod h1:ki/Scsa23edbh8IRZbCuNXR9TDcbvfaSijKtaqQgw+Q=
|
github.com/nats-io/nats.go v1.27.1/go.mod h1:XpbWUlOElGwTYbMR7imivs7jJj9GtK7ypv321Wp6pjc=
|
||||||
github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8=
|
github.com/nats-io/nkeys v0.4.4 h1:xvBJ8d69TznjcQl9t6//Q5xXuVhyYiSos6RPtvQNTwA=
|
||||||
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
|
github.com/nats-io/nkeys v0.4.4/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
|
||||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||||
github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
@ -514,25 +463,20 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
|||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||||
github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg=
|
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
|
||||||
github.com/onsi/ginkgo/v2 v2.5.0 h1:TRtrvv2vdQqzkwrQ1ke6vtXf7IK34RBUJafIy1wMwls=
|
github.com/onsi/ginkgo/v2 v2.5.0 h1:TRtrvv2vdQqzkwrQ1ke6vtXf7IK34RBUJafIy1wMwls=
|
||||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48=
|
|
||||||
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
|
||||||
github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E=
|
github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E=
|
||||||
github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
|
github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
|
||||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
|
||||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
|
||||||
github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE=
|
github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE=
|
||||||
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
|
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||||
github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
|
github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
|
||||||
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
|
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
|
||||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||||
@ -544,45 +488,33 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||||||
github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
|
github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
|
||||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
|
||||||
github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
|
||||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
|
||||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
|
||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic=
|
github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic=
|
||||||
github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4=
|
github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4=
|
||||||
|
github.com/redis/go-redis/v9 v9.0.1/go.mod h1:/xDTe9EF1LM61hek62Poq2nzQSGj0xSrEtEHbBQevps=
|
||||||
|
github.com/redis/go-redis/v9 v9.0.5 h1:CuQcn5HIEeK7BgElubPP8CGtE0KakrnbBSTLjathl5o=
|
||||||
|
github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk=
|
||||||
github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc=
|
github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc=
|
||||||
github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA=
|
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
|
github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
|
||||||
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
|
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
|
||||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
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 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
|
||||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
|
||||||
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
|
||||||
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||||
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
@ -590,23 +522,24 @@ github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go
|
|||||||
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||||
|
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||||
|
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
|
||||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
|
||||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||||
|
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
||||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
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.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
@ -614,9 +547,21 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
|||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
|
github.com/swaggo/echo-swagger v1.4.0 h1:RCxLKySw1SceHLqnmc41pKyiIeE+OiD7NSI7FUOBlLo=
|
||||||
|
github.com/swaggo/echo-swagger v1.4.0/go.mod h1:Wh3VlwjZGZf/LH0s81tz916JokuPG7y/ZqaqnckYqoQ=
|
||||||
|
github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw=
|
||||||
|
github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM=
|
||||||
|
github.com/swaggo/swag v1.16.1 h1:fTNRhKstPKxcnoKsytm4sahr8FaYzUcT7i1/3nd/fBg=
|
||||||
|
github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKikGxto=
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
|
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/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
|
||||||
|
github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE=
|
||||||
|
github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU=
|
||||||
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
|
github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
|
||||||
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
|
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
|
||||||
@ -638,43 +583,34 @@ github.com/valyala/histogram v1.2.0 h1:wyYGAZZt3CpwUiIb9AU/Zbllg1llXyrtApRS815OL
|
|||||||
github.com/valyala/histogram v1.2.0/go.mod h1:Hb4kBwb4UxsaNbbbh+RRz8ZR6pdodR57tzWUS3BUzXY=
|
github.com/valyala/histogram v1.2.0/go.mod h1:Hb4kBwb4UxsaNbbbh+RRz8ZR6pdodR57tzWUS3BUzXY=
|
||||||
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||||
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||||
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.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
github.com/zerodha/logf v0.5.5 h1:AhxHlixHNYwhFjvlgTv6uO4VBKYKxx2I6SbHoHtWLBk=
|
github.com/zerodha/logf v0.5.5 h1:AhxHlixHNYwhFjvlgTv6uO4VBKYKxx2I6SbHoHtWLBk=
|
||||||
github.com/zerodha/logf v0.5.5/go.mod h1:HWpfKsie+WFFpnUnUxelT6Z0FC6xu9+qt+oXNMPg6y8=
|
github.com/zerodha/logf v0.5.5/go.mod h1:HWpfKsie+WFFpnUnUxelT6Z0FC6xu9+qt+oXNMPg6y8=
|
||||||
go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
|
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
|
||||||
go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY=
|
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
|
||||||
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
|
||||||
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
|
||||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
|
||||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||||
|
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
||||||
|
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
@ -696,15 +632,15 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl
|
|||||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@ -719,24 +655,20 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
|
|||||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
|
||||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
|
||||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||||
|
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||||
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@ -750,23 +682,19 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -775,23 +703,16 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -799,36 +720,40 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
||||||
|
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
@ -852,7 +777,6 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw
|
|||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
@ -862,13 +786,11 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn
|
|||||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
|
||||||
|
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@ -893,7 +815,6 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww
|
|||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
@ -906,45 +827,32 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx
|
|||||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
|
||||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
|
||||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
|
||||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
|
||||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
|
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
|
||||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
|
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
|
||||||
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
|
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
|
||||||
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
|
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
|
||||||
@ -952,13 +860,14 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||||
@ -971,4 +880,3 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt
|
|||||||
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
|
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
|
||||||
|
@ -12,23 +12,28 @@ import (
|
|||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateAccountHandler route.
|
// HandleAccountCreate godoc
|
||||||
// POST: /api/account/create
|
// @Summary Create a new custodial account.
|
||||||
// Returns the public key.
|
// @Description Create a new custodial account.
|
||||||
func CreateAccountHandler(cu *custodial.Custodial) func(echo.Context) error {
|
// @Tags account
|
||||||
|
// @Accept */*
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} OkResp
|
||||||
|
// @Failure 500 {object} ErrResp
|
||||||
|
// @Router /account/create [post]
|
||||||
|
func HandleAccountCreate(cu *custodial.Custodial) func(echo.Context) error {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
trackingId := uuid.NewString()
|
|
||||||
|
|
||||||
generatedKeyPair, err := keypair.Generate()
|
generatedKeyPair, err := keypair.Generate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := cu.Keystore.WriteKeyPair(c.Request().Context(), generatedKeyPair)
|
id, err := cu.Store.WriteKeyPair(c.Request().Context(), generatedKeyPair)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trackingId := uuid.NewString()
|
||||||
taskPayload, err := json.Marshal(task.AccountPayload{
|
taskPayload, err := json.Marshal(task.AccountPayload{
|
||||||
PublicKey: generatedKeyPair.Public,
|
PublicKey: generatedKeyPair.Public,
|
||||||
TrackingId: trackingId,
|
TrackingId: trackingId,
|
||||||
@ -38,7 +43,8 @@ func CreateAccountHandler(cu *custodial.Custodial) func(echo.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err = cu.TaskerClient.CreateTask(
|
_, err = cu.TaskerClient.CreateTask(
|
||||||
tasker.AccountPrepareTask,
|
c.Request().Context(),
|
||||||
|
tasker.AccountRegisterTask,
|
||||||
tasker.DefaultPriority,
|
tasker.DefaultPriority,
|
||||||
&tasker.Task{
|
&tasker.Task{
|
||||||
Id: trackingId,
|
Id: trackingId,
|
||||||
|
11
internal/api/errors.go
Normal file
11
internal/api/errors.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewBadRequestError(message ...interface{}) *echo.HTTPError {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest, message...)
|
||||||
|
}
|
64
internal/api/network.go
Normal file
64
internal/api/network.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/grassrootseconomics/celoutils"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
||||||
|
"github.com/grassrootseconomics/w3-celo-patch"
|
||||||
|
"github.com/grassrootseconomics/w3-celo-patch/module/eth"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleNetworkAccountStatus godoc
|
||||||
|
// @Summary Get an address's network balance and nonce.
|
||||||
|
// @Description Return network balance and nonce.
|
||||||
|
// @Tags network
|
||||||
|
// @Accept */*
|
||||||
|
// @Produce json
|
||||||
|
// @Param address path string true "Account Public Key"
|
||||||
|
// @Success 200 {object} OkResp
|
||||||
|
// @Failure 400 {object} ErrResp
|
||||||
|
// @Failure 500 {object} ErrResp
|
||||||
|
// @Router /account/status/{address} [get]
|
||||||
|
func HandleNetworkAccountStatus(cu *custodial.Custodial) func(echo.Context) error {
|
||||||
|
return func(c echo.Context) error {
|
||||||
|
var (
|
||||||
|
accountStatusRequest struct {
|
||||||
|
Address string `param:"address" validate:"required,eth_addr_checksum"`
|
||||||
|
}
|
||||||
|
networkBalance big.Int
|
||||||
|
networkNonce uint64
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := c.Bind(&accountStatusRequest); err != nil {
|
||||||
|
return NewBadRequestError(ErrInvalidJSON)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.Validate(accountStatusRequest); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cu.CeloProvider.Client.CallCtx(
|
||||||
|
c.Request().Context(),
|
||||||
|
eth.Nonce(celoutils.HexToAddress(accountStatusRequest.Address), nil).Returns(&networkNonce),
|
||||||
|
eth.Balance(celoutils.HexToAddress(accountStatusRequest.Address), nil).Returns(&networkBalance),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if networkNonce > 0 {
|
||||||
|
networkNonce--
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(http.StatusOK, OkResp{
|
||||||
|
Ok: true,
|
||||||
|
Result: H{
|
||||||
|
"balance": fmt.Sprintf("%s CELO", w3.FromWei(&networkBalance, 18)),
|
||||||
|
"nonce": networkNonce,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -1,74 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
|
||||||
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/tasker/task"
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SignTxHandler route.
|
|
||||||
// POST: /api/sign/transfer
|
|
||||||
// JSON Body:
|
|
||||||
// from -> ETH address
|
|
||||||
// to -> ETH address
|
|
||||||
// voucherAddress -> ETH address
|
|
||||||
// amount -> int (6 d.p. precision)
|
|
||||||
// e.g. 1000000 = 1 VOUCHER
|
|
||||||
// Returns the task id.
|
|
||||||
func SignTransferHandler(cu *custodial.Custodial) func(echo.Context) error {
|
|
||||||
return func(c echo.Context) error {
|
|
||||||
trackingId := uuid.NewString()
|
|
||||||
|
|
||||||
var transferRequest struct {
|
|
||||||
From string `json:"from" validate:"required,eth_checksum"`
|
|
||||||
To string `json:"to" validate:"required,eth_checksum"`
|
|
||||||
VoucherAddress string `json:"voucherAddress" validate:"required,eth_checksum"`
|
|
||||||
Amount uint64 `json:"amount" validate:"required,numeric"`
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.Bind(&transferRequest); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.Validate(transferRequest); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Checksum addresses
|
|
||||||
taskPayload, err := json.Marshal(task.TransferPayload{
|
|
||||||
TrackingId: trackingId,
|
|
||||||
From: transferRequest.From,
|
|
||||||
To: transferRequest.To,
|
|
||||||
VoucherAddress: transferRequest.VoucherAddress,
|
|
||||||
Amount: transferRequest.Amount,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = cu.TaskerClient.CreateTask(
|
|
||||||
tasker.SignTransferTask,
|
|
||||||
tasker.HighPriority,
|
|
||||||
&tasker.Task{
|
|
||||||
Id: trackingId,
|
|
||||||
Payload: taskPayload,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(http.StatusOK, OkResp{
|
|
||||||
Ok: true,
|
|
||||||
Result: H{
|
|
||||||
"trackingId": trackingId,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
98
internal/api/sign_transfer.go
Normal file
98
internal/api/sign_transfer.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
||||||
|
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/internal/tasker/task"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleSignTransfer godoc
|
||||||
|
//
|
||||||
|
// @Summary Sign and dispatch transfer request.
|
||||||
|
// @Description Sign and dispatch a transfer request.
|
||||||
|
// @Tags network
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param signTransferRequest body object{from=string,to=string,voucherAddress=string,amount=uint64} true "Sign Transfer Request"
|
||||||
|
// @Success 200 {object} OkResp
|
||||||
|
// @Failure 400 {object} ErrResp
|
||||||
|
// @Failure 500 {object} ErrResp
|
||||||
|
// @Router /sign/transfer [post]
|
||||||
|
func HandleSignTransfer(cu *custodial.Custodial) func(echo.Context) error {
|
||||||
|
return func(c echo.Context) error {
|
||||||
|
var (
|
||||||
|
req struct {
|
||||||
|
From string `json:"from" validate:"required,eth_addr_checksum"`
|
||||||
|
To string `json:"to" validate:"required,eth_addr_checksum"`
|
||||||
|
VoucherAddress string `json:"voucherAddress" validate:"required,eth_addr_checksum"`
|
||||||
|
Amount uint64 `json:"amount" validate:"gt=0"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := c.Bind(&req); err != nil {
|
||||||
|
return NewBadRequestError(ErrInvalidJSON)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.Validate(req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
accountActive, gasLock, err := cu.Store.GetAccountStatus(c.Request().Context(), req.From)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !accountActive {
|
||||||
|
return c.JSON(http.StatusForbidden, ErrResp{
|
||||||
|
Ok: false,
|
||||||
|
Message: "Account pending activation. Try again later.",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if gasLock {
|
||||||
|
return c.JSON(http.StatusForbidden, ErrResp{
|
||||||
|
Ok: false,
|
||||||
|
Message: "Gas lock. Gas balance unavailable. Try again later.",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
trackingId := uuid.NewString()
|
||||||
|
|
||||||
|
taskPayload, err := json.Marshal(task.TransferPayload{
|
||||||
|
TrackingId: trackingId,
|
||||||
|
From: req.From,
|
||||||
|
To: req.To,
|
||||||
|
VoucherAddress: req.VoucherAddress,
|
||||||
|
Amount: req.Amount,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = cu.TaskerClient.CreateTask(
|
||||||
|
c.Request().Context(),
|
||||||
|
tasker.SignTransferTask,
|
||||||
|
tasker.HighPriority,
|
||||||
|
&tasker.Task{
|
||||||
|
Id: trackingId,
|
||||||
|
Payload: taskPayload,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(http.StatusOK, OkResp{
|
||||||
|
Ok: true,
|
||||||
|
Result: H{
|
||||||
|
"trackingId": trackingId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
107
internal/api/sign_transfer_auth.go
Normal file
107
internal/api/sign_transfer_auth.go
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/internal/tasker/task"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Max 10k vouchers per approval session
|
||||||
|
const approvalSafetyLimit = 10000 * 1000000
|
||||||
|
|
||||||
|
// HandleSignTransferAuthorization godoc
|
||||||
|
//
|
||||||
|
// @Summary Sign and dispatch a transfer authorization (approve) request.
|
||||||
|
// @Description Sign and dispatch a transfer authorization (approve) request.
|
||||||
|
// @Tags network
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param signTransferAuthorzationRequest body object{amount=uint64,authorizer=string,authorizedAddress=string,voucherAddress=string} true "Sign Transfer Authorization (approve) Request"
|
||||||
|
// @Success 200 {object} OkResp
|
||||||
|
// @Failure 400 {object} ErrResp
|
||||||
|
// @Failure 500 {object} ErrResp
|
||||||
|
// @Router /sign/transferAuth [post]
|
||||||
|
func HandleSignTranserAuthorization(cu *custodial.Custodial) func(echo.Context) error {
|
||||||
|
return func(c echo.Context) error {
|
||||||
|
var (
|
||||||
|
req struct {
|
||||||
|
Amount uint64 `json:"amount" validate:"gte=0"`
|
||||||
|
Authorizer string `json:"authorizer" validate:"required,eth_addr_checksum"`
|
||||||
|
AuthorizedAddress string `json:"authorizedAddress" validate:"required,eth_addr_checksum"`
|
||||||
|
VoucherAddress string `json:"voucherAddress" validate:"required,eth_addr_checksum"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := c.Bind(&req); err != nil {
|
||||||
|
return NewBadRequestError(ErrInvalidJSON)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.Validate(req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
accountActive, gasLock, err := cu.Store.GetAccountStatus(c.Request().Context(), req.Authorizer)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Amount > approvalSafetyLimit {
|
||||||
|
return c.JSON(http.StatusForbidden, ErrResp{
|
||||||
|
Ok: false,
|
||||||
|
Message: "Approval amount per session exceeds 10k.",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if !accountActive {
|
||||||
|
return c.JSON(http.StatusForbidden, ErrResp{
|
||||||
|
Ok: false,
|
||||||
|
Message: "Account pending activation. Try again later.",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if gasLock {
|
||||||
|
return c.JSON(http.StatusForbidden, ErrResp{
|
||||||
|
Ok: false,
|
||||||
|
Message: "Gas lock. Gas balance unavailable. Try again later.",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
trackingId := uuid.NewString()
|
||||||
|
|
||||||
|
taskPayload, err := json.Marshal(task.TransferAuthPayload{
|
||||||
|
TrackingId: trackingId,
|
||||||
|
Amount: req.Amount,
|
||||||
|
Authorizer: req.Authorizer,
|
||||||
|
AuthorizedAddress: req.AuthorizedAddress,
|
||||||
|
VoucherAddress: req.VoucherAddress,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = cu.TaskerClient.CreateTask(
|
||||||
|
c.Request().Context(),
|
||||||
|
tasker.SignTransferTaskAuth,
|
||||||
|
tasker.DefaultPriority,
|
||||||
|
&tasker.Task{
|
||||||
|
Id: trackingId,
|
||||||
|
Payload: taskPayload,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(http.StatusOK, OkResp{
|
||||||
|
Ok: true,
|
||||||
|
Result: H{
|
||||||
|
"trackingId": trackingId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
15
internal/api/swagger.go
Normal file
15
internal/api/swagger.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
// @title CIC Custodial API
|
||||||
|
// @version 1.0
|
||||||
|
// @description Interact with CIC Custodial API
|
||||||
|
// @termsOfService https://grassecon.org/pages/terms-and-conditions.html
|
||||||
|
|
||||||
|
// @contact.name API Support
|
||||||
|
// @contact.url https://grassecon.org/pages/contact-us
|
||||||
|
// @contact.email devops@grassecon.org
|
||||||
|
|
||||||
|
// @license.name AGPL-3.0
|
||||||
|
// @license.url https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||||
|
|
||||||
|
// @BasePath /api
|
@ -3,26 +3,38 @@ package api
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TxStatus(store store.Store) func(echo.Context) error {
|
// HandleTrackTx godoc
|
||||||
|
// @Summary Track an OTX (Origin transaction) status.
|
||||||
|
// @Description Track an OTX (Origin transaction) status.
|
||||||
|
// @Tags track
|
||||||
|
// @Accept */*
|
||||||
|
// @Produce json
|
||||||
|
// @Param trackingId path string true "Tracking Id"
|
||||||
|
// @Success 200 {object} OkResp
|
||||||
|
// @Failure 400 {object} ErrResp
|
||||||
|
// @Failure 500 {object} ErrResp
|
||||||
|
// @Router /track/{trackingId} [get]
|
||||||
|
func HandleTrackTx(cu *custodial.Custodial) func(echo.Context) error {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
var txStatusRequest struct {
|
var (
|
||||||
TrackingId string `param:"trackingId" validate:"required,uuid"`
|
txStatusRequest struct {
|
||||||
}
|
TrackingId string `param:"trackingId" validate:"required,uuid"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
if err := c.Bind(&txStatusRequest); err != nil {
|
if err := c.Bind(&txStatusRequest); err != nil {
|
||||||
return err
|
return NewBadRequestError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.Validate(txStatusRequest); err != nil {
|
if err := c.Validate(txStatusRequest); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: handle potential timeouts
|
txs, err := cu.Store.GetTxStatus(c.Request().Context(), txStatusRequest.TrackingId)
|
||||||
txs, err := store.GetTxStatusByTrackingId(c.Request().Context(), txStatusRequest.TrackingId)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -30,7 +42,7 @@ func TxStatus(store store.Store) func(echo.Context) error {
|
|||||||
return c.JSON(http.StatusOK, OkResp{
|
return c.JSON(http.StatusOK, OkResp{
|
||||||
Ok: true,
|
Ok: true,
|
||||||
Result: H{
|
Result: H{
|
||||||
"transactions": txs,
|
"transaction": txs,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
const (
|
import "errors"
|
||||||
INTERNAL_ERROR = "ERR_INTERNAL"
|
|
||||||
VALIDATION_ERROR = "ERR_VALIDATE"
|
var (
|
||||||
DUPLICATE_ERROR = "ERR_DUPLICATE"
|
ErrInvalidJSON = errors.New("Invalid JSON structure.")
|
||||||
)
|
)
|
||||||
|
|
||||||
type H map[string]any
|
type H map[string]any
|
||||||
@ -15,6 +15,5 @@ type OkResp struct {
|
|||||||
|
|
||||||
type ErrResp struct {
|
type ErrResp struct {
|
||||||
Ok bool `json:"ok"`
|
Ok bool `json:"ok"`
|
||||||
Code string `json:"errorCode"`
|
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/celo-org/celo-blockchain/common"
|
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -11,16 +10,9 @@ type Validator struct {
|
|||||||
|
|
||||||
func (v *Validator) Validate(i interface{}) error {
|
func (v *Validator) Validate(i interface{}) error {
|
||||||
if err := v.ValidatorProvider.Struct(i); err != nil {
|
if err := v.ValidatorProvider.Struct(i); err != nil {
|
||||||
return err
|
if _, ok := err.(validator.ValidationErrors); ok {
|
||||||
|
return NewBadRequestError(err.(validator.ValidationErrors).Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func EthChecksumValidator(fl validator.FieldLevel) bool {
|
|
||||||
addr, err := common.NewMixedcaseAddressFromString(fl.Field().String())
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return addr.ValidChecksum()
|
|
||||||
}
|
|
||||||
|
28
internal/custodial/abis.go
Normal file
28
internal/custodial/abis.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package custodial
|
||||||
|
|
||||||
|
import "github.com/grassrootseconomics/w3-celo-patch"
|
||||||
|
|
||||||
|
const (
|
||||||
|
Approve = "approve"
|
||||||
|
Check = "check"
|
||||||
|
GiveTo = "giveTo"
|
||||||
|
MintTo = "mintTo"
|
||||||
|
NextTime = "nextTime"
|
||||||
|
Register = "register"
|
||||||
|
Transfer = "transfer"
|
||||||
|
TransferFrom = "transferFrom"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Define common smart contrcat ABI's that can be injected into the system container.
|
||||||
|
// Any relevant function signature that will be used by the custodial system can be defined here.
|
||||||
|
func initAbis() map[string]*w3.Func {
|
||||||
|
return map[string]*w3.Func{
|
||||||
|
Approve: w3.MustNewFunc("approve(address, uint256)", "bool"),
|
||||||
|
Check: w3.MustNewFunc("check(address)", "bool"),
|
||||||
|
GiveTo: w3.MustNewFunc("giveTo(address)", "uint256"),
|
||||||
|
MintTo: w3.MustNewFunc("mintTo(address, uint256)", "bool"),
|
||||||
|
NextTime: w3.MustNewFunc("nextTime(address)", "uint256"),
|
||||||
|
Register: w3.MustNewFunc("register(address)", ""),
|
||||||
|
Transfer: w3.MustNewFunc("transfer(address,uint256)", "bool"),
|
||||||
|
}
|
||||||
|
}
|
@ -1,22 +1,89 @@
|
|||||||
package custodial
|
package custodial
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/bsm/redislock"
|
"github.com/bsm/redislock"
|
||||||
|
"github.com/celo-org/celo-blockchain/common"
|
||||||
|
eth_crypto "github.com/celo-org/celo-blockchain/crypto"
|
||||||
"github.com/grassrootseconomics/celoutils"
|
"github.com/grassrootseconomics/celoutils"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/events"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/keystore"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/nonce"
|
"github.com/grassrootseconomics/cic-custodial/internal/nonce"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/pkg/util"
|
||||||
|
"github.com/grassrootseconomics/w3-celo-patch"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
"github.com/zerodha/logf"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Custodial struct {
|
type (
|
||||||
CeloProvider *celoutils.Provider
|
Opts struct {
|
||||||
EventEmitter events.EventEmitter
|
ApprovalTimeout time.Duration
|
||||||
Keystore keystore.Keystore
|
CeloProvider *celoutils.Provider
|
||||||
LockProvider *redislock.Client
|
LockProvider *redislock.Client
|
||||||
Noncestore nonce.Noncestore
|
Logg logf.Logger
|
||||||
PgStore store.Store
|
Noncestore nonce.Noncestore
|
||||||
SystemContainer *tasker.SystemContainer
|
Store store.Store
|
||||||
TaskerClient *tasker.TaskerClient
|
RedisClient *redis.Client
|
||||||
|
RegistryAddress string
|
||||||
|
SystemPrivateKey string
|
||||||
|
SystemPublicKey string
|
||||||
|
TaskerClient *tasker.TaskerClient
|
||||||
|
}
|
||||||
|
|
||||||
|
Custodial struct {
|
||||||
|
ApprovalTimeout time.Duration
|
||||||
|
Abis map[string]*w3.Func
|
||||||
|
CeloProvider *celoutils.Provider
|
||||||
|
LockProvider *redislock.Client
|
||||||
|
Logg logf.Logger
|
||||||
|
Noncestore nonce.Noncestore
|
||||||
|
Store store.Store
|
||||||
|
RedisClient *redis.Client
|
||||||
|
RegistryMap map[string]common.Address
|
||||||
|
SystemPrivateKey *ecdsa.PrivateKey
|
||||||
|
SystemPublicKey string
|
||||||
|
TaskerClient *tasker.TaskerClient
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewCustodial(o Opts) (*Custodial, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), util.SLATimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
registryMap, err := o.CeloProvider.RegistryMap(ctx, celoutils.HexToAddress(o.RegistryAddress))
|
||||||
|
if err != nil {
|
||||||
|
o.Logg.Error("custodial: critical error loading contracts from registry: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
systemNonce, err := o.Noncestore.Peek(ctx, o.SystemPublicKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
o.Logg.Info("custodial: loaded_nonce", "system_nonce", systemNonce)
|
||||||
|
|
||||||
|
privateKey, err := eth_crypto.HexToECDSA(o.SystemPrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Custodial{
|
||||||
|
ApprovalTimeout: o.ApprovalTimeout,
|
||||||
|
Abis: initAbis(),
|
||||||
|
CeloProvider: o.CeloProvider,
|
||||||
|
LockProvider: o.LockProvider,
|
||||||
|
Logg: o.Logg,
|
||||||
|
Noncestore: o.Noncestore,
|
||||||
|
Store: o.Store,
|
||||||
|
RedisClient: o.RedisClient,
|
||||||
|
RegistryMap: registryMap,
|
||||||
|
SystemPrivateKey: privateKey,
|
||||||
|
SystemPublicKey: o.SystemPublicKey,
|
||||||
|
TaskerClient: o.TaskerClient,
|
||||||
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
package events
|
|
||||||
|
|
||||||
type EventEmitter interface {
|
|
||||||
Close()
|
|
||||||
Publish(subject string, dedupId string, eventPayload interface{}) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type EventPayload struct {
|
|
||||||
OtxId uint `json:"otxId"`
|
|
||||||
TrackingId string `json:"trackingId"`
|
|
||||||
TxHash string `json:"txHash"`
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
package events
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/nats-io/nats.go"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
StreamName string = "CUSTODIAL"
|
|
||||||
StreamSubjects string = "CUSTODIAL.*"
|
|
||||||
// Subjects
|
|
||||||
AccountNewNonce string = "CUSTODIAL.accountNewNonce"
|
|
||||||
AccountRegister string = "CUSTODIAL.accountRegister"
|
|
||||||
AccountGiftGas string = "CUSTODIAL.systemNewAccountGas"
|
|
||||||
AccountGiftVoucher string = "CUSTODIAL.systemNewAccountVoucher"
|
|
||||||
AccountRefillGas string = "CUSTODIAL.systemRefillAccountGas"
|
|
||||||
DispatchFail string = "CUSTODIAL.dispatchFail"
|
|
||||||
DispatchSuccess string = "CUSTODIAL.dispatchSuccess"
|
|
||||||
SignTransfer string = "CUSTODIAL.signTransfer"
|
|
||||||
)
|
|
||||||
|
|
||||||
type JetStreamOpts struct {
|
|
||||||
ServerUrl string
|
|
||||||
PersistDuration time.Duration
|
|
||||||
DedupDuration time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
type JetStream struct {
|
|
||||||
jsCtx nats.JetStreamContext
|
|
||||||
nc *nats.Conn
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewJetStreamEventEmitter(o JetStreamOpts) (EventEmitter, error) {
|
|
||||||
natsConn, err := nats.Connect(o.ServerUrl)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
js, err := natsConn.JetStream()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bootstrap stream if it doesn't exist.
|
|
||||||
stream, _ := js.StreamInfo(StreamName)
|
|
||||||
if stream == nil {
|
|
||||||
_, err = js.AddStream(&nats.StreamConfig{
|
|
||||||
Name: StreamName,
|
|
||||||
MaxAge: o.PersistDuration,
|
|
||||||
Storage: nats.FileStorage,
|
|
||||||
Subjects: []string{StreamSubjects},
|
|
||||||
Duplicates: o.DedupDuration,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &JetStream{
|
|
||||||
jsCtx: js,
|
|
||||||
nc: natsConn,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close gracefully shutdowns the JetStream connection.
|
|
||||||
func (js *JetStream) Close() {
|
|
||||||
if js.nc != nil {
|
|
||||||
js.nc.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Publish publishes the JSON data to the NATS stream.
|
|
||||||
func (js *JetStream) Publish(subject string, dedupId string, eventPayload interface{}) error {
|
|
||||||
jsonData, err := json.Marshal(eventPayload)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = js.jsCtx.Publish(subject, jsonData, nats.MsgId(dedupId))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
package keystore
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/ecdsa"
|
|
||||||
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/pkg/keypair"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Keystore defines how keypairs should be stored and accessed from a storage backend.
|
|
||||||
type Keystore interface {
|
|
||||||
WriteKeyPair(context.Context, keypair.Key) (uint, error)
|
|
||||||
LoadPrivateKey(context.Context, string) (*ecdsa.PrivateKey, error)
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
package keystore
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/ecdsa"
|
|
||||||
|
|
||||||
eth_crypto "github.com/celo-org/celo-blockchain/crypto"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/queries"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/pkg/keypair"
|
|
||||||
"github.com/jackc/pgx/v5/pgxpool"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
Opts struct {
|
|
||||||
PostgresPool *pgxpool.Pool
|
|
||||||
Queries *queries.Queries
|
|
||||||
}
|
|
||||||
|
|
||||||
PostgresKeystore struct {
|
|
||||||
db *pgxpool.Pool
|
|
||||||
queries *queries.Queries
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewPostgresKeytore(o Opts) Keystore {
|
|
||||||
return &PostgresKeystore{
|
|
||||||
db: o.PostgresPool,
|
|
||||||
queries: o.Queries,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteKeyPair inserts a keypair into the db and returns the linked id.
|
|
||||||
func (ks *PostgresKeystore) WriteKeyPair(ctx context.Context, keypair keypair.Key) (uint, error) {
|
|
||||||
var (
|
|
||||||
id uint
|
|
||||||
)
|
|
||||||
|
|
||||||
if err := ks.db.QueryRow(ctx, ks.queries.WriteKeyPair, keypair.Public, keypair.Private).Scan(&id); err != nil {
|
|
||||||
return id, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return id, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadPrivateKey loads a private key as a crypto primitive for direct use. An id is used to search for the private key.
|
|
||||||
func (ks *PostgresKeystore) LoadPrivateKey(ctx context.Context, publicKey string) (*ecdsa.PrivateKey, error) {
|
|
||||||
var (
|
|
||||||
privateKeyString string
|
|
||||||
)
|
|
||||||
|
|
||||||
if err := ks.db.QueryRow(ctx, ks.queries.LoadKeyPair, publicKey).Scan(&privateKeyString); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
privateKey, err := eth_crypto.HexToECDSA(privateKeyString)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return privateKey, nil
|
|
||||||
}
|
|
@ -7,6 +7,5 @@ type Noncestore interface {
|
|||||||
Peek(context.Context, string) (uint64, error)
|
Peek(context.Context, string) (uint64, error)
|
||||||
Acquire(context.Context, string) (uint64, error)
|
Acquire(context.Context, string) (uint64, error)
|
||||||
Return(context.Context, string) error
|
Return(context.Context, string) error
|
||||||
SyncNetworkNonce(context.Context, string) (uint64, error)
|
SetAccountNonce(context.Context, string, uint64) error
|
||||||
SetNewAccountNonce(context.Context, string) error
|
|
||||||
}
|
}
|
||||||
|
@ -2,35 +2,52 @@ package nonce
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/grassrootseconomics/celoutils"
|
"github.com/grassrootseconomics/celoutils"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
||||||
redispool "github.com/grassrootseconomics/cic-custodial/pkg/redis"
|
redispool "github.com/grassrootseconomics/cic-custodial/pkg/redis"
|
||||||
"github.com/grassrootseconomics/w3-celo-patch"
|
|
||||||
"github.com/grassrootseconomics/w3-celo-patch/module/eth"
|
"github.com/grassrootseconomics/w3-celo-patch/module/eth"
|
||||||
|
"github.com/jackc/pgx/v5"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Opts struct {
|
type (
|
||||||
RedisPool *redispool.RedisPool
|
Opts struct {
|
||||||
CeloProvider *celoutils.Provider
|
ChainProvider *celoutils.Provider
|
||||||
}
|
RedisPool *redispool.RedisPool
|
||||||
|
Store store.Store
|
||||||
|
}
|
||||||
|
|
||||||
// RedisNoncestore implements `Noncestore`
|
// RedisNoncestore implements `Noncestore`
|
||||||
type RedisNoncestore struct {
|
RedisNoncestore struct {
|
||||||
chainProvider *celoutils.Provider
|
chainProvider *celoutils.Provider
|
||||||
redis *redispool.RedisPool
|
redis *redispool.RedisPool
|
||||||
}
|
store store.Store
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func NewRedisNoncestore(o Opts) Noncestore {
|
func NewRedisNoncestore(o Opts) Noncestore {
|
||||||
return &RedisNoncestore{
|
return &RedisNoncestore{
|
||||||
|
chainProvider: o.ChainProvider,
|
||||||
redis: o.RedisPool,
|
redis: o.RedisPool,
|
||||||
chainProvider: o.CeloProvider,
|
store: o.Store,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *RedisNoncestore) Peek(ctx context.Context, publicKey string) (uint64, error) {
|
func (n *RedisNoncestore) Peek(ctx context.Context, publicKey string) (uint64, error) {
|
||||||
nonce, err := n.redis.Client.Get(ctx, publicKey).Uint64()
|
nonce, err := n.redis.Client.Get(ctx, publicKey).Uint64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
if err == redis.Nil {
|
||||||
|
nonce, err = n.bootstrap(ctx, publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nonce, nil
|
||||||
|
} else {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nonce, nil
|
return nonce, nil
|
||||||
@ -43,7 +60,14 @@ func (n *RedisNoncestore) Acquire(ctx context.Context, publicKey string) (uint64
|
|||||||
|
|
||||||
nonce, err := n.redis.Client.Get(ctx, publicKey).Uint64()
|
nonce, err := n.redis.Client.Get(ctx, publicKey).Uint64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil
|
if err == redis.Nil {
|
||||||
|
nonce, err = n.bootstrap(ctx, publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = n.redis.Client.Incr(ctx, publicKey).Err()
|
err = n.redis.Client.Incr(ctx, publicKey).Err()
|
||||||
@ -70,32 +94,37 @@ func (n *RedisNoncestore) Return(ctx context.Context, publicKey string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *RedisNoncestore) SyncNetworkNonce(ctx context.Context, publicKey string) (uint64, error) {
|
func (n *RedisNoncestore) SetAccountNonce(ctx context.Context, publicKey string, nonce uint64) error {
|
||||||
var (
|
if err := n.redis.Client.Set(ctx, publicKey, nonce, 0).Err(); err != nil {
|
||||||
networkNonce uint64
|
|
||||||
)
|
|
||||||
|
|
||||||
err := n.chainProvider.Client.CallCtx(
|
|
||||||
ctx,
|
|
||||||
eth.Nonce(w3.A(publicKey), nil).Returns(&networkNonce),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = n.redis.Client.Set(ctx, publicKey, networkNonce, 0).Err()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return networkNonce, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *RedisNoncestore) SetNewAccountNonce(ctx context.Context, publicKey string) error {
|
|
||||||
err := n.redis.Client.Set(ctx, publicKey, 0, 0).Err()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bootstrap can be used to restore a destroyed redis nonce cache automatically.
|
||||||
|
// It first uses the otx_sign table as a source of nonce values.
|
||||||
|
// If the otx_sign table is corrupted, it can fallback to the network nonce.
|
||||||
|
// Ideally, the redis nonce cache should never be lost.
|
||||||
|
func (n *RedisNoncestore) bootstrap(ctx context.Context, publicKey string) (uint64, error) {
|
||||||
|
lastDbNonce, err := n.store.GetNextNonce(ctx, publicKey)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
err := n.chainProvider.Client.CallCtx(
|
||||||
|
ctx,
|
||||||
|
eth.Nonce(celoutils.HexToAddress(publicKey), nil).Returns(&lastDbNonce),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := n.SetAccountNonce(ctx, publicKey, lastDbNonce); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastDbNonce, nil
|
||||||
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
package queries
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/knadh/goyesql/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Queries struct {
|
|
||||||
// Keystore
|
|
||||||
WriteKeyPair string `query:"write-key-pair"`
|
|
||||||
LoadKeyPair string `query:"load-key-pair"`
|
|
||||||
// Store
|
|
||||||
CreateOTX string `query:"create-otx"`
|
|
||||||
CreateDispatchStatus string `query:"create-dispatch-status"`
|
|
||||||
UpdateChainStatus string `query:"update-chain-status"`
|
|
||||||
GetTxStatusByTrackingId string `query:"get-tx-status-by-tracking-id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadQueries(q goyesql.Queries) (*Queries, error) {
|
|
||||||
loadedQueries := &Queries{}
|
|
||||||
|
|
||||||
if err := goyesql.ScanToStruct(loadedQueries, q, nil); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to scan queries %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return loadedQueries, nil
|
|
||||||
}
|
|
73
internal/store/account.go
Normal file
73
internal/store/account.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *PgStore) ActivateAccount(
|
||||||
|
ctx context.Context,
|
||||||
|
publicAddress string,
|
||||||
|
) error {
|
||||||
|
if _, err := s.db.Exec(
|
||||||
|
ctx,
|
||||||
|
s.queries.ActivateAccount,
|
||||||
|
publicAddress,
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PgStore) GetAccountStatus(
|
||||||
|
ctx context.Context,
|
||||||
|
publicAddress string,
|
||||||
|
) (bool, bool, error) {
|
||||||
|
var (
|
||||||
|
accountActive bool
|
||||||
|
gasLock bool
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := s.db.QueryRow(
|
||||||
|
ctx,
|
||||||
|
s.queries.GetAccountStatus,
|
||||||
|
publicAddress,
|
||||||
|
).Scan(
|
||||||
|
&accountActive,
|
||||||
|
&gasLock,
|
||||||
|
); err != nil {
|
||||||
|
return false, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return accountActive, gasLock, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PgStore) GasLock(
|
||||||
|
ctx context.Context,
|
||||||
|
publicAddress string,
|
||||||
|
) error {
|
||||||
|
if _, err := s.db.Exec(
|
||||||
|
ctx,
|
||||||
|
s.queries.GasLock,
|
||||||
|
publicAddress,
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PgStore) GasUnlock(
|
||||||
|
ctx context.Context,
|
||||||
|
publicAddress string,
|
||||||
|
) error {
|
||||||
|
if _, err := s.db.Exec(
|
||||||
|
ctx,
|
||||||
|
s.queries.GasUnlock,
|
||||||
|
publicAddress,
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,34 +0,0 @@
|
|||||||
package store
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s *PostgresStore) CreateDispatchStatus(ctx context.Context, dispatch DispatchStatus) error {
|
|
||||||
if _, err := s.db.Exec(
|
|
||||||
ctx,
|
|
||||||
s.queries.CreateDispatchStatus,
|
|
||||||
dispatch.OtxId,
|
|
||||||
dispatch.Status,
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *PostgresStore) UpdateChainStatus(ctx context.Context, txHash string, status enum.OtxStatus, block uint64) error {
|
|
||||||
if _, err := s.db.Exec(
|
|
||||||
ctx,
|
|
||||||
s.queries.UpdateChainStatus,
|
|
||||||
txHash,
|
|
||||||
status,
|
|
||||||
block,
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
53
internal/store/keystore.go
Normal file
53
internal/store/keystore.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
|
||||||
|
eth_crypto "github.com/celo-org/celo-blockchain/crypto"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/pkg/keypair"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *PgStore) WriteKeyPair(
|
||||||
|
ctx context.Context,
|
||||||
|
keypair keypair.Key,
|
||||||
|
) (uint, error) {
|
||||||
|
var (
|
||||||
|
id uint
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := s.db.QueryRow(
|
||||||
|
ctx,
|
||||||
|
s.queries.WriteKeyPair,
|
||||||
|
keypair.Public,
|
||||||
|
keypair.Private,
|
||||||
|
).Scan(&id); err != nil {
|
||||||
|
return id, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PgStore) LoadPrivateKey(
|
||||||
|
ctx context.Context,
|
||||||
|
publicKey string,
|
||||||
|
) (*ecdsa.PrivateKey, error) {
|
||||||
|
var (
|
||||||
|
privateKeyString string
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := s.db.QueryRow(
|
||||||
|
ctx,
|
||||||
|
s.queries.LoadKeyPair,
|
||||||
|
publicKey,
|
||||||
|
).Scan(&privateKeyString); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
privateKey, err := eth_crypto.HexToECDSA(privateKeyString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return privateKey, nil
|
||||||
|
}
|
@ -2,20 +2,39 @@ package store
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"math/big"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/georgysavva/scany/v2/pgxscan"
|
"github.com/georgysavva/scany/v2/pgxscan"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TxStatus struct {
|
type (
|
||||||
Type string `db:"type" json:"txType"`
|
Otx struct {
|
||||||
TxHash string `db:"tx_hash" json:"txHash"`
|
TrackingId string
|
||||||
TransferValue uint64 `db:"transfer_value" json:"transferValue"`
|
Type enum.OtxType
|
||||||
CreatedAt time.Time `db:"created_at" json:"createdAt"`
|
RawTx string
|
||||||
Status string `db:"status" json:"status"`
|
TxHash string
|
||||||
}
|
From string
|
||||||
|
Data string
|
||||||
|
GasLimit uint64
|
||||||
|
TransferValue uint64
|
||||||
|
GasPrice *big.Int
|
||||||
|
Nonce uint64
|
||||||
|
}
|
||||||
|
TxStatus struct {
|
||||||
|
CreatedAt time.Time `db:"created_at" json:"createdAt"`
|
||||||
|
Status string `db:"status" json:"status"`
|
||||||
|
TransferValue uint64 `db:"transfer_value" json:"transferValue"`
|
||||||
|
TxHash string `db:"tx_hash" json:"txHash"`
|
||||||
|
Type string `db:"type" json:"txType"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func (s *PostgresStore) CreateOtx(ctx context.Context, otx OTX) (uint, error) {
|
func (s *PgStore) CreateOtx(
|
||||||
|
ctx context.Context,
|
||||||
|
otx Otx,
|
||||||
|
) (uint, error) {
|
||||||
var (
|
var (
|
||||||
id uint
|
id uint
|
||||||
)
|
)
|
||||||
@ -33,27 +52,103 @@ func (s *PostgresStore) CreateOtx(ctx context.Context, otx OTX) (uint, error) {
|
|||||||
otx.GasLimit,
|
otx.GasLimit,
|
||||||
otx.TransferValue,
|
otx.TransferValue,
|
||||||
otx.Nonce,
|
otx.Nonce,
|
||||||
).Scan(&id); err != nil {
|
).Scan(
|
||||||
|
&id,
|
||||||
|
); err != nil {
|
||||||
return id, err
|
return id, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *PostgresStore) GetTxStatusByTrackingId(ctx context.Context, trackingId string) ([]*TxStatus, error) {
|
func (s *PgStore) GetNextNonce(
|
||||||
|
ctx context.Context,
|
||||||
|
publicAddress string,
|
||||||
|
) (uint64, error) {
|
||||||
var (
|
var (
|
||||||
txs []*TxStatus
|
lastNonce uint64
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := pgxscan.Select(
|
if err := s.db.QueryRow(
|
||||||
ctx,
|
ctx,
|
||||||
s.db,
|
s.queries.GetNextNonce,
|
||||||
&txs,
|
publicAddress,
|
||||||
s.queries.GetTxStatusByTrackingId,
|
).Scan(
|
||||||
trackingId,
|
&lastNonce,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return txs, nil
|
return lastNonce, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PgStore) GetTxStatus(
|
||||||
|
ctx context.Context,
|
||||||
|
trackingId string,
|
||||||
|
) (TxStatus, error) {
|
||||||
|
var (
|
||||||
|
tx TxStatus
|
||||||
|
)
|
||||||
|
|
||||||
|
rows, err := s.db.Query(
|
||||||
|
ctx,
|
||||||
|
s.queries.GetTxStatusByTrackingId,
|
||||||
|
trackingId,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return tx, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := pgxscan.ScanOne(
|
||||||
|
&tx,
|
||||||
|
rows,
|
||||||
|
); err != nil {
|
||||||
|
return tx, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PgStore) CreateDispatchStatus(
|
||||||
|
ctx context.Context,
|
||||||
|
otxId uint,
|
||||||
|
otxStatus enum.OtxStatus,
|
||||||
|
) error {
|
||||||
|
if _, err := s.db.Exec(
|
||||||
|
ctx,
|
||||||
|
s.queries.CreateDispatchStatus,
|
||||||
|
otxId,
|
||||||
|
otxStatus,
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PgStore) UpdateDispatchStatus(
|
||||||
|
ctx context.Context,
|
||||||
|
txSuccess bool,
|
||||||
|
txHash string,
|
||||||
|
txBlock uint64,
|
||||||
|
) error {
|
||||||
|
var (
|
||||||
|
status = enum.SUCCESS
|
||||||
|
)
|
||||||
|
|
||||||
|
if !txSuccess {
|
||||||
|
status = enum.REVERTED
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := s.db.Exec(
|
||||||
|
ctx,
|
||||||
|
s.queries.UpdateDispatchStatus,
|
||||||
|
txHash,
|
||||||
|
status,
|
||||||
|
txBlock,
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
package store
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/queries"
|
|
||||||
"github.com/jackc/pgx/v5/pgxpool"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
Opts struct {
|
|
||||||
PostgresPool *pgxpool.Pool
|
|
||||||
Queries *queries.Queries
|
|
||||||
}
|
|
||||||
|
|
||||||
PostgresStore struct {
|
|
||||||
db *pgxpool.Pool
|
|
||||||
queries *queries.Queries
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewPostgresStore(o Opts) Store {
|
|
||||||
return &PostgresStore{
|
|
||||||
db: o.PostgresPool,
|
|
||||||
queries: o.Queries,
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,33 +2,129 @@ package store
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/pkg/keypair"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/pkg/util"
|
||||||
|
"github.com/jackc/pgx/v5/pgxpool"
|
||||||
|
"github.com/jackc/tern/v2/migrate"
|
||||||
|
"github.com/knadh/goyesql/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
OTX struct {
|
|
||||||
TrackingId string
|
|
||||||
Type enum.OtxType
|
|
||||||
RawTx string
|
|
||||||
TxHash string
|
|
||||||
From string
|
|
||||||
Data string
|
|
||||||
GasLimit uint64
|
|
||||||
TransferValue uint64
|
|
||||||
GasPrice uint64
|
|
||||||
Nonce uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
DispatchStatus struct {
|
|
||||||
OtxId uint
|
|
||||||
Status enum.OtxStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
Store interface {
|
Store interface {
|
||||||
CreateOtx(ctx context.Context, otx OTX) (id uint, err error)
|
// Keypair related actions.
|
||||||
CreateDispatchStatus(ctx context.Context, dispatch DispatchStatus) error
|
LoadPrivateKey(context.Context, string) (*ecdsa.PrivateKey, error)
|
||||||
GetTxStatusByTrackingId(ctx context.Context, trackingId string) ([]*TxStatus, error)
|
WriteKeyPair(context.Context, keypair.Key) (uint, error)
|
||||||
UpdateChainStatus(ctx context.Context, txHash string, status enum.OtxStatus, block uint64) error
|
// Otx related actions.
|
||||||
|
CreateOtx(context.Context, Otx) (uint, error)
|
||||||
|
GetNextNonce(context.Context, string) (uint64, error)
|
||||||
|
GetTxStatus(context.Context, string) (TxStatus, error)
|
||||||
|
CreateDispatchStatus(context.Context, uint, enum.OtxStatus) error
|
||||||
|
UpdateDispatchStatus(context.Context, bool, string, uint64) error
|
||||||
|
// Account related actions.
|
||||||
|
ActivateAccount(context.Context, string) error
|
||||||
|
GetAccountStatus(context.Context, string) (bool, bool, error)
|
||||||
|
// Gas quota related actions.
|
||||||
|
GasLock(context.Context, string) error
|
||||||
|
GasUnlock(context.Context, string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
Opts struct {
|
||||||
|
DSN string
|
||||||
|
MigrationsFolderPath string
|
||||||
|
QueriesFolderPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
PgStore struct {
|
||||||
|
db *pgxpool.Pool
|
||||||
|
queries *queries
|
||||||
|
}
|
||||||
|
|
||||||
|
queries struct {
|
||||||
|
// Keystore related queries.
|
||||||
|
WriteKeyPair string `query:"write-key-pair"`
|
||||||
|
LoadKeyPair string `query:"load-key-pair"`
|
||||||
|
// Otx related queries.
|
||||||
|
CreateOTX string `query:"create-otx"`
|
||||||
|
GetNextNonce string `query:"get-next-nonce"`
|
||||||
|
GetTxStatusByTrackingId string `query:"get-tx-status-by-tracking-id"`
|
||||||
|
CreateDispatchStatus string `query:"create-dispatch-status"`
|
||||||
|
UpdateDispatchStatus string `query:"update-dispatch-status"`
|
||||||
|
// Account related queries.
|
||||||
|
ActivateAccount string `query:"activate-account"`
|
||||||
|
GetAccountStatus string `query:"get-account-status-by-address"`
|
||||||
|
GasLock string `query:"acc-gas-lock"`
|
||||||
|
GasUnlock string `query:"acc-gas-unlock"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func NewPgStore(o Opts) (Store, error) {
|
||||||
|
parsedConfig, err := pgxpool.ParseConfig(o.DSN)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dbPool, err := pgxpool.NewWithConfig(context.Background(), parsedConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
queries, err := loadQueries(o.QueriesFolderPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := runMigrations(context.Background(), dbPool, o.MigrationsFolderPath); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &PgStore{
|
||||||
|
db: dbPool,
|
||||||
|
queries: queries,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadQueries(queriesPath string) (*queries, error) {
|
||||||
|
parsedQueries, err := goyesql.ParseFile(queriesPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
loadedQueries := &queries{}
|
||||||
|
|
||||||
|
if err := goyesql.ScanToStruct(loadedQueries, parsedQueries, nil); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to scan queries %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadedQueries, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runMigrations(ctx context.Context, dbPool *pgxpool.Pool, migrationsPath string) error {
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, util.SLATimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
conn, err := dbPool.Acquire(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer conn.Release()
|
||||||
|
|
||||||
|
migrator, err := migrate.NewMigrator(ctx, conn.Conn(), "schema_version")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := migrator.LoadMigrations(os.DirFS(migrationsPath)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := migrator.Migrate(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
59
internal/sub/handler.go
Normal file
59
internal/sub/handler.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package sub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/nats-io/nats.go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
ChainEvent struct {
|
||||||
|
Block uint64 `json:"block"`
|
||||||
|
From string `json:"from"`
|
||||||
|
To string `json:"to"`
|
||||||
|
ContractAddress string `json:"contractAddress"`
|
||||||
|
Success bool `json:"success"`
|
||||||
|
TxHash string `json:"transactionHash"`
|
||||||
|
TxIndex uint `json:"transactionIndex"`
|
||||||
|
Value uint64 `json:"value"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Sub) processEventHandler(ctx context.Context, msg *nats.Msg) error {
|
||||||
|
var (
|
||||||
|
chainEvent ChainEvent
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := json.Unmarshal(msg.Data, &chainEvent); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.cu.Store.UpdateDispatchStatus(
|
||||||
|
ctx,
|
||||||
|
chainEvent.Success,
|
||||||
|
chainEvent.TxHash,
|
||||||
|
chainEvent.Block,
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if chainEvent.Success {
|
||||||
|
switch msg.Subject {
|
||||||
|
case "CHAIN.register":
|
||||||
|
if err := s.cu.Store.ActivateAccount(ctx, chainEvent.To); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.cu.Store.GasUnlock(ctx, chainEvent.To); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case "CHAIN.gas":
|
||||||
|
if err := s.cu.Store.GasUnlock(ctx, chainEvent.To); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
95
internal/sub/jetstream.go
Normal file
95
internal/sub/jetstream.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package sub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/pkg/util"
|
||||||
|
"github.com/nats-io/nats.go"
|
||||||
|
"github.com/zerodha/logf"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
durableId = "cic-custodial"
|
||||||
|
pullStream = "CHAIN"
|
||||||
|
pullSubject = "CHAIN.*"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
SubOpts struct {
|
||||||
|
CustodialContainer *custodial.Custodial
|
||||||
|
JsCtx nats.JetStreamContext
|
||||||
|
Logg logf.Logger
|
||||||
|
NatsConn *nats.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
Sub struct {
|
||||||
|
cu *custodial.Custodial
|
||||||
|
jsCtx nats.JetStreamContext
|
||||||
|
logg logf.Logger
|
||||||
|
natsConn *nats.Conn
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewSub(o SubOpts) (*Sub, error) {
|
||||||
|
_, err := o.JsCtx.AddConsumer(pullStream, &nats.ConsumerConfig{
|
||||||
|
Durable: durableId,
|
||||||
|
AckPolicy: nats.AckExplicitPolicy,
|
||||||
|
FilterSubject: pullSubject,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Sub{
|
||||||
|
cu: o.CustodialContainer,
|
||||||
|
jsCtx: o.JsCtx,
|
||||||
|
logg: o.Logg,
|
||||||
|
natsConn: o.NatsConn,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Sub) Process() error {
|
||||||
|
subOpts := []nats.SubOpt{
|
||||||
|
nats.ManualAck(),
|
||||||
|
nats.Bind(pullStream, durableId),
|
||||||
|
}
|
||||||
|
|
||||||
|
natsSub, err := s.jsCtx.PullSubscribe(pullSubject, durableId, subOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
events, err := natsSub.Fetch(1)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, nats.ErrTimeout) {
|
||||||
|
continue
|
||||||
|
} else if errors.Is(err, nats.ErrConnectionClosed) {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(events) > 0 {
|
||||||
|
msg := events[0]
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), util.SLATimeout)
|
||||||
|
|
||||||
|
if err := s.processEventHandler(ctx, msg); err != nil {
|
||||||
|
s.logg.Error("sub: handler error", "error", err)
|
||||||
|
msg.Nak()
|
||||||
|
} else {
|
||||||
|
msg.Ack()
|
||||||
|
}
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Sub) Close() {
|
||||||
|
if s.natsConn != nil {
|
||||||
|
s.natsConn.Close()
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package tasker
|
package tasker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
@ -9,17 +10,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
taskTimeout = 60
|
taskTimeout = 60 * time.Second
|
||||||
|
taskRetention = 48 * time.Hour
|
||||||
)
|
)
|
||||||
|
|
||||||
type TaskerClientOpts struct {
|
type TaskerClientOpts struct {
|
||||||
RedisPool *redis.RedisPool
|
RedisPool *redis.RedisPool
|
||||||
TaskRetention time.Duration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type TaskerClient struct {
|
type TaskerClient struct {
|
||||||
Client *asynq.Client
|
Client *asynq.Client
|
||||||
taskRetention time.Duration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTaskerClient(o TaskerClientOpts) *TaskerClient {
|
func NewTaskerClient(o TaskerClientOpts) *TaskerClient {
|
||||||
@ -28,21 +28,26 @@ func NewTaskerClient(o TaskerClientOpts) *TaskerClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TaskerClient) CreateTask(taskName TaskName, queueName QueueName, task *Task) (*asynq.TaskInfo, error) {
|
func (c *TaskerClient) CreateTask(ctx context.Context, taskName TaskName, queueName QueueName, task *Task, extraOpts ...asynq.Option) (*asynq.TaskInfo, error) {
|
||||||
if task.Id == "" {
|
if task.Id == "" {
|
||||||
task.Id = uuid.NewString()
|
task.Id = uuid.NewString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defaultOpts := []asynq.Option{
|
||||||
|
asynq.Queue(string(queueName)),
|
||||||
|
asynq.TaskID(task.Id),
|
||||||
|
asynq.Retention(taskRetention),
|
||||||
|
asynq.Timeout(taskTimeout),
|
||||||
|
}
|
||||||
|
defaultOpts = append(defaultOpts, extraOpts...)
|
||||||
|
|
||||||
qTask := asynq.NewTask(
|
qTask := asynq.NewTask(
|
||||||
string(taskName),
|
string(taskName),
|
||||||
task.Payload,
|
task.Payload,
|
||||||
asynq.Queue(string(queueName)),
|
defaultOpts...,
|
||||||
asynq.TaskID(task.Id),
|
|
||||||
asynq.Retention(c.taskRetention),
|
|
||||||
asynq.Timeout(taskTimeout*time.Second),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
taskInfo, err := c.Client.Enqueue(qTask)
|
taskInfo, err := c.Client.EnqueueContext(ctx, qTask)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -4,22 +4,24 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bsm/redislock"
|
"github.com/grassrootseconomics/cic-custodial/pkg/logg"
|
||||||
"github.com/grassrootseconomics/cic-custodial/pkg/redis"
|
"github.com/grassrootseconomics/cic-custodial/pkg/redis"
|
||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
"github.com/zerodha/logf"
|
"github.com/zerodha/logf"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
fixedRetryCount = 25
|
retryRequeueInterval = 1 * time.Second
|
||||||
fixedRetryPeriod = time.Second * 1
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TaskerServerOpts struct {
|
type TaskerServerOpts struct {
|
||||||
Concurrency int
|
Concurrency int
|
||||||
Logg logf.Logger
|
ErrorHandler asynq.ErrorHandler
|
||||||
LogLevel asynq.LogLevel
|
IsFailureHandler func(error) bool
|
||||||
RedisPool *redis.RedisPool
|
Logg logf.Logger
|
||||||
|
LogLevel asynq.LogLevel
|
||||||
|
RedisPool *redis.RedisPool
|
||||||
|
RetryHandler asynq.RetryDelayFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
type TaskerServer struct {
|
type TaskerServer struct {
|
||||||
@ -31,14 +33,17 @@ func NewTaskerServer(o TaskerServerOpts) *TaskerServer {
|
|||||||
server := asynq.NewServer(
|
server := asynq.NewServer(
|
||||||
o.RedisPool,
|
o.RedisPool,
|
||||||
asynq.Config{
|
asynq.Config{
|
||||||
Concurrency: o.Concurrency,
|
Concurrency: o.Concurrency,
|
||||||
IsFailure: expectedFailures,
|
DelayedTaskCheckInterval: retryRequeueInterval,
|
||||||
LogLevel: o.LogLevel,
|
ErrorHandler: o.ErrorHandler,
|
||||||
|
IsFailure: o.IsFailureHandler,
|
||||||
|
LogLevel: o.LogLevel,
|
||||||
|
Logger: logg.AsynqCompatibleLogger(o.Logg),
|
||||||
Queues: map[string]int{
|
Queues: map[string]int{
|
||||||
string(HighPriority): 5,
|
string(HighPriority): 7,
|
||||||
string(DefaultPriority): 2,
|
string(DefaultPriority): 3,
|
||||||
},
|
},
|
||||||
RetryDelayFunc: retryDelay,
|
RetryDelayFunc: o.RetryHandler,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,6 +55,10 @@ func NewTaskerServer(o TaskerServerOpts) *TaskerServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ts *TaskerServer) RegisterMiddlewareStack(middlewareStack []asynq.MiddlewareFunc) {
|
||||||
|
ts.mux.Use(middlewareStack...)
|
||||||
|
}
|
||||||
|
|
||||||
func (ts *TaskerServer) RegisterHandlers(taskName TaskName, taskHandler func(context.Context, *asynq.Task) error) {
|
func (ts *TaskerServer) RegisterHandlers(taskName TaskName, taskHandler func(context.Context, *asynq.Task) error) {
|
||||||
ts.mux.HandleFunc(string(taskName), taskHandler)
|
ts.mux.HandleFunc(string(taskName), taskHandler)
|
||||||
}
|
}
|
||||||
@ -66,22 +75,3 @@ func (ts *TaskerServer) Stop() {
|
|||||||
ts.server.Stop()
|
ts.server.Stop()
|
||||||
ts.server.Shutdown()
|
ts.server.Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectedFailures(err error) bool {
|
|
||||||
switch err {
|
|
||||||
// Ignore lock contention errors; retry until lock obtain.
|
|
||||||
case redislock.ErrNotObtained:
|
|
||||||
return false
|
|
||||||
default:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Immidiatel
|
|
||||||
func retryDelay(count int, err error, task *asynq.Task) time.Duration {
|
|
||||||
if count < fixedRetryCount {
|
|
||||||
return fixedRetryPeriod
|
|
||||||
} else {
|
|
||||||
return asynq.DefaultRetryDelayFunc(count, err, task)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,122 +0,0 @@
|
|||||||
package task
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/celo-org/celo-blockchain/common/hexutil"
|
|
||||||
"github.com/grassrootseconomics/celoutils"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/events"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
|
||||||
"github.com/grassrootseconomics/w3-celo-patch"
|
|
||||||
"github.com/hibiken/asynq"
|
|
||||||
)
|
|
||||||
|
|
||||||
func AccountGiftGasProcessor(cu *custodial.Custodial) func(context.Context, *asynq.Task) error {
|
|
||||||
return func(ctx context.Context, t *asynq.Task) error {
|
|
||||||
var (
|
|
||||||
payload AccountPayload
|
|
||||||
)
|
|
||||||
|
|
||||||
if err := json.Unmarshal(t.Payload(), &payload); err != nil {
|
|
||||||
return fmt.Errorf("account: failed %v: %w", err, asynq.SkipRetry)
|
|
||||||
}
|
|
||||||
|
|
||||||
lock, err := cu.LockProvider.Obtain(
|
|
||||||
ctx,
|
|
||||||
cu.SystemContainer.LockPrefix+cu.SystemContainer.PublicKey,
|
|
||||||
cu.SystemContainer.LockTimeout,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer lock.Release(ctx)
|
|
||||||
|
|
||||||
nonce, err := cu.Noncestore.Acquire(ctx, cu.SystemContainer.PublicKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
if nErr := cu.Noncestore.Return(ctx, cu.SystemContainer.PublicKey); nErr != nil {
|
|
||||||
err = nErr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
builtTx, err := cu.CeloProvider.SignGasTransferTx(
|
|
||||||
cu.SystemContainer.PrivateKey,
|
|
||||||
celoutils.GasTransferTxOpts{
|
|
||||||
To: w3.A(payload.PublicKey),
|
|
||||||
Nonce: nonce,
|
|
||||||
Value: cu.SystemContainer.GiftableGasValue,
|
|
||||||
GasFeeCap: celoutils.SafeGasFeeCap,
|
|
||||||
GasTipCap: celoutils.SafeGasTipCap,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
rawTx, err := builtTx.MarshalBinary()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
id, err := cu.PgStore.CreateOtx(ctx, store.OTX{
|
|
||||||
TrackingId: payload.TrackingId,
|
|
||||||
Type: enum.GIFT_GAS,
|
|
||||||
RawTx: hexutil.Encode(rawTx),
|
|
||||||
TxHash: builtTx.Hash().Hex(),
|
|
||||||
From: cu.SystemContainer.PublicKey,
|
|
||||||
Data: hexutil.Encode(builtTx.Data()),
|
|
||||||
GasPrice: builtTx.GasPrice().Uint64(),
|
|
||||||
GasLimit: builtTx.Gas(),
|
|
||||||
TransferValue: cu.SystemContainer.GiftableGasValue.Uint64(),
|
|
||||||
Nonce: builtTx.Nonce(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
disptachJobPayload, err := json.Marshal(TxPayload{
|
|
||||||
OtxId: id,
|
|
||||||
Tx: builtTx,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = cu.TaskerClient.CreateTask(
|
|
||||||
tasker.DispatchTxTask,
|
|
||||||
tasker.HighPriority,
|
|
||||||
&tasker.Task{
|
|
||||||
Payload: disptachJobPayload,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
eventPayload := &events.EventPayload{
|
|
||||||
OtxId: id,
|
|
||||||
TrackingId: payload.TrackingId,
|
|
||||||
TxHash: builtTx.Hash().Hex(),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cu.EventEmitter.Publish(
|
|
||||||
events.AccountGiftGas,
|
|
||||||
builtTx.Hash().Hex(),
|
|
||||||
eventPayload,
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,132 +0,0 @@
|
|||||||
package task
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/celo-org/celo-blockchain/common/hexutil"
|
|
||||||
"github.com/grassrootseconomics/celoutils"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/events"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
|
||||||
"github.com/grassrootseconomics/w3-celo-patch"
|
|
||||||
"github.com/hibiken/asynq"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GiftVoucherProcessor(cu *custodial.Custodial) func(context.Context, *asynq.Task) error {
|
|
||||||
return func(ctx context.Context, t *asynq.Task) error {
|
|
||||||
var (
|
|
||||||
payload AccountPayload
|
|
||||||
)
|
|
||||||
|
|
||||||
if err := json.Unmarshal(t.Payload(), &payload); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
lock, err := cu.LockProvider.Obtain(
|
|
||||||
ctx,
|
|
||||||
cu.SystemContainer.LockPrefix+cu.SystemContainer.PublicKey,
|
|
||||||
cu.SystemContainer.LockTimeout,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer lock.Release(ctx)
|
|
||||||
|
|
||||||
nonce, err := cu.Noncestore.Acquire(ctx, cu.SystemContainer.PublicKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
if nErr := cu.Noncestore.Return(ctx, cu.SystemContainer.PublicKey); nErr != nil {
|
|
||||||
err = nErr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
input, err := cu.SystemContainer.Abis["mintTo"].EncodeArgs(
|
|
||||||
w3.A(payload.PublicKey),
|
|
||||||
cu.SystemContainer.GiftableTokenValue,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
builtTx, err := cu.CeloProvider.SignContractExecutionTx(
|
|
||||||
cu.SystemContainer.PrivateKey,
|
|
||||||
celoutils.ContractExecutionTxOpts{
|
|
||||||
ContractAddress: cu.SystemContainer.GiftableToken,
|
|
||||||
InputData: input,
|
|
||||||
GasFeeCap: celoutils.SafeGasFeeCap,
|
|
||||||
GasTipCap: celoutils.SafeGasTipCap,
|
|
||||||
GasLimit: cu.SystemContainer.TokenTransferGasLimit,
|
|
||||||
Nonce: nonce,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
rawTx, err := builtTx.MarshalBinary()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
id, err := cu.PgStore.CreateOtx(ctx, store.OTX{
|
|
||||||
TrackingId: payload.TrackingId,
|
|
||||||
Type: enum.ACCOUNT_REGISTER,
|
|
||||||
RawTx: hexutil.Encode(rawTx),
|
|
||||||
TxHash: builtTx.Hash().Hex(),
|
|
||||||
From: cu.SystemContainer.PublicKey,
|
|
||||||
Data: hexutil.Encode(builtTx.Data()),
|
|
||||||
GasPrice: builtTx.GasPrice().Uint64(),
|
|
||||||
GasLimit: builtTx.Gas(),
|
|
||||||
TransferValue: cu.SystemContainer.GiftableTokenValue.Uint64(),
|
|
||||||
Nonce: builtTx.Nonce(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
disptachJobPayload, err := json.Marshal(TxPayload{
|
|
||||||
OtxId: id,
|
|
||||||
Tx: builtTx,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = cu.TaskerClient.CreateTask(
|
|
||||||
tasker.DispatchTxTask,
|
|
||||||
tasker.HighPriority,
|
|
||||||
&tasker.Task{
|
|
||||||
Payload: disptachJobPayload,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
eventPayload := &events.EventPayload{
|
|
||||||
OtxId: id,
|
|
||||||
TrackingId: payload.TrackingId,
|
|
||||||
TxHash: builtTx.Hash().Hex(),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cu.EventEmitter.Publish(
|
|
||||||
events.AccountGiftVoucher,
|
|
||||||
builtTx.Hash().Hex(),
|
|
||||||
eventPayload,
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
package task
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/events"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
|
||||||
"github.com/hibiken/asynq"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AccountPayload struct {
|
|
||||||
PublicKey string `json:"publicKey"`
|
|
||||||
TrackingId string `json:"trackingId"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func AccountPrepare(cu *custodial.Custodial) func(context.Context, *asynq.Task) error {
|
|
||||||
return func(ctx context.Context, t *asynq.Task) error {
|
|
||||||
var payload AccountPayload
|
|
||||||
|
|
||||||
if err := json.Unmarshal(t.Payload(), &payload); err != nil {
|
|
||||||
return fmt.Errorf("account: failed %v: %w", err, asynq.SkipRetry)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cu.Noncestore.SetNewAccountNonce(ctx, payload.PublicKey); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := cu.TaskerClient.CreateTask(
|
|
||||||
tasker.AccountRegisterTask,
|
|
||||||
tasker.DefaultPriority,
|
|
||||||
&tasker.Task{
|
|
||||||
Payload: t.Payload(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = cu.TaskerClient.CreateTask(
|
|
||||||
tasker.AccountGiftGasTask,
|
|
||||||
tasker.DefaultPriority,
|
|
||||||
&tasker.Task{
|
|
||||||
Payload: t.Payload(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = cu.TaskerClient.CreateTask(
|
|
||||||
tasker.AccountGiftVoucherTask,
|
|
||||||
tasker.DefaultPriority,
|
|
||||||
&tasker.Task{
|
|
||||||
Payload: t.Payload(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
eventPayload := events.EventPayload{
|
|
||||||
TrackingId: payload.TrackingId,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cu.EventEmitter.Publish(
|
|
||||||
events.AccountNewNonce,
|
|
||||||
payload.PublicKey,
|
|
||||||
eventPayload,
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,17 +3,16 @@ package task
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bsm/redislock"
|
||||||
"github.com/celo-org/celo-blockchain/common/hexutil"
|
"github.com/celo-org/celo-blockchain/common/hexutil"
|
||||||
"github.com/grassrootseconomics/celoutils"
|
"github.com/grassrootseconomics/celoutils"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/events"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
||||||
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
||||||
"github.com/grassrootseconomics/w3-celo-patch"
|
|
||||||
"github.com/grassrootseconomics/w3-celo-patch/module/eth"
|
"github.com/grassrootseconomics/w3-celo-patch/module/eth"
|
||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
)
|
)
|
||||||
@ -21,57 +20,104 @@ import (
|
|||||||
func AccountRefillGasProcessor(cu *custodial.Custodial) func(context.Context, *asynq.Task) error {
|
func AccountRefillGasProcessor(cu *custodial.Custodial) func(context.Context, *asynq.Task) error {
|
||||||
return func(ctx context.Context, t *asynq.Task) error {
|
return func(ctx context.Context, t *asynq.Task) error {
|
||||||
var (
|
var (
|
||||||
|
err error
|
||||||
payload AccountPayload
|
payload AccountPayload
|
||||||
balance big.Int
|
|
||||||
|
nextTime big.Int
|
||||||
|
checkStatus bool
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := json.Unmarshal(t.Payload(), &payload); err != nil {
|
if err := json.Unmarshal(t.Payload(), &payload); err != nil {
|
||||||
return fmt.Errorf("account: failed %v: %w", err, asynq.SkipRetry)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cu.CeloProvider.Client.CallCtx(
|
if err := cu.CeloProvider.Client.CallCtx(
|
||||||
ctx,
|
ctx,
|
||||||
eth.Balance(w3.A(payload.PublicKey), nil).Returns(&balance),
|
eth.CallFunc(
|
||||||
|
cu.Abis[custodial.NextTime],
|
||||||
|
cu.RegistryMap[celoutils.GasFaucet],
|
||||||
|
celoutils.HexToAddress(payload.PublicKey),
|
||||||
|
).Returns(&nextTime),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if belowThreshold := balance.Cmp(cu.SystemContainer.GasRefillThreshold); belowThreshold > 0 {
|
// The user recently requested funds, there is a cooldown applied.
|
||||||
|
// We can schedule an attempt after the cooldown period has passed + 10 seconds.
|
||||||
|
if nextTime.Int64() > time.Now().Unix() {
|
||||||
|
_, err = cu.TaskerClient.CreateTask(
|
||||||
|
ctx,
|
||||||
|
tasker.AccountRefillGasTask,
|
||||||
|
tasker.DefaultPriority,
|
||||||
|
&tasker.Task{
|
||||||
|
Payload: t.Payload(),
|
||||||
|
},
|
||||||
|
asynq.ProcessAt(time.Unix(nextTime.Int64()+10, 0)),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cu.CeloProvider.Client.CallCtx(
|
||||||
|
ctx,
|
||||||
|
eth.CallFunc(
|
||||||
|
cu.Abis[custodial.Check],
|
||||||
|
cu.RegistryMap[celoutils.GasFaucet],
|
||||||
|
celoutils.HexToAddress(payload.PublicKey),
|
||||||
|
).Returns(&checkStatus),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// The gas faucet backend returns a false status, a poke will fail.
|
||||||
|
if !checkStatus {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
lock, err := cu.LockProvider.Obtain(
|
lock, err := cu.LockProvider.Obtain(
|
||||||
ctx,
|
ctx,
|
||||||
cu.SystemContainer.LockPrefix+cu.SystemContainer.PublicKey,
|
lockPrefix+cu.SystemPublicKey,
|
||||||
cu.SystemContainer.LockTimeout,
|
lockTimeout,
|
||||||
nil,
|
&redislock.Options{
|
||||||
|
RetryStrategy: lockRetry(),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer lock.Release(ctx)
|
defer lock.Release(ctx)
|
||||||
|
|
||||||
nonce, err := cu.Noncestore.Acquire(ctx, cu.SystemContainer.PublicKey)
|
nonce, err := cu.Noncestore.Acquire(ctx, cu.SystemPublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if nErr := cu.Noncestore.Return(ctx, cu.SystemContainer.PublicKey); nErr != nil {
|
if nErr := cu.Noncestore.Return(ctx, cu.SystemPublicKey); nErr != nil {
|
||||||
err = nErr
|
err = nErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// TODO: Review gas params
|
input, err := cu.Abis[custodial.GiveTo].EncodeArgs(
|
||||||
builtTx, err := cu.CeloProvider.SignGasTransferTx(
|
celoutils.HexToAddress(payload.PublicKey),
|
||||||
cu.SystemContainer.PrivateKey,
|
)
|
||||||
celoutils.GasTransferTxOpts{
|
if err != nil {
|
||||||
To: w3.A(payload.PublicKey),
|
return err
|
||||||
Nonce: nonce,
|
}
|
||||||
Value: cu.SystemContainer.GiftableGasValue,
|
|
||||||
GasFeeCap: celoutils.SafeGasFeeCap,
|
builtTx, err := cu.CeloProvider.SignContractExecutionTx(
|
||||||
GasTipCap: celoutils.SafeGasTipCap,
|
cu.SystemPrivateKey,
|
||||||
|
celoutils.ContractExecutionTxOpts{
|
||||||
|
ContractAddress: cu.RegistryMap[celoutils.GasFaucet],
|
||||||
|
InputData: input,
|
||||||
|
GasFeeCap: celoutils.SafeGasFeeCap,
|
||||||
|
GasTipCap: celoutils.SafeGasTipCap,
|
||||||
|
GasLimit: uint64(celoutils.SafeGasLimit),
|
||||||
|
Nonce: nonce,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -83,17 +129,16 @@ func AccountRefillGasProcessor(cu *custodial.Custodial) func(context.Context, *a
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := cu.PgStore.CreateOtx(ctx, store.OTX{
|
id, err := cu.Store.CreateOtx(ctx, store.Otx{
|
||||||
TrackingId: payload.TrackingId,
|
TrackingId: payload.TrackingId,
|
||||||
Type: enum.REFILL_GAS,
|
Type: enum.REFILL_GAS,
|
||||||
RawTx: hexutil.Encode(rawTx),
|
RawTx: hexutil.Encode(rawTx),
|
||||||
TxHash: builtTx.Hash().Hex(),
|
TxHash: builtTx.Hash().Hex(),
|
||||||
From: cu.SystemContainer.PublicKey,
|
From: cu.SystemPublicKey,
|
||||||
Data: hexutil.Encode(builtTx.Data()),
|
Data: hexutil.Encode(builtTx.Data()),
|
||||||
GasPrice: builtTx.GasPrice().Uint64(),
|
GasPrice: builtTx.GasPrice(),
|
||||||
GasLimit: builtTx.Gas(),
|
GasLimit: builtTx.Gas(),
|
||||||
TransferValue: cu.SystemContainer.GiftableGasValue.Uint64(),
|
Nonce: builtTx.Nonce(),
|
||||||
Nonce: builtTx.Nonce(),
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -108,6 +153,7 @@ func AccountRefillGasProcessor(cu *custodial.Custodial) func(context.Context, *a
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err = cu.TaskerClient.CreateTask(
|
_, err = cu.TaskerClient.CreateTask(
|
||||||
|
ctx,
|
||||||
tasker.DispatchTxTask,
|
tasker.DispatchTxTask,
|
||||||
tasker.HighPriority,
|
tasker.HighPriority,
|
||||||
&tasker.Task{
|
&tasker.Task{
|
||||||
@ -118,20 +164,6 @@ func AccountRefillGasProcessor(cu *custodial.Custodial) func(context.Context, *a
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
eventPayload := &events.EventPayload{
|
|
||||||
OtxId: id,
|
|
||||||
TrackingId: payload.TrackingId,
|
|
||||||
TxHash: builtTx.Hash().Hex(),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cu.EventEmitter.Publish(
|
|
||||||
events.AccountRefillGas,
|
|
||||||
builtTx.Hash().Hex(),
|
|
||||||
eventPayload,
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,68 +3,73 @@ package task
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
|
"github.com/bsm/redislock"
|
||||||
"github.com/celo-org/celo-blockchain/common/hexutil"
|
"github.com/celo-org/celo-blockchain/common/hexutil"
|
||||||
"github.com/grassrootseconomics/celoutils"
|
"github.com/grassrootseconomics/celoutils"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/events"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
||||||
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
||||||
"github.com/grassrootseconomics/w3-celo-patch"
|
|
||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type AccountPayload struct {
|
||||||
|
PublicKey string `json:"publicKey"`
|
||||||
|
TrackingId string `json:"trackingId"`
|
||||||
|
}
|
||||||
|
|
||||||
func AccountRegisterOnChainProcessor(cu *custodial.Custodial) func(context.Context, *asynq.Task) error {
|
func AccountRegisterOnChainProcessor(cu *custodial.Custodial) func(context.Context, *asynq.Task) error {
|
||||||
return func(ctx context.Context, t *asynq.Task) error {
|
return func(ctx context.Context, t *asynq.Task) error {
|
||||||
var (
|
var (
|
||||||
|
err error
|
||||||
payload AccountPayload
|
payload AccountPayload
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := json.Unmarshal(t.Payload(), &payload); err != nil {
|
if err := json.Unmarshal(t.Payload(), &payload); err != nil {
|
||||||
return fmt.Errorf("account: failed %v: %w", err, asynq.SkipRetry)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
lock, err := cu.LockProvider.Obtain(
|
lock, err := cu.LockProvider.Obtain(
|
||||||
ctx,
|
ctx,
|
||||||
cu.SystemContainer.LockPrefix+cu.SystemContainer.PublicKey,
|
lockPrefix+cu.SystemPublicKey,
|
||||||
cu.SystemContainer.LockTimeout,
|
lockTimeout,
|
||||||
nil,
|
&redislock.Options{
|
||||||
|
RetryStrategy: lockRetry(),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer lock.Release(ctx)
|
defer lock.Release(ctx)
|
||||||
|
|
||||||
nonce, err := cu.Noncestore.Acquire(ctx, cu.SystemContainer.PublicKey)
|
nonce, err := cu.Noncestore.Acquire(ctx, cu.SystemPublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if nErr := cu.Noncestore.Return(ctx, cu.SystemContainer.PublicKey); nErr != nil {
|
if nErr := cu.Noncestore.Return(ctx, cu.SystemPublicKey); nErr != nil {
|
||||||
err = nErr
|
err = nErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
input, err := cu.SystemContainer.Abis["add"].EncodeArgs(
|
input, err := cu.Abis[custodial.Register].EncodeArgs(
|
||||||
w3.A(payload.PublicKey),
|
celoutils.HexToAddress(payload.PublicKey),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Review gas params.
|
|
||||||
builtTx, err := cu.CeloProvider.SignContractExecutionTx(
|
builtTx, err := cu.CeloProvider.SignContractExecutionTx(
|
||||||
cu.SystemContainer.PrivateKey,
|
cu.SystemPrivateKey,
|
||||||
celoutils.ContractExecutionTxOpts{
|
celoutils.ContractExecutionTxOpts{
|
||||||
ContractAddress: cu.SystemContainer.AccountIndexContract,
|
ContractAddress: cu.RegistryMap[celoutils.CustodialProxy],
|
||||||
InputData: input,
|
InputData: input,
|
||||||
GasFeeCap: celoutils.SafeGasFeeCap,
|
GasFeeCap: celoutils.SafeGasFeeCap,
|
||||||
GasTipCap: celoutils.SafeGasTipCap,
|
GasTipCap: celoutils.SafeGasTipCap,
|
||||||
GasLimit: cu.SystemContainer.TokenTransferGasLimit,
|
GasLimit: uint64(celoutils.SafeGasLimit),
|
||||||
Nonce: nonce,
|
Nonce: nonce,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -77,14 +82,14 @@ func AccountRegisterOnChainProcessor(cu *custodial.Custodial) func(context.Conte
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := cu.PgStore.CreateOtx(ctx, store.OTX{
|
id, err := cu.Store.CreateOtx(ctx, store.Otx{
|
||||||
TrackingId: payload.TrackingId,
|
TrackingId: payload.TrackingId,
|
||||||
Type: enum.ACCOUNT_REGISTER,
|
Type: enum.ACCOUNT_REGISTER,
|
||||||
RawTx: hexutil.Encode(rawTx),
|
RawTx: hexutil.Encode(rawTx),
|
||||||
TxHash: builtTx.Hash().Hex(),
|
TxHash: builtTx.Hash().Hex(),
|
||||||
From: cu.SystemContainer.PublicKey,
|
From: cu.SystemPublicKey,
|
||||||
Data: hexutil.Encode(builtTx.Data()),
|
Data: hexutil.Encode(builtTx.Data()),
|
||||||
GasPrice: builtTx.GasPrice().Uint64(),
|
GasPrice: builtTx.GasPrice(),
|
||||||
GasLimit: builtTx.Gas(),
|
GasLimit: builtTx.Gas(),
|
||||||
Nonce: builtTx.Nonce(),
|
Nonce: builtTx.Nonce(),
|
||||||
})
|
})
|
||||||
@ -101,6 +106,7 @@ func AccountRegisterOnChainProcessor(cu *custodial.Custodial) func(context.Conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err = cu.TaskerClient.CreateTask(
|
_, err = cu.TaskerClient.CreateTask(
|
||||||
|
ctx,
|
||||||
tasker.DispatchTxTask,
|
tasker.DispatchTxTask,
|
||||||
tasker.HighPriority,
|
tasker.HighPriority,
|
||||||
&tasker.Task{
|
&tasker.Task{
|
||||||
@ -111,17 +117,7 @@ func AccountRegisterOnChainProcessor(cu *custodial.Custodial) func(context.Conte
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
eventPayload := &events.EventPayload{
|
if err := cu.Noncestore.SetAccountNonce(ctx, payload.PublicKey, 0); err != nil {
|
||||||
OtxId: id,
|
|
||||||
TrackingId: payload.TrackingId,
|
|
||||||
TxHash: builtTx.Hash().Hex(),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cu.EventEmitter.Publish(
|
|
||||||
events.AccountRegister,
|
|
||||||
builtTx.Hash().Hex(),
|
|
||||||
eventPayload,
|
|
||||||
); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -9,8 +9,6 @@ import (
|
|||||||
"github.com/celo-org/celo-blockchain/core/types"
|
"github.com/celo-org/celo-blockchain/core/types"
|
||||||
"github.com/grassrootseconomics/celoutils"
|
"github.com/grassrootseconomics/celoutils"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/events"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
||||||
"github.com/grassrootseconomics/w3-celo-patch/module/eth"
|
"github.com/grassrootseconomics/w3-celo-patch/module/eth"
|
||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
@ -25,53 +23,37 @@ func DispatchTx(cu *custodial.Custodial) func(context.Context, *asynq.Task) erro
|
|||||||
return func(ctx context.Context, t *asynq.Task) error {
|
return func(ctx context.Context, t *asynq.Task) error {
|
||||||
var (
|
var (
|
||||||
payload TxPayload
|
payload TxPayload
|
||||||
dispatchStatus store.DispatchStatus
|
|
||||||
eventPayload events.EventPayload
|
|
||||||
dispathchTx common.Hash
|
dispathchTx common.Hash
|
||||||
|
dispatchStatus enum.OtxStatus = enum.IN_NETWORK
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := json.Unmarshal(t.Payload(), &payload); err != nil {
|
if err := json.Unmarshal(t.Payload(), &payload); err != nil {
|
||||||
return fmt.Errorf("dispatch: failed %v: %w", err, asynq.SkipRetry)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
txHash := payload.Tx.Hash().Hex()
|
|
||||||
|
|
||||||
dispatchStatus.OtxId, eventPayload.OtxId = payload.OtxId, payload.OtxId
|
|
||||||
eventPayload.TxHash = txHash
|
|
||||||
|
|
||||||
if err := cu.CeloProvider.Client.CallCtx(
|
if err := cu.CeloProvider.Client.CallCtx(
|
||||||
ctx,
|
ctx,
|
||||||
eth.SendTx(payload.Tx).Returns(&dispathchTx),
|
eth.SendTx(payload.Tx).Returns(&dispathchTx),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
switch err.Error() {
|
switch err.Error() {
|
||||||
case celoutils.ErrGasPriceLow:
|
case celoutils.ErrGasPriceLow:
|
||||||
dispatchStatus.Status = enum.FAIL_LOW_GAS_PRICE
|
dispatchStatus = enum.FAIL_LOW_GAS_PRICE
|
||||||
case celoutils.ErrInsufficientGas:
|
case celoutils.ErrInsufficientGas:
|
||||||
dispatchStatus.Status = enum.FAIL_NO_GAS
|
dispatchStatus = enum.FAIL_NO_GAS
|
||||||
case celoutils.ErrNonceLow:
|
case celoutils.ErrNonceLow:
|
||||||
dispatchStatus.Status = enum.FAIL_LOW_NONCE
|
dispatchStatus = enum.FAIL_LOW_NONCE
|
||||||
default:
|
default:
|
||||||
dispatchStatus.Status = enum.FAIL_UNKNOWN_RPC_ERROR
|
dispatchStatus = enum.FAIL_UNKNOWN_RPC_ERROR
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cu.PgStore.CreateDispatchStatus(ctx, dispatchStatus); err != nil {
|
if err := cu.Store.CreateDispatchStatus(ctx, payload.OtxId, dispatchStatus); err != nil {
|
||||||
return fmt.Errorf("dispatch: failed %v: %w", err, asynq.SkipRetry)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cu.EventEmitter.Publish(events.DispatchFail, txHash, eventPayload); err != nil {
|
|
||||||
return fmt.Errorf("dispatch: failed %v: %w", err, asynq.SkipRetry)
|
return fmt.Errorf("dispatch: failed %v: %w", err, asynq.SkipRetry)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("dispatch: failed %v: %w", err, asynq.SkipRetry)
|
return fmt.Errorf("dispatch: failed %v: %w", err, asynq.SkipRetry)
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchStatus.Status = enum.IN_NETWORK
|
if err := cu.Store.CreateDispatchStatus(ctx, payload.OtxId, dispatchStatus); err != nil {
|
||||||
|
|
||||||
if err := cu.PgStore.CreateDispatchStatus(ctx, dispatchStatus); err != nil {
|
|
||||||
return fmt.Errorf("dispatch: failed %v: %w", err, asynq.SkipRetry)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cu.EventEmitter.Publish(events.DispatchSuccess, txHash, eventPayload); err != nil {
|
|
||||||
return fmt.Errorf("dispatch: failed %v: %w", err, asynq.SkipRetry)
|
return fmt.Errorf("dispatch: failed %v: %w", err, asynq.SkipRetry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,59 +3,53 @@ package task
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/bsm/redislock"
|
||||||
"github.com/celo-org/celo-blockchain/common/hexutil"
|
"github.com/celo-org/celo-blockchain/common/hexutil"
|
||||||
"github.com/grassrootseconomics/celoutils"
|
"github.com/grassrootseconomics/celoutils"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/events"
|
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
||||||
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
||||||
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
||||||
"github.com/grassrootseconomics/w3-celo-patch"
|
"github.com/grassrootseconomics/w3-celo-patch/module/eth"
|
||||||
"github.com/hibiken/asynq"
|
"github.com/hibiken/asynq"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type TransferPayload struct {
|
||||||
TransferPayload struct {
|
TrackingId string `json:"trackingId"`
|
||||||
TrackingId string `json:"trackingId"`
|
From string `json:"from" `
|
||||||
From string `json:"from" `
|
To string `json:"to"`
|
||||||
To string `json:"to"`
|
VoucherAddress string `json:"voucherAddress"`
|
||||||
VoucherAddress string `json:"voucherAddress"`
|
Amount uint64 `json:"amount"`
|
||||||
Amount uint64 `json:"amount"`
|
}
|
||||||
}
|
|
||||||
|
|
||||||
transferEventPayload struct {
|
|
||||||
DispatchTaskId string `json:"dispatchTaskId"`
|
|
||||||
OTXId uint `json:"otxId"`
|
|
||||||
TrackingId string `json:"trackingId"`
|
|
||||||
TxHash string `json:"txHash"`
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func SignTransfer(cu *custodial.Custodial) func(context.Context, *asynq.Task) error {
|
func SignTransfer(cu *custodial.Custodial) func(context.Context, *asynq.Task) error {
|
||||||
return func(ctx context.Context, t *asynq.Task) error {
|
return func(ctx context.Context, t *asynq.Task) error {
|
||||||
var (
|
var (
|
||||||
payload TransferPayload
|
err error
|
||||||
|
networkBalance big.Int
|
||||||
|
payload TransferPayload
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := json.Unmarshal(t.Payload(), &payload); err != nil {
|
if err := json.Unmarshal(t.Payload(), &payload); err != nil {
|
||||||
return fmt.Errorf("account: failed %v: %w", err, asynq.SkipRetry)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
lock, err := cu.LockProvider.Obtain(
|
lock, err := cu.LockProvider.Obtain(
|
||||||
ctx,
|
ctx,
|
||||||
cu.SystemContainer.LockPrefix+payload.From,
|
lockPrefix+payload.From,
|
||||||
cu.SystemContainer.LockTimeout,
|
lockTimeout,
|
||||||
nil,
|
&redislock.Options{
|
||||||
|
RetryStrategy: lockRetry(),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer lock.Release(ctx)
|
defer lock.Release(ctx)
|
||||||
|
|
||||||
key, err := cu.Keystore.LoadPrivateKey(ctx, payload.From)
|
key, err := cu.Store.LoadPrivateKey(ctx, payload.From)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -66,26 +60,28 @@ func SignTransfer(cu *custodial.Custodial) func(context.Context, *asynq.Task) er
|
|||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if nErr := cu.Noncestore.Return(ctx, cu.SystemContainer.PublicKey); nErr != nil {
|
if nErr := cu.Noncestore.Return(ctx, payload.From); nErr != nil {
|
||||||
err = nErr
|
err = nErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
input, err := cu.SystemContainer.Abis["transfer"].EncodeArgs(w3.A(payload.To), new(big.Int).SetUint64(payload.Amount))
|
input, err := cu.Abis[custodial.Transfer].EncodeArgs(
|
||||||
|
celoutils.HexToAddress(payload.To),
|
||||||
|
new(big.Int).SetUint64(payload.Amount),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Review gas params.
|
|
||||||
builtTx, err := cu.CeloProvider.SignContractExecutionTx(
|
builtTx, err := cu.CeloProvider.SignContractExecutionTx(
|
||||||
key,
|
key,
|
||||||
celoutils.ContractExecutionTxOpts{
|
celoutils.ContractExecutionTxOpts{
|
||||||
ContractAddress: w3.A(payload.VoucherAddress),
|
ContractAddress: celoutils.HexToAddress(payload.VoucherAddress),
|
||||||
InputData: input,
|
InputData: input,
|
||||||
GasFeeCap: celoutils.SafeGasFeeCap,
|
GasFeeCap: celoutils.SafeGasFeeCap,
|
||||||
GasTipCap: celoutils.SafeGasTipCap,
|
GasTipCap: celoutils.SafeGasTipCap,
|
||||||
GasLimit: cu.SystemContainer.TokenTransferGasLimit,
|
GasLimit: uint64(celoutils.SafeGasLimit),
|
||||||
Nonce: nonce,
|
Nonce: nonce,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -98,14 +94,14 @@ func SignTransfer(cu *custodial.Custodial) func(context.Context, *asynq.Task) er
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := cu.PgStore.CreateOtx(ctx, store.OTX{
|
id, err := cu.Store.CreateOtx(ctx, store.Otx{
|
||||||
TrackingId: payload.TrackingId,
|
TrackingId: payload.TrackingId,
|
||||||
Type: enum.TRANSFER_VOUCHER,
|
Type: enum.TRANSFER_VOUCHER,
|
||||||
RawTx: hexutil.Encode(rawTx),
|
RawTx: hexutil.Encode(rawTx),
|
||||||
TxHash: builtTx.Hash().Hex(),
|
TxHash: builtTx.Hash().Hex(),
|
||||||
From: payload.From,
|
From: payload.From,
|
||||||
Data: hexutil.Encode(builtTx.Data()),
|
Data: hexutil.Encode(builtTx.Data()),
|
||||||
GasPrice: builtTx.GasPrice().Uint64(),
|
GasPrice: builtTx.GasPrice(),
|
||||||
GasLimit: builtTx.Gas(),
|
GasLimit: builtTx.Gas(),
|
||||||
TransferValue: payload.Amount,
|
TransferValue: payload.Amount,
|
||||||
Nonce: builtTx.Nonce(),
|
Nonce: builtTx.Nonce(),
|
||||||
@ -114,6 +110,13 @@ func SignTransfer(cu *custodial.Custodial) func(context.Context, *asynq.Task) er
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := cu.CeloProvider.Client.CallCtx(
|
||||||
|
ctx,
|
||||||
|
eth.Balance(celoutils.HexToAddress(payload.From), nil).Returns(&networkBalance),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
disptachJobPayload, err := json.Marshal(TxPayload{
|
disptachJobPayload, err := json.Marshal(TxPayload{
|
||||||
OtxId: id,
|
OtxId: id,
|
||||||
Tx: builtTx,
|
Tx: builtTx,
|
||||||
@ -123,6 +126,7 @@ func SignTransfer(cu *custodial.Custodial) func(context.Context, *asynq.Task) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err = cu.TaskerClient.CreateTask(
|
_, err = cu.TaskerClient.CreateTask(
|
||||||
|
ctx,
|
||||||
tasker.DispatchTxTask,
|
tasker.DispatchTxTask,
|
||||||
tasker.HighPriority,
|
tasker.HighPriority,
|
||||||
&tasker.Task{
|
&tasker.Task{
|
||||||
@ -134,35 +138,29 @@ func SignTransfer(cu *custodial.Custodial) func(context.Context, *asynq.Task) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
gasRefillPayload, err := json.Marshal(AccountPayload{
|
gasRefillPayload, err := json.Marshal(AccountPayload{
|
||||||
PublicKey: payload.From,
|
PublicKey: payload.From,
|
||||||
|
TrackingId: payload.TrackingId,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = cu.TaskerClient.CreateTask(
|
if !balanceCheck(networkBalance) {
|
||||||
tasker.AccountRefillGasTask,
|
if err := cu.Store.GasLock(ctx, payload.From); err != nil {
|
||||||
tasker.DefaultPriority,
|
return err
|
||||||
&tasker.Task{
|
}
|
||||||
Payload: gasRefillPayload,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
eventPayload := &transferEventPayload{
|
_, err = cu.TaskerClient.CreateTask(
|
||||||
OTXId: id,
|
ctx,
|
||||||
TrackingId: payload.TrackingId,
|
tasker.AccountRefillGasTask,
|
||||||
TxHash: builtTx.Hash().Hex(),
|
tasker.DefaultPriority,
|
||||||
}
|
&tasker.Task{
|
||||||
|
Payload: gasRefillPayload,
|
||||||
if err := cu.EventEmitter.Publish(
|
},
|
||||||
events.SignTransfer,
|
)
|
||||||
builtTx.Hash().Hex(),
|
if err != nil {
|
||||||
eventPayload,
|
return err
|
||||||
); err != nil {
|
}
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
196
internal/tasker/task/sign_transfer_auth.go
Normal file
196
internal/tasker/task/sign_transfer_auth.go
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
package task
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/bsm/redislock"
|
||||||
|
"github.com/celo-org/celo-blockchain/common/hexutil"
|
||||||
|
"github.com/grassrootseconomics/celoutils"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/internal/custodial"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/internal/store"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/internal/tasker"
|
||||||
|
"github.com/grassrootseconomics/cic-custodial/pkg/enum"
|
||||||
|
"github.com/grassrootseconomics/w3-celo-patch/module/eth"
|
||||||
|
"github.com/hibiken/asynq"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TransferAuthPayload struct {
|
||||||
|
Amount uint64 `json:"amount"`
|
||||||
|
Authorizer string `json:"authorizer"`
|
||||||
|
AuthorizedAddress string `json:"authorizedAddress"`
|
||||||
|
TrackingId string `json:"trackingId"`
|
||||||
|
VoucherAddress string `json:"voucherAddress"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func SignTransferAuthorizationProcessor(cu *custodial.Custodial) func(context.Context, *asynq.Task) error {
|
||||||
|
return func(ctx context.Context, t *asynq.Task) error {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
networkBalance big.Int
|
||||||
|
payload TransferAuthPayload
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := json.Unmarshal(t.Payload(), &payload); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
lock, err := cu.LockProvider.Obtain(
|
||||||
|
ctx,
|
||||||
|
lockPrefix+payload.Authorizer,
|
||||||
|
lockTimeout,
|
||||||
|
&redislock.Options{
|
||||||
|
RetryStrategy: lockRetry(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer lock.Release(ctx)
|
||||||
|
|
||||||
|
key, err := cu.Store.LoadPrivateKey(ctx, payload.Authorizer)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
nonce, err := cu.Noncestore.Acquire(ctx, payload.Authorizer)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
if nErr := cu.Noncestore.Return(ctx, payload.Authorizer); nErr != nil {
|
||||||
|
err = nErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
input, err := cu.Abis[custodial.Approve].EncodeArgs(
|
||||||
|
celoutils.HexToAddress(payload.AuthorizedAddress),
|
||||||
|
new(big.Int).SetUint64(payload.Amount),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
builtTx, err := cu.CeloProvider.SignContractExecutionTx(
|
||||||
|
key,
|
||||||
|
celoutils.ContractExecutionTxOpts{
|
||||||
|
ContractAddress: celoutils.HexToAddress(payload.VoucherAddress),
|
||||||
|
InputData: input,
|
||||||
|
GasFeeCap: celoutils.SafeGasFeeCap,
|
||||||
|
GasTipCap: celoutils.SafeGasTipCap,
|
||||||
|
GasLimit: uint64(celoutils.SafeGasLimit),
|
||||||
|
Nonce: nonce,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawTx, err := builtTx.MarshalBinary()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := cu.Store.CreateOtx(ctx, store.Otx{
|
||||||
|
TrackingId: payload.TrackingId,
|
||||||
|
Type: enum.TRANSFER_AUTH,
|
||||||
|
RawTx: hexutil.Encode(rawTx),
|
||||||
|
TxHash: builtTx.Hash().Hex(),
|
||||||
|
From: cu.SystemPublicKey,
|
||||||
|
Data: hexutil.Encode(builtTx.Data()),
|
||||||
|
GasPrice: builtTx.GasPrice(),
|
||||||
|
GasLimit: builtTx.Gas(),
|
||||||
|
TransferValue: 0,
|
||||||
|
Nonce: builtTx.Nonce(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cu.CeloProvider.Client.CallCtx(
|
||||||
|
ctx,
|
||||||
|
eth.Balance(celoutils.HexToAddress(payload.Authorizer), nil).Returns(&networkBalance),
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
disptachJobPayload, err := json.Marshal(TxPayload{
|
||||||
|
OtxId: id,
|
||||||
|
Tx: builtTx,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = cu.TaskerClient.CreateTask(
|
||||||
|
ctx,
|
||||||
|
tasker.DispatchTxTask,
|
||||||
|
tasker.HighPriority,
|
||||||
|
&tasker.Task{
|
||||||
|
Payload: disptachJobPayload,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-revoke every session (15 min)
|
||||||
|
// Check if already a revoke request
|
||||||
|
if payload.Amount > 0 {
|
||||||
|
taskPayload, err := json.Marshal(TransferAuthPayload{
|
||||||
|
TrackingId: payload.TrackingId,
|
||||||
|
Amount: 0,
|
||||||
|
Authorizer: payload.Authorizer,
|
||||||
|
AuthorizedAddress: payload.AuthorizedAddress,
|
||||||
|
VoucherAddress: payload.VoucherAddress,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = cu.TaskerClient.CreateTask(
|
||||||
|
ctx,
|
||||||
|
tasker.SignTransferTaskAuth,
|
||||||
|
tasker.DefaultPriority,
|
||||||
|
&tasker.Task{
|
||||||
|
Payload: taskPayload,
|
||||||
|
},
|
||||||
|
asynq.ProcessIn(cu.ApprovalTimeout),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gasRefillPayload, err := json.Marshal(AccountPayload{
|
||||||
|
PublicKey: payload.Authorizer,
|
||||||
|
TrackingId: payload.TrackingId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !balanceCheck(networkBalance) {
|
||||||
|
if err := cu.Store.GasLock(ctx, payload.Authorizer); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = cu.TaskerClient.CreateTask(
|
||||||
|
ctx,
|
||||||
|
tasker.AccountRefillGasTask,
|
||||||
|
tasker.DefaultPriority,
|
||||||
|
&tasker.Task{
|
||||||
|
Payload: gasRefillPayload,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
39
internal/tasker/task/utils.go
Normal file
39
internal/tasker/task/utils.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package task
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bsm/redislock"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
lockPrefix = "lock:"
|
||||||
|
lockRetryDelay = 25 * time.Millisecond
|
||||||
|
lockTimeout = 1 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// 20 gwei = max gas price we are willing to pay
|
||||||
|
// 250k = max gas limit
|
||||||
|
// minGasBalanceRequired is optimistic that the immidiate next transfer request will be successful
|
||||||
|
// but the subsequent one could fail (though low probability), therefore we can trigger a gas lock.
|
||||||
|
// Therefore our system wide threshold is 0.01 CELO or 10000000000000000 gas units
|
||||||
|
// UPDATE: Feb 2025
|
||||||
|
// 0.04455 CELO
|
||||||
|
minGasBalanceRequired = big.NewInt(27000000000 * 550000 * 3)
|
||||||
|
)
|
||||||
|
|
||||||
|
// lockRetry will at most try to obtain the lock 20 times within ~0.5s.
|
||||||
|
// it is expected to prevent immidiate requeue of the task at the expense of more redis calls.
|
||||||
|
func lockRetry() redislock.RetryStrategy {
|
||||||
|
return redislock.LimitRetry(
|
||||||
|
redislock.LinearBackoff(lockRetryDelay),
|
||||||
|
20,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// balanceCheck compares the network balance with the system set min as threshold to execute a transfer.
|
||||||
|
func balanceCheck(networkBalance big.Int) bool {
|
||||||
|
return minGasBalanceRequired.Cmp(&networkBalance) < 0
|
||||||
|
}
|
@ -1,13 +1,7 @@
|
|||||||
package tasker
|
package tasker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"math/big"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/celo-org/celo-blockchain/common"
|
|
||||||
"github.com/grassrootseconomics/w3-celo-patch"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@ -15,36 +9,17 @@ type (
|
|||||||
TaskName string
|
TaskName string
|
||||||
)
|
)
|
||||||
|
|
||||||
type SystemContainer struct {
|
|
||||||
Abis map[string]*w3.Func
|
|
||||||
AccountIndexContract common.Address
|
|
||||||
GasFaucetContract common.Address
|
|
||||||
GasRefillThreshold *big.Int
|
|
||||||
GasRefillValue *big.Int
|
|
||||||
GiftableGasValue *big.Int
|
|
||||||
GiftableToken common.Address
|
|
||||||
GiftableTokenValue *big.Int
|
|
||||||
LockPrefix string
|
|
||||||
LockTimeout time.Duration
|
|
||||||
PrivateKey *ecdsa.PrivateKey
|
|
||||||
PublicKey string
|
|
||||||
TokenDecimals int
|
|
||||||
TokenTransferGasLimit uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type Task struct {
|
type Task struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
Payload json.RawMessage `json:"payload"`
|
Payload json.RawMessage `json:"payload"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AccountPrepareTask TaskName = "sys:prepare_account"
|
AccountRegisterTask TaskName = "sys:register_account"
|
||||||
AccountRegisterTask TaskName = "sys:register_account"
|
AccountRefillGasTask TaskName = "sys:refill_gas"
|
||||||
AccountGiftGasTask TaskName = "sys:gift_gas"
|
SignTransferTask TaskName = "usr:sign_transfer"
|
||||||
AccountGiftVoucherTask TaskName = "sys:gift_token"
|
SignTransferTaskAuth TaskName = "usr:sign_transfer_auth"
|
||||||
AccountRefillGasTask TaskName = "sys:refill_gas"
|
DispatchTxTask TaskName = "rpc:dispatch"
|
||||||
SignTransferTask TaskName = "usr:sign_transfer"
|
|
||||||
DispatchTxTask TaskName = "rpc:dispatch"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -3,6 +3,7 @@ CREATE TABLE IF NOT EXISTS keystore (
|
|||||||
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||||
public_key TEXT NOT NULL,
|
public_key TEXT NOT NULL,
|
||||||
private_key TEXT NOT NULL,
|
private_key TEXT NOT NULL,
|
||||||
active BOOLEAN DEFAULT true,
|
active BOOLEAN DEFAULT false,
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS public_key_idx ON keystore(public_key);
|
@ -12,7 +12,7 @@ INSERT INTO otx_tx_type (value) VALUES
|
|||||||
-- Origin tx table
|
-- Origin tx table
|
||||||
CREATE TABLE IF NOT EXISTS otx_sign (
|
CREATE TABLE IF NOT EXISTS otx_sign (
|
||||||
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||||
tracking_id TEXT NOT NULL,
|
tracking_id uuid NOT NULL,
|
||||||
"type" TEXT REFERENCES otx_tx_type(value) NOT NULL,
|
"type" TEXT REFERENCES otx_tx_type(value) NOT NULL,
|
||||||
raw_tx TEXT NOT NULL,
|
raw_tx TEXT NOT NULL,
|
||||||
tx_hash TEXT NOT NULL,
|
tx_hash TEXT NOT NULL,
|
||||||
@ -24,8 +24,9 @@ CREATE TABLE IF NOT EXISTS otx_sign (
|
|||||||
nonce int NOT NULL,
|
nonce int NOT NULL,
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
CREATE INDEX IF NOT EXISTS tx_hash_idx ON otx_sign USING hash(tx_hash);
|
CREATE INDEX IF NOT EXISTS tracking_id_idx ON otx_sign (tracking_id);
|
||||||
CREATE INDEX IF NOT EXISTS from_idx ON otx_sign USING hash("from");
|
CREATE INDEX IF NOT EXISTS tx_hash_idx ON otx_sign (tx_hash);
|
||||||
|
CREATE INDEX IF NOT EXISTS from_idx ON otx_sign ("from");
|
||||||
|
|
||||||
-- Otx dispatch status enum table
|
-- Otx dispatch status enum table
|
||||||
-- Enforces referential integrity on the dispatch table
|
-- Enforces referential integrity on the dispatch table
|
||||||
|
28
migrations/003_gas_quota.sql
Normal file
28
migrations/003_gas_quota.sql
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
-- Gas quota meta table
|
||||||
|
CREATE TABLE IF NOT EXISTS gas_quota_meta (
|
||||||
|
default_quota INT NOT NULL
|
||||||
|
);
|
||||||
|
INSERT INTO gas_quota_meta (default_quota) VALUES (25);
|
||||||
|
|
||||||
|
-- Gas quota table
|
||||||
|
CREATE TABLE IF NOT EXISTS gas_quota (
|
||||||
|
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||||
|
key_id INT REFERENCES keystore(id) NOT NULL,
|
||||||
|
quota INT NOT NULL DEFAULT 0
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Gas quota trigger on keystore insert to default 0 quota
|
||||||
|
-- We wait for the event handler to correctly set the chain quota
|
||||||
|
create function insert_gas_quota()
|
||||||
|
returns trigger
|
||||||
|
as $$
|
||||||
|
begin
|
||||||
|
insert into gas_quota (key_id) values (new.id);
|
||||||
|
return new;
|
||||||
|
end;
|
||||||
|
$$ language plpgsql;
|
||||||
|
|
||||||
|
create trigger insert_gas_quota
|
||||||
|
after insert on keystore
|
||||||
|
for each row
|
||||||
|
execute procedure insert_gas_quota();
|
33
migrations/004_updated_at.sql
Normal file
33
migrations/004_updated_at.sql
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
ALTER TABLE keystore
|
||||||
|
ADD COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
||||||
|
|
||||||
|
ALTER TABLE otx_dispatch
|
||||||
|
ADD COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
||||||
|
|
||||||
|
ALTER TABLE gas_quota
|
||||||
|
ADD COLUMN updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
||||||
|
|
||||||
|
-- updated_at function
|
||||||
|
create function update_timestamp()
|
||||||
|
returns trigger
|
||||||
|
as $$
|
||||||
|
begin
|
||||||
|
new.updated_at = current_timestamp;
|
||||||
|
return new;
|
||||||
|
end;
|
||||||
|
$$ language plpgsql;
|
||||||
|
|
||||||
|
create trigger update_keystore_timestamp
|
||||||
|
before update on keystore
|
||||||
|
for each row
|
||||||
|
execute procedure update_timestamp();
|
||||||
|
|
||||||
|
create trigger update_otx_dispatch_timestamp
|
||||||
|
before update on otx_dispatch
|
||||||
|
for each row
|
||||||
|
execute procedure update_timestamp();
|
||||||
|
|
||||||
|
create trigger update_gas_quota_timestamp
|
||||||
|
before update on gas_quota
|
||||||
|
for each row
|
||||||
|
execute procedure update_timestamp();
|
34
migrations/005_remove_gas_quota.sql
Normal file
34
migrations/005_remove_gas_quota.sql
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
-- Replace gas_quota with gas_lock which checks network balance threshold
|
||||||
|
DROP TRIGGER IF EXISTS update_gas_quota_timestamp ON gas_quota;
|
||||||
|
DROP TABLE IF EXISTS gas_quota_meta;
|
||||||
|
DROP TABLE IF EXISTS gas_quota;
|
||||||
|
DROP TRIGGER IF EXISTS insert_gas_quota ON keystore;
|
||||||
|
DROP FUNCTION IF EXISTS insert_gas_quota;
|
||||||
|
|
||||||
|
-- Gas lock table
|
||||||
|
-- A gas_locked account indicates gas balance is below threshold awaiting next available top up
|
||||||
|
CREATE TABLE IF NOT EXISTS gas_lock (
|
||||||
|
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||||
|
key_id INT REFERENCES keystore(id) NOT NULL,
|
||||||
|
lock BOOLEAN DEFAULT true,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
create function insert_gas_lock()
|
||||||
|
returns trigger
|
||||||
|
as $$
|
||||||
|
begin
|
||||||
|
insert into gas_lock (key_id) values (new.id);
|
||||||
|
return new;
|
||||||
|
end;
|
||||||
|
$$ language plpgsql;
|
||||||
|
|
||||||
|
create trigger insert_gas_lock
|
||||||
|
after insert on keystore
|
||||||
|
for each row
|
||||||
|
execute procedure insert_gas_lock();
|
||||||
|
|
||||||
|
create trigger update_gas_lock_timestamp
|
||||||
|
before update on gas_lock
|
||||||
|
for each row
|
||||||
|
execute procedure update_timestamp();
|
1
migrations/006_transfer_auth.sql
Normal file
1
migrations/006_transfer_auth.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
INSERT INTO otx_tx_type (value) VALUES ('TRANSFER_AUTHORIZATION');
|
@ -1,7 +0,0 @@
|
|||||||
[database]
|
|
||||||
host = {{env "PG_HOST"}}
|
|
||||||
port = {{env "PG_PORT"}}
|
|
||||||
database = {{env "PG_DB"}}
|
|
||||||
user = {{env "PG_USER"}}
|
|
||||||
password = {{env "PG_PASSWORD"}}
|
|
||||||
sslmode = prefer
|
|
@ -19,9 +19,8 @@ const (
|
|||||||
FAIL_UNKNOWN_RPC_ERROR OtxStatus = "FAIL_UNKNOWN_RPC_ERROR"
|
FAIL_UNKNOWN_RPC_ERROR OtxStatus = "FAIL_UNKNOWN_RPC_ERROR"
|
||||||
REVERTED OtxStatus = "REVERTED"
|
REVERTED OtxStatus = "REVERTED"
|
||||||
|
|
||||||
GIFT_GAS OtxType = "GIFT_GAS"
|
|
||||||
ACCOUNT_REGISTER OtxType = "ACCOUNT_REGISTER"
|
ACCOUNT_REGISTER OtxType = "ACCOUNT_REGISTER"
|
||||||
GIFT_VOUCHER OtxType = "GIFT_VOUCHER"
|
|
||||||
REFILL_GAS OtxType = "REFILL_GAS"
|
REFILL_GAS OtxType = "REFILL_GAS"
|
||||||
|
TRANSFER_AUTH OtxType = "TRANSFER_AUTHORIZATION"
|
||||||
TRANSFER_VOUCHER OtxType = "TRANSFER_VOUCHER"
|
TRANSFER_VOUCHER OtxType = "TRANSFER_VOUCHER"
|
||||||
)
|
)
|
||||||
|
@ -13,21 +13,21 @@ func AsynqCompatibleLogger(lo logf.Logger) AsynqLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l AsynqLogger) Debug(args ...interface{}) {
|
func (l AsynqLogger) Debug(args ...interface{}) {
|
||||||
l.Lo.Debug("asynq", "debug", args[0])
|
l.Lo.Debug("asynq: server", "msg", args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l AsynqLogger) Info(args ...interface{}) {
|
func (l AsynqLogger) Info(args ...interface{}) {
|
||||||
l.Lo.Info("asynq", "info", args[0])
|
l.Lo.Info("asynq: server", "msg", args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l AsynqLogger) Warn(args ...interface{}) {
|
func (l AsynqLogger) Warn(args ...interface{}) {
|
||||||
l.Lo.Warn("asynq", "warn", args[0])
|
l.Lo.Warn("asynq: server", "msg", args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l AsynqLogger) Error(args ...interface{}) {
|
func (l AsynqLogger) Error(args ...interface{}) {
|
||||||
l.Lo.Error("asynq", "error", args[0])
|
l.Lo.Error("asynq: server", "msg", args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l AsynqLogger) Fatal(args ...interface{}) {
|
func (l AsynqLogger) Fatal(args ...interface{}) {
|
||||||
l.Lo.Fatal("asynq", "fatal", args[0])
|
l.Lo.Fatal("asynq: server", "msg", args[0])
|
||||||
}
|
}
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
package postgres
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/jackc/pgx/v5/pgxpool"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PostgresPoolOpts struct {
|
|
||||||
DSN string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPostgresPool creates a reusbale connection pool across the cic-custodial component.
|
|
||||||
func NewPostgresPool(o PostgresPoolOpts) (*pgxpool.Pool, error) {
|
|
||||||
parsedConfig, err := pgxpool.ParseConfig(o.DSN)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
dbPool, err := pgxpool.NewWithConfig(context.Background(), parsedConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
if err := dbPool.Ping(ctx); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return dbPool, nil
|
|
||||||
}
|
|
@ -2,23 +2,29 @@ package redis
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-redis/redis/v8"
|
"github.com/grassrootseconomics/cic-custodial/pkg/util"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RedisPoolOpts struct {
|
const (
|
||||||
DSN string
|
systemGlobalLockKey = "system:global_lock"
|
||||||
MinIdleConns int
|
)
|
||||||
}
|
|
||||||
|
|
||||||
type RedisPool struct {
|
type (
|
||||||
Client *redis.Client
|
RedisPoolOpts struct {
|
||||||
}
|
DSN string
|
||||||
|
MinIdleConns int
|
||||||
|
}
|
||||||
|
|
||||||
|
RedisPool struct {
|
||||||
|
Client *redis.Client
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// NewRedisPool creates a reusable connection across the cic-custodial componenent.
|
// NewRedisPool creates a reusable connection across the cic-custodial componenent.
|
||||||
// Note: Each db namespace requires its own connection pool.
|
// Note: Each db namespace requires its own connection pool.
|
||||||
func NewRedisPool(o RedisPoolOpts) (*RedisPool, error) {
|
func NewRedisPool(ctx context.Context, o RedisPoolOpts) (*RedisPool, error) {
|
||||||
redisOpts, err := redis.ParseURL(o.DSN)
|
redisOpts, err := redis.ParseURL(o.DSN)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -28,11 +34,10 @@ func NewRedisPool(o RedisPoolOpts) (*RedisPool, error) {
|
|||||||
|
|
||||||
redisClient := redis.NewClient(redisOpts)
|
redisClient := redis.NewClient(redisOpts)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(ctx, util.SLATimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
_, err = redisClient.Ping(ctx).Result()
|
if err := redisClient.SetNX(ctx, systemGlobalLockKey, false, 0).Err(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
pkg/util/sla.go
Normal file
8
pkg/util/sla.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SLATimeout is the max duration after which any network call/context should be aborted.
|
||||||
|
SLATimeout = 5 * time.Second
|
||||||
|
)
|
@ -34,6 +34,18 @@ INSERT INTO otx_sign(
|
|||||||
nonce
|
nonce
|
||||||
) VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) RETURNING id
|
) VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) RETURNING id
|
||||||
|
|
||||||
|
--name: get-next-nonce
|
||||||
|
-- Gets last nonce from the otx table for a particular address for bootstrapping purposes
|
||||||
|
-- $1: public_key
|
||||||
|
SELECT nonce + 1 AS nonce FROM otx_sign WHERE otx_sign.from = $1 ORDER BY created_at DESC LIMIT 1;
|
||||||
|
|
||||||
|
--name: get-tx-status-by-tracking-id
|
||||||
|
-- Gets tx status's from possible multiple txs with the same tracking_id
|
||||||
|
-- $1: tracking_id
|
||||||
|
SELECT otx_sign.type, otx_sign.tx_hash, otx_sign.transfer_value, otx_sign.created_at, otx_dispatch.status FROM otx_sign
|
||||||
|
INNER JOIN otx_dispatch ON otx_sign.id = otx_dispatch.otx_id
|
||||||
|
WHERE otx_sign.tracking_id=$1
|
||||||
|
|
||||||
--name: create-dispatch-status
|
--name: create-dispatch-status
|
||||||
-- Create a new dispatch status
|
-- Create a new dispatch status
|
||||||
-- $1: otx_id
|
-- $1: otx_id
|
||||||
@ -43,7 +55,7 @@ INSERT INTO otx_dispatch(
|
|||||||
"status"
|
"status"
|
||||||
) VALUES($1, $2) RETURNING id
|
) VALUES($1, $2) RETURNING id
|
||||||
|
|
||||||
--name: update-chain-status
|
--name: update-dispatch-status
|
||||||
-- Updates the status of the dispatched tx with the chain mine status
|
-- Updates the status of the dispatched tx with the chain mine status
|
||||||
-- $1: tx_hash
|
-- $1: tx_hash
|
||||||
-- $2: status
|
-- $2: status
|
||||||
@ -51,15 +63,34 @@ INSERT INTO otx_dispatch(
|
|||||||
UPDATE otx_dispatch SET "status" = $2, "block" = $3 WHERE otx_dispatch.id = (
|
UPDATE otx_dispatch SET "status" = $2, "block" = $3 WHERE otx_dispatch.id = (
|
||||||
SELECT otx_dispatch.id FROM otx_dispatch
|
SELECT otx_dispatch.id FROM otx_dispatch
|
||||||
INNER JOIN otx_sign ON otx_dispatch.otx_id = otx_sign.id
|
INNER JOIN otx_sign ON otx_dispatch.otx_id = otx_sign.id
|
||||||
WHERE otx_sign.tx_hash = $1
|
WHERE otx_sign.tx_hash=$1
|
||||||
AND otx_dispatch.status = 'IN_NETWORK'
|
AND otx_dispatch.status = 'IN_NETWORK'
|
||||||
)
|
)
|
||||||
|
|
||||||
--name: get-tx-status-by-tracking-id
|
--name: activate-account
|
||||||
-- Gets tx status's from possible multiple txs with the same tracking_id
|
-- Activate an account following successful quorum
|
||||||
-- $1: tracking_id
|
-- $1: public_key
|
||||||
SELECT otx_sign.type, otx_sign.tx_hash, otx_sign.transfer_value, otx_sign.created_at, otx_dispatch.status FROM otx_sign
|
UPDATE keystore SET active = true WHERE public_key=$1
|
||||||
INNER JOIN otx_dispatch ON otx_sign.id = otx_dispatch.otx_id
|
|
||||||
WHERE otx_sign.tracking_id = $1
|
|
||||||
|
|
||||||
-- TODO: Scroll by status type with cursor pagination
|
--name: get-account-status-by-address
|
||||||
|
-- Gets current gas lock and activation status for an individual account by address
|
||||||
|
-- $1: public_key
|
||||||
|
SELECT keystore.active, gas_lock.lock FROM keystore
|
||||||
|
INNER JOIN gas_lock ON keystore.id = gas_lock.key_id
|
||||||
|
WHERE keystore.public_key=$1
|
||||||
|
|
||||||
|
--name: acc-gas-lock
|
||||||
|
-- Locks an account for gas reasons
|
||||||
|
-- $1: public_key
|
||||||
|
UPDATE gas_lock SET lock = true WHERE key_id = (
|
||||||
|
SELECT id FROM keystore
|
||||||
|
WHERE public_key=$1
|
||||||
|
)
|
||||||
|
|
||||||
|
--name: acc-gas-unlock
|
||||||
|
-- Unlocks an account for gas reasons
|
||||||
|
-- $1: public_key
|
||||||
|
UPDATE gas_lock SET lock = false WHERE key_id = (
|
||||||
|
SELECT id FROM keystore
|
||||||
|
WHERE public_key=$1
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user