services/rfq/guard/guarddb/base/model.go
package base
import (
"errors"
"fmt"
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/synapsecns/sanguine/core/dbcommon"
"github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge"
"github.com/synapsecns/sanguine/services/rfq/guard/guarddb"
)
func init() {
namer := dbcommon.NewNamer(GetAllModels())
statusFieldName = namer.GetConsistentName("Status")
transactionIDFieldName = namer.GetConsistentName("TransactionID")
}
var (
// statusFieldName is the status field name.
statusFieldName string
// transactionIDFieldName is the transactions id field name.
transactionIDFieldName string
)
// PendingProvenModel is the primary event model.
type PendingProvenModel struct {
// CreatedAt is the creation time
CreatedAt time.Time
// UpdatedAt is the update time
UpdatedAt time.Time
// Origin is the origin chain id
Origin uint32
// RelayerAddress is the address of the relayer that called prove()
RelayerAddress string
// TransactionID is the transaction id of the event
TransactionID string `gorm:"column:transaction_id;primaryKey"`
// TxHash is the hash of the relay transaction on destination
TxHash string
// Status is the status of the event
Status guarddb.PendingProvenStatus `gorm:"column:status;index:idx_guard_status_name"`
// BlockNumber is the block number of the event
BlockNumber uint64
}
// FromPendingProven converts a quote request to an object that can be stored in the db.
func FromPendingProven(proven guarddb.PendingProven) PendingProvenModel {
return PendingProvenModel{
Origin: proven.Origin,
RelayerAddress: proven.RelayerAddress.Hex(),
TransactionID: hexutil.Encode(proven.TransactionID[:]),
TxHash: proven.TxHash.Hex(),
Status: proven.Status,
BlockNumber: proven.BlockNumber,
}
}
// ToPendingProven converts a db object to a pending proven.
func (p PendingProvenModel) ToPendingProven() (*guarddb.PendingProven, error) {
txID, err := hexutil.Decode(p.TransactionID)
if err != nil {
return nil, fmt.Errorf("could not get transaction id: %w", err)
}
transactionID, err := sliceToArray(txID)
if err != nil {
return nil, fmt.Errorf("could not convert transaction id: %w", err)
}
return &guarddb.PendingProven{
Origin: p.Origin,
RelayerAddress: common.HexToAddress(p.RelayerAddress),
TransactionID: transactionID,
TxHash: common.HexToHash(p.TxHash),
Status: p.Status,
BlockNumber: p.BlockNumber,
}, nil
}
// BridgeRequestModel is the primary event model.
type BridgeRequestModel struct {
// CreatedAt is the creation time
CreatedAt time.Time
// UpdatedAt is the update time
UpdatedAt time.Time
// TransactionID is the transaction id of the event
TransactionID string `gorm:"column:transaction_id;primaryKey"`
// OriginChainID is the origin chain for the transactions
OriginChainID uint32
// DestChainID is the destination chain for the tx
DestChainID uint32
// OriginSender is the original sender
OriginSender string
// DestRecipient is the recipient of the destination tx
DestRecipient string
// OriginToken is the origin token address
OriginToken string
// DestToken is the destination token address
DestToken string
// OriginAmount is the origin amount stored for sorting.
// This is not the source of truth, but is approximate
OriginAmount string
// DestAmount is the destination amount stored for sorting.
DestAmount string
// Deadline is the deadline for the relay
Deadline time.Time `gorm:"index"`
// OriginNonce is the nonce on the origin chain in the app.
// this is not effected by the message.sender nonce.
OriginNonce int `gorm:"index"`
// RawRequest is the raw request, hex encoded.
RawRequest string
// SendChainGas is true if the chain should send gas
SendChainGas bool
}
// FromBridgeRequest converts a bridge request object to db model.
func FromBridgeRequest(request guarddb.BridgeRequest) BridgeRequestModel {
return BridgeRequestModel{
TransactionID: hexutil.Encode(request.TransactionID[:]),
OriginChainID: request.Transaction.OriginChainId,
DestChainID: request.Transaction.DestChainId,
OriginSender: request.Transaction.OriginSender.String(),
DestRecipient: request.Transaction.DestRecipient.String(),
OriginToken: request.Transaction.OriginToken.String(),
RawRequest: hexutil.Encode(request.RawRequest),
SendChainGas: request.Transaction.SendChainGas,
DestToken: request.Transaction.DestToken.String(),
OriginAmount: request.Transaction.OriginAmount.String(),
DestAmount: request.Transaction.DestAmount.String(),
Deadline: time.Unix(int64(request.Transaction.Deadline.Uint64()), 0),
OriginNonce: int(request.Transaction.Nonce.Uint64()),
}
}
// ToBridgeRequest converts the bridge request db model to object.
func (b BridgeRequestModel) ToBridgeRequest() (*guarddb.BridgeRequest, error) {
txID, err := hexutil.Decode(b.TransactionID)
if err != nil {
return nil, fmt.Errorf("could not get transaction id: %w", err)
}
req, err := hexutil.Decode(b.RawRequest)
if err != nil {
return nil, fmt.Errorf("could not get request: %w", err)
}
transactionID, err := sliceToArray(txID)
if err != nil {
return nil, fmt.Errorf("could not convert transaction id: %w", err)
}
originAmount, ok := new(big.Int).SetString(b.OriginAmount, 10)
if !ok {
return nil, errors.New("could not convert origin amount")
}
destAmount, ok := new(big.Int).SetString(b.DestAmount, 10)
if !ok {
return nil, errors.New("could not convert dest amount")
}
return &guarddb.BridgeRequest{
TransactionID: transactionID,
RawRequest: req,
Transaction: fastbridge.IFastBridgeBridgeTransaction{
OriginChainId: b.OriginChainID,
DestChainId: b.DestChainID,
OriginSender: common.HexToAddress(b.OriginSender),
DestRecipient: common.HexToAddress(b.DestRecipient),
OriginToken: common.HexToAddress(b.OriginToken),
SendChainGas: b.SendChainGas,
DestToken: common.HexToAddress(b.DestToken),
OriginAmount: originAmount,
DestAmount: destAmount,
Deadline: big.NewInt(b.Deadline.Unix()),
Nonce: big.NewInt(int64(b.OriginNonce)),
},
}, nil
}
func sliceToArray(slice []byte) ([32]byte, error) {
var arr [32]byte
if len(slice) != 32 {
return arr, errors.New("slice is not 32 bytes long")
}
copy(arr[:], slice)
return arr, nil
}