421 lines
13 KiB
Go
421 lines
13 KiB
Go
package monitor
|
|
|
|
import (
|
|
"amb-monitor/config"
|
|
"amb-monitor/contract/abi"
|
|
"amb-monitor/entity"
|
|
"amb-monitor/ethclient"
|
|
"amb-monitor/repository"
|
|
"context"
|
|
"fmt"
|
|
"math/big"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
)
|
|
|
|
type EventHandler func(ctx context.Context, log *entity.Log, data map[string]interface{}) error
|
|
|
|
type BridgeEventHandler struct {
|
|
repo *repository.Repo
|
|
bridgeID string
|
|
homeClient *ethclient.Client
|
|
foreignClient *ethclient.Client
|
|
cfg *config.BridgeConfig
|
|
}
|
|
|
|
func NewBridgeEventHandler(repo *repository.Repo, bridgeID string, homeClient, foreignClient *ethclient.Client, cfg *config.BridgeConfig) *BridgeEventHandler {
|
|
return &BridgeEventHandler{
|
|
repo: repo,
|
|
bridgeID: bridgeID,
|
|
homeClient: homeClient,
|
|
foreignClient: foreignClient,
|
|
cfg: cfg,
|
|
}
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleUserRequestForAffirmation(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
encodedData := data["encodedData"].([]byte)
|
|
message := unmarshalMessage(p.bridgeID, entity.DirectionForeignToHome, encodedData)
|
|
err := p.repo.Messages.Ensure(ctx, message)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return p.repo.SentMessages.Ensure(ctx, &entity.SentMessage{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
MsgHash: message.MsgHash,
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleLegacyUserRequestForAffirmation(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
encodedData := data["encodedData"].([]byte)
|
|
encodedData = append(log.TransactionHash[:], encodedData...)
|
|
message := unmarshalLegacyMessage(p.bridgeID, entity.DirectionForeignToHome, encodedData)
|
|
err := p.repo.Messages.Ensure(ctx, message)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return p.repo.SentMessages.Ensure(ctx, &entity.SentMessage{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
MsgHash: message.MsgHash,
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleErcToNativeTransfer(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
from := data["from"].(common.Address)
|
|
value := data["value"].(*big.Int)
|
|
|
|
for _, addr := range p.cfg.Foreign.ErcToNativeBlacklistedSenders {
|
|
if from == addr {
|
|
return nil
|
|
}
|
|
}
|
|
logs, err := p.repo.Logs.FindByTxHash(ctx, log.TransactionHash)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get transaction logs for %s: %w", log.TransactionHash, err)
|
|
}
|
|
for _, l := range logs {
|
|
if l.Topic0 != nil && *l.Topic0 == abi.ERC_TO_NATIVE.Events["UserRequestForAffirmation"].ID {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
valueBytes := common.BigToHash(value)
|
|
msg := from[:]
|
|
msg = append(msg, valueBytes[:]...)
|
|
msg = append(msg, log.TransactionHash[:]...)
|
|
msgHash := crypto.Keccak256Hash(msg)
|
|
|
|
message := &entity.ErcToNativeMessage{
|
|
BridgeID: p.bridgeID,
|
|
Direction: entity.DirectionForeignToHome,
|
|
MsgHash: msgHash,
|
|
Sender: from,
|
|
Receiver: from,
|
|
Value: value.String(),
|
|
}
|
|
err = p.repo.ErcToNativeMessages.Ensure(ctx, message)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return p.repo.SentMessages.Ensure(ctx, &entity.SentMessage{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
MsgHash: msgHash,
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleErcToNativeUserRequestForAffirmation(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
recipient := data["recipient"].(common.Address)
|
|
value := data["value"].(*big.Int)
|
|
|
|
valueBytes := common.BigToHash(value)
|
|
msg := recipient[:]
|
|
msg = append(msg, valueBytes[:]...)
|
|
msg = append(msg, log.TransactionHash[:]...)
|
|
msgHash := crypto.Keccak256Hash(msg)
|
|
|
|
logs, err := p.repo.Logs.FindByTxHash(ctx, log.TransactionHash)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get transaction logs for %s: %w", log.TransactionHash, err)
|
|
}
|
|
var sender common.Address
|
|
for _, l := range logs {
|
|
if l.Topic0 != nil && *l.Topic0 == abi.ERC_TO_NATIVE.Events["Transfer"].ID && l.Topic1 != nil && l.Topic2 != nil && len(l.Data) == 32 {
|
|
transferSender := common.BytesToAddress(l.Topic1[:])
|
|
transferReceiver := common.BytesToAddress(l.Topic2[:])
|
|
transferValue := new(big.Int).SetBytes(l.Data)
|
|
if transferReceiver == p.cfg.Foreign.Address && value.Cmp(transferValue) == 0 {
|
|
for _, t := range p.cfg.Foreign.ErcToNativeTokens {
|
|
if l.Address == t.Address && l.BlockNumber >= t.StartBlock && (t.EndBlock == 0 || l.BlockNumber <= t.EndBlock) {
|
|
sender = transferSender
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
message := &entity.ErcToNativeMessage{
|
|
BridgeID: p.bridgeID,
|
|
Direction: entity.DirectionForeignToHome,
|
|
MsgHash: msgHash,
|
|
Sender: sender,
|
|
Receiver: recipient,
|
|
Value: value.String(),
|
|
}
|
|
err = p.repo.ErcToNativeMessages.Ensure(ctx, message)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return p.repo.SentMessages.Ensure(ctx, &entity.SentMessage{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
MsgHash: msgHash,
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleUserRequestForSignature(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
encodedData := data["encodedData"].([]byte)
|
|
message := unmarshalMessage(p.bridgeID, entity.DirectionHomeToForeign, encodedData)
|
|
err := p.repo.Messages.Ensure(ctx, message)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return p.repo.SentMessages.Ensure(ctx, &entity.SentMessage{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
MsgHash: message.MsgHash,
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleLegacyUserRequestForSignature(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
encodedData := data["encodedData"].([]byte)
|
|
encodedData = append(log.TransactionHash[:], encodedData...)
|
|
message := unmarshalLegacyMessage(p.bridgeID, entity.DirectionHomeToForeign, encodedData)
|
|
err := p.repo.Messages.Ensure(ctx, message)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return p.repo.SentMessages.Ensure(ctx, &entity.SentMessage{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
MsgHash: message.MsgHash,
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleErcToNativeUserRequestForSignature(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
recipient := data["recipient"].(common.Address)
|
|
value := data["value"].(*big.Int)
|
|
|
|
valueBytes := common.BigToHash(value)
|
|
msg := recipient[:]
|
|
msg = append(msg, valueBytes[:]...)
|
|
msg = append(msg, log.TransactionHash[:]...)
|
|
msg = append(msg, p.cfg.Foreign.Address[:]...)
|
|
msgHash := crypto.Keccak256Hash(msg)
|
|
|
|
sender := recipient
|
|
tx, err := p.homeClient.TransactionByHash(ctx, log.TransactionHash)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if tx.Value().Cmp(value) == 0 {
|
|
sender, err = p.homeClient.TransactionSender(tx)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to extract transaction sender: %w", err)
|
|
}
|
|
}
|
|
|
|
message := &entity.ErcToNativeMessage{
|
|
BridgeID: p.bridgeID,
|
|
Direction: entity.DirectionHomeToForeign,
|
|
MsgHash: msgHash,
|
|
Sender: sender,
|
|
Receiver: recipient,
|
|
Value: value.String(),
|
|
}
|
|
err = p.repo.ErcToNativeMessages.Ensure(ctx, message)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return p.repo.SentMessages.Ensure(ctx, &entity.SentMessage{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
MsgHash: msgHash,
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleSignedForUserRequest(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
msgHash := data["messageHash"].([32]byte)
|
|
validator := data["signer"].(common.Address)
|
|
|
|
return p.repo.SignedMessages.Ensure(ctx, &entity.SignedMessage{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
MsgHash: msgHash,
|
|
Signer: validator,
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleErcToNativeSignedForAffirmation(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
validator := data["signer"].(common.Address)
|
|
|
|
tx, err := p.homeClient.TransactionByHash(ctx, log.TransactionHash)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get transaction by hash %s: %w", log.TransactionHash, err)
|
|
}
|
|
msg := tx.Data()[16:]
|
|
|
|
return p.repo.SignedMessages.Ensure(ctx, &entity.SignedMessage{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
MsgHash: crypto.Keccak256Hash(msg),
|
|
Signer: validator,
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleRelayedMessage(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
messageID := data["messageId"].([32]byte)
|
|
status := data["status"].(bool)
|
|
|
|
return p.repo.ExecutedMessages.Ensure(ctx, &entity.ExecutedMessage{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
MessageID: messageID,
|
|
Status: status,
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleErcToNativeRelayedMessage(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
recipient := data["recipient"].(common.Address)
|
|
value := data["value"].(*big.Int)
|
|
transactionHash := data["transactionHash"].([32]byte)
|
|
|
|
valueBytes := common.BigToHash(value)
|
|
|
|
msg := recipient[:]
|
|
msg = append(msg, valueBytes[:]...)
|
|
msg = append(msg, transactionHash[:]...)
|
|
msg = append(msg, log.Address[:]...)
|
|
|
|
return p.repo.ExecutedMessages.Ensure(ctx, &entity.ExecutedMessage{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
MessageID: crypto.Keccak256Hash(msg),
|
|
Status: true,
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleAffirmationCompleted(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
messageID := data["messageId"].([32]byte)
|
|
status := data["status"].(bool)
|
|
|
|
return p.repo.ExecutedMessages.Ensure(ctx, &entity.ExecutedMessage{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
MessageID: messageID,
|
|
Status: status,
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleErcToNativeAffirmationCompleted(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
recipient := data["recipient"].(common.Address)
|
|
value := data["value"].(*big.Int)
|
|
transactionHash := data["transactionHash"].([32]byte)
|
|
|
|
valueBytes := common.BigToHash(value)
|
|
|
|
msg := recipient[:]
|
|
msg = append(msg, valueBytes[:]...)
|
|
msg = append(msg, transactionHash[:]...)
|
|
|
|
return p.repo.ExecutedMessages.Ensure(ctx, &entity.ExecutedMessage{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
MessageID: crypto.Keccak256Hash(msg),
|
|
Status: true,
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleCollectedSignatures(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
msgHash := data["messageHash"].([32]byte)
|
|
relayer := data["authorityResponsibleForRelay"].(common.Address)
|
|
numSignatures := data["NumberOfCollectedSignatures"].(*big.Int)
|
|
|
|
return p.repo.CollectedMessages.Ensure(ctx, &entity.CollectedMessage{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
MsgHash: msgHash,
|
|
ResponsibleSigner: relayer,
|
|
NumSignatures: uint(numSignatures.Uint64()),
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleUserRequestForInformation(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
messageID := data["messageId"].([32]byte)
|
|
requestSelector := data["requestSelector"].([32]byte)
|
|
sender := data["sender"].(common.Address)
|
|
requestData := data["data"].([]byte)
|
|
|
|
err := p.repo.InformationRequests.Ensure(ctx, &entity.InformationRequest{
|
|
BridgeID: p.bridgeID,
|
|
MessageID: messageID,
|
|
Direction: entity.DirectionHomeToForeign,
|
|
RequestSelector: requestSelector,
|
|
Sender: sender,
|
|
Executor: sender,
|
|
Data: requestData,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return p.repo.SentInformationRequests.Ensure(ctx, &entity.SentInformationRequest{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
MessageID: messageID,
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleSignedForInformation(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
messageID := data["messageId"].([32]byte)
|
|
validator := data["signer"].(common.Address)
|
|
|
|
tx, err := p.homeClient.TransactionByHash(ctx, log.TransactionHash)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get transaction by hash %s: %w", log.TransactionHash, err)
|
|
}
|
|
|
|
return p.repo.SignedInformationRequests.Ensure(ctx, &entity.SignedInformationRequest{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
MessageID: messageID,
|
|
Data: unmarshalConfirmInformationResult(tx.Data()),
|
|
Signer: validator,
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleInformationRetrieved(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
messageID := data["messageId"].([32]byte)
|
|
status := data["status"].(bool)
|
|
callbackStatus := data["callbackStatus"].(bool)
|
|
|
|
tx, err := p.homeClient.TransactionByHash(ctx, log.TransactionHash)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get transaction by hash %s: %w", log.TransactionHash, err)
|
|
}
|
|
|
|
return p.repo.ExecutedInformationRequests.Ensure(ctx, &entity.ExecutedInformationRequest{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
MessageID: messageID,
|
|
Status: status,
|
|
CallbackStatus: callbackStatus,
|
|
Data: unmarshalConfirmInformationResult(tx.Data()),
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleValidatorAdded(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
validator := data["validator"].(common.Address)
|
|
return p.repo.BridgeValidators.Ensure(ctx, &entity.BridgeValidator{
|
|
LogID: log.ID,
|
|
BridgeID: p.bridgeID,
|
|
ChainID: log.ChainID,
|
|
Address: validator,
|
|
})
|
|
}
|
|
|
|
func (p *BridgeEventHandler) HandleValidatorRemoved(ctx context.Context, log *entity.Log, data map[string]interface{}) error {
|
|
validator := data["validator"].(common.Address)
|
|
val, err := p.repo.BridgeValidators.FindActiveValidator(ctx, p.bridgeID, log.ChainID, validator)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if val == nil {
|
|
return nil
|
|
}
|
|
val.RemovedLogID = &log.ID
|
|
return p.repo.BridgeValidators.Ensure(ctx, val)
|
|
}
|