Vulnerability: [High] Function MigrateWithdrawal() may set gas limit so high for old withdrawals when migrating them by mistake and they can't be relayed in the L1 and users funds would be lost
Severity: medium

Description:
Function `MigrateWithdrawal()` in migrate.go will turn a LegacyWithdrawal into a bedrock style Withdrawal. it should set a min gas limit value for the withdrawals. to calculate a gas limit contract overestimates it and if the value goes higher than L1 maximum gas in the block then the withdraw can't be relayed in the L1 and users funds would be lost while the withdraw could be possible before the migration it won't be possible after it.\\nThis is `MigrateWithdrawal()` code:\\n```\\n// MigrateWithdrawal will turn a LegacyWithdrawal into a bedrock\\n// style Withdrawal.\\nfunc MigrateWithdrawal(withdrawal *LegacyWithdrawal, l1CrossDomainMessenger *common.Address) (*Withdrawal, error) {\\n // Attempt to parse the value\\n value, err := withdrawal.Value()\\n if err != nil {\\n  return nil, fmt.Errorf("cannot migrate withdrawal: %w", err)\\n }\\n\\n abi, err := bindings.L1CrossDomainMessengerMetaData.GetAbi()\\n if err != nil {\\n  return nil, err\\n }\\n\\n // Migrated withdrawals are specified as version 0. Both the\\n // L2ToL1MessagePasser and the CrossDomainMessenger use the same\\n // versioning scheme. Both should be set to version 0\\n versionedNonce := EncodeVersionedNonce(withdrawal.Nonce, new(big.Int))\\n // Encode the call to `relayMessage` on the `CrossDomainMessenger`.\\n // The minGasLimit can safely be 0 here.\\n data, err := abi.Pack(\\n  "relayMessage",\\n  versionedNonce,\\n  withdrawal.Sender,\\n  withdrawal.Target,\\n  value,\\n  new(big.Int),\\n  withdrawal.Data,\\n )\\n if err != nil {\\n  return nil, fmt.Errorf("cannot abi encode relayMessage: %w", err)\\n }\\n\\n // Set the outer gas limit. This cannot be zero\\n gasLimit := uint64(len(data)*16 + 200_000)\\n\\n w := NewWithdrawal(\\n  versionedNonce,\\n  &predeploys.L2CrossDomainMessengerAddr,\\n  l1CrossDomainMessenger,\\n  value,\\n  new(big.Int).SetUint64(gasLimit),\\n  data,\\n )\\n return w, nil\\n}\\n```\\n\\nAs you can see it sets the gas limit as `gasLimit := uint64(len(data)*16 + 200_000)` and contract set 16 gas per data byte but in Ethereum when data byte is 0 then the overhead intrinsic gas is 4 and contract overestimate the gas limit by setting 16 gas for each data. this can cause messages with big data(which calculated gas is higher than 30M) to not be relay able in the L1 because if transaction gas set lower than calculated gas then OptimisimPortal would reject it and if gas set higher than calculated gas then miners would reject the transaction. while if code correctly estimated the required gas the gas limit could be lower by the factor of 4. for example a message with about 2M zeros would get gas limit higher than 30M and it won't be withdrawable in the L1 while the real gas limit is 8M which is relayable.

Impact:
some withdraw messages from L2 to L1 that could be relayed before the migration can't be relayed after the migration because of the wrong gas estimation.

Recommended mitigation:
calculate gas estimation correctly, 4 for 0 bytes and 16 for none zero bytes.