github.com/status-im/status-go@v1.1.0/services/wallet/transfer/bridge_identifier.go (about)

     1  package transfer
     2  
     3  import (
     4  	"context"
     5  	"encoding/hex"
     6  	"fmt"
     7  	"math/big"
     8  
     9  	"github.com/ethereum/go-ethereum/common"
    10  	"github.com/ethereum/go-ethereum/common/hexutil"
    11  	"github.com/status-im/status-go/rpc/chain"
    12  	w_common "github.com/status-im/status-go/services/wallet/common"
    13  	"github.com/status-im/status-go/services/wallet/token"
    14  )
    15  
    16  // TODO: Find proper way to uniquely match Origin and Destination transactions (some sort of hash or uniqueID)
    17  // Current approach is not failsafe (for example, if multiple identical bridge operations are triggered
    18  // at the same time)
    19  // Recipient + Relayer + Data should match in both Origin and Destination transactions
    20  func getHopBridgeFromL1CrossTxID(recipient common.Address, relayer common.Address, logData []byte) string {
    21  	return fmt.Sprintf("FromL1_%s_%s_%s", recipient.String(), relayer.String(), hex.EncodeToString(logData))
    22  }
    23  
    24  func getHopBridgeFromL2CrossTxID(transferID *big.Int) string {
    25  	return fmt.Sprintf("FromL2_0x%s", transferID.Text(16))
    26  }
    27  
    28  type originTxParams struct {
    29  	fromNetworkID uint64
    30  	fromTxHash    common.Hash
    31  	fromAddress   common.Address
    32  	fromAsset     string
    33  	fromAmount    *big.Int
    34  	toNetworkID   uint64
    35  	toAddress     common.Address
    36  	crossTxID     string
    37  	timestamp     uint64
    38  }
    39  
    40  func upsertHopBridgeOriginTx(ctx context.Context, transactionManager *TransactionManager, params originTxParams) (*MultiTransaction, error) {
    41  	// Try to find "destination" half of the multiTx
    42  	multiTx, err := transactionManager.GetBridgeDestinationMultiTransaction(ctx, params.toNetworkID, params.crossTxID)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  
    47  	if multiTx == nil {
    48  		multiTx = NewMultiTransaction(
    49  			/* Timestamp:     */ params.timestamp, // Common data
    50  			/* FromNetworkID: */ params.fromNetworkID, // Data from "origin" transaction
    51  			/* ToNetworkID:   */ params.toNetworkID, // Data from "origin" transaction
    52  			/* FromTxHash:    */ params.fromTxHash, // Data from "origin" transaction
    53  			/* ToTxHash:      */ common.Hash{},
    54  			/* FromAddress:   */ params.fromAddress, // Data from "origin" transaction
    55  			/* ToAddress:     */ params.toAddress, // Data from "origin" transaction
    56  			/* FromAsset:     */ params.fromAsset, // Data from "origin" transaction
    57  			/* ToAsset:       */ params.fromAsset, // To be replaced by "destination" transaction, need to be non-null
    58  			/* FromAmount:    */ (*hexutil.Big)(params.fromAmount), // Data from "origin" transaction
    59  			/* ToAmount:      */ (*hexutil.Big)(params.fromAmount), // To be replaced by "destination" transaction, need to be non-null
    60  			/* Type:      	  */ MultiTransactionBridge, // Common data
    61  			/* CrossTxID:	  */ params.crossTxID, // Common data
    62  		)
    63  
    64  		_, err := transactionManager.InsertMultiTransaction(multiTx)
    65  		if err != nil {
    66  			return nil, err
    67  		}
    68  
    69  	} else {
    70  		multiTx.FromNetworkID = params.fromNetworkID
    71  		multiTx.FromTxHash = params.fromTxHash
    72  		multiTx.FromAddress = params.fromAddress
    73  		multiTx.FromAsset = params.fromAsset
    74  		multiTx.FromAmount = (*hexutil.Big)(params.fromAmount)
    75  		multiTx.Timestamp = params.timestamp
    76  
    77  		err := transactionManager.UpdateMultiTransaction(multiTx)
    78  		if err != nil {
    79  			return nil, err
    80  		}
    81  	}
    82  	return multiTx, nil
    83  }
    84  
    85  type destinationTxParams struct {
    86  	toNetworkID uint64
    87  	toTxHash    common.Hash
    88  	toAddress   common.Address
    89  	toAsset     string
    90  	toAmount    *big.Int
    91  	crossTxID   string
    92  	timestamp   uint64
    93  }
    94  
    95  func upsertHopBridgeDestinationTx(ctx context.Context, transactionManager *TransactionManager, params destinationTxParams) (*MultiTransaction, error) {
    96  	// Try to find "origin" half of the multiTx
    97  	multiTx, err := transactionManager.GetBridgeOriginMultiTransaction(ctx, params.toNetworkID, params.crossTxID)
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  
   102  	if multiTx == nil {
   103  		multiTx = NewMultiTransaction(
   104  			/* Timestamp: 	  */ params.timestamp, // Common data
   105  			/* FromNetworkID: */ 0, // not set
   106  			/* ToNetworkID:   */ params.toNetworkID, // Data from "destination" transaction
   107  			/* FromTxHash:    */ common.Hash{},
   108  			/* ToTxHash:      */ params.toTxHash, // Data from "destination" transaction
   109  			/* FromAddress:   */ params.toAddress, // To be replaced by "origin" transaction, need to be non-null
   110  			/* ToAddress:     */ params.toAddress, // Data from "destination" transaction
   111  			/* FromAsset:     */ params.toAsset, // To be replaced by "origin" transaction, need to be non-null
   112  			/* ToAsset:       */ params.toAsset, // Data from "destination" transaction
   113  			/* FromAmount:    */ (*hexutil.Big)(params.toAmount), // To be replaced by "origin" transaction, need to be non-null
   114  			/* ToAmount:      */ (*hexutil.Big)(params.toAmount), // Data from "destination" transaction
   115  			/* Type:      	  */ MultiTransactionBridge, // Common data
   116  			/* CrossTxID: 	  */ params.crossTxID, // Common data
   117  		)
   118  
   119  		_, err := transactionManager.InsertMultiTransaction(multiTx)
   120  		if err != nil {
   121  			return nil, err
   122  		}
   123  	} else {
   124  		multiTx.ToTxHash = params.toTxHash
   125  		multiTx.ToAsset = params.toAsset
   126  		multiTx.ToAmount = (*hexutil.Big)(params.toAmount)
   127  		multiTx.Timestamp = params.timestamp
   128  
   129  		err := transactionManager.UpdateMultiTransaction(multiTx)
   130  		if err != nil {
   131  			return nil, err
   132  		}
   133  	}
   134  	return multiTx, nil
   135  }
   136  
   137  func buildHopBridgeMultitransaction(ctx context.Context, client chain.ClientInterface, transactionManager *TransactionManager, tokenManager *token.Manager, subTx *Transfer) (*MultiTransaction, error) {
   138  	// Identify if it's from/to transaction
   139  	switch w_common.GetEventType(subTx.Log) {
   140  	case w_common.HopBridgeTransferSentToL2EventType:
   141  		// L1->L2 Origin transaction
   142  		toChainID, recipient, relayer, fromAmount, err := w_common.ParseHopBridgeTransferSentToL2Log(subTx.Log)
   143  		if err != nil {
   144  			return nil, err
   145  		}
   146  
   147  		params := originTxParams{
   148  			fromNetworkID: subTx.NetworkID,
   149  			fromTxHash:    subTx.Receipt.TxHash,
   150  			fromAddress:   subTx.From,
   151  			fromAsset:     "ETH",
   152  			fromAmount:    fromAmount,
   153  			toNetworkID:   toChainID,
   154  			toAddress:     recipient,
   155  			crossTxID:     getHopBridgeFromL1CrossTxID(recipient, relayer, subTx.Log.Data),
   156  			timestamp:     subTx.Timestamp,
   157  		}
   158  
   159  		return upsertHopBridgeOriginTx(ctx, transactionManager, params)
   160  
   161  	case w_common.HopBridgeTransferFromL1CompletedEventType:
   162  		// L1->L2 Destination transaction
   163  		recipient, relayer, toAmount, err := w_common.ParseHopBridgeTransferFromL1CompletedLog(subTx.Log)
   164  		if err != nil {
   165  			return nil, err
   166  		}
   167  
   168  		params := destinationTxParams{
   169  			toNetworkID: subTx.NetworkID,
   170  			toTxHash:    subTx.Receipt.TxHash,
   171  			toAddress:   recipient,
   172  			toAsset:     "ETH",
   173  			toAmount:    toAmount,
   174  			crossTxID:   getHopBridgeFromL1CrossTxID(recipient, relayer, subTx.Log.Data),
   175  			timestamp:   subTx.Timestamp,
   176  		}
   177  
   178  		return upsertHopBridgeDestinationTx(ctx, transactionManager, params)
   179  
   180  	case w_common.HopBridgeTransferSentEventType:
   181  		// L2->L1 / L2->L2 Origin transaction
   182  		transferID, toChainID, recipient, fromAmount, _, _, _, _, _, err := w_common.ParseHopBridgeTransferSentLog(subTx.Log)
   183  		if err != nil {
   184  			return nil, err
   185  		}
   186  
   187  		params := originTxParams{
   188  			fromNetworkID: subTx.NetworkID,
   189  			fromTxHash:    subTx.Receipt.TxHash,
   190  			fromAddress:   subTx.From,
   191  			fromAsset:     "ETH",
   192  			fromAmount:    fromAmount,
   193  			toNetworkID:   toChainID,
   194  			toAddress:     recipient,
   195  			crossTxID:     getHopBridgeFromL2CrossTxID(transferID),
   196  			timestamp:     subTx.Timestamp,
   197  		}
   198  
   199  		return upsertHopBridgeOriginTx(ctx, transactionManager, params)
   200  
   201  	case w_common.HopBridgeWithdrawalBondedEventType:
   202  		// L2->L1 / L2->L2 Destination transaction
   203  		transferID, toAmount, err := w_common.ParseHopWithdrawalBondedLog(subTx.Log)
   204  		if err != nil {
   205  			return nil, err
   206  		}
   207  
   208  		params := destinationTxParams{
   209  			toNetworkID: subTx.NetworkID,
   210  			toTxHash:    subTx.Receipt.TxHash,
   211  			toAddress:   subTx.Address,
   212  			toAsset:     "ETH",
   213  			toAmount:    toAmount,
   214  			crossTxID:   getHopBridgeFromL2CrossTxID(transferID),
   215  			timestamp:   subTx.Timestamp,
   216  		}
   217  
   218  		return upsertHopBridgeDestinationTx(ctx, transactionManager, params)
   219  	}
   220  	return nil, nil
   221  }