Skip to content

Commit eeb94ea

Browse files
committed
feat: add to_address filed in bridge api response (#1405)
## πŸ”„ Changes Summary - This PR adds `to_address` filed in bridge api response - No re-syncing is required as existing bridges can return zero address as `to_address` ## 🐞 Issues - Closes #1398
1 parent 43d4ac9 commit eeb94ea

File tree

14 files changed

+127
-31
lines changed

14 files changed

+127
-31
lines changed

β€Žbridgeservice/bridge_test.goβ€Ž

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,8 @@ func TestGetBridgesHandler(t *testing.T) {
535535
Amount: common.Big0,
536536
DepositCount: 0,
537537
Metadata: []byte("metadata"),
538+
TxnSender: common.HexToAddress("0x5555555555555555555555555555555555555555"),
539+
ToAddress: common.HexToAddress("0xF9D64d54D32EE2BDceAAbFA60C4C438E224427d0"),
538540
},
539541
}
540542

@@ -567,6 +569,11 @@ func TestGetBridgesHandler(t *testing.T) {
567569

568570
require.Equal(t, bridgeResponses, response.Bridges)
569571
require.Equal(t, len(expectedBridges), response.Count)
572+
573+
// Verify to_address is present in the response
574+
require.NotNil(t, response.Bridges)
575+
require.Len(t, response.Bridges, 1)
576+
require.Equal(t, bridgetypes.Address("0xF9D64d54D32EE2BDceAAbFA60C4C438E224427d0"), response.Bridges[0].ToAddress)
570577
})
571578

572579
t.Run("GetBridges for L1 network error", func(t *testing.T) {

β€Žbridgeservice/docs/docs.goβ€Ž

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,11 @@ const docTemplate = `{
757757
"type": "integer",
758758
"example": 10
759759
},
760+
"to_address": {
761+
"description": "Address of the contract that was the recipient of the transaction. This may differ from the bridge contract address.",
762+
"type": "string",
763+
"example": "0xF9D64d54D32EE2BDceAAbFA60C4C438E224427d0"
764+
},
760765
"tx_hash": {
761766
"description": "Hash of the transaction that included the bridge event",
762767
"type": "string",

β€Žbridgeservice/docs/swagger.jsonβ€Ž

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,11 @@
750750
"type": "integer",
751751
"example": 10
752752
},
753+
"to_address": {
754+
"description": "Address of the contract that was the recipient of the transaction. This may differ from the bridge contract address.",
755+
"type": "string",
756+
"example": "0xF9D64d54D32EE2BDceAAbFA60C4C438E224427d0"
757+
},
753758
"tx_hash": {
754759
"description": "Hash of the transaction that included the bridge event",
755760
"type": "string",

β€Žbridgeservice/docs/swagger.yamlβ€Ž

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ definitions:
8080
description: ID of the network where the bridge transaction originated
8181
example: 10
8282
type: integer
83+
to_address:
84+
description: Address of the contract that was the recipient of the transaction.
85+
This may differ from the bridge contract address.
86+
example: 0xF9D64d54D32EE2BDceAAbFA60C4C438E224427d0
87+
type: string
8388
tx_hash:
8489
description: Hash of the transaction that included the bridge event
8590
example: 0xdef4567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef

β€Žbridgeservice/types/types.goβ€Ž

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ type BridgeResponse struct {
140140

141141
// Address of the transaction sender who initiated the bridge transaction
142142
TxnSender Address `json:"txn_sender" example:"0xabc1234567890abcdef1234567890abcdef12345"`
143+
144+
// Address of the contract that was the recipient of the transaction. This may differ from the bridge contract address.
145+
ToAddress Address `json:"to_address" example:"0xF9D64d54D32EE2BDceAAbFA60C4C438E224427d0"`
143146
}
144147

145148
// ClaimsResult contains the list of claim records and the total count

β€Žbridgeservice/utils.goβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ func NewBridgeResponse(bridge *bridgesync.Bridge, networkID uint32,
127127
DepositCount: bridge.DepositCount,
128128
BridgeHash: bridgetypes.Hash(bridge.Hash().Hex()),
129129
TxnSender: bridgetypes.Address(bridge.TxnSender.Hex()),
130+
ToAddress: bridgetypes.Address(bridge.ToAddress.Hex()),
130131
}
131132
}
132133

β€Žbridgesync/backfill_tx_sender.goβ€Ž

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,8 @@ func (b *BackfillTxnSender) extractData(ctx context.Context,
337337
return common.Address{}, common.Address{}, ctx.Err()
338338
default:
339339
}
340-
return ExtractTxnSenderAndFrom(ctx, b.client, b.bridgeAddr, txHash, logEvent, b.log)
340+
txnSender, fromAddr, _, err = ExtractTxnAddresses(ctx, b.client, b.bridgeAddr, txHash, logEvent, b.log)
341+
return txnSender, fromAddr, err
341342
}
342343

343344
// bulkUpdate performs a bulk update of multiple records
@@ -370,7 +371,7 @@ func (b *BackfillTxnSender) bulkUpdate(
370371

371372
stmt, err := tx.PrepareContext(dbCtx, fmt.Sprintf(`
372373
UPDATE %s
373-
SET
374+
SET
374375
txn_sender = COALESCE(NULLIF(txn_sender, ''), ?),
375376
from_address = COALESCE(NULLIF(from_address, ''), ?)
376377
WHERE block_num = ? AND block_pos = ?;

β€Žbridgesync/downloader.goβ€Ž

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,13 @@ func (t *Transaction) From() common.Address {
139139
return common.HexToAddress(t.FromRaw)
140140
}
141141

142+
func (t *Transaction) ToAddress() common.Address {
143+
if t.To == "" {
144+
return common.Address{}
145+
}
146+
return common.HexToAddress(t.To)
147+
}
148+
142149
func RPCTransactionByHash(client aggkittypes.EthClienter,
143150
txHash common.Hash) (*Transaction, error) {
144151
// Use client.Call to fetch transaction details using eth_getTransactionByHash
@@ -150,33 +157,25 @@ func RPCTransactionByHash(client aggkittypes.EthClienter,
150157
return &tx, nil
151158
}
152159

153-
func extractTxnSender(
154-
client aggkittypes.EthClienter,
155-
txHash common.Hash) (common.Address, error) {
156-
tx, err := RPCTransactionByHash(client, txHash)
157-
if err != nil {
158-
return common.Address{}, fmt.Errorf("failed to get transaction by hash for %s: %w", txHash.Hex(), err)
159-
}
160-
return tx.From(), nil
161-
}
162-
163-
// ExtractTxnSenderAndFrom extracts the txn_sender and from address from the transaction trace.
164-
// Return txnSender (same for all events in the same transaction) and fromAddr (specific for the event)
165-
func ExtractTxnSenderAndFrom(ctx context.Context,
160+
// ExtractTxnAddresses extracts the txn_sender, from address, and to address from the transaction trace.
161+
func ExtractTxnAddresses(ctx context.Context,
166162
client aggkittypes.EthClienter,
167163
bridgeAddr common.Address,
168164
txHash common.Hash,
169165
logEvent *agglayerbridge.AgglayerbridgeBridgeEvent,
170-
logger *logger.Logger) (txnSender common.Address, fromAddr common.Address, err error) {
166+
logger *logger.Logger) (txnSender common.Address, fromAddr common.Address, toAddr common.Address, err error) {
171167
// If event is a message, fromAddr is log.origin_address
172168
// so we only need the txn_sender that can be obtained from hash_receipt
169+
// and toAddr from the transaction receipt (same source as txn_sender)
173170
if logEvent.LeafType == bridgeLeafTypeMessage {
174-
txnSender, err = extractTxnSender(client, txHash)
171+
tx, err := RPCTransactionByHash(client, txHash)
175172
if err != nil {
176-
return common.Address{}, common.Address{},
177-
fmt.Errorf("extractTxnSenderAndFrom: failed to extract txn sender from tx_hash:%s: %w", txHash.Hex(), err)
173+
return common.Address{}, common.Address{}, common.Address{},
174+
fmt.Errorf("extractTxnAddresses: failed to extract txn sender from tx_hash:%s: %w", txHash.Hex(), err)
178175
}
179-
return txnSender, logEvent.OriginAddress, nil
176+
txnSender = tx.From()
177+
toAddr = tx.ToAddress()
178+
return txnSender, logEvent.OriginAddress, toAddr, nil
180179
}
181180
foundCalls, rootCall, err := extractCallData(client, bridgeAddr, txHash, logger, func(c Call) (bool, error) {
182181
if logEvent.LeafType == bridgeLeafTypeAsset {
@@ -185,18 +184,19 @@ func ExtractTxnSenderAndFrom(ctx context.Context,
185184
return false, nil
186185
})
187186
if err != nil {
188-
return common.Address{}, common.Address{},
189-
fmt.Errorf("extractTxnSenderAndFrom:failed to extract bridge event data (tx hash: %s): %w", txHash, err)
187+
return common.Address{}, common.Address{}, common.Address{},
188+
fmt.Errorf("extractTxnAddresses:failed to extract bridge event data (tx hash: %s): %w", txHash, err)
190189
}
191190
txnSender = rootCall.From
191+
toAddr = rootCall.To
192192
fromAddr, err = ExtractFromAddrFromCalls(foundCalls, logEvent)
193193
if err != nil {
194-
return common.Address{}, common.Address{},
195-
fmt.Errorf("extractTxnSenderAndFrom: failed to extract fromAddr from tx_hash:%s calls: %w",
194+
return common.Address{}, common.Address{}, common.Address{},
195+
fmt.Errorf("extractTxnAddresses: failed to extract fromAddr from tx_hash:%s calls: %w",
196196
txHash.Hex(), err)
197197
}
198198

199-
return txnSender, fromAddr, nil
199+
return txnSender, fromAddr, toAddr, nil
200200
}
201201

202202
type bridgeCallParams struct {
@@ -355,7 +355,7 @@ func buildBridgeEventHandler(
355355
"DestinationNetwork: %d, DestinationAddress: %s, DepositCount: %d, Amount: %s, ",
356356
bridgeEvent.LeafType, bridgeEvent.OriginNetwork, bridgeEvent.OriginAddress.Hex(), bridgeEvent.DestinationNetwork,
357357
bridgeEvent.DestinationAddress.Hex(), bridgeEvent.DepositCount, bridgeEvent.Amount.String())
358-
txnSender, fromAddress, err := ExtractTxnSenderAndFrom(ctx, client, bridgeAddr, l.TxHash,
358+
txnSender, fromAddress, toAddress, err := ExtractTxnAddresses(ctx, client, bridgeAddr, l.TxHash,
359359
bridgeEvent, logger)
360360
if err != nil {
361361
return fmt.Errorf("failed to extract bridge event data (tx hash: %s): %w", l.TxHash, err)
@@ -376,6 +376,7 @@ func buildBridgeEventHandler(
376376
Metadata: bridgeEvent.Metadata,
377377
DepositCount: bridgeEvent.DepositCount,
378378
TxnSender: txnSender,
379+
ToAddress: toAddress,
379380
}})
380381
return nil
381382
}

β€Žbridgesync/downloader_test.goβ€Ž

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import (
2828
// mainnet:
2929
// case https://etherscan.io/tx/0x8db8e288d25102b64d8a37ad05769817d1b43f0384dd05da075d24d2cee9cb65 (bn: 19566985) -> fix
3030
// case: https://etherscan.io/tx/0x0b276867aa22d1c162c2700d35c500a124a6a953c7b24931a1d3efc63f7cd4ab (bn: 22770713)
31-
func TestExtractTxnSenderAndFromExploratory(t *testing.T) {
31+
func TestExtractTxnAddressesExploratory(t *testing.T) {
3232
t.Skip("Skipping exploratory test")
3333
ctx := t.Context()
3434
l1url := os.Getenv("L1URL")
@@ -1016,7 +1016,7 @@ func TestTxnSenderField(t *testing.T) {
10161016
}
10171017
}
10181018

1019-
func TestExtractTxnSenderAndFrom(t *testing.T) {
1019+
func TestExtractTxnAddresses(t *testing.T) {
10201020
bridgeAddr := common.HexToAddress("0x10")
10211021
txHash := common.HexToHash("0xabcde12345abcde12345abcde12345abcde12345abcde12345abcde12345abcd")
10221022

@@ -1029,6 +1029,7 @@ func TestExtractTxnSenderAndFrom(t *testing.T) {
10291029
responseTransactionHashError error
10301030
expectedTxnSender common.Address
10311031
expectedFrom common.Address
1032+
expectedTo common.Address
10321033
expectErr string
10331034
}{
10341035
{
@@ -1042,6 +1043,23 @@ func TestExtractTxnSenderAndFrom(t *testing.T) {
10421043
responseTransactionHashError: fmt.Errorf("RPC error"),
10431044
expectErr: "RPC error",
10441045
},
1046+
{
1047+
name: "messageLeaf: successful extraction with to address",
1048+
logEvent: &agglayerbridge.AgglayerbridgeBridgeEvent{
1049+
LeafType: bridgeLeafTypeMessage,
1050+
OriginAddress: common.HexToAddress("0x40"),
1051+
DestinationNetwork: 1,
1052+
DestinationAddress: common.HexToAddress("0x30"),
1053+
Amount: big.NewInt(100),
1054+
},
1055+
responseTransactionHash: &Transaction{
1056+
FromRaw: "0x1111111111111111111111111111111111111111",
1057+
To: "0x2222222222222222222222222222222222222222",
1058+
},
1059+
expectedTxnSender: common.HexToAddress("0x1111111111111111111111111111111111111111"),
1060+
expectedFrom: common.HexToAddress("0x40"),
1061+
expectedTo: common.HexToAddress("0x2222222222222222222222222222222222222222"),
1062+
},
10451063
{
10461064
name: "assetLeaf: error can't find From from calls",
10471065
logEvent: &agglayerbridge.AgglayerbridgeBridgeEvent{
@@ -1066,6 +1084,30 @@ func TestExtractTxnSenderAndFrom(t *testing.T) {
10661084
},
10671085
expectErr: "failed to extract",
10681086
},
1087+
{
1088+
name: "assetLeaf: successful extraction with to address from rootCall",
1089+
logEvent: &agglayerbridge.AgglayerbridgeBridgeEvent{
1090+
LeafType: bridgeLeafTypeAsset,
1091+
OriginAddress: common.HexToAddress("0x50"),
1092+
DestinationNetwork: 1,
1093+
DestinationAddress: common.HexToAddress("0x30"),
1094+
Amount: big.NewInt(100),
1095+
},
1096+
responseDebugTrace: &Call{
1097+
From: common.HexToAddress("0x3333333333333333333333333333333333333333"),
1098+
To: common.HexToAddress("0x4444444444444444444444444444444444444444"),
1099+
Calls: []Call{
1100+
{
1101+
To: bridgeAddr,
1102+
From: common.HexToAddress("0x50"),
1103+
Input: append(BridgeAssetMethodID, make([]byte, 100)...),
1104+
},
1105+
},
1106+
},
1107+
expectedTxnSender: common.HexToAddress("0x3333333333333333333333333333333333333333"),
1108+
expectedFrom: common.HexToAddress("0x50"),
1109+
expectedTo: common.HexToAddress("0x4444444444444444444444444444444444444444"),
1110+
},
10691111
}
10701112
for _, tt := range tests {
10711113
t.Run(tt.name, func(t *testing.T) {
@@ -1091,14 +1133,15 @@ func TestExtractTxnSenderAndFrom(t *testing.T) {
10911133
}).Return(nil).
10921134
Maybe()
10931135

1094-
txnSender, from, err := ExtractTxnSenderAndFrom(ctx, ethClient,
1136+
txnSender, from, to, err := ExtractTxnAddresses(ctx, ethClient,
10951137
bridgeAddr, txHash, tt.logEvent, logger)
10961138
if tt.expectErr != "" {
10971139
require.ErrorContains(t, err, tt.expectErr)
10981140
} else {
10991141
require.NoError(t, err)
11001142
require.Equal(t, tt.expectedTxnSender, txnSender)
11011143
require.Equal(t, tt.expectedFrom, from)
1144+
require.Equal(t, tt.expectedTo, to)
11021145
}
11031146
})
11041147
}

β€Žbridgesync/e2e_test.goβ€Ž

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ func TestBridgeEventE2E(t *testing.T) {
7878
bridge.BlockTimestamp = block.Time()
7979
require.NoError(t, err)
8080
require.Equal(t, receipt.Status, types.ReceiptStatusSuccessful)
81+
// Extract ToAddress from the transaction
82+
txDetails, _, err := simulatedClient.TransactionByHash(ctx, tx.Hash())
83+
require.NoError(t, err)
84+
if txDetails.To() != nil {
85+
bridge.ToAddress = *txDetails.To()
86+
}
8187
expectedBridges = append(expectedBridges, bridge)
8288
expectedRoot, err := l1Setup.BridgeContract.GetRoot(nil)
8389
require.NoError(t, err)

0 commit comments

Comments
Β (0)