Skip to content

Commit 13ddc60

Browse files
committed
feat: crawll binance spot tx
1 parent 0b5c68b commit 13ddc60

File tree

22 files changed

+340
-7
lines changed

22 files changed

+340
-7
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package main
2+
3+
import (
4+
"time"
5+
6+
"github.com/defipod/mochi/pkg/config"
7+
"github.com/defipod/mochi/pkg/entities"
8+
"github.com/defipod/mochi/pkg/job"
9+
"github.com/defipod/mochi/pkg/logger"
10+
)
11+
12+
func main() {
13+
cfg := config.LoadConfig(config.DefaultConfigLoaders())
14+
log := logger.NewLogrusLogger()
15+
// *** entities ***
16+
err := entities.Init(cfg, log)
17+
if err != nil {
18+
log.Fatal(err, "failed to init entities")
19+
}
20+
entity := entities.Get()
21+
defer entity.GetSvc().Sentry.Flush(2 * time.Second)
22+
23+
if err := job.NewCrawlBinanceSpotTransactionsJob(entity, log).Run(); err != nil {
24+
log.Fatal(err, "failed to run job")
25+
}
26+
27+
log.Info("done")
28+
}

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ require (
111111
github.com/leodido/go-urn v1.2.4 // indirect
112112
github.com/linkedin/goavro/v2 v2.11.1 // indirect
113113
github.com/magiconair/properties v1.8.7 // indirect
114+
github.com/mattn/go-colorable v0.1.13 // indirect
114115
github.com/mattn/go-isatty v0.0.20 // indirect
115116
github.com/mattn/go-runewidth v0.0.14 // indirect
116117
github.com/mattn/go-sqlite3 v2.0.1+incompatible // indirect
@@ -158,6 +159,7 @@ require (
158159
github.com/consolelabs/mochi-typeset v0.0.0-20231120101232-7743776c4c84
159160
github.com/gammazero/workerpool v1.1.3
160161
github.com/getsentry/sentry-go v0.18.0
162+
github.com/k0kubun/pp/v3 v3.2.0
161163
github.com/pkg/errors v0.9.1
162164
github.com/shopspring/decimal v1.2.0
163165
github.com/xssnick/tonutils-go v1.8.5

go.sum

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc
7474
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
7575
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
7676
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
77+
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
78+
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
7779
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8=
7880
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
7981
github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o=
@@ -533,6 +535,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
533535
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
534536
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
535537
github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=
538+
github.com/k0kubun/pp/v3 v3.2.0 h1:h33hNTZ9nVFNP3u2Fsgz8JXiF5JINoZfFq4SvKJwNcs=
539+
github.com/k0kubun/pp/v3 v3.2.0/go.mod h1:ODtJQbQcIRfAD3N+theGCV1m/CBxweERz2dapdz1EwA=
536540
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
537541
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
538542
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@@ -592,6 +596,7 @@ github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO
592596
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
593597
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
594598
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
599+
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
595600
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
596601
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
597602
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
@@ -601,6 +606,7 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
601606
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
602607
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
603608
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
609+
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
604610
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
605611
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
606612
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
@@ -1058,6 +1064,7 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc
10581064
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
10591065
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
10601066
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1067+
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
10611068
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
10621069
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
10631070
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
2+
-- +migrate Up
3+
create table if not exists binance_trackings (
4+
id serial primary key,
5+
profile_id text,
6+
spot_last_time timestamp
7+
);
8+
9+
create table binance_spot_transactions (
10+
id serial,
11+
profile_id text,
12+
symbol text,
13+
order_id integer,
14+
order_list_id integer,
15+
client_order_id text,
16+
price text,
17+
orig_qty text,
18+
executed_qty text,
19+
cumulative_quote_qty text,
20+
status text,
21+
time_in_force text,
22+
type text,
23+
side text,
24+
stop_price text,
25+
iceberg_qty text,
26+
time timestamp,
27+
update_time timestamp,
28+
is_working boolean,
29+
orig_quote_order_qty text,
30+
working_time timestamp,
31+
self_trade_prevention_mode text
32+
);
33+
34+
create unique index binance_spot_transactions_profile_id_order_id_index on binance_spot_transactions (profile_id, order_id);
35+
-- +migrate Down
36+
drop table if exists binance_trackings;
37+
drop index if exists binance_spot_transactions_profile_id_order_id_index;
38+
drop table if exists binance_spot_transactions;

pkg/entities/binance_data.go

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"math/rand"
66
"strconv"
7+
"time"
78

89
"github.com/defipod/mochi/pkg/consts"
910
"github.com/defipod/mochi/pkg/logger"
@@ -67,18 +68,51 @@ func (e *Entity) IntegrateBinanceData(req request.IntegrationBinanceData) (*mode
6768
}
6869

6970
func (e *Entity) UnlinkBinance(req request.UnlinkBinance) error {
70-
res, err := e.svc.MochiProfile.GetByDiscordID(req.DiscordUserId, true)
71-
if err != nil {
71+
res, err := e.svc.MochiProfile.GetByDiscordID(req.DiscordUserId, true)
72+
if err != nil {
7273
e.log.Fields(logger.Fields{"discordUserId": req.DiscordUserId}).Error(err, "[entities.UnlinkBinance] - fail to get profile by discord id")
7374
return err
74-
}
75+
}
7576

76-
err = e.svc.MochiProfile.UnlinkDex(res.ID, consts.PlatformBinance)
77+
err = e.svc.MochiProfile.UnlinkDex(res.ID, consts.PlatformBinance)
7778
if err != nil {
78-
e.log.Fields(logger.Fields{"profileId": res.ID, "platform": consts.PlatformBinance}).Error(err, "[entities.UnlinkBinance] - fail to unlink binance")
79-
return err
79+
e.log.Fields(logger.Fields{"profileId": res.ID, "platform": consts.PlatformBinance}).Error(err, "[entities.UnlinkBinance] - fail to unlink binance")
80+
return err
8081
}
8182

82-
return nil
83+
return nil
84+
}
85+
86+
func binanceStartTime() time.Time {
87+
return time.Unix(1499943600, 0).UTC()
8388
}
89+
func (e *Entity) CrawlBinanceSpotTransactions() {
90+
e.log.Info("Watching Binance account from profile ...")
91+
// get all binance associated account
92+
res, err := e.svc.MochiProfile.GetAllBinanceAccount()
93+
if err != nil {
94+
e.log.Error(err, "[entities.CrawlBinanceSpotTransactions] - fail to get all binance associated account")
95+
return
96+
}
97+
98+
for idx, binance := range res.Data {
99+
binanceTracking, err := e.repo.BinanceTracking.FirstOrCreate(&model.BinanceTracking{ProfileId: binance.ProfileId, SpotLastTime: binanceStartTime()})
100+
if err != nil {
101+
e.log.Fields(logger.Fields{"profileId": binance.ProfileId}).Error(err, "[entities.CrawlBinanceSpotTransactions] - fail to first or create binance tracking")
102+
continue
103+
}
104+
res.Data[idx].SpotLastTime = binanceTracking.SpotLastTime
105+
}
84106

107+
for _, binance := range res.Data {
108+
e.log.Fields(logger.Fields{"profileId": binance.ProfileId}).Info("[entities.CrawlBinanceSpotTransactions] - start crawling binance spot transactions")
109+
// get spot transactions
110+
startTime := strconv.Itoa(int(binance.SpotLastTime.UnixMilli()))
111+
endTime := strconv.Itoa(int(time.Date(2024, 2, 20, 0, 0, 0, 0, time.UTC).UnixMilli()))
112+
_, err := e.svc.Binance.GetSpotTransactions(binance.ApiKey, binance.ApiSecret, startTime, endTime)
113+
if err != nil {
114+
e.log.Fields(logger.Fields{"profileId": binance.ProfileId}).Error(err, "[entities.CrawlBinanceSpotTransactions] - fail to get spot transactions")
115+
continue
116+
}
117+
}
118+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package job
2+
3+
import (
4+
"github.com/defipod/mochi/pkg/entities"
5+
"github.com/defipod/mochi/pkg/logger"
6+
)
7+
8+
type crawlBinanceSpotTransactions struct {
9+
entity *entities.Entity
10+
log logger.Logger
11+
}
12+
13+
func NewCrawlBinanceSpotTransactionsJob(e *entities.Entity, l logger.Logger) Job {
14+
return &crawlBinanceSpotTransactions{
15+
entity: e,
16+
log: l,
17+
}
18+
}
19+
20+
func (j *crawlBinanceSpotTransactions) Run() error {
21+
j.log.Infof("Start crawling binance spot transaction ...")
22+
j.entity.CrawlBinanceSpotTransactions()
23+
return nil
24+
}

pkg/model/binance_spot_transaction.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package model
2+
3+
import "time"
4+
5+
type BinanceSpotTransaction struct {
6+
ID int64 `json:"id"`
7+
ProfileId string `json:"profile_id"`
8+
Symbol string `json:"symbol"`
9+
OrderId int64 `json:"order_id"`
10+
OrderListId int64 `json:"order_list_id"`
11+
ClientOrderId string `json:"client_order_id"`
12+
Price string `json:"price"`
13+
OrigQty string `json:"orig_qty"`
14+
ExecutedQty string `json:"executed_qty"`
15+
CummulativeQuoteQty string `json:"cummulative_quote_qty"`
16+
Status string `json:"status"`
17+
TimeInForce string `json:"time_in_force"`
18+
Type string `json:"type"`
19+
Side string `json:"side"`
20+
StopPrice string `json:"stop_price"`
21+
IcebergQty string `json:"iceberg_qty"`
22+
Time time.Time `json:"time"`
23+
UpdateTime time.Time `json:"update_time"`
24+
IsWorking bool `json:"is_working"`
25+
OrigQuoteOrderQty string `json:"orig_quote_order_qty"`
26+
WorkingTime time.Time `json:"working_time"`
27+
SelfTradePreventionMode string `json:"self_trade_prevention_mode"`
28+
}

pkg/model/binance_tracking.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package model
2+
3+
import "time"
4+
5+
type BinanceTracking struct {
6+
ID int64 `json:"id"`
7+
ProfileId string `json:"profile_id"`
8+
SpotLastTime time.Time `json:"spot_last_time"`
9+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package binancespottransaction
2+
3+
import (
4+
"gorm.io/gorm"
5+
6+
"github.com/defipod/mochi/pkg/model"
7+
)
8+
9+
type pg struct {
10+
db *gorm.DB
11+
}
12+
13+
func NewPG(db *gorm.DB) Store {
14+
return &pg{db: db}
15+
}
16+
17+
func (pg *pg) Create(tx *model.BinanceSpotTransaction) error {
18+
return pg.db.Create(&tx).Error
19+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package binancespottransaction
2+
3+
import "github.com/defipod/mochi/pkg/model"
4+
5+
type Store interface {
6+
Create(tx *model.BinanceSpotTransaction) error
7+
}

pkg/repo/binance_tracking/pg.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package binancetracking
2+
3+
import (
4+
"gorm.io/gorm"
5+
6+
"github.com/defipod/mochi/pkg/model"
7+
)
8+
9+
type pg struct {
10+
db *gorm.DB
11+
}
12+
13+
func NewPG(db *gorm.DB) Store {
14+
return &pg{db: db}
15+
}
16+
17+
func (pg *pg) FirstOrCreate(binanceTracking *model.BinanceTracking) (*model.BinanceTracking, error) {
18+
return binanceTracking, pg.db.Where("profile_id = ?", binanceTracking.ProfileId).FirstOrCreate(&binanceTracking).Error
19+
}

pkg/repo/binance_tracking/store.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package binancetracking
2+
3+
import "github.com/defipod/mochi/pkg/model"
4+
5+
type Store interface {
6+
FirstOrCreate(binanceTracking *model.BinanceTracking) (*model.BinanceTracking, error)
7+
}

pkg/repo/pg/repo.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
ac "github.com/defipod/mochi/pkg/repo/airdrop_campaign"
99
autoActionHistory "github.com/defipod/mochi/pkg/repo/auto_action_history"
1010
autoTrigger "github.com/defipod/mochi/pkg/repo/auto_trigger"
11+
binancespottransaction "github.com/defipod/mochi/pkg/repo/binance_spot_transaction"
12+
binacetracking "github.com/defipod/mochi/pkg/repo/binance_tracking"
1113
"github.com/defipod/mochi/pkg/repo/chain"
1214
coingeckoinfo "github.com/defipod/mochi/pkg/repo/coingecko_info"
1315
coingeckosupportedtokens "github.com/defipod/mochi/pkg/repo/coingecko_supported_tokens"
@@ -190,5 +192,7 @@ func NewRepo(db *gorm.DB) *repo.Repo {
190192
UserNotificationSetting: usernotificationsetting.NewPG(db),
191193
NotificationFlag: notificationflag.NewPG(db),
192194
TokenPriceSnapshot: tokenpricesnapshot.NewPG(db),
195+
BinanceTracking: binacetracking.NewPG(db),
196+
BinanceSpotTransaction: binancespottransaction.NewPG(db),
193197
}
194198
}

pkg/repo/repo.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
ac "github.com/defipod/mochi/pkg/repo/airdrop_campaign"
66
autoActionHistory "github.com/defipod/mochi/pkg/repo/auto_action_history"
77
autoTrigger "github.com/defipod/mochi/pkg/repo/auto_trigger"
8+
binancespottransaction "github.com/defipod/mochi/pkg/repo/binance_spot_transaction"
9+
binancetracking "github.com/defipod/mochi/pkg/repo/binance_tracking"
810
"github.com/defipod/mochi/pkg/repo/chain"
911
coingeckoinfo "github.com/defipod/mochi/pkg/repo/coingecko_info"
1012
coingeckosupportedtokens "github.com/defipod/mochi/pkg/repo/coingecko_supported_tokens"
@@ -185,4 +187,6 @@ type Repo struct {
185187
UserNotificationSetting usernotificationsetting.Store
186188
NotificationFlag notificationflag.Store
187189
TokenPriceSnapshot tokenpricesnapshot.Store
190+
BinanceTracking binancetracking.Store
191+
BinanceSpotTransaction binancespottransaction.Store
188192
}

pkg/response/binance.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,26 @@ type BinanceApiTickerPriceResponse struct {
217217
Symbol string `json:"symbol"`
218218
Price string `json:"price"`
219219
}
220+
221+
type BinanceSpotTransaction struct {
222+
Symbol string `json:"symbol"`
223+
OrderId int64 `json:"order_id"`
224+
OrderListId int64 `json:"order_list_id"`
225+
ClientOrderId string `json:"client_order_id"`
226+
Price string `json:"price"`
227+
OrigQty string `json:"orig_qty"`
228+
ExecutedQty string `json:"executed_qty"`
229+
CummulativeQuoteQty string `json:"cummulative_quote_qty"`
230+
Status string `json:"status"`
231+
TimeInForce string `json:"time_in_force"`
232+
Type string `json:"type"`
233+
Side string `json:"side"`
234+
StopPrice string `json:"stop_price"`
235+
IcebergQty string `json:"iceberg_qty"`
236+
Time int64 `json:"time"`
237+
UpdateTime int64 `json:"update_time"`
238+
IsWorking bool `json:"is_working"`
239+
OrigQuoteOrderQty string `json:"orig_quote_order_qty"`
240+
WorkingTime int64 `json:"working_time"`
241+
SelfTradePreventionMode string `json:"self_trade_prevention_mode"`
242+
}

0 commit comments

Comments
 (0)