status-go/services/wallet/transfer/transaction_manager_multitr...

152 lines
5.2 KiB
Go

package transfer
import (
"context"
"fmt"
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/account"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/services/wallet/bridge"
wallet_common "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/signal"
)
const multiTransactionColumns = "id, from_network_id, from_tx_hash, from_address, from_asset, from_amount, to_network_id, to_tx_hash, to_address, to_asset, to_amount, type, cross_tx_id, timestamp"
const selectMultiTransactionColumns = "id, COALESCE(from_network_id, 0), from_tx_hash, from_address, from_asset, from_amount, COALESCE(to_network_id, 0), to_tx_hash, to_address, to_asset, to_amount, type, cross_tx_id, timestamp"
func (tm *TransactionManager) InsertMultiTransaction(multiTransaction *MultiTransaction) (wallet_common.MultiTransactionIDType, error) {
return multiTransaction.ID, tm.storage.CreateMultiTransaction(multiTransaction)
}
func (tm *TransactionManager) UpdateMultiTransaction(multiTransaction *MultiTransaction) error {
return tm.storage.UpdateMultiTransaction(multiTransaction)
}
func (tm *TransactionManager) CreateMultiTransactionFromCommand(command *MultiTransactionCommand,
data []*bridge.TransactionBridge) (*MultiTransaction, error) {
multiTransaction := multiTransactionFromCommand(command)
if multiTransaction.Type == MultiTransactionSend && multiTransaction.FromNetworkID == 0 && len(data) == 1 {
multiTransaction.FromNetworkID = data[0].ChainID
}
return multiTransaction, nil
}
func (tm *TransactionManager) SendTransactionForSigningToKeycard(ctx context.Context, multiTransaction *MultiTransaction, data []*bridge.TransactionBridge, bridges map[string]bridge.Bridge) error {
acc, err := tm.accountsDB.GetAccountByAddress(types.Address(multiTransaction.FromAddress))
if err != nil {
return err
}
kp, err := tm.accountsDB.GetKeypairByKeyUID(acc.KeyUID)
if err != nil {
return err
}
if !kp.MigratedToKeycard() {
return fmt.Errorf("account being used is not migrated to a keycard, password is required")
}
tm.multiTransactionForKeycardSigning = multiTransaction
tm.transactionsBridgeData = data
hashes, err := tm.buildTransactions(bridges)
if err != nil {
return err
}
signal.SendTransactionsForSigningEvent(hashes)
return nil
}
func (tm *TransactionManager) SendTransactions(ctx context.Context, multiTransaction *MultiTransaction, data []*bridge.TransactionBridge, bridges map[string]bridge.Bridge, account *account.SelectedExtKey) (*MultiTransactionCommandResult, error) {
updateDataFromMultiTx(data, multiTransaction)
hashes, err := sendTransactions(data, bridges, account)
if err != nil {
return nil, err
}
return &MultiTransactionCommandResult{
ID: int64(multiTransaction.ID),
Hashes: hashes,
}, nil
}
func (tm *TransactionManager) ProceedWithTransactionsSignatures(ctx context.Context, signatures map[string]SignatureDetails) (*MultiTransactionCommandResult, error) {
if err := addSignaturesToTransactions(tm.transactionsForKeycardSigning, signatures); err != nil {
return nil, err
}
// send transactions
hashes := make(map[uint64][]types.Hash)
for _, desc := range tm.transactionsForKeycardSigning {
txWithSignature, err := tm.transactor.AddSignatureToTransaction(desc.chainID, desc.builtTx, desc.signature)
if err != nil {
return nil, err
}
hash, err := tm.transactor.SendTransactionWithSignature(desc.from, tm.multiTransactionForKeycardSigning.FromAsset, tm.multiTransactionForKeycardSigning.ID, txWithSignature)
if err != nil {
return nil, err // TODO: One of transfers within transaction could have been sent. Need to notify user about it
}
hashes[desc.chainID] = append(hashes[desc.chainID], hash)
}
_, err := tm.InsertMultiTransaction(tm.multiTransactionForKeycardSigning)
if err != nil {
log.Error("failed to insert multi transaction", "err", err)
}
return &MultiTransactionCommandResult{
ID: int64(tm.multiTransactionForKeycardSigning.ID),
Hashes: hashes,
}, nil
}
func (tm *TransactionManager) GetMultiTransactions(ctx context.Context, ids []wallet_common.MultiTransactionIDType) ([]*MultiTransaction, error) {
return tm.storage.ReadMultiTransactions(&MultiTxDetails{IDs: ids})
}
func (tm *TransactionManager) GetBridgeOriginMultiTransaction(ctx context.Context, toChainID uint64, crossTxID string) (*MultiTransaction, error) {
details := NewMultiTxDetails()
details.ToChainID = toChainID
details.CrossTxID = crossTxID
multiTxs, err := tm.storage.ReadMultiTransactions(details)
if err != nil {
return nil, err
}
for _, multiTx := range multiTxs {
// Origin MultiTxs will have a missing "ToTxHash"
if multiTx.ToTxHash == emptyHash {
return multiTx, nil
}
}
return nil, nil
}
func (tm *TransactionManager) GetBridgeDestinationMultiTransaction(ctx context.Context, toChainID uint64, crossTxID string) (*MultiTransaction, error) {
details := NewMultiTxDetails()
details.ToChainID = toChainID
details.CrossTxID = crossTxID
multiTxs, err := tm.storage.ReadMultiTransactions(details)
if err != nil {
return nil, err
}
for _, multiTx := range multiTxs {
// Destination MultiTxs will have a missing "FromTxHash"
if multiTx.FromTxHash == emptyHash {
return multiTx, nil
}
}
return nil, nil
}