-
Notifications
You must be signed in to change notification settings - Fork 135
/
Copy pathmain.go
125 lines (103 loc) · 4.22 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package main
import (
"context"
"github.com/xssnick/tonutils-go/address"
"github.com/xssnick/tonutils-go/liteclient"
"github.com/xssnick/tonutils-go/tlb"
"github.com/xssnick/tonutils-go/ton"
"github.com/xssnick/tonutils-go/ton/jetton"
"log"
)
func main() {
client := liteclient.NewConnectionPool()
cfg, err := liteclient.GetConfigFromUrl(context.Background(), "https://ton.org/global.config.json")
if err != nil {
log.Fatalln("get config err: ", err.Error())
return
}
// connect to mainnet lite servers
err = client.AddConnectionsFromConfig(context.Background(), cfg)
if err != nil {
log.Fatalln("connection err: ", err.Error())
return
}
// initialize ton api lite connection wrapper with full proof checks
api := ton.NewAPIClient(client, ton.ProofCheckPolicyFast).WithRetry()
api.SetTrustedBlockFromConfig(cfg)
master, err := api.CurrentMasterchainInfo(context.Background()) // we fetch block just to trigger chain proof check
if err != nil {
log.Fatalln("get masterchain info err: ", err.Error())
return
}
// address on which we are accepting payments
treasuryAddress := address.MustParseAddr("EQAYqo4u7VF0fa4DPAebk4g9lBytj2VFny7pzXR0trjtXQaO")
acc, err := api.GetAccount(context.Background(), master, treasuryAddress)
if err != nil {
log.Fatalln("get masterchain info err: ", err.Error())
return
}
// Cursor of processed transaction, save it to your db
// We start from last transaction, will not process transactions older than we started from.
// After each processed transaction, save lt to your db, to continue after restart
lastProcessedLT := acc.LastTxLT
// channel with new transactions
transactions := make(chan *tlb.Transaction)
// it is a blocking call, so we start it asynchronously
go api.SubscribeOnTransactions(context.Background(), treasuryAddress, lastProcessedLT, transactions)
log.Println("waiting for transfers...")
// USDT master contract addr, but can be any jetton
usdt := jetton.NewJettonMasterClient(api, address.MustParseAddr("EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs"))
// get our jetton wallet address
treasuryJettonWallet, err := usdt.GetJettonWalletAtBlock(context.Background(), treasuryAddress, master)
if err != nil {
log.Fatalln("get jetton wallet address err: ", err.Error())
return
}
// listen for new transactions from channel
for tx := range transactions {
// only internal messages can increase the balance
if tx.IO.In != nil && tx.IO.In.MsgType == tlb.MsgTypeInternal {
ti := tx.IO.In.AsInternal()
src := ti.SrcAddr
if dsc, ok := tx.Description.(tlb.TransactionDescriptionOrdinary); ok && dsc.BouncePhase != nil {
if _, ok = dsc.BouncePhase.Phase.(tlb.BouncePhaseOk); ok {
// transaction was bounced, and coins were returned to sender
// this can happen mostly on custom contracts
continue
}
}
if !ti.ExtraCurrencies.IsEmpty() {
kv, err := ti.ExtraCurrencies.LoadAll()
if err != nil {
log.Fatalln("load extra currencies err: ", err.Error())
return
}
for _, dictKV := range kv {
currencyId := dictKV.Key.MustLoadUInt(32)
amount := dictKV.Value.MustLoadVarUInt(32)
log.Println("received", amount.String(), "ExtraCurrency with id", currencyId, "from", src.String())
}
}
// verify that event sender is our jetton wallet
if ti.SrcAddr.Equals(treasuryJettonWallet.Address()) {
var transfer jetton.TransferNotification
if err = tlb.LoadFromCell(&transfer, ti.Body.BeginParse()); err == nil {
// convert decimals to 6 for USDT (it can be fetched from jetton details too), default is 9
amt := tlb.MustFromNano(transfer.Amount.Nano(), 6)
// reassign sender to real jetton sender instead of its jetton wallet contract
src = transfer.Sender
log.Println("received", amt.String(), "USDT from", src.String())
}
}
if ti.Amount.Nano().Sign() > 0 {
// show received ton amount
log.Println("received", ti.Amount.String(), "TON from", src.String())
}
}
// update last processed lt and save it in db
lastProcessedLT = tx.LT
}
// it can happen due to none of available liteservers know old enough state for our address
// (when our unprocessed transactions are too old)
log.Println("something went wrong, transaction listening unexpectedly finished")
}