• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

synapsecns / sanguine / 3202516510

07 Oct 2022 05:46AM UTC coverage: 50.548% (+7.4%) from 43.1%
3202516510

Pull #242

github

Simon
extend clickhouse lifetime + remove comments
Pull Request #242: Adding statistic query, centralizing parsing, adding price/fee, symbol getters

404 of 404 new or added lines in 4 files covered. (100.0%)

5902 of 11676 relevant lines covered (50.55%)

0.54 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

4.44
/services/explorer/consumer/parser.go
1
package consumer
2

3
import (
4
        "context"
5
        "database/sql"
6
        "fmt"
7
        "github.com/ethereum/go-ethereum/common"
8
        ethTypes "github.com/ethereum/go-ethereum/core/types"
9
        "github.com/ethereum/go-ethereum/crypto"
10
        "github.com/synapsecns/sanguine/services/explorer/contracts/bridge"
11
        "github.com/synapsecns/sanguine/services/explorer/contracts/swap"
12
        "github.com/synapsecns/sanguine/services/explorer/db"
13
        model "github.com/synapsecns/sanguine/services/explorer/db/sql"
14
        bridgeTypes "github.com/synapsecns/sanguine/services/explorer/types/bridge"
15
        swapTypes "github.com/synapsecns/sanguine/services/explorer/types/swap"
16
        "math/big"
17
        "time"
18
)
19

20
// BoolToUint8 is a helper function to handle bool to uint8 conversion for clickhouse.
21
func BoolToUint8(input *bool) *uint8 {
1✔
22
        if input == nil {
1✔
23
                return nil
×
24
        }
×
25
        if *input {
2✔
26
                one := uint8(1)
1✔
27
                return &one
1✔
28
        }
1✔
29
        zero := uint8(0)
1✔
30
        return &zero
1✔
31
}
32

33
// ToNullString is a helper function to convert values to null string.
34
func ToNullString(str *string) sql.NullString {
1✔
35
        var newNullStr sql.NullString
1✔
36
        if str != nil {
2✔
37
                newNullStr.Valid = true
1✔
38
                newNullStr.String = *str
1✔
39
        } else {
2✔
40
                newNullStr.Valid = false
1✔
41
        }
1✔
42
        return newNullStr
1✔
43
}
44

45
// Parser parses events and stores them.
46
type Parser interface {
47
        // ParseAndStore parses the logs and stores them in the database.
48
        ParseAndStore(ctx context.Context, log ethTypes.Log, chainID uint32) error
49
}
50

51
// BridgeParser parses events from the bridge contract.
52
type BridgeParser struct {
53
        // consumerDB is the database to store parsed data in
54
        consumerDB db.ConsumerDB
55
        // Filterer is the bridge Filterer we use to parse events
56
        Filterer *bridge.SynapseBridgeFilterer
57
        // bridgeAddress is the address of the bridge
58
        bridgeAddress common.Address
59
        // fetcher is a Bridge Config Fetcher
60
        fetcher BridgeConfigFetcher
61
        // consumerFetcher is the Fetcher for sender and timestamp
62
        consumerFetcher *Fetcher
63
}
64

65
// NewBridgeParser creates a new parser for a given bridge.
66
func NewBridgeParser(consumerDB db.ConsumerDB, bridgeAddress common.Address, bridgeConfigFetcher BridgeConfigFetcher, consumerFetcher *Fetcher) (*BridgeParser, error) {
×
67
        filterer, err := bridge.NewSynapseBridgeFilterer(bridgeAddress, nil)
×
68
        if err != nil {
×
69
                return nil, fmt.Errorf("could not create %T: %w", bridge.SynapseBridgeFilterer{}, err)
×
70
        }
×
71
        return &BridgeParser{consumerDB, filterer, bridgeAddress, bridgeConfigFetcher, consumerFetcher}, nil
×
72
}
73

74
// EventType returns the event type of a bridge log.
75
func (p *BridgeParser) EventType(log ethTypes.Log) (_ bridgeTypes.EventType, ok bool) {
×
76
        for _, logTopic := range log.Topics {
×
77
                eventType := bridge.EventTypeFromTopic(logTopic)
×
78
                if eventType == nil {
×
79
                        continue
×
80
                }
81

82
                return *eventType, true
×
83
        }
84
        // return an unknown event to avoid cases where user failed to check the event type
85
        return bridgeTypes.EventType(len(bridgeTypes.AllEventTypes()) + 2), false
×
86
}
87

88
// SwapParser parses events from the swap contract.
89
type SwapParser struct {
90
        // consumerDB is the database to store parsed data in
91
        consumerDB db.ConsumerDB
92
        // Filterer is the swap Filterer we use to parse events
93
        Filterer *swap.SwapFlashLoanFilterer
94
        // consumerFetcher is the Fetcher for sender and timestamp
95
        consumerFetcher *Fetcher
96
}
97

98
// NewSwapParser creates a new parser for a given bridge.
99
func NewSwapParser(consumerDB db.ConsumerDB, swapAddress common.Address, consumerFetcher *Fetcher) (*SwapParser, error) {
×
100
        filterer, err := swap.NewSwapFlashLoanFilterer(swapAddress, nil)
×
101
        if err != nil {
×
102
                return nil, fmt.Errorf("could not create %T: %w", bridge.SynapseBridgeFilterer{}, err)
×
103
        }
×
104
        return &SwapParser{consumerDB, filterer, consumerFetcher}, nil
×
105
}
106

107
// EventType returns the event type of a swap log.
108
func (p *SwapParser) EventType(log ethTypes.Log) (_ swapTypes.EventType, ok bool) {
×
109
        for _, logTopic := range log.Topics {
×
110
                eventType := swap.EventTypeFromTopic(logTopic)
×
111
                if eventType == nil {
×
112
                        continue
×
113
                }
114

115
                return *eventType, true
×
116
        }
117
        // return an unknown event to avoid cases where user failed to check the event type
118
        return swapTypes.EventType(len(swapTypes.AllEventTypes()) + 2), false
×
119
}
120

121
// eventToBridgeEvent stores a bridge event.
122
func eventToBridgeEvent(event bridgeTypes.EventLog, chainID uint32) model.BridgeEvent {
×
123
        var recipient sql.NullString
×
124
        if event.GetRecipient() != nil {
×
125
                recipient.Valid = true
×
126
                recipient.String = event.GetRecipient().String()
×
127
        } else {
×
128
                recipient.Valid = false
×
129
        }
×
130
        var recipientBytes sql.NullString
×
131
        if event.GetRecipientBytes() != nil {
×
132
                recipientBytes.Valid = true
×
133
                recipientBytes.String = common.Bytes2Hex(event.GetRecipientBytes()[:])
×
134
        } else {
×
135
                recipientBytes.Valid = false
×
136
        }
×
137
        var destinationChainID *big.Int
×
138
        if event.GetDestinationChainID() != nil {
×
139
                destinationChainID = big.NewInt(int64(event.GetDestinationChainID().Uint64()))
×
140
        }
×
141
        var tokenIndexFrom *big.Int
×
142
        if event.GetTokenIndexFrom() != nil {
×
143
                tokenIndexFrom = big.NewInt(int64(*event.GetTokenIndexFrom()))
×
144
        }
×
145
        var tokenIndexTo *big.Int
×
146
        if event.GetTokenIndexTo() != nil {
×
147
                tokenIndexTo = big.NewInt(int64(*event.GetTokenIndexTo()))
×
148
        }
×
149
        var swapSuccess *big.Int
×
150
        if event.GetSwapSuccess() != nil {
×
151
                swapSuccess = big.NewInt(int64(*BoolToUint8(event.GetSwapSuccess())))
×
152
        }
×
153
        var swapTokenIndex *big.Int
×
154
        if event.GetSwapTokenIndex() != nil {
×
155
                swapTokenIndex = big.NewInt(int64(*event.GetSwapTokenIndex()))
×
156
        }
×
157
        var kappa sql.NullString
×
158
        if event.GetKappa() != nil {
×
159
                kappa.Valid = true
×
160
                kappa.String = common.Bytes2Hex(event.GetKappa()[:])
×
161
        } else {
×
162
                kappa.Valid = false
×
163
        }
×
164

165
        return model.BridgeEvent{
×
166
                InsertTime:         uint64(time.Now().UnixNano()),
×
167
                ContractAddress:    event.GetContractAddress().String(),
×
168
                ChainID:            chainID,
×
169
                EventType:          event.GetEventType().Int(),
×
170
                BlockNumber:        event.GetBlockNumber(),
×
171
                TxHash:             event.GetTxHash().String(),
×
172
                Amount:             event.GetAmount(),
×
173
                EventIndex:         event.GetEventIndex(),
×
174
                DestinationKappa:   crypto.Keccak256Hash(event.GetTxHash().Bytes()).String(),
×
175
                Sender:             "",
×
176
                Recipient:          recipient,
×
177
                RecipientBytes:     recipientBytes,
×
178
                DestinationChainID: destinationChainID,
×
179
                Token:              event.GetToken().String(),
×
180
                Fee:                event.GetFee(),
×
181
                Kappa:              kappa,
×
182
                TokenIndexFrom:     tokenIndexFrom,
×
183
                TokenIndexTo:       tokenIndexTo,
×
184
                MinDy:              event.GetMinDy(),
×
185
                Deadline:           event.GetDeadline(),
×
186
                SwapSuccess:        swapSuccess,
×
187
                SwapTokenIndex:     swapTokenIndex,
×
188
                SwapMinAmount:      event.GetSwapMinAmount(),
×
189
                SwapDeadline:       event.GetSwapDeadline(),
×
190

×
191
                // placeholders for further data maturation of this event.
×
192
                TokenID:      sql.NullString{},
×
193
                AmountUSD:    nil,
×
194
                FeeAmountUSD: nil,
×
195
                TokenDecimal: nil,
×
196
                TokenSymbol:  sql.NullString{},
×
197
        }
×
198
}
199

200
// ParseAndStore parses the bridge logs and stores them in the database.
201
//
202
// nolint:gocognit,cyclop,dupl
203
func (p *BridgeParser) ParseAndStore(ctx context.Context, log ethTypes.Log, chainID uint32) error {
×
204
        logTopic := log.Topics[0]
×
205
        iFace, err := func(log ethTypes.Log) (bridgeTypes.EventLog, error) {
×
206
                switch logTopic {
×
207
                case bridge.Topic(bridgeTypes.DepositEvent):
×
208
                        iFace, err := p.Filterer.ParseTokenDeposit(log)
×
209
                        if err != nil {
×
210
                                return nil, fmt.Errorf("could not parse deposit: %w", err)
×
211
                        }
×
212
                        return iFace, nil
×
213
                case bridge.Topic(bridgeTypes.RedeemEvent):
×
214
                        iFace, err := p.Filterer.ParseTokenRedeem(log)
×
215
                        if err != nil {
×
216
                                return nil, fmt.Errorf("could not parse redeem: %w", err)
×
217
                        }
×
218
                        return iFace, nil
×
219
                case bridge.Topic(bridgeTypes.WithdrawEvent):
×
220
                        iFace, err := p.Filterer.ParseTokenWithdraw(log)
×
221
                        if err != nil {
×
222
                                return nil, fmt.Errorf("could not parse withdraw: %w", err)
×
223
                        }
×
224
                        return iFace, nil
×
225
                case bridge.Topic(bridgeTypes.MintEvent):
×
226
                        iFace, err := p.Filterer.ParseTokenMint(log)
×
227
                        if err != nil {
×
228
                                return nil, fmt.Errorf("could not parse mint: %w", err)
×
229
                        }
×
230
                        return iFace, nil
×
231
                case bridge.Topic(bridgeTypes.DepositAndSwapEvent):
×
232
                        iFace, err := p.Filterer.ParseTokenDepositAndSwap(log)
×
233
                        if err != nil {
×
234
                                return nil, fmt.Errorf("could not parse deposit and swap: %w", err)
×
235
                        }
×
236
                        return iFace, nil
×
237
                case bridge.Topic(bridgeTypes.MintAndSwapEvent):
×
238
                        iFace, err := p.Filterer.ParseTokenMintAndSwap(log)
×
239
                        if err != nil {
×
240
                                return nil, fmt.Errorf("could not parse mint and swap: %w", err)
×
241
                        }
×
242
                        return iFace, nil
×
243
                case bridge.Topic(bridgeTypes.RedeemAndSwapEvent):
×
244
                        iFace, err := p.Filterer.ParseTokenRedeemAndSwap(log)
×
245
                        if err != nil {
×
246
                                return nil, fmt.Errorf("could not parse redeem and swap: %w", err)
×
247
                        }
×
248
                        return iFace, nil
×
249
                case bridge.Topic(bridgeTypes.RedeemAndRemoveEvent):
×
250
                        iFace, err := p.Filterer.ParseTokenRedeemAndRemove(log)
×
251
                        if err != nil {
×
252
                                return nil, fmt.Errorf("could not parse redeem and remove: %w", err)
×
253
                        }
×
254
                        return iFace, nil
×
255
                case bridge.Topic(bridgeTypes.WithdrawAndRemoveEvent):
×
256
                        iFace, err := p.Filterer.ParseTokenWithdrawAndRemove(log)
×
257
                        if err != nil {
×
258
                                return nil, fmt.Errorf("could not parse withdraw and remove: %w", err)
×
259
                        }
×
260
                        return iFace, nil
×
261
                case bridge.Topic(bridgeTypes.RedeemV2Event):
×
262
                        iFace, err := p.Filterer.ParseTokenRedeemV2(log)
×
263
                        if err != nil {
×
264
                                return nil, fmt.Errorf("could not parse redeem v2: %w", err)
×
265
                        }
×
266
                        return iFace, nil
×
267
                default:
×
268
                        return nil, fmt.Errorf("unknown topic: %s", logTopic.Hex())
×
269
                }
270
        }(log)
271

272
        if err != nil {
×
273
                // Switch failed.
×
274
                return err
×
275
        }
×
276

277
        // get TokenID from BridgeConfig data
278
        tokenID, err := p.fetcher.GetTokenID(ctx, chainID, iFace.GetToken())
×
279
        if err != nil {
×
280
                return fmt.Errorf("could not parse get token from bridge config event: %w", err)
×
281
        }
×
282

283
        // get Token from BridgeConfig data (for getting token decimal but use this for anything else).
284
        token, err := p.fetcher.GetToken(ctx, chainID, tokenID)
×
285
        if err != nil {
×
286
                return fmt.Errorf("could not parse get token from bridge config event: %w", err)
×
287
        }
×
288

289
        // populate bridge event type so following operations can mature the event data.
290
        bridgeEvent := eventToBridgeEvent(iFace, chainID)
×
291
        // Add TokenID to bridgeEvent
×
292
        bridgeEvent.TokenID = ToNullString(tokenID)
×
293
        // Add TokenDecimal to bridgeEvent
×
294
        bridgeEvent.TokenDecimal = &token.TokenDecimals
×
295

×
296
        // Get timestamp from consumer
×
297
        timeStamp, err := p.consumerFetcher.FetchClient.GetBlockTime(ctx, int(chainID), int(iFace.GetBlockNumber()))
×
298
        // If we have a timestamp, populate the following attributes of bridgeEvent.
×
299
        if err == nil {
×
300
                // Add the price of the token at the block the event occurred using coin gecko (to bridgeEvent).
×
301
                tokenPrice, symbol := GetTokenMetadataWithTokenID(ctx, *timeStamp.Response, tokenID)
×
302
                if tokenPrice != nil {
×
303
                        // Add AmountUSD to bridgeEvent (if price is not nil)
×
304
                        bridgeEvent.AmountUSD = GetAmountUSD(iFace.GetAmount(), token.TokenDecimals, tokenPrice)
×
305
                        // Add AmountUSD to bridgeEvent (if price is not nil)
×
306
                        bridgeEvent.AmountUSD = GetAmountUSD(iFace.GetAmount(), token.TokenDecimals, tokenPrice)
×
307
                        // Add TokenSymbol to bridgeEvent
×
308
                        bridgeEvent.TokenSymbol = ToNullString(symbol)
×
309
                }
×
310
        }
311

312
        // TODO fix GetTxSender, make this actually successfully get a sender value
313
        // sender, err := p.consumerFetcher.FetchClient.GetTxSender(ctx, int(chainID), iFace.GetTxHash().String())
314
        // if err != nil || sender != nil {
315
        //        return fmt.Errorf("could not get tx sender: %w", err)
316
        //}
317
        // bridgeEvent.Sender = *sender.Response
318
        //
319
        bridgeEvent.Sender = "FAKE_SENDER"
×
320
        err = p.consumerDB.StoreEvent(ctx, &bridgeEvent, nil)
×
321
        if err != nil {
×
322
                return fmt.Errorf("could not store event: %w", err)
×
323
        }
×
324
        return nil
×
325
}
326

327
// eventToSwapEvent stores a swap event.
328
func eventToSwapEvent(event swapTypes.EventLog, chainID uint32) model.SwapEvent {
×
329
        var buyer sql.NullString
×
330
        if event.GetBuyer() != nil {
×
331
                buyer.Valid = true
×
332
                buyer.String = event.GetBuyer().String()
×
333
        } else {
×
334
                buyer.Valid = false
×
335
        }
×
336
        var provider sql.NullString
×
337
        if event.GetProvider() != nil {
×
338
                provider.Valid = true
×
339
                provider.String = event.GetProvider().String()
×
340
        } else {
×
341
                provider.Valid = false
×
342
        }
×
343
        var tokenIndex *big.Int
×
344
        if event.GetTokenIndex() != nil {
×
345
                tokenIndex = big.NewInt(int64(*event.GetTokenIndex()))
×
346
        }
×
347
        var receiver sql.NullString
×
348
        if event.GetReceiver() != nil {
×
349
                receiver.Valid = true
×
350
                receiver.String = event.GetReceiver().String()
×
351
        } else {
×
352
                receiver.Valid = false
×
353
        }
×
354

355
        return model.SwapEvent{
×
356
                InsertTime:      uint64(time.Now().UnixNano()),
×
357
                ContractAddress: event.GetContractAddress().String(),
×
358
                ChainID:         chainID,
×
359
                EventType:       event.GetEventType().Int(),
×
360
                BlockNumber:     event.GetBlockNumber(),
×
361
                TxHash:          event.GetTxHash().String(),
×
362
                EventIndex:      event.GetEventIndex(),
×
363
                Sender:          "",
×
364
                Buyer:           buyer,
×
365
                TokensSold:      event.GetTokensSold(),
×
366
                TokensBought:    event.GetTokensBought(),
×
367
                SoldID:          event.GetSoldId(),
×
368
                BoughtID:        event.GetBoughtId(),
×
369
                Provider:        provider,
×
370
                TokenAmounts:    event.GetTokenAmounts(),
×
371
                Fees:            event.GetFees(),
×
372
                Invariant:       event.GetInvariant(),
×
373
                LPTokenSupply:   event.GetLPTokenSupply(),
×
374
                LPTokenAmount:   event.GetLPTokenAmount(),
×
375
                NewAdminFee:     event.GetNewAdminFee(),
×
376
                NewSwapFee:      event.GetNewSwapFee(),
×
377
                TokenIndex:      tokenIndex,
×
378
                Amount:          event.GetAmount(),
×
379
                AmountFee:       event.GetAmountFee(),
×
380
                ProtocolFee:     event.GetProtocolFee(),
×
381
                OldA:            event.GetOldA(),
×
382
                NewA:            event.GetNewA(),
×
383
                InitialTime:     event.GetInitialTime(),
×
384
                FutureTime:      event.GetFutureTime(),
×
385
                CurrentA:        event.GetCurrentA(),
×
386
                Time:            event.GetTime(),
×
387
                Receiver:        receiver,
×
388

×
389
                AmountsUSD:    nil,
×
390
                FeeAmountsUSD: nil,
×
391
                TokenDecimal:  nil,
×
392
                TokenSymbol:   sql.NullString{},
×
393
        }
×
394
}
395

396
// ParseAndStore parses and stores the swap logs.
397
//
398
//nolint:gocognit,cyclop,dupl
399
func (p *SwapParser) ParseAndStore(ctx context.Context, log ethTypes.Log, chainID uint32) error {
×
400
        logTopic := log.Topics[0]
×
401
        iFace, err := func(log ethTypes.Log) (swapTypes.EventLog, error) {
×
402
                switch logTopic {
×
403
                case swap.Topic(swapTypes.TokenSwapEvent):
×
404
                        iFace, err := p.Filterer.ParseTokenSwap(log)
×
405
                        if err != nil {
×
406
                                return nil, fmt.Errorf("could not store token swap: %w", err)
×
407
                        }
×
408
                        return iFace, nil
×
409
                case swap.Topic(swapTypes.AddLiquidityEvent):
×
410
                        iFace, err := p.Filterer.ParseAddLiquidity(log)
×
411
                        if err != nil {
×
412
                                return nil, fmt.Errorf("could not store add liquidity: %w", err)
×
413
                        }
×
414
                        return iFace, nil
×
415
                case swap.Topic(swapTypes.RemoveLiquidityEvent):
×
416
                        iFace, err := p.Filterer.ParseRemoveLiquidity(log)
×
417
                        if err != nil {
×
418
                                return nil, fmt.Errorf("could not store remove liquidity: %w", err)
×
419
                        }
×
420
                        return iFace, nil
×
421
                case swap.Topic(swapTypes.RemoveLiquidityOneEvent):
×
422
                        iFace, err := p.Filterer.ParseRemoveLiquidityOne(log)
×
423
                        if err != nil {
×
424
                                return nil, fmt.Errorf("could not store remove liquidity one: %w", err)
×
425
                        }
×
426
                        return iFace, nil
×
427
                case swap.Topic(swapTypes.RemoveLiquidityImbalanceEvent):
×
428
                        iFace, err := p.Filterer.ParseRemoveLiquidityImbalance(log)
×
429
                        if err != nil {
×
430
                                return nil, fmt.Errorf("could not store remove liquidity imbalance: %w", err)
×
431
                        }
×
432
                        return iFace, nil
×
433
                case swap.Topic(swapTypes.NewAdminFeeEvent):
×
434
                        iFace, err := p.Filterer.ParseNewAdminFee(log)
×
435
                        if err != nil {
×
436
                                return nil, fmt.Errorf("could not store new admin fee: %w", err)
×
437
                        }
×
438
                        return iFace, nil
×
439
                case swap.Topic(swapTypes.NewSwapFeeEvent):
×
440
                        iFace, err := p.Filterer.ParseNewSwapFee(log)
×
441
                        if err != nil {
×
442
                                return nil, fmt.Errorf("could not store new swap fee: %w", err)
×
443
                        }
×
444
                        return iFace, nil
×
445
                case swap.Topic(swapTypes.RampAEvent):
×
446
                        iFace, err := p.Filterer.ParseRampA(log)
×
447
                        if err != nil {
×
448
                                return nil, fmt.Errorf("could not store ramp a: %w", err)
×
449
                        }
×
450
                        return iFace, nil
×
451
                case swap.Topic(swapTypes.StopRampAEvent):
×
452
                        iFace, err := p.Filterer.ParseStopRampA(log)
×
453
                        if err != nil {
×
454
                                return nil, fmt.Errorf("could not store stop ramp a: %w", err)
×
455
                        }
×
456
                        return iFace, nil
×
457
                case swap.Topic(swapTypes.FlashLoanEvent):
×
458
                        iFace, err := p.Filterer.ParseFlashLoan(log)
×
459
                        if err != nil {
×
460
                                return nil, fmt.Errorf("could not store flash loan: %w", err)
×
461
                        }
×
462
                        return iFace, nil
×
463
                default:
×
464
                        return nil, fmt.Errorf("unknown topic: %s", logTopic.Hex())
×
465
                }
466
        }(log)
467
        if err != nil {
×
468
                // Switch failed.
×
469
                return err
×
470
        }
×
471

472
        // populate swap event type so following operations can mature the event data.
473
        swapEvent := eventToSwapEvent(iFace, chainID)
×
474
        // Add sender to swapEvent
×
475

×
476
        // TODO need to add the following data to this swap event
×
477
        // TokenDecimal: call getToken(uint8 index) (IERC20) from swap contract then index decimal
×
478
        // TokenSymbol: call getToken(uint8 index) (IERC20) from swap contract then index symbol
×
479
        // AmountsUSD: Get price data from GetPrice(timestamp, coin gecko id)
×
480
        // FeeAmountsUSD: Get price data from GetPrice(timestamp, coin gecko id)
×
481
        // var amountsUSD []*big.Int
×
482
        // amountsUSD = append(amountsUSD, nil)
×
483
        // swapEvent.AmountsUSD = amountsUSD
×
484
        //
×
485
        // var feeAmountsUSD []*big.Int
×
486
        // feeAmountsUSD = append(feeAmountsUSD, nil)
×
487
        // swapEvent.FeeAmountsUSD = feeAmountsUSD
×
488
        // TODO potential refactor: delete SwapEvent.Amount and SwapEvent.Fee.
×
489
        // These values will just be a single element array in SwapEvent.Amounts and SwapEvent.Fees
×
490

×
491
        // Store bridgeEvent
×
492
        err = p.consumerDB.StoreEvent(ctx, nil, &swapEvent)
×
493
        if err != nil {
×
494
                return fmt.Errorf("could not store event: %w", err)
×
495
        }
×
496
        return nil
×
497
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2024 Coveralls, Inc