Skip to content

Commit

Permalink
Merge pull request #387 from multiversx/migration-support-for-all-bal…
Browse files Browse the repository at this point in the history
…ance-2

Migration support for all balance
  • Loading branch information
iulianpascalau authored Nov 28, 2024
2 parents 59e4ee6 + 9964265 commit ff65d37
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 24 deletions.
2 changes: 1 addition & 1 deletion cmd/migration/config/config-mainnet-eth.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
PrivateKeyFile = "keys/ethereum.sk" # the path to the file containing the relayer eth private key
MultisigContractAddress = "0x1Ff78EB04d44a803E73c44FEf8790c5cAbD14596"
SafeContractAddress = "0x92A26975433A61CF1134802586aa669bAB8B69f3"
GasLimitBase = 350000
GasLimitBase = 400000
GasLimitForEach = 30000
[Eth.GasStation]
Enabled = true
Expand Down
3 changes: 1 addition & 2 deletions cmd/migration/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import (
"context"
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/multiversx/mx-bridge-eth-go/executors/ethereum"
Expand All @@ -11,5 +10,5 @@ import (
// BatchCreator defines the operations implemented by an entity that can create an Ethereum batch message that can be used
// in signing or transfer execution
type BatchCreator interface {
CreateBatchInfo(ctx context.Context, newSafeAddress common.Address, partialMigration map[string]*big.Float) (*ethereum.BatchInfo, error)
CreateBatchInfo(ctx context.Context, newSafeAddress common.Address, partialMigration map[string]*ethereum.FloatWrapper) (*ethereum.BatchInfo, error)
}
29 changes: 29 additions & 0 deletions cmd/migration/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"math/big"
"os"
"strings"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/multiversx/mx-bridge-eth-go/clients"
ethereumClient "github.com/multiversx/mx-bridge-eth-go/clients/ethereum"
"github.com/multiversx/mx-bridge-eth-go/clients/gasManagement"
"github.com/multiversx/mx-bridge-eth-go/clients/gasManagement/factory"
Expand Down Expand Up @@ -309,6 +311,11 @@ func executeTransfer(ctx *cli.Context, cfg config.MigrationToolConfig) error {
return err
}

err = waitForGasPrice(gs)
if err != nil {
return err
}

args := ethereum.ArgsMigrationBatchExecutor{
EthereumChainWrapper: components.ethereumChainWrapper,
CryptoHandler: components.cryptoHandler,
Expand All @@ -328,6 +335,28 @@ func executeTransfer(ctx *cli.Context, cfg config.MigrationToolConfig) error {
return executor.ExecuteTransfer(context.Background())
}

func waitForGasPrice(gs clients.GasHandler) error {
log.Info("Fetching a gas price value. Please wait...")
numRetries := 5
timeBetweenChecks := time.Second

var err error
var gasPrice *big.Int
for i := 0; i < numRetries; i++ {
time.Sleep(timeBetweenChecks)
gasPrice, err = gs.GetCurrentGasPrice()
if err != nil {
log.Debug("waitForGasPrice", "error", err)
continue
}

log.Info("Fetched the gas price", "value", gasPrice.String())
return nil
}

return err
}

func loadConfig(filepath string) (config.MigrationToolConfig, error) {
cfg := config.MigrationToolConfig{}
err := chainCore.LoadTomlFile(&cfg, filepath)
Expand Down
47 changes: 42 additions & 5 deletions executors/ethereum/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ type SignatureInfo struct {
Signature string `json:"Signature"`
}

// FloatWrapper is a wrapper of the big.Float that supports specifying if the value is maximum
type FloatWrapper struct {
*big.Float
IsMax bool
}

var maxValues = []string{"all", "max", "*"}

// TokensBalancesDisplayString will convert the deposit balances into a human-readable string
func TokensBalancesDisplayString(batchInfo *BatchInfo) string {
maxTokenLen := 0
Expand Down Expand Up @@ -69,32 +77,61 @@ func TokensBalancesDisplayString(batchInfo *BatchInfo) string {
}

// ConvertPartialMigrationStringToMap converts the partial migration string to its map representation
func ConvertPartialMigrationStringToMap(partialMigration string) (map[string]*big.Float, error) {
func ConvertPartialMigrationStringToMap(partialMigration string) (map[string]*FloatWrapper, error) {
partsSeparator := ","
tokenAmountSeparator := ":"
parts := strings.Split(partialMigration, partsSeparator)

partialMap := make(map[string]*big.Float)
partialMap := make(map[string]*FloatWrapper)
for _, part := range parts {
part = strings.Trim(part, " \t\n")
splt := strings.Split(part, tokenAmountSeparator)
if len(splt) != 2 {
return nil, fmt.Errorf("%w at token %s, invalid format", errInvalidPartialMigrationString, part)
}

token := splt[0]
if isMaxValueString(splt[1]) {
partialMap[token] = &FloatWrapper{
Float: big.NewFloat(0),
IsMax: true,
}

continue
}

amount, ok := big.NewFloat(0).SetString(splt[1])
if !ok {
return nil, fmt.Errorf("%w at token %s, not a number", errInvalidPartialMigrationString, part)
}

token := splt[0]
if partialMap[token] == nil {
partialMap[token] = big.NewFloat(0).Set(amount)
partialMap[token] = &FloatWrapper{
Float: big.NewFloat(0).Set(amount),
IsMax: false,
}
continue
}

partialMap[token].Add(partialMap[token], amount)
if partialMap[token].IsMax {
// do not attempt to add something to an already max float
continue
}

partialMap[token].Add(partialMap[token].Float, amount)
}

return partialMap, nil
}

func isMaxValueString(value string) bool {
value = strings.ToLower(value)

for _, maxValue := range maxValues {
if value == maxValue {
return true
}
}

return false
}
45 changes: 40 additions & 5 deletions executors/ethereum/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,46 @@ func TestConvertPartialMigrationStringToMap(t *testing.T) {
results, err := ConvertPartialMigrationStringToMap(str)
assert.Nil(t, err)

expectedResults := map[string]*big.Float{
"k": big.NewFloat(3.2),
"f": big.NewFloat(1),
"g": big.NewFloat(0.001),
"h": big.NewFloat(0),
expectedResults := map[string]*FloatWrapper{
"k": {Float: big.NewFloat(3.2)},
"f": {Float: big.NewFloat(1)},
"g": {Float: big.NewFloat(0.001)},
"h": {Float: big.NewFloat(0)},
}

assert.Nil(t, err)
assert.Equal(t, expectedResults, results)
})
t.Run("should work with maximum available", func(t *testing.T) {
t.Parallel()

str := "k:1,l:0,m:*,n:AlL,o:MaX"
results, err := ConvertPartialMigrationStringToMap(str)
assert.Nil(t, err)

expectedResults := map[string]*FloatWrapper{
"k": {Float: big.NewFloat(1)},
"l": {Float: big.NewFloat(0), IsMax: false},
"m": {Float: big.NewFloat(0), IsMax: true},
"n": {Float: big.NewFloat(0), IsMax: true},
"o": {Float: big.NewFloat(0), IsMax: true},
}

assert.Nil(t, err)
assert.Equal(t, expectedResults, results)
})
t.Run("should not add on a token with max value", func(t *testing.T) {
t.Parallel()

str := "k:1,l:0,m:*,k:*,n:1,k:4"
results, err := ConvertPartialMigrationStringToMap(str)
assert.Nil(t, err)

expectedResults := map[string]*FloatWrapper{
"k": {Float: big.NewFloat(0), IsMax: true},
"l": {Float: big.NewFloat(0), IsMax: false},
"m": {Float: big.NewFloat(0), IsMax: true},
"n": {Float: big.NewFloat(1), IsMax: false},
}

assert.Nil(t, err)
Expand Down
15 changes: 8 additions & 7 deletions executors/ethereum/migrationBatchCreator.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func NewMigrationBatchCreator(args ArgsMigrationBatchCreator) (*migrationBatchCr
}

// CreateBatchInfo creates an instance of type BatchInfo
func (creator *migrationBatchCreator) CreateBatchInfo(ctx context.Context, newSafeAddress common.Address, partialMigration map[string]*big.Float) (*BatchInfo, error) {
func (creator *migrationBatchCreator) CreateBatchInfo(ctx context.Context, newSafeAddress common.Address, partialMigration map[string]*FloatWrapper) (*BatchInfo, error) {
creator.logger.Info("started the batch creation process...")

depositStart := uint64(0) // deposits inside a batch are not tracked, we can start from 0
Expand All @@ -78,7 +78,7 @@ func (creator *migrationBatchCreator) CreateBatchInfo(ctx context.Context, newSa
"free batch ID", freeBatchID, "time took", endTime.Sub(startTime))

if partialMigration == nil {
partialMigration = make(map[string]*big.Float)
partialMigration = make(map[string]*FloatWrapper)
}

tokensList, err := creator.getTokensList(ctx, partialMigration)
Expand Down Expand Up @@ -175,7 +175,7 @@ func (creator *migrationBatchCreator) checkAvailableBatch(
return nil
}

func (creator *migrationBatchCreator) getTokensList(ctx context.Context, partialMigration map[string]*big.Float) ([]string, error) {
func (creator *migrationBatchCreator) getTokensList(ctx context.Context, partialMigration map[string]*FloatWrapper) ([]string, error) {
tokens, err := creator.mvxDataGetter.GetAllKnownTokens(ctx)
if err != nil {
return nil, err
Expand Down Expand Up @@ -224,7 +224,7 @@ func (creator *migrationBatchCreator) fetchERC20ContractsAddresses(ctx context.C
return deposits, nil
}

func (creator *migrationBatchCreator) fetchBalances(ctx context.Context, deposits []*DepositInfo, partialMigration map[string]*big.Float) error {
func (creator *migrationBatchCreator) fetchBalances(ctx context.Context, deposits []*DepositInfo, partialMigration map[string]*FloatWrapper) error {
for _, deposit := range deposits {
balance, err := creator.erc20ContractsHolder.BalanceOf(ctx, deposit.ContractAddress, creator.safeContractAddress)
if err != nil {
Expand All @@ -237,9 +237,10 @@ func (creator *migrationBatchCreator) fetchBalances(ctx context.Context, deposit
}
deposit.Decimals = decimals

trimAmount := partialMigration[deposit.Token]
if trimAmount != nil {
denominatedTrimAmount := big.NewFloat(0).Set(trimAmount)
trimValue := partialMigration[deposit.Token]
trimIsNeeded := trimValue != nil && !trimValue.IsMax
if trimIsNeeded {
denominatedTrimAmount := big.NewFloat(0).Set(trimValue.Float)
multiplier := big.NewInt(10)
multiplier.Exp(multiplier, big.NewInt(int64(deposit.Decimals)), nil)
denominatedTrimAmount.Mul(denominatedTrimAmount, big.NewFloat(0).SetInt(multiplier))
Expand Down
62 changes: 58 additions & 4 deletions executors/ethereum/migrationBatchCreator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -561,11 +561,65 @@ func TestMigrationBatchCreator_CreateBatchInfo(t *testing.T) {
expectedBatch.DepositsInfo[1].DenominatedAmount, _ = big.NewFloat(0).SetString("0.000000000000000020")
expectedBatch.DepositsInfo[2].DenominatedAmount, _ = big.NewFloat(0).SetString("120")

partialMap := map[string]*big.Float{
"tkn1": big.NewFloat(0.017),
"tkn3": big.NewFloat(120),
token2Value, _ := big.NewFloat(0).SetString("0.000000000000000020")
partialMap := map[string]*FloatWrapper{
"tkn1": {Float: big.NewFloat(0.017)},
"tkn2": {Float: token2Value},
"tkn3": {Float: big.NewFloat(120)},
}

batch, err := creator.CreateBatchInfo(context.Background(), newSafeContractAddress, partialMap)
assert.Nil(t, err)
assert.Equal(t, expectedBatch, batch)
})
t.Run("with trim and all quantity", func(t *testing.T) {
expectedBatch := &BatchInfo{
OldSafeContractAddress: safeContractAddress.String(),
NewSafeContractAddress: newSafeContractAddress.String(),
BatchID: firstFreeBatchId,
MessageHash: common.HexToHash("0x8c1b5bb16418a3dec1990fe8c0cd8363e9e56ca6870b6c7f0e7496f4411f60b0"),
DepositsInfo: []*DepositInfo{
{
DepositNonce: 1,
Token: "tkn1",
ContractAddressString: common.BytesToAddress(tkn1Erc20Address).String(),
ContractAddress: common.BytesToAddress(tkn1Erc20Address),
Amount: big.NewInt(17),
AmountString: "17",
DenominatedAmountString: "0.017",
Decimals: 3,
},
{
DepositNonce: 2,
Token: "tkn2",
ContractAddressString: common.BytesToAddress(tkn2Erc20Address).String(),
ContractAddress: common.BytesToAddress(tkn2Erc20Address),
Amount: big.NewInt(38),
AmountString: "38",
DenominatedAmountString: "0.000000000000000038",
Decimals: 18,
},
{
DepositNonce: 3,
Token: "tkn3",
ContractAddressString: common.BytesToAddress(tkn3Erc20Address).String(),
ContractAddress: common.BytesToAddress(tkn3Erc20Address),
Amount: big.NewInt(120),
AmountString: "120",
DenominatedAmountString: "120",
Decimals: 0,
},
},
}
expectedBatch.DepositsInfo[0].DenominatedAmount, _ = big.NewFloat(0).SetString("0.017")
expectedBatch.DepositsInfo[1].DenominatedAmount, _ = big.NewFloat(0).SetString("0.000000000000000038")
expectedBatch.DepositsInfo[2].DenominatedAmount, _ = big.NewFloat(0).SetString("120")

partialMap := map[string]*FloatWrapper{
"tkn1": {Float: big.NewFloat(0.017)},
"tkn2": {Float: big.NewFloat(0), IsMax: true},
"tkn3": {Float: big.NewFloat(120)},
}
partialMap["tkn2"], _ = big.NewFloat(0).SetString("0.000000000000000020")

batch, err := creator.CreateBatchInfo(context.Background(), newSafeContractAddress, partialMap)
assert.Nil(t, err)
Expand Down

0 comments on commit ff65d37

Please sign in to comment.