Skip to content

Commit b572dd7

Browse files
committed
add backend service
1 parent e22e5d4 commit b572dd7

File tree

8 files changed

+2701
-0
lines changed

8 files changed

+2701
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Compiler files
22
cache/
33
out/
4+
artifacts/
5+
.deps/
46

57
# Ignores development broadcast logs
68
!/broadcast

backend/Dockerfile

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
FROM golang:1.24-alpine AS builder
2+
RUN apk add --no-cache git
3+
WORKDIR /app
4+
COPY go.mod go.sum ./
5+
RUN go mod download
6+
COPY . .
7+
RUN go build -o server main.go
8+
9+
FROM alpine:3.18
10+
RUN apk add --no-cache ca-certificates
11+
WORKDIR /app
12+
COPY --from=builder /app/server .
13+
EXPOSE 8080
14+
15+
CMD ["./server"]

backend/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# build docker image
2+
`docker build . -t nubila-service`
3+
4+
# start service
5+
Assume $RPC_URL is the RPC of the blockchain where the contracts are deployed to
6+
## without vesting manager contract
7+
Before deploying vesting manager contract, the total supply is the initial supply, 1_000_000_000, and the circulating amount is 0.
8+
`docker run -p 8080:8080 -e RPC_URL="$RPC_URL" nubila-service`
9+
10+
## with vesting manager contract
11+
Once we have the vesting manager contract deployed, the service is started as follows:
12+
`docker run -p 8080:8080 -e MANAGER_ADDRESS="$MANAGER_ADDR" -e RPC_URL="$RPC_URL" nubila-service`
13+
14+
# Query
15+
## total supply
16+
localhost:8080/total
17+
18+
## circulating
19+
localhost:8080/circulating

backend/contract/IERC20.go

Lines changed: 645 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/contract/VestingManager.go

Lines changed: 1590 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/go.mod

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
module github.com/CoderZhi/nubila-token/backend
2+
3+
go 1.24.0
4+
5+
toolchain go1.24.9
6+
7+
require (
8+
github.com/ethereum/go-ethereum v1.16.3
9+
github.com/gin-gonic/gin v1.11.0
10+
)
11+
12+
require (
13+
github.com/Microsoft/go-winio v0.6.2 // indirect
14+
github.com/StackExchange/wmi v1.2.1 // indirect
15+
github.com/bits-and-blooms/bitset v1.20.0 // indirect
16+
github.com/bytedance/sonic v1.14.0 // indirect
17+
github.com/bytedance/sonic/loader v0.3.0 // indirect
18+
github.com/cloudwego/base64x v0.1.6 // indirect
19+
github.com/consensys/gnark-crypto v0.18.0 // indirect
20+
github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect
21+
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect
22+
github.com/deckarep/golang-set/v2 v2.6.0 // indirect
23+
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
24+
github.com/ethereum/c-kzg-4844/v2 v2.1.3 // indirect
25+
github.com/ethereum/go-verkle v0.2.2 // indirect
26+
github.com/fsnotify/fsnotify v1.6.0 // indirect
27+
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
28+
github.com/gin-contrib/sse v1.1.0 // indirect
29+
github.com/go-ole/go-ole v1.3.0 // indirect
30+
github.com/go-playground/locales v0.14.1 // indirect
31+
github.com/go-playground/universal-translator v0.18.1 // indirect
32+
github.com/go-playground/validator/v10 v10.27.0 // indirect
33+
github.com/goccy/go-json v0.10.4 // indirect
34+
github.com/goccy/go-yaml v1.18.0 // indirect
35+
github.com/google/uuid v1.3.0 // indirect
36+
github.com/gorilla/websocket v1.4.2 // indirect
37+
github.com/holiman/uint256 v1.3.2 // indirect
38+
github.com/json-iterator/go v1.1.12 // indirect
39+
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
40+
github.com/leodido/go-urn v1.4.0 // indirect
41+
github.com/mattn/go-isatty v0.0.20 // indirect
42+
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
43+
github.com/modern-go/reflect2 v1.0.2 // indirect
44+
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
45+
github.com/quic-go/qpack v0.5.1 // indirect
46+
github.com/quic-go/quic-go v0.54.0 // indirect
47+
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
48+
github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe // indirect
49+
github.com/tklauser/go-sysconf v0.3.12 // indirect
50+
github.com/tklauser/numcpus v0.6.1 // indirect
51+
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
52+
github.com/ugorji/go/codec v1.3.0 // indirect
53+
go.uber.org/mock v0.5.0 // indirect
54+
golang.org/x/arch v0.20.0 // indirect
55+
golang.org/x/crypto v0.40.0 // indirect
56+
golang.org/x/mod v0.25.0 // indirect
57+
golang.org/x/net v0.42.0 // indirect
58+
golang.org/x/sync v0.16.0 // indirect
59+
golang.org/x/sys v0.36.0 // indirect
60+
golang.org/x/text v0.27.0 // indirect
61+
golang.org/x/tools v0.34.0 // indirect
62+
google.golang.org/protobuf v1.36.9 // indirect
63+
)

backend/go.sum

Lines changed: 268 additions & 0 deletions
Large diffs are not rendered by default.

backend/main.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package main
2+
3+
import (
4+
"math/big"
5+
"os"
6+
"time"
7+
8+
"github.com/CoderZhi/nubila-token/backend/contract"
9+
"github.com/ethereum/go-ethereum/common"
10+
"github.com/ethereum/go-ethereum/ethclient"
11+
"github.com/gin-gonic/gin"
12+
)
13+
14+
func main() {
15+
rpc := os.Getenv("RPC_URL")
16+
addr := os.Getenv("MANAGER_ADDRESS")
17+
client, err := ethclient.Dial(rpc)
18+
if err != nil {
19+
panic(err)
20+
}
21+
var token *contract.IERC20
22+
if addr != "" {
23+
manager, err := contract.NewVestingManager(common.HexToAddress(addr), client)
24+
if err != nil {
25+
panic(err)
26+
}
27+
tokenAddr, err := manager.Token(nil)
28+
if err != nil {
29+
panic(err)
30+
}
31+
token, err = contract.NewIERC20(tokenAddr, client)
32+
if err != nil {
33+
panic(err)
34+
}
35+
}
36+
var (
37+
initSupply = big.NewFloat(1_000_000_000)
38+
decimal = big.NewFloat(1e18)
39+
totalSupply *big.Float
40+
withheld *big.Float
41+
totalSupplyTs time.Time
42+
withheldTs time.Time
43+
)
44+
getTotalSupply := func() (*big.Float, error) {
45+
if token == nil {
46+
return initSupply, nil
47+
}
48+
if time.Since(totalSupplyTs) < time.Minute && totalSupply != nil {
49+
return totalSupply, nil
50+
}
51+
supply, err := token.TotalSupply(nil)
52+
if err != nil {
53+
return nil, err
54+
}
55+
totalSupply = new(big.Float).Quo(new(big.Float).SetInt(supply), decimal)
56+
totalSupplyTs = time.Now()
57+
return totalSupply, nil
58+
}
59+
getWithheld := func() (*big.Float, error) {
60+
if token == nil {
61+
return initSupply, nil
62+
}
63+
if time.Since(withheldTs) < time.Minute && withheld != nil {
64+
return withheld, nil
65+
}
66+
balance, err := token.BalanceOf(nil, common.HexToAddress(addr))
67+
if err != nil {
68+
return nil, err
69+
}
70+
withheld = new(big.Float).Quo(new(big.Float).SetInt(balance), decimal)
71+
withheldTs = time.Now()
72+
return withheld, nil
73+
}
74+
75+
r := gin.Default()
76+
77+
r.GET("/total", func(c *gin.Context) {
78+
total, err := getTotalSupply()
79+
if err != nil {
80+
c.JSON(500, gin.H{"error": err.Error()})
81+
return
82+
}
83+
c.String(200, total.Text('f', 18))
84+
})
85+
r.GET("/circulating", func(c *gin.Context) {
86+
total, err := getTotalSupply()
87+
if err != nil {
88+
c.JSON(500, gin.H{"error": err.Error()})
89+
return
90+
}
91+
withheld, err := getWithheld()
92+
if err != nil {
93+
c.JSON(500, gin.H{"error": err.Error()})
94+
return
95+
}
96+
c.String(200, new(big.Float).Sub(total, withheld).Text('f', 18))
97+
})
98+
r.Run(":8080")
99+
}

0 commit comments

Comments
 (0)