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

Execute EIP-1559 transaction #1957

Merged
merged 8 commits into from
Aug 16, 2023
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import io.gnosis.data.models.Owner
import io.gnosis.data.models.Safe
import io.gnosis.data.repositories.CredentialsRepository
import io.gnosis.data.repositories.SafeRepository
import io.gnosis.data.utils.toSignatureString
import io.gnosis.safe.BuildConfig
import io.gnosis.safe.Error
import io.gnosis.safe.notifications.models.PushNotification
Expand Down Expand Up @@ -234,7 +235,7 @@ class NotificationRepository(
val registrationHash = registrationHashForChain.hexToByteArray()
owners.forEach {
try {
val signature = credentialsRepository.signWithOwner(it, registrationHash).addHexPrefix()
val signature = credentialsRepository.signWithOwner(it, registrationHash).toSignatureString().addHexPrefix()
addSignature(signature)
} catch (e: Exception) {
Timber.e(e, "Exception while signing")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import io.gnosis.data.repositories.SafeRepository
import io.gnosis.data.repositories.TransactionRepository
import io.gnosis.data.utils.SemVer
import io.gnosis.data.utils.calculateSafeTxHash
import io.gnosis.data.utils.toSignatureString
import io.gnosis.safe.ui.assets.coins.CoinsViewData
import io.gnosis.safe.ui.base.AppDispatchers
import io.gnosis.safe.ui.base.BaseStateViewModel
Expand Down Expand Up @@ -240,7 +241,7 @@ class SendAssetReviewViewModel
signature = signedSafeTxHash ?: credentialsRepository.signWithOwner(
selectedOwner,
safeTxHash.hexToByteArray()
),
).toSignatureString(),
safeTxGas = txExecutionInfo.safeTxGas.toLong(),
safeTxHash = safeTxHash,
sender = selectedOwner.address
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ data class OwnerViewData(
val name: String?,
val type: Owner.Type,
val balance: String? = null,
val zeroBalance: Boolean = true
val zeroBalance: Boolean = false
)

fun Owner.Type.stringRes(): Int =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import io.gnosis.data.repositories.SafeRepository
import io.gnosis.data.repositories.TransactionRepository
import io.gnosis.data.utils.SemVer
import io.gnosis.data.utils.calculateSafeTxHash
import io.gnosis.data.utils.toSignatureString
import io.gnosis.safe.Tracker
import io.gnosis.safe.ui.base.AppDispatchers
import io.gnosis.safe.ui.base.BaseStateViewModel
Expand Down Expand Up @@ -100,7 +101,7 @@ class ConfirmRejectionViewModel
safeAddress = safe.address,
toAddress = safe.address,
nonce = rejectionExecutionInfo.nonce,
signature = signedSafeTxHash ?: credentialsRepository.signWithOwner(selectedOwner, safeTxHash.hexToByteArray()),
signature = signedSafeTxHash ?: credentialsRepository.signWithOwner(selectedOwner, safeTxHash.hexToByteArray()).toSignatureString(),
safeTxGas = rejectionExecutionInfo.safeTxGas.toLong(),
safeTxHash = safeTxHash,
sender = selectedOwner.address
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import io.gnosis.data.repositories.SafeRepository
import io.gnosis.data.repositories.TransactionRepository
import io.gnosis.data.utils.SemVer
import io.gnosis.data.utils.calculateSafeTxHash
import io.gnosis.data.utils.toSignatureString
import io.gnosis.safe.Tracker
import io.gnosis.safe.ui.base.AppDispatchers
import io.gnosis.safe.ui.base.BaseStateViewModel
Expand Down Expand Up @@ -231,7 +232,7 @@ class TransactionDetailsViewModel
signedSafeTxHash = signedSafeTxHash ?: credentialsRepository.signWithOwner(
selectedOwner!!,
executionInfo.safeTxHash.hexToByteArray()
)
).toSignatureString()
)
}.onSuccess {
txDetails = it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ import io.gnosis.safe.databinding.TxReviewSettingsChangeBinding
import io.gnosis.safe.databinding.TxReviewTransferBinding
import io.gnosis.safe.di.components.ViewComponent
import io.gnosis.safe.ui.base.BaseStateViewModel.ViewAction.Loading
import io.gnosis.safe.ui.base.BaseStateViewModel.ViewAction.NavigateTo
import io.gnosis.safe.ui.base.BaseStateViewModel.ViewAction.ShowError
import io.gnosis.safe.ui.base.SafeOverviewBaseFragment
import io.gnosis.safe.ui.base.fragment.BaseViewBindingFragment
import io.gnosis.safe.ui.transactions.details.SigningMode
import io.gnosis.safe.ui.transactions.details.TransactionDetailsFragmentDirections
import io.gnosis.safe.ui.transactions.details.viewdata.TransactionInfoViewData
import io.gnosis.safe.utils.BalanceFormatter
import io.gnosis.safe.utils.ParamSerializer
Expand Down Expand Up @@ -210,8 +210,7 @@ class TxReviewFragment : BaseViewBindingFragment<FragmentTxReviewBinding>() {
txDetails!!.txData?.dataDecoded?.parameters?.getOrNull(0)?.let { param ->
if (param is Param.Bytes && param.valueDecoded != null) {
findNavController().navigate(
//TODO adjust direction
TransactionDetailsFragmentDirections.actionTransactionDetailsFragmentToTransactionDetailsActionMultisendFragment(
TxReviewFragmentDirections.actionTxReviewFragmentToTransactionDetailsActionMultisendFragment(
chain,
paramSerializer.serializeDecodedValues(param.valueDecoded!!),
paramSerializer.serializeAddressInfoIndex(txDetails!!.txData?.addressInfoIndex)
Expand All @@ -226,8 +225,7 @@ class TxReviewFragment : BaseViewBindingFragment<FragmentTxReviewBinding>() {
txDataDecoded.setOnClickListener {
txDetails!!.txData?.let {
findNavController().navigate(
//TODO adjust direction
TransactionDetailsFragmentDirections.actionTransactionDetailsFragmentToTransactionDetailsActionFragment(
TxReviewFragmentDirections.actionTxReviewFragmentToTransactionDetailsActionFragment(
chain = chain,
action = it.dataDecoded?.method ?: "",
data = it.hexData ?: "",
Expand Down Expand Up @@ -304,6 +302,10 @@ class TxReviewFragment : BaseViewBindingFragment<FragmentTxReviewBinding>() {
)
)
}
submitButton.setOnClickListener {
submitButton.isEnabled = false
viewModel.signAndExecute()
}
refresh.setOnRefreshListener {
loadEstimation()
}
Expand Down Expand Up @@ -338,9 +340,14 @@ class TxReviewFragment : BaseViewBindingFragment<FragmentTxReviewBinding>() {
is UpdateFee -> {
binding.estimatedFee.value = action.fee
binding.refresh.isRefreshing = false
binding.submitButton.isEnabled = true
}
is NavigateTo -> {
findNavController().navigate(action.navDirections)
}
is ShowError -> {
binding.refresh.isRefreshing = false
binding.submitButton.isEnabled = false
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@ import io.gnosis.safe.ui.settings.app.SettingsHandler
import io.gnosis.safe.ui.settings.owner.list.OwnerViewData
import io.gnosis.safe.utils.BalanceFormatter
import io.gnosis.safe.utils.convertAmount
import pm.gnosis.crypto.ECDSASignature
import pm.gnosis.crypto.utils.Sha3Utils
import pm.gnosis.model.Solidity
import pm.gnosis.models.Fee1559
import pm.gnosis.models.TransactionEip1559
import pm.gnosis.models.Wei
import pm.gnosis.svalinn.accounts.utils.rlp
import java.math.BigDecimal
import java.math.BigInteger
import javax.inject.Inject
Expand Down Expand Up @@ -56,6 +60,8 @@ class TxReviewViewModel

private var ethTx: TransactionEip1559? = null

private var ethTxSignature: ECDSASignature? = null

init {
safeLaunch {
activeSafe = safeRepository.getActiveSafe()!!
Expand Down Expand Up @@ -131,7 +137,13 @@ class TxReviewViewModel
TxReviewState(viewAction = Loading(true))
}

ethTx = rpcClient.ethTransaction(activeSafe, it.address, txData, executionInfo, BigInteger.valueOf(DEFAULT_MINER_TIP))
ethTx = rpcClient.ethTransaction(
activeSafe,
it.address,
txData,
executionInfo,
BigInteger.valueOf(DEFAULT_MINER_TIP)
)
val estimationParams = rpcClient.estimate(activeSafe.chain, ethTx!!)

executionKey = executionKey!!.copy(
Expand All @@ -145,14 +157,16 @@ class TxReviewViewModel

val gasPrice = estimationParams.gasPrice
minNonce = estimationParams.nonce
// If user has not edited the fee data, we set the fee values
// Otherwise, we keep the user's values
if (!userEditedFeeData) {
nonce = minNonce
gasLimit = estimationParams.estimate
maxPriorityFeePerGas = Wei(BigInteger.valueOf(DEFAULT_MINER_TIP)).toGWei(activeSafe.chain.currency.decimals)
maxFeePerGas = Wei(gasPrice).toGWei(activeSafe.chain.currency.decimals).plus(maxPriorityFeePerGas!!)
}

val totalFee = balanceString(gasLimit!! * (gasPrice + DEFAULT_MINER_TIP.toBigInteger()))
val totalFee = balanceString(gasLimit!! * Wei.fromGWei(maxFeePerGas!!).value)

updateState {
TxReviewState(viewAction = UpdateFee(totalFee))
Expand All @@ -162,26 +176,78 @@ class TxReviewViewModel
}
}

fun updateEstimationParams(nonce: BigInteger, gasLimit: BigInteger, maxPriorityFeePerGas: BigDecimal, maxFeePerGas: BigDecimal) {
fun updateEstimationParams(
nonce: BigInteger,
gasLimit: BigInteger,
maxPriorityFeePerGas: BigDecimal,
maxFeePerGas: BigDecimal
) {
this.userEditedFeeData = true
this.nonce = nonce
this.gasLimit = gasLimit
this.maxPriorityFeePerGas = maxPriorityFeePerGas
this.maxFeePerGas = maxFeePerGas
val totalFee = balanceString(gasLimit * (maxFeePerGas.toBigInteger() + maxPriorityFeePerGas.toBigInteger()))
val totalFee = balanceString(gasLimit * Wei.fromGWei(maxFeePerGas).value)
safeLaunch {
updateState {
TxReviewState(viewAction = UpdateFee(totalFee))
}
}
}

fun signAndExecute() {
safeLaunch {
executionKey?.let {
ethTx = ethTx!!.copy(nonce = nonce!!)
ethTx!!.fee = Fee1559(
gas = gasLimit!!,
maxPriorityFee = Wei.fromGWei(maxPriorityFeePerGas!!).value,
maxFeePerGas = Wei.fromGWei(maxFeePerGas!!).value
)
val owner = credentialsRepository.owner(it.address)!!
when (owner.type) {
Owner.Type.IMPORTED, Owner.Type.GENERATED -> {
val ethTxHash = Sha3Utils.keccak(byteArrayOf(ethTx!!.type.toByte(), *ethTx!!.rlp()))
ethTxSignature = credentialsRepository.signWithOwner(owner, ethTxHash)
sendForExecution()
}

Owner.Type.LEDGER_NANO_X -> {

}

Owner.Type.KEYSTONE -> {

}
}
}
}
}

fun sendForExecution() {
safeLaunch {
ethTxSignature?.let {
rpcClient.send(ethTx!!, it)

updateState {
TxReviewState(
viewAction =
ViewAction.NavigateTo(
TxReviewFragmentDirections.actionTxReviewFragmentToTxSuccessFragment()
)
)
}
}
}
}

private fun balanceString(balance: BigInteger): String {
return "${balanceFormatter.shortAmount(
balance.convertAmount(
activeSafe.chain.currency.decimals
return "${
balanceFormatter.shortAmount(
balance.convertAmount(
activeSafe.chain.currency.decimals
)
)
)
} ${activeSafe.chain.currency.symbol}"
}

Expand All @@ -205,4 +271,3 @@ data class DefaultKey(
data class UpdateFee(
val fee: String?
) : BaseStateViewModel.ViewAction

13 changes: 13 additions & 0 deletions app/src/main/res/navigation/main_nav.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1262,6 +1262,15 @@
app:argType="io.gnosis.safe.ui.transactions.details.viewdata.TransactionDetailsViewData"
app:nullable="true" />

<action
android:id="@+id/action_txReviewFragment_to_transactionDetailsActionMultisendFragment"
app:destination="@id/transactionDetailsActionMultisendFragment" />

<action
android:id="@+id/action_txReviewFragment_to_transactionDetailsActionFragment"
app:destination="@id/transactionDetailsActionFragment"
app:popUpTo="@id/txReviewFragment" />

<action
android:id="@+id/action_txReviewFragment_to_txEditFeeLegacyFragment"
app:destination="@id/txEditFeeLegacyFragment"
Expand All @@ -1282,6 +1291,10 @@
app:destination="@id/txAdvancedParamsFragment"
app:popUpTo="@id/txReviewFragment" />

<action
android:id="@+id/action_txReviewFragment_to_txSuccessFragment"
app:destination="@id/txSuccessFragment" />

</fragment>

<fragment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
import pm.gnosis.crypto.ECDSASignature
import pm.gnosis.utils.asEthereumAddress
import pm.gnosis.utils.hexToByteArray
import pm.gnosis.utils.toHexString
import java.math.BigInteger


class ConfirmRejectionViewModelTest {
Expand Down Expand Up @@ -55,7 +57,7 @@ class ConfirmRejectionViewModelTest {
)
coEvery { safeRepository.getActiveSafe() } returns Safe("0x1230B3d59858296A31053C1b8562Ecf89A2f888b".asEthereumAddress()!!, "safe_name")
coEvery { safeRepository.getSafes() } returns emptyList()
coEvery { credentialsRepository.signWithOwner(any(), any()) } returns ""
coEvery { credentialsRepository.signWithOwner(any(), any()) } returns ECDSASignature(BigInteger.ZERO, BigInteger.ZERO)
coEvery {
transactionRepository.proposeTransaction(
any(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import pm.gnosis.crypto.ECDSASignature
import pm.gnosis.utils.asEthereumAddress
import pm.gnosis.utils.hexToByteArray
import java.math.BigInteger
Expand Down Expand Up @@ -409,7 +410,7 @@ class TransactionDetailsViewModelTest {
val ownerAddress = "0x1230B3d59858296A31053C1b8562Ecf89A2f888b".asEthereumAddress()!!
val owner = Owner(ownerAddress, null, Owner.Type.IMPORTED, null)
coEvery { safeRepository.getActiveSafe() } returns Safe(ownerAddress, "safe_name")
coEvery { credentialsRepository.signWithOwner(any(), any()) } returns ""
coEvery { credentialsRepository.signWithOwner(any(), any()) } returns ECDSASignature(BigInteger.ZERO, BigInteger.ZERO)
coEvery {
transactionRepository.submitConfirmation(
any(),
Expand Down Expand Up @@ -459,7 +460,7 @@ class TransactionDetailsViewModelTest {
val owner = Owner(someAddress, null, Owner.Type.IMPORTED, null)
coEvery { safeRepository.getActiveSafe() } returns Safe(someAddress, "safe_name")
coEvery { safeRepository.getSafes() } returns emptyList()
coEvery { credentialsRepository.signWithOwner(any(), any()) } returns ""
coEvery { credentialsRepository.signWithOwner(any(), any()) } returns ECDSASignature(BigInteger.ZERO, BigInteger.ZERO)
coEvery {
transactionRepository.submitConfirmation(
any(),
Expand Down
2 changes: 1 addition & 1 deletion buildsystem/versions.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ ext {
play_services_auth : '17.0.0',
retrofit : '2.6.2',
status_keycard : '3.0.1',
svalinn : '608165c271',//'v0.15.0',
svalinn : '6853d63e8a',//'v0.15.0',
timber : '4.7.1',
zxing : '3.3.1',
play_core : '1.9.1',
Expand Down
1 change: 1 addition & 0 deletions data/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ dependencies {
api "com.github.gnosis.svalinn-kotlin:ethereum:$versions.svalinn"
api "com.github.gnosis.svalinn-kotlin:ethereum-rpc:$versions.svalinn"
api "com.github.gnosis.svalinn-kotlin:models:$versions.svalinn"
api "com.github.gnosis.svalinn-kotlin:accounts-kethereum:$versions.svalinn"
api "com.github.gnosis.svalinn-kotlin:crypto:$versions.svalinn"
api("com.github.gnosis.svalinn-kotlin:ethereum-rpc-retrofit:$versions.svalinn") {
exclude group: "com.squareup.retrofit2", module: "converter-moshi"
Expand Down
Loading
Loading