Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions bridgeservice/bridge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,8 @@ func TestGetBridgesHandler(t *testing.T) {
Amount: common.Big0,
DepositCount: 0,
Metadata: []byte("metadata"),
TxnSender: common.HexToAddress("0x5555555555555555555555555555555555555555"),
ToAddress: common.HexToAddress("0xF9D64d54D32EE2BDceAAbFA60C4C438E224427d0"),
},
}

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

require.Equal(t, bridgeResponses, response.Bridges)
require.Equal(t, len(expectedBridges), response.Count)

// Verify to_address is present in the response
require.NotNil(t, response.Bridges)
require.Len(t, response.Bridges, 1)
require.Equal(t, bridgetypes.Address("0xF9D64d54D32EE2BDceAAbFA60C4C438E224427d0"), response.Bridges[0].ToAddress)
})

t.Run("GetBridges for L1 network error", func(t *testing.T) {
Expand Down
5 changes: 5 additions & 0 deletions bridgeservice/docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,11 @@ const docTemplate = `{
"type": "integer",
"example": 10
},
"to_address": {
"description": "Address of the contract that was the recipient of the transaction. This may differ from the bridge contract address.",
"type": "string",
"example": "0xF9D64d54D32EE2BDceAAbFA60C4C438E224427d0"
},
"tx_hash": {
"description": "Hash of the transaction that included the bridge event",
"type": "string",
Expand Down
5 changes: 5 additions & 0 deletions bridgeservice/docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,11 @@
"type": "integer",
"example": 10
},
"to_address": {
"description": "Address of the contract that was the recipient of the transaction. This may differ from the bridge contract address.",
"type": "string",
"example": "0xF9D64d54D32EE2BDceAAbFA60C4C438E224427d0"
},
"tx_hash": {
"description": "Hash of the transaction that included the bridge event",
"type": "string",
Expand Down
5 changes: 5 additions & 0 deletions bridgeservice/docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ definitions:
description: ID of the network where the bridge transaction originated
example: 10
type: integer
to_address:
description: Address of the contract that was the recipient of the transaction.
This may differ from the bridge contract address.
example: 0xF9D64d54D32EE2BDceAAbFA60C4C438E224427d0
type: string
tx_hash:
description: Hash of the transaction that included the bridge event
example: 0xdef4567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
Expand Down
3 changes: 3 additions & 0 deletions bridgeservice/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ type BridgeResponse struct {

// Address of the transaction sender who initiated the bridge transaction
TxnSender Address `json:"txn_sender" example:"0xabc1234567890abcdef1234567890abcdef12345"`

// Address of the contract that was the recipient of the transaction. This may differ from the bridge contract address.
ToAddress Address `json:"to_address" example:"0xF9D64d54D32EE2BDceAAbFA60C4C438E224427d0"`
}

// ClaimsResult contains the list of claim records and the total count
Expand Down
1 change: 1 addition & 0 deletions bridgeservice/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ func NewBridgeResponse(bridge *bridgesync.Bridge, networkID uint32,
DepositCount: bridge.DepositCount,
BridgeHash: bridgetypes.Hash(bridge.Hash().Hex()),
TxnSender: bridgetypes.Address(bridge.TxnSender.Hex()),
ToAddress: bridgetypes.Address(bridge.ToAddress.Hex()),
}
}

Expand Down
5 changes: 3 additions & 2 deletions bridgesync/backfill_tx_sender.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,8 @@ func (b *BackfillTxnSender) extractData(ctx context.Context,
return common.Address{}, common.Address{}, ctx.Err()
default:
}
return ExtractTxnSenderAndFrom(ctx, b.client, b.bridgeAddr, txHash, logEvent, b.log)
txnSender, fromAddr, _, err = ExtractTxnAddresses(ctx, b.client, b.bridgeAddr, txHash, logEvent, b.log)
return txnSender, fromAddr, err
}

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

stmt, err := tx.PrepareContext(dbCtx, fmt.Sprintf(`
UPDATE %s
SET
SET
txn_sender = COALESCE(NULLIF(txn_sender, ''), ?),
from_address = COALESCE(NULLIF(from_address, ''), ?)
WHERE block_num = ? AND block_pos = ?;
Expand Down
49 changes: 25 additions & 24 deletions bridgesync/downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,13 @@ func (t *Transaction) From() common.Address {
return common.HexToAddress(t.FromRaw)
}

func (t *Transaction) ToAddress() common.Address {
if t.To == "" {
return common.Address{}
}
return common.HexToAddress(t.To)
}

func RPCTransactionByHash(client aggkittypes.EthClienter,
txHash common.Hash) (*Transaction, error) {
// Use client.Call to fetch transaction details using eth_getTransactionByHash
Expand All @@ -150,33 +157,25 @@ func RPCTransactionByHash(client aggkittypes.EthClienter,
return &tx, nil
}

func extractTxnSender(
client aggkittypes.EthClienter,
txHash common.Hash) (common.Address, error) {
tx, err := RPCTransactionByHash(client, txHash)
if err != nil {
return common.Address{}, fmt.Errorf("failed to get transaction by hash for %s: %w", txHash.Hex(), err)
}
return tx.From(), nil
}

// ExtractTxnSenderAndFrom extracts the txn_sender and from address from the transaction trace.
// Return txnSender (same for all events in the same transaction) and fromAddr (specific for the event)
func ExtractTxnSenderAndFrom(ctx context.Context,
// ExtractTxnAddresses extracts the txn_sender, from address, and to address from the transaction trace.
func ExtractTxnAddresses(ctx context.Context,
client aggkittypes.EthClienter,
bridgeAddr common.Address,
txHash common.Hash,
logEvent *agglayerbridge.AgglayerbridgeBridgeEvent,
logger *logger.Logger) (txnSender common.Address, fromAddr common.Address, err error) {
logger *logger.Logger) (txnSender common.Address, fromAddr common.Address, toAddr common.Address, err error) {
// If event is a message, fromAddr is log.origin_address
// so we only need the txn_sender that can be obtained from hash_receipt
// and toAddr from the transaction receipt (same source as txn_sender)
if logEvent.LeafType == bridgeLeafTypeMessage {
txnSender, err = extractTxnSender(client, txHash)
tx, err := RPCTransactionByHash(client, txHash)
if err != nil {
return common.Address{}, common.Address{},
fmt.Errorf("extractTxnSenderAndFrom: failed to extract txn sender from tx_hash:%s: %w", txHash.Hex(), err)
return common.Address{}, common.Address{}, common.Address{},
fmt.Errorf("extractTxnAddresses: failed to extract txn sender from tx_hash:%s: %w", txHash.Hex(), err)
}
return txnSender, logEvent.OriginAddress, nil
txnSender = tx.From()
toAddr = tx.ToAddress()
return txnSender, logEvent.OriginAddress, toAddr, nil
}
foundCalls, rootCall, err := extractCallData(client, bridgeAddr, txHash, logger, func(c Call) (bool, error) {
if logEvent.LeafType == bridgeLeafTypeAsset {
Expand All @@ -185,18 +184,19 @@ func ExtractTxnSenderAndFrom(ctx context.Context,
return false, nil
})
if err != nil {
return common.Address{}, common.Address{},
fmt.Errorf("extractTxnSenderAndFrom:failed to extract bridge event data (tx hash: %s): %w", txHash, err)
return common.Address{}, common.Address{}, common.Address{},
fmt.Errorf("extractTxnAddresses:failed to extract bridge event data (tx hash: %s): %w", txHash, err)
}
txnSender = rootCall.From
toAddr = rootCall.To
fromAddr, err = ExtractFromAddrFromCalls(foundCalls, logEvent)
if err != nil {
return common.Address{}, common.Address{},
fmt.Errorf("extractTxnSenderAndFrom: failed to extract fromAddr from tx_hash:%s calls: %w",
return common.Address{}, common.Address{}, common.Address{},
fmt.Errorf("extractTxnAddresses: failed to extract fromAddr from tx_hash:%s calls: %w",
txHash.Hex(), err)
}

return txnSender, fromAddr, nil
return txnSender, fromAddr, toAddr, nil
}

type bridgeCallParams struct {
Expand Down Expand Up @@ -355,7 +355,7 @@ func buildBridgeEventHandler(
"DestinationNetwork: %d, DestinationAddress: %s, DepositCount: %d, Amount: %s, ",
bridgeEvent.LeafType, bridgeEvent.OriginNetwork, bridgeEvent.OriginAddress.Hex(), bridgeEvent.DestinationNetwork,
bridgeEvent.DestinationAddress.Hex(), bridgeEvent.DepositCount, bridgeEvent.Amount.String())
txnSender, fromAddress, err := ExtractTxnSenderAndFrom(ctx, client, bridgeAddr, l.TxHash,
txnSender, fromAddress, toAddress, err := ExtractTxnAddresses(ctx, client, bridgeAddr, l.TxHash,
bridgeEvent, logger)
if err != nil {
return fmt.Errorf("failed to extract bridge event data (tx hash: %s): %w", l.TxHash, err)
Expand All @@ -376,6 +376,7 @@ func buildBridgeEventHandler(
Metadata: bridgeEvent.Metadata,
DepositCount: bridgeEvent.DepositCount,
TxnSender: txnSender,
ToAddress: toAddress,
}})
return nil
}
Expand Down
49 changes: 46 additions & 3 deletions bridgesync/downloader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (
// mainnet:
// case https://etherscan.io/tx/0x8db8e288d25102b64d8a37ad05769817d1b43f0384dd05da075d24d2cee9cb65 (bn: 19566985) -> fix
// case: https://etherscan.io/tx/0x0b276867aa22d1c162c2700d35c500a124a6a953c7b24931a1d3efc63f7cd4ab (bn: 22770713)
func TestExtractTxnSenderAndFromExploratory(t *testing.T) {
func TestExtractTxnAddressesExploratory(t *testing.T) {
t.Skip("Skipping exploratory test")
ctx := t.Context()
l1url := os.Getenv("L1URL")
Expand Down Expand Up @@ -1016,7 +1016,7 @@ func TestTxnSenderField(t *testing.T) {
}
}

func TestExtractTxnSenderAndFrom(t *testing.T) {
func TestExtractTxnAddresses(t *testing.T) {
bridgeAddr := common.HexToAddress("0x10")
txHash := common.HexToHash("0xabcde12345abcde12345abcde12345abcde12345abcde12345abcde12345abcd")

Expand All @@ -1029,6 +1029,7 @@ func TestExtractTxnSenderAndFrom(t *testing.T) {
responseTransactionHashError error
expectedTxnSender common.Address
expectedFrom common.Address
expectedTo common.Address
expectErr string
}{
{
Expand All @@ -1042,6 +1043,23 @@ func TestExtractTxnSenderAndFrom(t *testing.T) {
responseTransactionHashError: fmt.Errorf("RPC error"),
expectErr: "RPC error",
},
{
name: "messageLeaf: successful extraction with to address",
logEvent: &agglayerbridge.AgglayerbridgeBridgeEvent{
LeafType: bridgeLeafTypeMessage,
OriginAddress: common.HexToAddress("0x40"),
DestinationNetwork: 1,
DestinationAddress: common.HexToAddress("0x30"),
Amount: big.NewInt(100),
},
responseTransactionHash: &Transaction{
FromRaw: "0x1111111111111111111111111111111111111111",
To: "0x2222222222222222222222222222222222222222",
},
expectedTxnSender: common.HexToAddress("0x1111111111111111111111111111111111111111"),
expectedFrom: common.HexToAddress("0x40"),
expectedTo: common.HexToAddress("0x2222222222222222222222222222222222222222"),
},
{
name: "assetLeaf: error can't find From from calls",
logEvent: &agglayerbridge.AgglayerbridgeBridgeEvent{
Expand All @@ -1066,6 +1084,30 @@ func TestExtractTxnSenderAndFrom(t *testing.T) {
},
expectErr: "failed to extract",
},
{
name: "assetLeaf: successful extraction with to address from rootCall",
logEvent: &agglayerbridge.AgglayerbridgeBridgeEvent{
LeafType: bridgeLeafTypeAsset,
OriginAddress: common.HexToAddress("0x50"),
DestinationNetwork: 1,
DestinationAddress: common.HexToAddress("0x30"),
Amount: big.NewInt(100),
},
responseDebugTrace: &Call{
From: common.HexToAddress("0x3333333333333333333333333333333333333333"),
To: common.HexToAddress("0x4444444444444444444444444444444444444444"),
Calls: []Call{
{
To: bridgeAddr,
From: common.HexToAddress("0x50"),
Input: append(BridgeAssetMethodID, make([]byte, 100)...),
},
},
},
expectedTxnSender: common.HexToAddress("0x3333333333333333333333333333333333333333"),
expectedFrom: common.HexToAddress("0x50"),
expectedTo: common.HexToAddress("0x4444444444444444444444444444444444444444"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand All @@ -1091,14 +1133,15 @@ func TestExtractTxnSenderAndFrom(t *testing.T) {
}).Return(nil).
Maybe()

txnSender, from, err := ExtractTxnSenderAndFrom(ctx, ethClient,
txnSender, from, to, err := ExtractTxnAddresses(ctx, ethClient,
bridgeAddr, txHash, tt.logEvent, logger)
if tt.expectErr != "" {
require.ErrorContains(t, err, tt.expectErr)
} else {
require.NoError(t, err)
require.Equal(t, tt.expectedTxnSender, txnSender)
require.Equal(t, tt.expectedFrom, from)
require.Equal(t, tt.expectedTo, to)
}
})
}
Expand Down
6 changes: 6 additions & 0 deletions bridgesync/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ func TestBridgeEventE2E(t *testing.T) {
bridge.BlockTimestamp = block.Time()
require.NoError(t, err)
require.Equal(t, receipt.Status, types.ReceiptStatusSuccessful)
// Extract ToAddress from the transaction
txDetails, _, err := simulatedClient.TransactionByHash(ctx, tx.Hash())
require.NoError(t, err)
if txDetails.To() != nil {
bridge.ToAddress = *txDetails.To()
}
expectedBridges = append(expectedBridges, bridge)
expectedRoot, err := l1Setup.BridgeContract.GetRoot(nil)
require.NoError(t, err)
Expand Down
6 changes: 6 additions & 0 deletions bridgesync/migrations/bridgesync0012.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- +migrate Down
ALTER TABLE bridge DROP COLUMN to_address;

-- +migrate Up
ALTER TABLE bridge ADD COLUMN to_address VARCHAR;

7 changes: 7 additions & 0 deletions bridgesync/migrations/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ var mig0010 string
//go:embed bridgesync0011.sql
var mig0011 string

//go:embed bridgesync0012.sql
var mig0012 string

func RunMigrations(dbPath string) error {
migrations := []types.Migration{
{
Expand Down Expand Up @@ -87,6 +90,10 @@ func RunMigrations(dbPath string) error {
ID: "bridgesync0011",
SQL: mig0011,
},
{
ID: "bridgesync0012",
SQL: mig0012,
},
}
migrations = append(migrations, treeMigrations.Migrations...)
return db.RunMigrations(dbPath, migrations)
Expand Down
5 changes: 3 additions & 2 deletions bridgesync/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ type Bridge struct {
Metadata []byte `meddler:"metadata"`
DepositCount uint32 `meddler:"deposit_count"`
TxnSender common.Address `meddler:"txn_sender,address"`
ToAddress common.Address `meddler:"to_address,address"`
}

func (b *Bridge) String() string {
Expand All @@ -145,11 +146,11 @@ func (b *Bridge) String() string {
return fmt.Sprintf("Bridge{BlockNum: %d, BlockPos: %d, FromAddress: %s, TxHash: %s, "+
"BlockTimestamp: %d, LeafType: %d, OriginNetwork: %d, OriginAddress: %s, "+
"DestinationNetwork: %d, DestinationAddress: %s, Amount: %s, Metadata: %x, "+
"DepositCount: %d, TxnSender: %s}",
"DepositCount: %d, TxnSender: %s, ToAddress: %s}",
b.BlockNum, b.BlockPos, b.FromAddress.String(), b.TxHash.String(),
b.BlockTimestamp, b.LeafType, b.OriginNetwork, b.OriginAddress.String(),
b.DestinationNetwork, b.DestinationAddress.String(), amountStr, b.Metadata,
b.DepositCount, b.TxnSender.String())
b.DepositCount, b.TxnSender.String(), b.ToAddress.String())
}

// Hash returns the hash of the bridge event as expected by the exit tree
Expand Down
5 changes: 5 additions & 0 deletions docs/assets/swagger/bridge_service/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,11 @@
"type": "integer",
"example": 10
},
"to_address": {
"description": "Address of the contract that was the recipient of the transaction. This may differ from the bridge contract address.",
"type": "string",
"example": "0xF9D64d54D32EE2BDceAAbFA60C4C438E224427d0"
},
"tx_hash": {
"description": "Hash of the transaction that included the bridge event",
"type": "string",
Expand Down
Loading