-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(rfq-relayer): fee pricer considers v2 CallValue and CallParams [SLT-320] #3299
Changes from all commits
1c7138e
76c1d6f
8aeb626
a42cef9
43da983
73531fd
9baed17
b123b0f
4e448e8
62d16f7
1376b7b
2620aaf
32df025
b9cd947
cfb8d3c
cebce1e
3186071
af05543
ae348be
842a0f6
f8d6d4f
9de9cfb
a97da60
308e66b
d081602
7e6e1fc
596d105
7a72ad4
9fde9a8
a9b3a18
2a132a8
9833e0d
7d47ab0
f93b3b3
2510a2b
d9db854
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
// Package bridgetransactionv2 is the bridge transaction contract. | ||
package bridgetransactionv2 | ||
|
||
//go:generate go run github.com/synapsecns/sanguine/tools/abigen generate --sol ../../../../packages/contracts-rfq/flattened/BridgeTransactionV2Harness.sol --pkg bridgetransactionv2 --sol-version 0.8.24 --filename bridgetransactionv2 --evm-version istanbul |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package bridgetransactionv2 | ||
|
||
import ( | ||
"github.com/ethereum/go-ethereum/accounts/abi/bind" | ||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/core/vm" | ||
) | ||
|
||
// BridgeTransactionV2Ref is a bound fast bridge contract that returns the address of the contract. | ||
// | ||
//nolint:golint | ||
type BridgeTransactionV2Ref struct { | ||
*BridgeTransactionV2Harness | ||
address common.Address | ||
} | ||
|
||
// Address gets the ocntract address. | ||
func (f *BridgeTransactionV2Ref) Address() common.Address { | ||
return f.address | ||
} | ||
|
||
// NewBridgeTransactionV2Ref creates a new fast bridge mock contract with a ref. | ||
func NewBridgeTransactionV2Ref(address common.Address, backend bind.ContractBackend) (*BridgeTransactionV2Ref, error) { | ||
bridgetransactionv2, err := NewBridgeTransactionV2Harness(address, backend) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return &BridgeTransactionV2Ref{ | ||
BridgeTransactionV2Harness: bridgetransactionv2, | ||
address: address, | ||
}, nil | ||
} | ||
|
||
var _ vm.ContractRef = &BridgeTransactionV2Ref{} |
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -21,15 +21,19 @@ import ( | |||||||||||||
cctpTest "github.com/synapsecns/sanguine/services/cctp-relayer/testutil" | ||||||||||||||
omnirpcClient "github.com/synapsecns/sanguine/services/omnirpc/client" | ||||||||||||||
"github.com/synapsecns/sanguine/services/rfq/api/client" | ||||||||||||||
"github.com/synapsecns/sanguine/services/rfq/contracts/bridgetransactionv2" | ||||||||||||||
"github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" | ||||||||||||||
"github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" | ||||||||||||||
"github.com/synapsecns/sanguine/services/rfq/guard/guarddb" | ||||||||||||||
guardService "github.com/synapsecns/sanguine/services/rfq/guard/service" | ||||||||||||||
"github.com/synapsecns/sanguine/services/rfq/relayer/chain" | ||||||||||||||
"github.com/synapsecns/sanguine/services/rfq/relayer/reldb" | ||||||||||||||
"github.com/synapsecns/sanguine/services/rfq/relayer/service" | ||||||||||||||
"github.com/synapsecns/sanguine/services/rfq/testutil" | ||||||||||||||
"github.com/synapsecns/sanguine/services/rfq/util" | ||||||||||||||
"golang.org/x/sync/errgroup" | ||||||||||||||
|
||||||||||||||
"github.com/brianvoe/gofakeit/v6" | ||||||||||||||
) | ||||||||||||||
|
||||||||||||||
type IntegrationSuite struct { | ||||||||||||||
|
@@ -403,6 +407,8 @@ func (i *IntegrationSuite) TestZap() { | |||||||||||||
_ = i.guard.Start(i.GetTestContext()) | ||||||||||||||
}() | ||||||||||||||
|
||||||||||||||
fmt.Printf("omnirpc url: %s\n", i.destBackend.RPCAddress()) | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove unnecessary debug print statement The line Apply this diff to remove the debug print: - fmt.Printf("omnirpc url: %s\n", i.destBackend.RPCAddress()) 📝 Committable suggestion
Suggested change
|
||||||||||||||
|
||||||||||||||
// load token contracts | ||||||||||||||
const startAmount = 1000 | ||||||||||||||
const rfqAmount = 900 | ||||||||||||||
|
@@ -868,3 +874,107 @@ func (i *IntegrationSuite) TestConcurrentBridges() { | |||||||||||||
return true | ||||||||||||||
}) | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
//nolint:gosec | ||||||||||||||
func (i *IntegrationSuite) TestEncodeBridgeTransactionParity() { | ||||||||||||||
_, handle := i.manager.GetBridgeTransactionV2(i.GetTestContext(), i.originBackend) | ||||||||||||||
|
||||||||||||||
mockAddress := func() common.Address { | ||||||||||||||
// Generate 20 random bytes for the address | ||||||||||||||
b := make([]byte, 20) | ||||||||||||||
for i := range b { | ||||||||||||||
b[i] = byte(gofakeit.Number(0, 255)) | ||||||||||||||
} | ||||||||||||||
return common.BytesToAddress(b) | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
// Generate random values that will be used for both transactions | ||||||||||||||
originChainId := uint32(gofakeit.Number(1, 1000000)) | ||||||||||||||
destChainId := uint32(gofakeit.Number(1, 1000000)) | ||||||||||||||
originSender := mockAddress() | ||||||||||||||
destRecipient := mockAddress() | ||||||||||||||
originToken := mockAddress() | ||||||||||||||
destToken := mockAddress() | ||||||||||||||
originAmount := new(big.Int).SetUint64(gofakeit.Uint64()) | ||||||||||||||
destAmount := new(big.Int).SetUint64(gofakeit.Uint64()) | ||||||||||||||
originFeeAmount := new(big.Int).SetUint64(gofakeit.Uint64()) | ||||||||||||||
deadline := new(big.Int).SetUint64(gofakeit.Uint64()) | ||||||||||||||
nonce := new(big.Int).SetUint64(gofakeit.Uint64()) | ||||||||||||||
exclusivityRelayer := mockAddress() | ||||||||||||||
exclusivityEndTime := new(big.Int).SetUint64(gofakeit.Uint64()) | ||||||||||||||
zapNative := new(big.Int).SetUint64(gofakeit.Uint64()) | ||||||||||||||
|
||||||||||||||
// Random size and values for zapData | ||||||||||||||
zapDataSize := gofakeit.Number(0, 1000) | ||||||||||||||
zapData := make([]byte, zapDataSize) | ||||||||||||||
for i := range zapDataSize { | ||||||||||||||
zapData[i] = gofakeit.Uint8() | ||||||||||||||
} | ||||||||||||||
Comment on lines
+910
to
+912
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix incorrect range loop syntax Using range on an integer (zapDataSize) is incorrect. This will cause a compilation error. Apply this diff to fix the loop: -for i := range zapDataSize {
+for i := 0; i < zapDataSize; i++ {
zapData[i] = gofakeit.Uint8()
} 📝 Committable suggestion
Suggested change
|
||||||||||||||
|
||||||||||||||
// Create first transaction | ||||||||||||||
bridgeTx := bridgetransactionv2.IFastBridgeV2BridgeTransactionV2{ | ||||||||||||||
OriginChainId: originChainId, | ||||||||||||||
DestChainId: destChainId, | ||||||||||||||
OriginSender: originSender, | ||||||||||||||
DestRecipient: destRecipient, | ||||||||||||||
OriginToken: originToken, | ||||||||||||||
DestToken: destToken, | ||||||||||||||
OriginAmount: originAmount, | ||||||||||||||
DestAmount: destAmount, | ||||||||||||||
OriginFeeAmount: originFeeAmount, | ||||||||||||||
Deadline: deadline, | ||||||||||||||
Nonce: nonce, | ||||||||||||||
ExclusivityRelayer: exclusivityRelayer, | ||||||||||||||
ExclusivityEndTime: exclusivityEndTime, | ||||||||||||||
ZapNative: zapNative, | ||||||||||||||
ZapData: zapData, | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
// Create second transaction with same values | ||||||||||||||
tx := fastbridgev2.IFastBridgeV2BridgeTransactionV2{ | ||||||||||||||
OriginChainId: originChainId, | ||||||||||||||
DestChainId: destChainId, | ||||||||||||||
OriginSender: originSender, | ||||||||||||||
DestRecipient: destRecipient, | ||||||||||||||
OriginToken: originToken, | ||||||||||||||
DestToken: destToken, | ||||||||||||||
OriginAmount: originAmount, | ||||||||||||||
DestAmount: destAmount, | ||||||||||||||
OriginFeeAmount: originFeeAmount, | ||||||||||||||
Deadline: deadline, | ||||||||||||||
Nonce: nonce, | ||||||||||||||
ExclusivityRelayer: exclusivityRelayer, | ||||||||||||||
ExclusivityEndTime: exclusivityEndTime, | ||||||||||||||
ZapNative: zapNative, | ||||||||||||||
ZapData: zapData, | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
expectedEncoded, err := handle.EncodeV2(&bind.CallOpts{Context: i.GetTestContext()}, bridgeTx) | ||||||||||||||
i.NoError(err) | ||||||||||||||
|
||||||||||||||
encoded, err := chain.EncodeBridgeTx(tx) | ||||||||||||||
i.NoError(err) | ||||||||||||||
|
||||||||||||||
i.Equal(expectedEncoded, encoded) | ||||||||||||||
|
||||||||||||||
// Test decoding | ||||||||||||||
decodedTx, err := chain.DecodeBridgeTx(encoded) | ||||||||||||||
i.NoError(err) | ||||||||||||||
|
||||||||||||||
// Verify all fields match the original transaction | ||||||||||||||
i.Equal(tx.OriginChainId, decodedTx.OriginChainId) | ||||||||||||||
i.Equal(tx.DestChainId, decodedTx.DestChainId) | ||||||||||||||
i.Equal(tx.OriginSender, decodedTx.OriginSender) | ||||||||||||||
i.Equal(tx.DestRecipient, decodedTx.DestRecipient) | ||||||||||||||
i.Equal(tx.OriginToken, decodedTx.OriginToken) | ||||||||||||||
i.Equal(tx.DestToken, decodedTx.DestToken) | ||||||||||||||
i.Equal(tx.OriginAmount.String(), decodedTx.OriginAmount.String()) | ||||||||||||||
i.Equal(tx.DestAmount.String(), decodedTx.DestAmount.String()) | ||||||||||||||
i.Equal(tx.OriginFeeAmount.String(), decodedTx.OriginFeeAmount.String()) | ||||||||||||||
i.Equal(tx.Deadline.String(), decodedTx.Deadline.String()) | ||||||||||||||
i.Equal(tx.Nonce.String(), decodedTx.Nonce.String()) | ||||||||||||||
i.Equal(tx.ExclusivityRelayer, decodedTx.ExclusivityRelayer) | ||||||||||||||
i.Equal(tx.ExclusivityEndTime.String(), decodedTx.ExclusivityEndTime.String()) | ||||||||||||||
i.Equal(tx.ZapNative.String(), decodedTx.ZapNative.String()) | ||||||||||||||
i.Equal(tx.ZapData, decodedTx.ZapData) | ||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package chain | ||
|
||
import ( | ||
"encoding/binary" | ||
"fmt" | ||
"math/big" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" | ||
) | ||
|
||
const ( | ||
// Field sizes in bytes. | ||
sizeVersion = 2 | ||
sizeChainID = 4 | ||
sizeAddress = 20 | ||
sizeUint256 = 32 | ||
|
||
// Field offsets in bytes. | ||
offsetVersion = 0 | ||
offsetOriginChainID = offsetVersion + sizeVersion | ||
offsetDestChainID = offsetOriginChainID + sizeChainID | ||
offsetOriginSender = offsetDestChainID + sizeChainID | ||
offsetDestRecipient = offsetOriginSender + sizeAddress | ||
offsetOriginToken = offsetDestRecipient + sizeAddress | ||
offsetDestToken = offsetOriginToken + sizeAddress | ||
offsetOriginAmount = offsetDestToken + sizeAddress | ||
offsetDestAmount = offsetOriginAmount + sizeUint256 | ||
offsetOriginFeeAmount = offsetDestAmount + sizeUint256 | ||
offsetDeadline = offsetOriginFeeAmount + sizeUint256 | ||
offsetNonce = offsetDeadline + sizeUint256 | ||
offsetExclusivityRelayer = offsetNonce + sizeUint256 | ||
offsetExclusivityEndTime = offsetExclusivityRelayer + sizeAddress | ||
offsetZapNative = offsetExclusivityEndTime + sizeUint256 | ||
offsetZapData = offsetZapNative + sizeUint256 | ||
) | ||
|
||
// Helper function to properly encode uint256. | ||
func padUint256(b *big.Int) []byte { | ||
// Convert big.Int to bytes | ||
bytes := b.Bytes() | ||
// Create 32-byte array (initialized to zeros) | ||
result := make([]byte, 32) | ||
// Copy bytes to right side of array (left-pad with zeros) | ||
copy(result[32-len(bytes):], bytes) | ||
return result | ||
} | ||
|
||
// EncodeBridgeTx encodes a bridge transaction into a byte array. | ||
func EncodeBridgeTx(tx fastbridgev2.IFastBridgeV2BridgeTransactionV2) ([]byte, error) { | ||
// Initialize with total size including ZapData | ||
result := make([]byte, offsetZapData+len(tx.ZapData)) | ||
|
||
// Version | ||
result[offsetVersion] = 0 | ||
result[offsetVersion+1] = 2 | ||
|
||
// Chain IDs | ||
binary.BigEndian.PutUint32(result[offsetOriginChainID:offsetOriginChainID+sizeChainID], tx.OriginChainId) | ||
binary.BigEndian.PutUint32(result[offsetDestChainID:offsetDestChainID+sizeChainID], tx.DestChainId) | ||
|
||
// Addresses | ||
copy(result[offsetOriginSender:offsetOriginSender+sizeAddress], tx.OriginSender.Bytes()) | ||
copy(result[offsetDestRecipient:offsetDestRecipient+sizeAddress], tx.DestRecipient.Bytes()) | ||
copy(result[offsetOriginToken:offsetOriginToken+sizeAddress], tx.OriginToken.Bytes()) | ||
copy(result[offsetDestToken:offsetDestToken+sizeAddress], tx.DestToken.Bytes()) | ||
|
||
// uint256 values | ||
copy(result[offsetOriginAmount:offsetOriginAmount+sizeUint256], padUint256(tx.OriginAmount)) | ||
copy(result[offsetDestAmount:offsetDestAmount+sizeUint256], padUint256(tx.DestAmount)) | ||
copy(result[offsetOriginFeeAmount:offsetOriginFeeAmount+sizeUint256], padUint256(tx.OriginFeeAmount)) | ||
copy(result[offsetDeadline:offsetDeadline+sizeUint256], padUint256(tx.Deadline)) | ||
copy(result[offsetNonce:offsetNonce+sizeUint256], padUint256(tx.Nonce)) | ||
|
||
// Exclusivity address | ||
copy(result[offsetExclusivityRelayer:offsetExclusivityRelayer+sizeAddress], tx.ExclusivityRelayer.Bytes()) | ||
|
||
// More uint256 values | ||
copy(result[offsetExclusivityEndTime:offsetExclusivityEndTime+sizeUint256], padUint256(tx.ExclusivityEndTime)) | ||
copy(result[offsetZapNative:offsetZapNative+sizeUint256], padUint256(tx.ZapNative)) | ||
|
||
// Replace append with copy for ZapData | ||
copy(result[offsetZapData:], tx.ZapData) | ||
|
||
return result, nil | ||
} | ||
|
||
// DecodeBridgeTx decodes a byte array into a bridge transaction. | ||
func DecodeBridgeTx(data []byte) (fastbridgev2.IFastBridgeV2BridgeTransactionV2, error) { | ||
if len(data) < offsetZapData { | ||
return fastbridgev2.IFastBridgeV2BridgeTransactionV2{}, fmt.Errorf("data too short: got %d bytes, need at least %d", len(data), offsetZapData) | ||
} | ||
|
||
tx := fastbridgev2.IFastBridgeV2BridgeTransactionV2{ | ||
OriginChainId: binary.BigEndian.Uint32(data[offsetOriginChainID:offsetDestChainID]), | ||
DestChainId: binary.BigEndian.Uint32(data[offsetDestChainID:offsetOriginSender]), | ||
OriginSender: common.BytesToAddress(data[offsetOriginSender:offsetDestRecipient]), | ||
DestRecipient: common.BytesToAddress(data[offsetDestRecipient:offsetOriginToken]), | ||
OriginToken: common.BytesToAddress(data[offsetOriginToken:offsetDestToken]), | ||
DestToken: common.BytesToAddress(data[offsetDestToken:offsetOriginAmount]), | ||
OriginAmount: new(big.Int).SetBytes(data[offsetOriginAmount:offsetDestAmount]), | ||
DestAmount: new(big.Int).SetBytes(data[offsetDestAmount:offsetOriginFeeAmount]), | ||
OriginFeeAmount: new(big.Int).SetBytes(data[offsetOriginFeeAmount:offsetDeadline]), | ||
Deadline: new(big.Int).SetBytes(data[offsetDeadline:offsetNonce]), | ||
Nonce: new(big.Int).SetBytes(data[offsetNonce:offsetExclusivityRelayer]), | ||
ExclusivityRelayer: common.BytesToAddress(data[offsetExclusivityRelayer:offsetExclusivityEndTime]), | ||
ExclusivityEndTime: new(big.Int).SetBytes(data[offsetExclusivityEndTime:offsetZapNative]), | ||
ZapNative: new(big.Int).SetBytes(data[offsetZapNative:offsetZapData]), | ||
ZapData: data[offsetZapData:], | ||
} | ||
Comment on lines
+90
to
+110
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add comprehensive validation in While |
||
|
||
return tx, nil | ||
} | ||
Comment on lines
+94
to
+113
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Implement unit tests for encoding and decoding functions To ensure the reliability of Would you like assistance in creating unit tests for these functions? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve retry mechanism implementation
The retry mechanism needs several improvements:
Apply this diff to improve the implementation:
Additionally, add the following test to cover the retry mechanism:
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 390-395: ethergo/backends/anvil/anvil.go#L390-L395
Added lines #L390 - L395 were not covered by tests
[warning] 397-398: ethergo/backends/anvil/anvil.go#L397-L398
Added lines #L397 - L398 were not covered by tests