397 lines
8.5 KiB
Go
397 lines
8.5 KiB
Go
package routeexecution
|
|
|
|
import (
|
|
"database/sql"
|
|
|
|
sq "github.com/Masterminds/squirrel"
|
|
|
|
"github.com/status-im/status-go/eth-node/types"
|
|
"github.com/status-im/status-go/services/wallet/requests"
|
|
"github.com/status-im/status-go/services/wallet/router/routes"
|
|
"github.com/status-im/status-go/services/wallet/transfer"
|
|
"github.com/status-im/status-go/sqlite"
|
|
|
|
ethTypes "github.com/ethereum/go-ethereum/core/types"
|
|
)
|
|
|
|
type DB struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
func NewDB(db *sql.DB) *DB {
|
|
return &DB{db: db}
|
|
}
|
|
|
|
func (db *DB) PutRouteData(routeData *RouteData) (err error) {
|
|
var tx *sql.Tx
|
|
tx, err = db.db.Begin()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
if err == nil {
|
|
err = tx.Commit()
|
|
return
|
|
}
|
|
_ = tx.Rollback()
|
|
}()
|
|
|
|
if err = putRouteInputParams(tx, routeData.RouteInputParams); err != nil {
|
|
return
|
|
}
|
|
|
|
if err = putBuildTxParams(tx, routeData.BuildInputParams); err != nil {
|
|
return
|
|
}
|
|
|
|
if err = putPathsData(tx, routeData.RouteInputParams.Uuid, routeData.PathsData); err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (db *DB) GetRouteData(uuid string) (*RouteData, error) {
|
|
return getRouteData(db.db, uuid)
|
|
}
|
|
|
|
func putRouteInputParams(creator sqlite.StatementCreator, p *requests.RouteInputParams) error {
|
|
q := sq.Replace("route_input_parameters").
|
|
SetMap(sq.Eq{"route_input_params_json": &sqlite.JSONBlob{Data: p}})
|
|
|
|
query, args, err := q.ToSql()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
stmt, err := creator.Prepare(query)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer stmt.Close()
|
|
|
|
_, err = stmt.Exec(args...)
|
|
|
|
return err
|
|
}
|
|
|
|
func putBuildTxParams(creator sqlite.StatementCreator, p *requests.RouterBuildTransactionsParams) error {
|
|
q := sq.Replace("route_build_tx_parameters").
|
|
SetMap(sq.Eq{"route_build_tx_params_json": &sqlite.JSONBlob{Data: p}})
|
|
|
|
query, args, err := q.ToSql()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
stmt, err := creator.Prepare(query)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer stmt.Close()
|
|
|
|
_, err = stmt.Exec(args...)
|
|
|
|
return err
|
|
}
|
|
|
|
func putPathsData(creator sqlite.StatementCreator, uuid string, d []*transfer.RouterTransactionDetails) error {
|
|
for i, pathData := range d {
|
|
if err := putPathData(creator, uuid, i, pathData); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func putPathData(creator sqlite.StatementCreator, uuid string, pathIdx int, d *transfer.RouterTransactionDetails) (err error) {
|
|
err = putPath(creator, uuid, pathIdx, d.RouterPath)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if d.ApprovalTxData != nil {
|
|
err = putPathTransaction(creator, uuid, pathIdx, true, d.RouterPath.FromChain.ChainID, d.ApprovalTxData)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
err = putSentTransaction(creator, d.RouterPath.FromChain.ChainID, d.ApprovalTxData.SentHash, d.ApprovalTxData.Tx)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
if d.TxData != nil {
|
|
err = putPathTransaction(creator, uuid, pathIdx, false, d.RouterPath.FromChain.ChainID, d.TxData)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
err = putSentTransaction(creator, d.RouterPath.FromChain.ChainID, d.TxData.SentHash, d.TxData.Tx)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func putPath(
|
|
creator sqlite.StatementCreator,
|
|
uuid string,
|
|
pathIdx int,
|
|
p *routes.Path) error {
|
|
q := sq.Replace("route_paths").
|
|
SetMap(sq.Eq{"uuid": uuid, "path_idx": pathIdx, "path_json": &sqlite.JSONBlob{Data: p}})
|
|
|
|
query, args, err := q.ToSql()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
stmt, err := creator.Prepare(query)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer stmt.Close()
|
|
|
|
_, err = stmt.Exec(args...)
|
|
|
|
return err
|
|
}
|
|
|
|
func putPathTransaction(
|
|
creator sqlite.StatementCreator,
|
|
uuid string,
|
|
pathIdx int,
|
|
isApproval bool,
|
|
chainID uint64,
|
|
txData *transfer.TransactionData,
|
|
) error {
|
|
q := sq.Replace("route_path_transactions").
|
|
SetMap(sq.Eq{
|
|
"uuid": uuid,
|
|
"path_idx": pathIdx,
|
|
"is_approval": isApproval,
|
|
"chain_id": chainID,
|
|
"tx_hash": txData.SentHash[:],
|
|
"tx_args_json": &sqlite.JSONBlob{Data: txData.TxArgs},
|
|
"hash_to_sign": txData.HashToSign[:],
|
|
"sig": txData.Signature,
|
|
})
|
|
|
|
query, args, err := q.ToSql()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
stmt, err := creator.Prepare(query)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer stmt.Close()
|
|
|
|
_, err = stmt.Exec(args...)
|
|
|
|
return err
|
|
}
|
|
|
|
func putSentTransaction(
|
|
creator sqlite.StatementCreator,
|
|
chainID uint64,
|
|
txHash types.Hash,
|
|
tx *ethTypes.Transaction,
|
|
) error {
|
|
q := sq.Replace("sent_transactions").
|
|
SetMap(sq.Eq{
|
|
"chain_id": chainID,
|
|
"tx_hash": txHash[:],
|
|
"tx_json": &sqlite.JSONBlob{Data: tx},
|
|
})
|
|
|
|
query, args, err := q.ToSql()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
stmt, err := creator.Prepare(query)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer stmt.Close()
|
|
|
|
_, err = stmt.Exec(args...)
|
|
|
|
return err
|
|
}
|
|
|
|
func getRouteData(creator sqlite.StatementCreator, uuid string) (*RouteData, error) {
|
|
routeInputParams, err := getRouteInputParams(creator, uuid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
buildTxParams, err := getBuildTxParams(creator, uuid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pathsData, err := getPathsData(creator, uuid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &RouteData{
|
|
RouteInputParams: routeInputParams,
|
|
BuildInputParams: buildTxParams,
|
|
PathsData: pathsData,
|
|
}, nil
|
|
}
|
|
|
|
func getRouteInputParams(creator sqlite.StatementCreator, uuid string) (*requests.RouteInputParams, error) {
|
|
var p requests.RouteInputParams
|
|
q := sq.Select("route_input_params_json").
|
|
From("route_input_parameters").
|
|
Where(sq.Eq{"uuid": uuid})
|
|
|
|
query, args, err := q.ToSql()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
stmt, err := creator.Prepare(query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer stmt.Close()
|
|
|
|
err = stmt.QueryRow(args...).Scan(&sqlite.JSONBlob{Data: &p})
|
|
return &p, err
|
|
}
|
|
|
|
func getBuildTxParams(creator sqlite.StatementCreator, uuid string) (*requests.RouterBuildTransactionsParams, error) {
|
|
var p requests.RouterBuildTransactionsParams
|
|
q := sq.Select("route_build_tx_params_json").
|
|
From("route_build_tx_parameters").
|
|
Where(sq.Eq{"uuid": uuid})
|
|
|
|
query, args, err := q.ToSql()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
stmt, err := creator.Prepare(query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer stmt.Close()
|
|
|
|
err = stmt.QueryRow(args...).Scan(&sqlite.JSONBlob{Data: &p})
|
|
return &p, err
|
|
}
|
|
|
|
func getPathsData(creator sqlite.StatementCreator, uuid string) ([]*transfer.RouterTransactionDetails, error) {
|
|
var pathsData []*transfer.RouterTransactionDetails
|
|
|
|
paths, err := getPaths(creator, uuid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for pathIdx, path := range paths {
|
|
pathData := &transfer.RouterTransactionDetails{RouterPath: path}
|
|
pathData.ApprovalTxData, err = getPathTransaction(creator, uuid, pathIdx, true)
|
|
if err != nil && err != sql.ErrNoRows {
|
|
return nil, err
|
|
}
|
|
pathData.TxData, err = getPathTransaction(creator, uuid, pathIdx, false)
|
|
if err != nil && err != sql.ErrNoRows {
|
|
return nil, err
|
|
}
|
|
|
|
pathsData = append(pathsData, pathData)
|
|
}
|
|
|
|
return pathsData, nil
|
|
}
|
|
|
|
func getPaths(creator sqlite.StatementCreator, uuid string) ([]*routes.Path, error) {
|
|
var paths []*routes.Path
|
|
q := sq.Select("path_json").
|
|
From("route_paths").
|
|
Where(sq.Eq{"uuid": uuid}).
|
|
OrderBy("path_idx ASC")
|
|
|
|
query, args, err := q.ToSql()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
stmt, err := creator.Prepare(query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer stmt.Close()
|
|
|
|
rows, err := stmt.Query(args...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
for rows.Next() {
|
|
var p routes.Path
|
|
err = rows.Scan(&sqlite.JSONBlob{Data: &p})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
paths = append(paths, &p)
|
|
}
|
|
|
|
return paths, nil
|
|
}
|
|
|
|
func getPathTransaction(creator sqlite.StatementCreator, uuid string, pathIdx int, isApproval bool) (*transfer.TransactionData, error) {
|
|
q := sq.Select("rpt.tx_args_json", "st.tx_json", "rpt.hash_to_sign", "rpt.sig", "rpt.tx_hash").
|
|
From("route_path_transactions rpt").
|
|
LeftJoin(`sent_transactions st ON
|
|
rpt.chain_id = st.chain_id AND
|
|
rpt.tx_hash = st.tx_hash`).
|
|
Where(sq.Eq{"rpt.uuid": uuid, "rpt.path_idx": pathIdx, "rpt.is_approval": isApproval})
|
|
|
|
query, args, err := q.ToSql()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
stmt, err := creator.Prepare(query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer stmt.Close()
|
|
|
|
tx := new(transfer.TransactionData)
|
|
var hashToSign []byte
|
|
var sentHash []byte
|
|
err = stmt.QueryRow(args...).Scan(
|
|
&sqlite.JSONBlob{Data: &tx.TxArgs},
|
|
&sqlite.JSONBlob{Data: &tx.Tx},
|
|
&hashToSign,
|
|
&tx.Signature,
|
|
&sentHash,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(hashToSign) > 0 {
|
|
tx.HashToSign = types.BytesToHash(hashToSign)
|
|
}
|
|
if len(sentHash) > 0 {
|
|
tx.SentHash = types.BytesToHash(sentHash)
|
|
}
|
|
|
|
return tx, nil
|
|
}
|