Add notional asset lookup (#239)
* Add notional job * fix coingecko integration * Add deployment for notional jobs --------- Co-authored-by: Agustin Pazos <agpazos85@gmail.com>
This commit is contained in:
parent
3c597917f5
commit
4f438ae188
|
@ -0,0 +1,13 @@
|
||||||
|
ENVIRONMENT=production
|
||||||
|
NAMESPACE=wormscan
|
||||||
|
NAME=wormscan-notional-job
|
||||||
|
IMAGE_NAME=
|
||||||
|
RESOURCES_LIMITS_MEMORY=30Mi
|
||||||
|
RESOURCES_LIMITS_CPU=20m
|
||||||
|
RESOURCES_REQUESTS_MEMORY=15Mi
|
||||||
|
RESOURCES_REQUESTS_CPU=10m
|
||||||
|
P2P_NETWORK=mainnet
|
||||||
|
COINGECKO_URL=https://api.coingecko.com/api/v3
|
||||||
|
NOTIONAL_CHANNEL=WORMSCAN:NOTIONAL
|
||||||
|
LOG_LEVEL=INFO
|
||||||
|
CRONTAB_SCHEDULE=*/5 * * * *
|
|
@ -0,0 +1,13 @@
|
||||||
|
ENVIRONMENT=staging
|
||||||
|
NAMESPACE=wormscan
|
||||||
|
NAME=wormscan-notional-job
|
||||||
|
IMAGE_NAME=
|
||||||
|
RESOURCES_LIMITS_MEMORY=30Mi
|
||||||
|
RESOURCES_LIMITS_CPU=20m
|
||||||
|
RESOURCES_REQUESTS_MEMORY=15Mi
|
||||||
|
RESOURCES_REQUESTS_CPU=10m
|
||||||
|
P2P_NETWORK=mainnet
|
||||||
|
COINGECKO_URL=https://api.coingecko.com/api/v3
|
||||||
|
NOTIONAL_CHANNEL=WORMSCAN:NOTIONAL
|
||||||
|
LOG_LEVEL=INFO
|
||||||
|
CRONTAB_SCHEDULE=*/5 * * * *
|
|
@ -0,0 +1,13 @@
|
||||||
|
ENVIRONMENT=test
|
||||||
|
NAMESPACE=wormscan-testnet
|
||||||
|
NAME=wormscan-notional-job
|
||||||
|
IMAGE_NAME=
|
||||||
|
RESOURCES_LIMITS_MEMORY=30Mi
|
||||||
|
RESOURCES_LIMITS_CPU=20m
|
||||||
|
RESOURCES_REQUESTS_MEMORY=15Mi
|
||||||
|
RESOURCES_REQUESTS_CPU=10m
|
||||||
|
P2P_NETWORK=mainnet
|
||||||
|
COINGECKO_URL=https://api.coingecko.com/api/v3
|
||||||
|
NOTIONAL_CHANNEL=WORMSCAN:NOTIONAL
|
||||||
|
LOG_LEVEL=INFO
|
||||||
|
CRONTAB_SCHEDULE=*/5 * * * *
|
|
@ -0,0 +1,34 @@
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: notional
|
||||||
|
namespace: {{ .NAMESPACE }}
|
||||||
|
spec:
|
||||||
|
schedule: "{{ .CRONTAB_SCHEDULE }}"
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: {{ .NAME }}
|
||||||
|
image: {{ .IMAGE_NAME }}
|
||||||
|
imagePullPolicy: Always
|
||||||
|
env:
|
||||||
|
- name: ENV
|
||||||
|
value: {{ .ENVIRONMENT }}
|
||||||
|
- name: P2P_NETWORK
|
||||||
|
value: {{ .P2P_NETWORK }}
|
||||||
|
- name: LOG_LEVEL
|
||||||
|
value: {{ .LOG_LEVEL }}
|
||||||
|
- name: JOB_ID
|
||||||
|
value: JOB_NOTIONAL_USD
|
||||||
|
- name: COINGECKO_URL
|
||||||
|
value: {{ .COINGECKO_URL }}
|
||||||
|
- name: NOTIONAL_CHANNEL
|
||||||
|
value: {{ .NOTIONAL_CHANNEL }}
|
||||||
|
- name: CACHE_URL
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: config
|
||||||
|
key: redis-uri
|
||||||
|
restartPolicy: OnFailure
|
1
go.work
1
go.work
|
@ -10,4 +10,5 @@ use (
|
||||||
./pipeline
|
./pipeline
|
||||||
./spy
|
./spy
|
||||||
./tx-tracker
|
./tx-tracker
|
||||||
|
./jobs
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
# syntax=docker.io/docker/dockerfile:1.3@sha256:42399d4635eddd7a9b8a24be879d2f9a930d0ed040a61324cfdf59ef1357b3b2
|
||||||
|
FROM --platform=linux/amd64 docker.io/golang:1.19.2@sha256:0467d7d12d170ed8d998a2dae4a09aa13d0aa56e6d23c4ec2b1e4faacf86a813 AS build
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY jobs jobs
|
||||||
|
COPY common common
|
||||||
|
|
||||||
|
# Build the Go app
|
||||||
|
RUN cd jobs && CGO_ENABLED=0 GOOS=linux go build -o "./jobs-app" cmd/main.go
|
||||||
|
|
||||||
|
############################
|
||||||
|
# STEP 2 build a small image
|
||||||
|
############################
|
||||||
|
FROM alpine
|
||||||
|
#Copy certificates
|
||||||
|
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||||
|
# Copy our static executable.
|
||||||
|
COPY --from=build "/app/jobs/jobs-app" "/jobs-app"
|
||||||
|
# Run the binary.
|
||||||
|
ENTRYPOINT ["/jobs-app"]
|
|
@ -0,0 +1,17 @@
|
||||||
|
SHELL := /bin/bash
|
||||||
|
|
||||||
|
|
||||||
|
## help: print this help message
|
||||||
|
.PHONY: help
|
||||||
|
help:
|
||||||
|
@echo 'Usage:'
|
||||||
|
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'
|
||||||
|
|
||||||
|
build:
|
||||||
|
go build -o jobs cmd/main.go
|
||||||
|
|
||||||
|
test:
|
||||||
|
go test -v -cover ./...
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: build doc test
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Jobs
|
||||||
|
This component contains the jobs to be scheduler.
|
|
@ -0,0 +1,67 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/go-redis/redis"
|
||||||
|
"github.com/wormhole-foundation/wormhole-explorer/common/logger"
|
||||||
|
"github.com/wormhole-foundation/wormhole-explorer/jobs/config"
|
||||||
|
"github.com/wormhole-foundation/wormhole-explorer/jobs/internal/coingecko"
|
||||||
|
"github.com/wormhole-foundation/wormhole-explorer/jobs/jobs"
|
||||||
|
"github.com/wormhole-foundation/wormhole-explorer/jobs/jobs/notional"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type exitCode int
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
defer handleExit()
|
||||||
|
context := context.Background()
|
||||||
|
|
||||||
|
// get the config
|
||||||
|
cfg, errConf := config.New(context)
|
||||||
|
if errConf != nil {
|
||||||
|
log.Fatal("error creating config", errConf)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger := logger.New("wormhole-explorer-jobs", logger.WithLevel(cfg.LogLevel))
|
||||||
|
logger.Info("started job execution", zap.String("job_id", cfg.JobID))
|
||||||
|
|
||||||
|
var err error
|
||||||
|
switch cfg.JobID {
|
||||||
|
case jobs.JobIDNotional:
|
||||||
|
notionalJob := initNotionalJob(context, cfg, logger)
|
||||||
|
err = notionalJob.Run()
|
||||||
|
default:
|
||||||
|
logger.Fatal("Invalid job id", zap.String("job_id", cfg.JobID))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("failed job execution", zap.String("job_id", cfg.JobID), zap.Error(err))
|
||||||
|
} else {
|
||||||
|
logger.Info("finish job execution successfully", zap.String("job_id", cfg.JobID))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// initNotionalJob initializes notional job.
|
||||||
|
func initNotionalJob(ctx context.Context, cfg *config.Configuration, logger *zap.Logger) *notional.NotionalJob {
|
||||||
|
// init coingecko api client.
|
||||||
|
api := coingecko.NewCoingeckoAPI(cfg.CoingeckoURL)
|
||||||
|
// init redis client.
|
||||||
|
redisClient := redis.NewClient(&redis.Options{Addr: cfg.CacheURL})
|
||||||
|
// create notional job.
|
||||||
|
notionalJob := notional.NewNotionalJob(api, redisClient, cfg.P2pNetwork, cfg.NotionalChannel, logger)
|
||||||
|
return notionalJob
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleExit() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
if e, ok := r.(exitCode); ok {
|
||||||
|
os.Exit(int(e))
|
||||||
|
}
|
||||||
|
panic(r) // not an Exit, bubble up
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Package config implement a simple configuration package.
|
||||||
|
// It define a type [Configuration] that represent the aplication configuration
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
"github.com/sethvargo/go-envconfig"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Configuration is the configuration for the job
|
||||||
|
type Configuration struct {
|
||||||
|
Env string `env:"ENV,default=development"`
|
||||||
|
LogLevel string `env:"LOG_LEVEL,default=INFO"`
|
||||||
|
JobID string `env:"JOB_ID,required"`
|
||||||
|
CoingeckoURL string `env:"COINGECKO_URL,required"`
|
||||||
|
CacheURL string `env:"CACHE_URL,required"`
|
||||||
|
NotionalChannel string `env:"NOTIONAL_CHANNEL,required"`
|
||||||
|
P2pNetwork string `env:"P2P_NETWORK,required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a configuration with the values from .env file and environment variables.
|
||||||
|
func New(ctx context.Context) (*Configuration, error) {
|
||||||
|
_ = godotenv.Load(".env", "../.env")
|
||||||
|
|
||||||
|
var configuration Configuration
|
||||||
|
if err := envconfig.Process(ctx, &configuration); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &configuration, nil
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
module github.com/wormhole-foundation/wormhole-explorer/jobs
|
||||||
|
|
||||||
|
go 1.19
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/go-redis/redis v6.15.9+incompatible
|
||||||
|
github.com/joho/godotenv v1.5.1
|
||||||
|
github.com/sethvargo/go-envconfig v0.9.0
|
||||||
|
github.com/wormhole-foundation/wormhole-explorer/common v0.0.0-20230417134228-3c597917f5c8
|
||||||
|
github.com/wormhole-foundation/wormhole/sdk v0.0.0-20230417145436-53703d8ffcf0
|
||||||
|
go.uber.org/zap v1.24.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
|
||||||
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
||||||
|
github.com/ethereum/go-ethereum v1.10.21 // indirect
|
||||||
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
|
github.com/holiman/uint256 v1.2.1 // indirect
|
||||||
|
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||||
|
github.com/onsi/gomega v1.27.6 // indirect
|
||||||
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
|
||||||
|
golang.org/x/sys v0.6.0 // indirect
|
||||||
|
)
|
|
@ -0,0 +1,118 @@
|
||||||
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
|
github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k=
|
||||||
|
github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU=
|
||||||
|
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
|
||||||
|
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
|
||||||
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
|
||||||
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
|
||||||
|
github.com/ethereum/go-ethereum v1.10.21 h1:5lqsEx92ZaZzRyOqBEXux4/UR06m296RGzN3ol3teJY=
|
||||||
|
github.com/ethereum/go-ethereum v1.10.21/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg=
|
||||||
|
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/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
||||||
|
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||||
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
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/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
|
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.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
||||||
|
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
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/sethvargo/go-envconfig v0.9.0 h1:Q6FQ6hVEeTECULvkJZakq3dZMeBQ3JUpcKMfPQbKMDE=
|
||||||
|
github.com/sethvargo/go-envconfig v0.9.0/go.mod h1:Iz1Gy1Sf3T64TQlJSvee81qDhf7YIlt8GMUX6yyNFs0=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
|
github.com/wormhole-foundation/wormhole-explorer/common v0.0.0-20230417134228-3c597917f5c8 h1:nJPjdHphY0JGPorg3GrGzIf8J4YR1eyTalxT7MzPIZg=
|
||||||
|
github.com/wormhole-foundation/wormhole-explorer/common v0.0.0-20230417134228-3c597917f5c8/go.mod h1:wySbOH0GO2dRhkTktCCCBnZ4FgNIpy3fL4hEbNMz5KI=
|
||||||
|
github.com/wormhole-foundation/wormhole/sdk v0.0.0-20230417145436-53703d8ffcf0 h1:uEJOLDlkpDxpShkCbFobYPd3MHZpNpkpt0+iyQnb9x4=
|
||||||
|
github.com/wormhole-foundation/wormhole/sdk v0.0.0-20230417145436-53703d8ffcf0/go.mod h1:dE12DOucCq23gjGGGhtbyx41FBxuHxjpPvG+ArO+8t0=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||||
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||||
|
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||||
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
|
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||||
|
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||||
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
|
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/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|
@ -0,0 +1,89 @@
|
||||||
|
package coingecko
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/wormhole-foundation/wormhole-explorer/common/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CoingeckoAPI is a client for the coingecko API
|
||||||
|
type CoingeckoAPI struct {
|
||||||
|
url string
|
||||||
|
client *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCoingeckoAPI creates a new coingecko client
|
||||||
|
func NewCoingeckoAPI(url string) *CoingeckoAPI {
|
||||||
|
return &CoingeckoAPI{
|
||||||
|
url: url,
|
||||||
|
client: http.DefaultClient,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotionalUSD is the response from the coingecko API.
|
||||||
|
type NotionalUSD struct {
|
||||||
|
Price *float64 `json:"usd"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNotionalUSD returns the notional USD value for the given ids
|
||||||
|
// ids is a list of coingecko chain identifier.
|
||||||
|
func (c *CoingeckoAPI) GetNotionalUSD(ids []string) (map[string]NotionalUSD, error) {
|
||||||
|
var response map[string]NotionalUSD
|
||||||
|
notionalUrl := fmt.Sprintf("%s/simple/price?ids=%s&vs_currencies=usd", c.url, strings.Join(ids, ","))
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodGet, notionalUrl, nil)
|
||||||
|
if err != nil {
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
res, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(body, &response)
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChainIDs returns the coingecko chain ids for the given p2p network.
|
||||||
|
func GetChainIDs(p2pNetwork string) []string {
|
||||||
|
if p2pNetwork == domain.P2pMainNet {
|
||||||
|
return []string{
|
||||||
|
"solana",
|
||||||
|
"ethereum",
|
||||||
|
"terra-luna",
|
||||||
|
"binancecoin",
|
||||||
|
"matic-network",
|
||||||
|
"avalanche-2",
|
||||||
|
"oasis-network",
|
||||||
|
"algorand",
|
||||||
|
"aurora",
|
||||||
|
"fantom",
|
||||||
|
"karura",
|
||||||
|
"acala",
|
||||||
|
"klay-token",
|
||||||
|
"celo",
|
||||||
|
"near",
|
||||||
|
"moonbeam",
|
||||||
|
"neon",
|
||||||
|
"terra-luna-2",
|
||||||
|
"injective-protocol",
|
||||||
|
"aptos",
|
||||||
|
"sui",
|
||||||
|
"arbitrum",
|
||||||
|
"optimism",
|
||||||
|
"xpla",
|
||||||
|
"bitcoin",
|
||||||
|
"base-protocol"}
|
||||||
|
}
|
||||||
|
// TODO: define chains ids for testnet.
|
||||||
|
return []string{}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Package jobs define an interface to execute jobs
|
||||||
|
package jobs
|
||||||
|
|
||||||
|
// JobIDNotional is the job id for notional job.
|
||||||
|
const (
|
||||||
|
JobIDNotional = "JOB_NOTIONAL_USD"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Job is the interface for jobs.
|
||||||
|
type Job interface {
|
||||||
|
Run() error
|
||||||
|
}
|
|
@ -0,0 +1,213 @@
|
||||||
|
// Package notional contains the logic to get the notional value of assets
|
||||||
|
package notional
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-redis/redis"
|
||||||
|
"github.com/wormhole-foundation/wormhole-explorer/jobs/internal/coingecko"
|
||||||
|
"github.com/wormhole-foundation/wormhole/sdk/vaa"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NotionalCacheKey is the cache key for notional value by chainID
|
||||||
|
const NotionalCacheKey = "WORMSCAN:NOTIONAL:CHAIN_ID:%d"
|
||||||
|
|
||||||
|
// NotionalJob is the job to get the notional value of assets.
|
||||||
|
type NotionalJob struct {
|
||||||
|
coingeckoAPI *coingecko.CoingeckoAPI
|
||||||
|
cacheClient *redis.Client
|
||||||
|
cacheChannel string
|
||||||
|
p2pNetwork string
|
||||||
|
logger *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNotionalJob creates a new notional job.
|
||||||
|
func NewNotionalJob(api *coingecko.CoingeckoAPI, cacheClient *redis.Client, p2pNetwork, cacheChannel string, logger *zap.Logger) *NotionalJob {
|
||||||
|
return &NotionalJob{
|
||||||
|
coingeckoAPI: api,
|
||||||
|
cacheClient: cacheClient,
|
||||||
|
cacheChannel: cacheChannel,
|
||||||
|
p2pNetwork: p2pNetwork,
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run runs the notional job.
|
||||||
|
func (j *NotionalJob) Run() error {
|
||||||
|
// get chains coingecko ids by p2p network.
|
||||||
|
chainIDs := coingecko.GetChainIDs(j.p2pNetwork)
|
||||||
|
if len(chainIDs) == 0 {
|
||||||
|
return fmt.Errorf("no chain ids found for p2p network %s", j.p2pNetwork)
|
||||||
|
}
|
||||||
|
|
||||||
|
// get notional value of assets.
|
||||||
|
coingeckoNotionals, err := j.coingeckoAPI.GetNotionalUSD(chainIDs)
|
||||||
|
if err != nil {
|
||||||
|
j.logger.Error("failed to get notional value of assets",
|
||||||
|
zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert notionals with coingecko assets ids to notionals with wormhole chainIDs.
|
||||||
|
notionals := convertToWormholeChainIDs(coingeckoNotionals)
|
||||||
|
|
||||||
|
// save notional value of assets in cache.
|
||||||
|
err = j.updateNotionalCache(notionals)
|
||||||
|
if err != nil {
|
||||||
|
j.logger.Error("failed to update notional value of assets in cache",
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Any("notionals", notionals))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// publish notional value of assets to redis pubsub.
|
||||||
|
err = j.cacheClient.Publish(j.cacheChannel, "NOTIONA_UPDATED").Err()
|
||||||
|
if err != nil {
|
||||||
|
j.logger.Error("failed to publish notional update message to redis pubsub",
|
||||||
|
zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateNotionalCache updates the notional value of assets in cache.
|
||||||
|
func (j *NotionalJob) updateNotionalCache(notionals map[vaa.ChainID]NotionalCacheField) error {
|
||||||
|
for chainID, notional := range notionals {
|
||||||
|
key := fmt.Sprintf(NotionalCacheKey, chainID)
|
||||||
|
err := j.cacheClient.Set(key, notional, 0).Err()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotionalCacheField is the notional value of assets in cache.
|
||||||
|
type NotionalCacheField struct {
|
||||||
|
NotionalUsd float64 `json:"notional_usd"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary implements the encoding.BinaryMarshaler interface.
|
||||||
|
func (n NotionalCacheField) MarshalBinary() ([]byte, error) {
|
||||||
|
return json.Marshal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertToWormholeChainIDs converts the coingecko chain ids to wormhole chain ids.
|
||||||
|
func convertToWormholeChainIDs(m map[string]coingecko.NotionalUSD) map[vaa.ChainID]NotionalCacheField {
|
||||||
|
w := make(map[vaa.ChainID]NotionalCacheField, len(m))
|
||||||
|
now := time.Now()
|
||||||
|
for k, v := range m {
|
||||||
|
switch k {
|
||||||
|
case "solana":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDSolana] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "ethereum":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDEthereum] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "terra-luna":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDTerra] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "binancecoin":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDBSC] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "matic-network":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDPolygon] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "avalanche-2":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDAvalanche] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "oasis-network":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDOasis] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "algorand":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDAlgorand] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "aurora":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDAurora] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "fantom":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDFantom] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "karura":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDKarura] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "acala":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDAcala] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "klay-token":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDKlaytn] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "celo":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDCelo] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "near":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDNear] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "moonbeam":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDMoonbeam] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "neon":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDNeon] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "terra-luna-2":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDTerra2] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "injective-protocol":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDInjective] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "aptos":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDAptos] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "sui":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDSui] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "arbitrum":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDArbitrum] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "optimism":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDOptimism] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "xpla":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDXpla] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "bitcoin":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDBtc] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
case "base-protocol":
|
||||||
|
if v.Price != nil {
|
||||||
|
w[vaa.ChainIDBase] = NotionalCacheField{NotionalUsd: *v.Price, UpdatedAt: now}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return w
|
||||||
|
}
|
Loading…
Reference in New Issue