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 }