Skip to content
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

Merge v3 v3p5 2024.10.16 #358

Merged
merged 67 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
e76d3c9
- added migration batch creator components
iulianpascalau Sep 2, 2024
09c9833
- fixes
iulianpascalau Sep 2, 2024
0b73e33
- added signing capability to the migration tool
iulianpascalau Sep 3, 2024
2fe6240
- linter fix
iulianpascalau Sep 3, 2024
703a778
- made the migration tool automatically fetch the tokens list
iulianpascalau Sep 3, 2024
5d860dc
- fixes
iulianpascalau Sep 3, 2024
1a5f57d
- fixes after review: renaming
iulianpascalau Sep 4, 2024
55fd6db
Merge pull request #330 from multiversx/create-migration-app
iulianpascalau Sep 5, 2024
2b02015
Merge branch 'feat/migration-app' into signing
iulianpascalau Sep 5, 2024
67ea3dc
- fixes after review
iulianpascalau Sep 5, 2024
a08de87
- fixes
iulianpascalau Sep 5, 2024
c1ceb9c
Merge branch 'signing' into fetch-tokens-list
iulianpascalau Sep 5, 2024
afe1fb1
Merge pull request #331 from multiversx/signing
iulianpascalau Sep 5, 2024
7dfe930
Merge branch 'feat/migration-app' into fetch-tokens-list
iulianpascalau Sep 5, 2024
d276170
- minor config fix
iulianpascalau Sep 6, 2024
2b97dfc
- added migration executor implementation
iulianpascalau Sep 6, 2024
b833567
Merge branch 'fetch-tokens-list' into execute
iulianpascalau Sep 6, 2024
759a9a8
Merge pull request #333 from multiversx/fetch-tokens-list
dragos-rebegea Sep 6, 2024
ed52cc4
- fixes after merge
iulianpascalau Sep 6, 2024
55fc59f
Merge branch 'feat/migration-app' into execute
iulianpascalau Sep 6, 2024
d652f62
- fixes in test files
iulianpascalau Sep 6, 2024
dcce982
Merge remote-tracking branch 'origin/execute' into execute
iulianpascalau Sep 6, 2024
ad8c3fd
- fixes after review
iulianpascalau Sep 6, 2024
a8ceae9
Merge pull request #334 from multiversx/execute
dragos-rebegea Sep 6, 2024
2d7593c
- migration tool fixes
iulianpascalau Sep 13, 2024
4ac7748
Merge pull request #340 from multiversx/migration-fixes
iulianpascalau Sep 16, 2024
b8e82c1
Merge branch 'feat/v3' into merge-feat-v3-migration-app-2024.09.16
iulianpascalau Sep 16, 2024
c91cdef
Merge pull request #341 from multiversx/merge-feat-v3-migration-app-2…
iulianpascalau Sep 16, 2024
e387d46
Merge pull request #329 from multiversx/feat/migration-app
iulianpascalau Sep 16, 2024
22440b2
- new contracts
iulianpascalau Sep 26, 2024
f0421b6
- new contracts
iulianpascalau Sep 26, 2024
121e86d
- added missing set for the sc bridge proxy
iulianpascalau Sep 27, 2024
3fc9ccb
- adding execution protections
iulianpascalau Sep 30, 2024
2eac664
- new contracts
iulianpascalau Sep 30, 2024
8b9dc86
- finished implementation
iulianpascalau Sep 30, 2024
80e3c41
- new contracts
iulianpascalau Oct 1, 2024
64a673b
- fix after review
iulianpascalau Oct 1, 2024
d025404
- integrated new contracts
iulianpascalau Oct 1, 2024
63f6ca4
Merge pull request #344 from multiversx/new-contracts-2024.09.26
iulianpascalau Oct 1, 2024
e4d90a2
Merge branch 'feat/v3' into mvx-executor-improvement
iulianpascalau Oct 1, 2024
7e48630
- integrated the released version of the price aggregator contract
iulianpascalau Oct 2, 2024
680d586
Merge pull request #347 from multiversx/integrated-released-price-agg…
iulianpascalau Oct 2, 2024
ac8b0ea
Merge branch 'feat/v3' into mvx-executor-improvement
iulianpascalau Oct 2, 2024
bf599e6
- integrated the new version of the price aggregator contract
iulianpascalau Oct 2, 2024
ca973ab
Merge pull request #348 from multiversx/new-price-aggregator-contract…
dragos-rebegea Oct 2, 2024
be16359
Merge branch 'feat/v3' into mvx-executor-improvement
iulianpascalau Oct 2, 2024
0a8e83d
Merge pull request #345 from multiversx/mvx-executor-improvement
iulianpascalau Oct 2, 2024
d4ebf70
- integrated the new contracts
iulianpascalau Oct 4, 2024
145fab3
Merge pull request #349 from multiversx/new-contracts-2024.10.04
iulianpascalau Oct 4, 2024
63662ed
- added amount on the migration tool (for tests)
iulianpascalau Oct 4, 2024
7ddfdf8
Merge pull request #350 from multiversx/amount-in-migration-tool
iulianpascalau Oct 4, 2024
fcf06af
- integrated the price aggregator
iulianpascalau Oct 4, 2024
b7d377d
- renamed constants
iulianpascalau Oct 4, 2024
4764d80
- new contract & fixes
iulianpascalau Oct 4, 2024
6d36769
- new contracts
iulianpascalau Oct 4, 2024
5e47bc9
Merge pull request #351 from multiversx/new-price-aggregator-2024.10.04
iulianpascalau Oct 4, 2024
b332105
- new price-aggregator contract
iulianpascalau Oct 8, 2024
d93f4b1
Merge pull request #352 from multiversx/new-price-aggregator-2024.10.08
iulianpascalau Oct 8, 2024
0391c06
- removed TODO & added extra tests for withdrawals
iulianpascalau Oct 9, 2024
627afb9
- removed useless check
iulianpascalau Oct 9, 2024
af47429
Merge pull request #353 from multiversx/extra-check-in-e2e-tests
iulianpascalau Oct 10, 2024
750efde
- fixed the migration app to use correct batch ID
iulianpascalau Oct 12, 2024
5c14856
Merge pull request #354 from multiversx/fix-migration-app
iulianpascalau Oct 15, 2024
6f981c5
- integrated new contracts
iulianpascalau Oct 16, 2024
77b339d
Merge pull request #356 from multiversx/new-contracts-2024.10.15
iulianpascalau Oct 16, 2024
49e601c
Merge branch 'feat/v3' into merge-v3-v3p5-2024.10.16
iulianpascalau Oct 16, 2024
c76ea5f
- linter fix
iulianpascalau Oct 16, 2024
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
3 changes: 3 additions & 0 deletions clients/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,7 @@ var (

// ErrNoPendingBatchAvailable signals that no pending batch is available
ErrNoPendingBatchAvailable = errors.New("no pending batch available")

// ErrNilCryptoHandler signals that a nil crypto handler was provided
ErrNilCryptoHandler = errors.New("nil crypto handler")
)
40 changes: 15 additions & 25 deletions clients/ethereum/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ package ethereum

import (
"context"
"crypto/ecdsa"
"fmt"
"math/big"
"sync"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/multiversx/mx-bridge-eth-go/clients"
Expand All @@ -34,7 +32,7 @@ type ArgsEthereumClient struct {
Log chainCore.Logger
AddressConverter core.AddressConverter
Broadcaster Broadcaster
PrivateKey *ecdsa.PrivateKey
CryptoHandler CryptoHandler
TokensMapper TokensMapper
SignatureHolder SignaturesHolder
SafeContractAddress common.Address
Expand All @@ -52,8 +50,7 @@ type client struct {
log chainCore.Logger
addressConverter core.AddressConverter
broadcaster Broadcaster
privateKey *ecdsa.PrivateKey
publicKey *ecdsa.PublicKey
cryptoHandler CryptoHandler
tokensMapper TokensMapper
signatureHolder SignaturesHolder
safeContractAddress common.Address
Expand All @@ -76,20 +73,13 @@ func NewEthereumClient(args ArgsEthereumClient) (*client, error) {
return nil, err
}

publicKey := args.PrivateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
return nil, errPublicKeyCast
}

c := &client{
clientWrapper: args.ClientWrapper,
erc20ContractsHandler: args.Erc20ContractsHandler,
log: args.Log,
addressConverter: args.AddressConverter,
broadcaster: args.Broadcaster,
privateKey: args.PrivateKey,
publicKey: publicKeyECDSA,
cryptoHandler: args.CryptoHandler,
tokensMapper: args.TokensMapper,
signatureHolder: args.SignatureHolder,
safeContractAddress: args.SafeContractAddress,
Expand All @@ -102,7 +92,7 @@ func NewEthereumClient(args ArgsEthereumClient) (*client, error) {
}

c.log.Info("NewEthereumClient",
"relayer address", crypto.PubkeyToAddress(*publicKeyECDSA),
"relayer address", c.cryptoHandler.GetAddress(),
"safe contract address", c.safeContractAddress.String())

return c, err
Expand All @@ -124,8 +114,8 @@ func checkArgs(args ArgsEthereumClient) error {
if check.IfNil(args.Broadcaster) {
return errNilBroadcaster
}
if args.PrivateKey == nil {
return clients.ErrNilPrivateKey
if check.IfNil(args.CryptoHandler) {
return clients.ErrNilCryptoHandler
}
if check.IfNil(args.TokensMapper) {
return clients.ErrNilTokensMapper
Expand Down Expand Up @@ -256,7 +246,7 @@ func (c *client) WasExecuted(ctx context.Context, batchID uint64) (bool, error)

// BroadcastSignatureForMessageHash will send the signature for the provided message hash
func (c *client) BroadcastSignatureForMessageHash(msgHash common.Hash) {
signature, err := crypto.Sign(msgHash.Bytes(), c.privateKey)
signature, err := c.cryptoHandler.Sign(msgHash)
if err != nil {
c.log.Error("error generating signature", "msh hash", msgHash, "error", err)
return
Expand All @@ -267,6 +257,11 @@ func (c *client) BroadcastSignatureForMessageHash(msgHash common.Hash) {

// GenerateMessageHash will generate the message hash based on the provided batch
func (c *client) GenerateMessageHash(batch *batchProcessor.ArgListsBatch, batchId uint64) (common.Hash, error) {
return GenerateMessageHash(batch, batchId)
}

// GenerateMessageHash will generate the message hash based on the provided batch
func GenerateMessageHash(batch *batchProcessor.ArgListsBatch, batchId uint64) (common.Hash, error) {
if batch == nil {
return common.Hash{}, clients.ErrNilBatch
}
Expand Down Expand Up @@ -336,9 +331,7 @@ func (c *client) ExecuteTransfer(
return "", fmt.Errorf("%w in client.ExecuteTransfer", clients.ErrMultisigContractPaused)
}

fromAddress := crypto.PubkeyToAddress(*c.publicKey)

nonce, err := c.getNonce(ctx, fromAddress)
nonce, err := c.getNonce(ctx, c.cryptoHandler.GetAddress())
if err != nil {
return "", err
}
Expand All @@ -348,7 +341,7 @@ func (c *client) ExecuteTransfer(
return "", err
}

auth, err := bind.NewKeyedTransactorWithChainID(c.privateKey, chainId)
auth, err := c.cryptoHandler.CreateKeyedTransactor(chainId)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -496,10 +489,7 @@ func (c *client) WhitelistedTokens(ctx context.Context, token common.Address) (b
}

func (c *client) checkRelayerFundsForFee(ctx context.Context, transferFee *big.Int) error {

ethereumRelayerAddress := crypto.PubkeyToAddress(*c.publicKey)

existingBalance, err := c.clientWrapper.BalanceAt(ctx, ethereumRelayerAddress, nil)
existingBalance, err := c.clientWrapper.BalanceAt(ctx, c.cryptoHandler.GetAddress(), nil)
if err != nil {
return err
}
Expand Down
89 changes: 67 additions & 22 deletions clients/ethereum/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/multiversx/mx-bridge-eth-go/clients"
"github.com/multiversx/mx-bridge-eth-go/clients/ethereum/contract"
bridgeCore "github.com/multiversx/mx-bridge-eth-go/core"
Expand All @@ -33,8 +32,6 @@ var expectedRecipients = []common.Address{common.BytesToAddress([]byte("to1")),
var expectedNonces = []*big.Int{big.NewInt(10), big.NewInt(30)}

func createMockEthereumClientArgs() ArgsEthereumClient {
sk, _ := crypto.HexToECDSA("9bb971db41e3815a669a71c3f1bcb24e0b81f21e04bf11faa7a34b9b40e7cfb1")

addressConverter, err := converters.NewAddressConverter()
if err != nil {
panic(err)
Expand All @@ -46,7 +43,7 @@ func createMockEthereumClientArgs() ArgsEthereumClient {
Log: logger.GetOrCreate("test"),
AddressConverter: addressConverter,
Broadcaster: &testsCommon.BroadcasterStub{},
PrivateKey: sk,
CryptoHandler: &bridgeTests.CryptoHandlerStub{},
TokensMapper: &bridgeTests.TokensMapperStub{
ConvertTokenCalled: func(ctx context.Context, sourceBytes []byte) ([]byte, error) {
return append([]byte("ERC20"), sourceBytes...), nil
Expand Down Expand Up @@ -137,12 +134,12 @@ func TestNewEthereumClient(t *testing.T) {
assert.Equal(t, errNilBroadcaster, err)
assert.True(t, check.IfNil(c))
})
t.Run("nil private key", func(t *testing.T) {
t.Run("nil crypto handler", func(t *testing.T) {
args := createMockEthereumClientArgs()
args.PrivateKey = nil
args.CryptoHandler = nil
c, err := NewEthereumClient(args)

assert.Equal(t, clients.ErrNilPrivateKey, err)
assert.Equal(t, clients.ErrNilCryptoHandler, err)
assert.True(t, check.IfNil(c))
})
t.Run("nil tokens mapper", func(t *testing.T) {
Expand Down Expand Up @@ -475,23 +472,54 @@ func TestClient_GenerateMessageHash(t *testing.T) {
func TestClient_BroadcastSignatureForMessageHash(t *testing.T) {
t.Parallel()

expectedSig := "b556014dd984183e4662dc3204e522a5a92093fd6f64bb2da9c1b66b8d5ad12d774e05728b83c76bf09bb91af93ede4118f59aa949c7d02c86051dd0fa140c9900"
broadcastCalled := false
t.Run("sign failed should not broadcast", func(t *testing.T) {
t.Parallel()

hash := common.HexToHash("c99286352d865e33f1747761cbd440a7906b9bd8a5261cb6909e5ba18dd19b08")
args := createMockEthereumClientArgs()
args.Broadcaster = &testsCommon.BroadcasterStub{
BroadcastSignatureCalled: func(signature []byte, messageHash []byte) {
assert.Equal(t, hash.Bytes(), messageHash)
assert.Equal(t, expectedSig, hex.EncodeToString(signature))
broadcastCalled = true
},
}
expectedError := errors.New("expected error")
hash := common.HexToHash("hash")
args := createMockEthereumClientArgs()
args.Broadcaster = &testsCommon.BroadcasterStub{
BroadcastSignatureCalled: func(signature []byte, messageHash []byte) {
assert.Fail(t, "should have not called bradcast")
},
}
args.CryptoHandler = &bridgeTests.CryptoHandlerStub{
SignCalled: func(msgHash common.Hash) ([]byte, error) {
assert.Equal(t, hash.Bytes(), msgHash.Bytes())
return nil, expectedError
},
}

c, _ := NewEthereumClient(args)
c.BroadcastSignatureForMessageHash(hash)
c, _ := NewEthereumClient(args)
c.BroadcastSignatureForMessageHash(hash)
})
t.Run("should work", func(t *testing.T) {
t.Parallel()

expectedSig := "expected sig"
broadcastCalled := false

hash := common.HexToHash("hash")
args := createMockEthereumClientArgs()
args.Broadcaster = &testsCommon.BroadcasterStub{
BroadcastSignatureCalled: func(signature []byte, messageHash []byte) {
assert.Equal(t, hash.Bytes(), messageHash)
assert.Equal(t, expectedSig, string(signature))
broadcastCalled = true
},
}
args.CryptoHandler = &bridgeTests.CryptoHandlerStub{
SignCalled: func(msgHash common.Hash) ([]byte, error) {
assert.Equal(t, hash.Bytes(), msgHash.Bytes())
return []byte(expectedSig), nil
},
}

assert.True(t, broadcastCalled)
c, _ := NewEthereumClient(args)
c.BroadcastSignatureForMessageHash(hash)

assert.True(t, broadcastCalled)
})
}

func TestClient_WasExecuted(t *testing.T) {
Expand All @@ -517,6 +545,11 @@ func TestClient_ExecuteTransfer(t *testing.T) {
t.Parallel()

args := createMockEthereumClientArgs()
args.CryptoHandler = &bridgeTests.CryptoHandlerStub{
CreateKeyedTransactorCalled: func(chainId *big.Int) (*bind.TransactOpts, error) {
return &bind.TransactOpts{}, nil
},
}
batch := createMockTransferBatch()
argLists := batchProcessor.ExtractListMvxToEth(batch)
signatures := make([][]byte, 10)
Expand Down Expand Up @@ -589,6 +622,18 @@ func TestClient_ExecuteTransfer(t *testing.T) {
assert.Equal(t, "", hash)
assert.True(t, errors.Is(err, expectedErr))
})
t.Run("create keyed transactor fails", func(t *testing.T) {
expectedErr := errors.New("expected error create keyed transactor")
c, _ := NewEthereumClient(args)
c.cryptoHandler = &bridgeTests.CryptoHandlerStub{
CreateKeyedTransactorCalled: func(chainId *big.Int) (*bind.TransactOpts, error) {
return nil, expectedErr
},
}
hash, err := c.ExecuteTransfer(context.Background(), common.Hash{}, argLists, batch.ID, 10)
assert.Equal(t, "", hash)
assert.True(t, errors.Is(err, expectedErr))
})
t.Run("get current gas price fails", func(t *testing.T) {
expectedErr := errors.New("expected error get current gas price")
c, _ := NewEthereumClient(args)
Expand All @@ -599,7 +644,7 @@ func TestClient_ExecuteTransfer(t *testing.T) {
}
hash, err := c.ExecuteTransfer(context.Background(), common.Hash{}, argLists, batch.ID, 10)
assert.Equal(t, "", hash)
assert.True(t, errors.Is(err, expectedErr))
assert.ErrorIs(t, err, expectedErr)
})
t.Run("not enough quorum", func(t *testing.T) {
c, _ := NewEthereumClient(args)
Expand Down
63 changes: 63 additions & 0 deletions clients/ethereum/cryptoHandler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package ethereum

import (
"crypto/ecdsa"
"math/big"
"os"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
ethCrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/multiversx/mx-bridge-eth-go/core/converters"
)

type cryptoHandler struct {
privateKey *ecdsa.PrivateKey
publicKey *ecdsa.PublicKey
address common.Address
}

// NewCryptoHandler creates a new instance of type cryptoHandler able to sign messages and provide the containing public key
func NewCryptoHandler(privateKeyFilename string) (*cryptoHandler, error) {
privateKeyBytes, err := os.ReadFile(privateKeyFilename)
if err != nil {
return nil, err
}
privateKeyString := converters.TrimWhiteSpaceCharacters(string(privateKeyBytes))
privateKey, err := ethCrypto.HexToECDSA(privateKeyString)
if err != nil {
return nil, err
}

publicKey := privateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
return nil, errPublicKeyCast
}

return &cryptoHandler{
privateKey: privateKey,
publicKey: publicKeyECDSA,
address: ethCrypto.PubkeyToAddress(*publicKeyECDSA),
}, nil
}

// Sign signs the provided message hash with the containing private key
func (handler *cryptoHandler) Sign(msgHash common.Hash) ([]byte, error) {
return ethCrypto.Sign(msgHash.Bytes(), handler.privateKey)
}

// GetAddress returns the corresponding address of the containing public key
func (handler *cryptoHandler) GetAddress() common.Address {
return handler.address
}

// CreateKeyedTransactor creates a keyed transactor used to create transactions on Ethereum chain
func (handler *cryptoHandler) CreateKeyedTransactor(chainId *big.Int) (*bind.TransactOpts, error) {
return bind.NewKeyedTransactorWithChainID(handler.privateKey, chainId)
}

// IsInterfaceNil returns true if there is no value under the interface
func (handler *cryptoHandler) IsInterfaceNil() bool {
return handler == nil
}
Loading
Loading