-
Notifications
You must be signed in to change notification settings - Fork 117
/
Copy pathjetton_converters.go
211 lines (202 loc) · 6.71 KB
/
jetton_converters.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
package api
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/tonkeeper/tongo/abi"
"github.com/tonkeeper/tongo/tlb"
"net/http"
"sort"
"strings"
"github.com/tonkeeper/opentonapi/pkg/bath"
"github.com/tonkeeper/opentonapi/pkg/core"
"github.com/tonkeeper/opentonapi/pkg/oas"
"github.com/tonkeeper/tongo"
"github.com/tonkeeper/tongo/liteapi"
"github.com/tonkeeper/tongo/ton"
)
func jettonPreview(master ton.AccountID, meta NormalizedMetadata) oas.JettonPreview {
preview := oas.JettonPreview{
Address: master.ToRaw(),
Name: meta.Name,
Symbol: meta.Symbol,
Verification: oas.JettonVerificationType(meta.Verification),
Decimals: meta.Decimals,
Image: meta.PreviewImage,
}
if meta.CustomPayloadApiUri != "" {
preview.CustomPayloadAPIURI = oas.NewOptString(meta.CustomPayloadApiUri)
}
return preview
}
func jettonMetadata(account ton.AccountID, meta NormalizedMetadata) oas.JettonMetadata {
metadata := oas.JettonMetadata{
Address: account.ToRaw(),
Name: meta.Name,
Symbol: meta.Symbol,
Decimals: fmt.Sprintf("%d", meta.Decimals),
Social: meta.Social,
Websites: meta.Websites,
}
if meta.Description != "" {
metadata.Description.SetTo(meta.Description)
}
if meta.Image != "" {
metadata.Image.SetTo(meta.Image)
}
if meta.CustomPayloadApiUri != "" {
metadata.CustomPayloadAPIURI.SetTo(meta.CustomPayloadApiUri)
}
return metadata
}
func (h *Handler) convertJettonHistory(ctx context.Context, account ton.AccountID, master *ton.AccountID, history map[core.TraceID][]core.JettonOperation, acceptLanguage oas.OptString) ([]oas.AccountEvent, int64, error) {
var lastLT uint64
var events []oas.AccountEvent
for id, ops := range history {
event := oas.AccountEvent{
EventID: id.Hash.Hex(),
Account: convertAccountAddress(account, h.addressBook),
Timestamp: id.UTime, // TODO: or first/last op Utime
IsScam: false,
Lt: int64(id.Lt), // TODO: or first/last op Lt
Extra: 0,
}
for _, op := range ops {
var action bath.Action
switch op.Operation {
case core.TransferJettonOperation:
transferAction := bath.JettonTransferAction{
Jetton: op.JettonMaster,
Recipient: op.Destination,
Sender: op.Source,
Amount: tlb.VarUInteger16(*op.Amount.BigInt()),
}
action.Type = "JettonTransfer"
action.JettonTransfer = &transferAction
var payload abi.JettonPayload
err := json.Unmarshal([]byte(op.ForwardPayload), &payload)
if err != nil {
break
}
switch p := payload.Value.(type) {
case abi.TextCommentJettonPayload:
comment := string(p.Text)
action.JettonTransfer.Comment = &comment
case abi.EncryptedTextCommentJettonPayload:
action.JettonTransfer.EncryptedComment = &bath.EncryptedComment{EncryptionType: "simple", CipherText: p.CipherText}
}
case core.MintJettonOperation:
mintAction := bath.JettonMintAction{
Jetton: op.JettonMaster,
Recipient: *op.Destination,
Amount: tlb.VarUInteger16(*op.Amount.BigInt()),
}
action.Type = "JettonMint"
action.JettonMint = &mintAction
case core.BurnJettonOperation:
burnAction := bath.JettonBurnAction{
Jetton: op.JettonMaster,
Sender: *op.Source,
Amount: tlb.VarUInteger16(*op.Amount.BigInt()),
}
action.Type = "JettonTransfer"
action.JettonBurn = &burnAction
default:
continue
}
convertedAction, err := h.convertAction(ctx, &account, action, acceptLanguage)
if err != nil {
return nil, 0, err
}
event.Actions = append(event.Actions, convertedAction)
if lastLT == 0 {
lastLT = op.Lt
}
if op.Lt < lastLT {
lastLT = op.Lt
}
}
if len(event.Actions) == 0 {
continue
}
event.IsScam = h.spamFilter.CheckActions(event.Actions, &account, nil)
events = append(events, event)
}
sort.Slice(events, func(i, j int) bool {
return events[i].Lt > events[j].Lt
})
return events, int64(lastLT), nil
}
func (h *Handler) convertJettonBalance(ctx context.Context, wallet core.JettonWallet, currencies []string) (oas.JettonBalance, error) {
todayRates, yesterdayRates, weekRates, monthRates, _ := h.getRates()
for idx, currency := range currencies {
if jetton, err := tongo.ParseAddress(currency); err == nil {
currency = jetton.ID.ToRaw()
} else {
currency = strings.ToUpper(currency)
}
currencies[idx] = currency
}
jettonBalance := oas.JettonBalance{
Balance: wallet.Balance.String(),
WalletAddress: convertAccountAddress(wallet.Address, h.addressBook),
Extensions: wallet.Extensions,
}
if wallet.Lock != nil {
jettonBalance.Lock = oas.NewOptJettonBalanceLock(oas.JettonBalanceLock{
Amount: wallet.Lock.FullBalance.String(),
Till: wallet.Lock.UnlockTime,
})
}
var err error
rates := make(map[string]oas.TokenRates)
for _, currency := range currencies {
rates, err = convertRates(rates, wallet.JettonAddress.ToRaw(), currency, todayRates, yesterdayRates, weekRates, monthRates)
if err != nil {
continue
}
}
price := rates[wallet.JettonAddress.ToRaw()]
if len(rates) > 0 && len(price.Prices.Value) > 0 {
jettonBalance.Price.SetTo(price)
}
meta, err := h.storage.GetJettonMasterMetadata(ctx, wallet.JettonAddress)
if err != nil && err.Error() == "not enough refs" {
// happens when metadata is broken, for example.
return oas.JettonBalance{}, toError(http.StatusInternalServerError, err)
}
if err != nil && errors.Is(err, liteapi.ErrOnchainContentOnly) {
// we don't support such jettons
return oas.JettonBalance{}, toError(http.StatusInternalServerError, err)
}
if err != nil && !errors.Is(err, core.ErrEntityNotFound) {
return oas.JettonBalance{}, toError(http.StatusNotFound, err)
}
var normalizedMetadata NormalizedMetadata
info, ok := h.addressBook.GetJettonInfoByAddress(wallet.JettonAddress)
if ok {
normalizedMetadata = NormalizeMetadata(meta, &info, core.TrustNone)
} else {
trust := core.TrustNone
if h.spamFilter != nil {
trust = h.spamFilter.JettonTrust(wallet.JettonAddress, meta.Symbol, meta.Name, meta.Image)
}
normalizedMetadata = NormalizeMetadata(meta, nil, trust)
}
jettonBalance.Jetton = jettonPreview(wallet.JettonAddress, normalizedMetadata)
return jettonBalance, nil
}
func (h *Handler) convertJettonInfo(ctx context.Context, master core.JettonMaster, holders map[tongo.AccountID]int32) oas.JettonInfo {
meta := h.GetJettonNormalizedMetadata(ctx, master.Address)
metadata := jettonMetadata(master.Address, meta)
return oas.JettonInfo{
Mintable: master.Mintable,
TotalSupply: master.TotalSupply.String(),
Metadata: metadata,
Verification: oas.JettonVerificationType(meta.Verification),
HoldersCount: holders[master.Address],
Admin: convertOptAccountAddress(master.Admin, h.addressBook),
Preview: meta.PreviewImage,
}
}