Skip to content

Commit

Permalink
feat: add decoding for claim tx
Browse files Browse the repository at this point in the history
  • Loading branch information
compojoom committed Oct 1, 2024
1 parent c8edf91 commit 720bd77
Show file tree
Hide file tree
Showing 11 changed files with 419 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ enum class TransactionViewType {
STAKE_DEPOSIT_QUEUED,
STAKE_VALIDATOR_EXIT,
STAKE_VALIDATOR_EXIT_QUEUED,
STAKE_WITHDRAW,
STAKE_WITHDRAW_QUEUED,
CONFLICT
}

Expand Down Expand Up @@ -82,6 +84,8 @@ class TransactionViewHolderFactory : BaseFactory<BaseTransactionViewHolder<Trans
TransactionViewType.STAKE_DEPOSIT_QUEUED.ordinal -> StakeDepositQueuedViewHolder(viewBinding as ItemTxQueuedStakeDepositBinding)
TransactionViewType.STAKE_VALIDATOR_EXIT.ordinal -> StakeValidatorExitViewHolder(viewBinding as ItemTxStakeValidatorExitBinding)
TransactionViewType.STAKE_VALIDATOR_EXIT_QUEUED.ordinal -> StakeValidatorExitQueuedViewHolder(viewBinding as ItemTxQueuedStakeValidatorExitBinding)
TransactionViewType.STAKE_WITHDRAW.ordinal -> StakeWithdrawViewHolder(viewBinding as ItemTxStakeWithdrawBinding)
TransactionViewType.STAKE_WITHDRAW_QUEUED.ordinal -> StakeWithdrawQueuedViewHolder(viewBinding as ItemTxQueuedStakeWithdrawBinding)
else -> throw UnsupportedViewType(javaClass.name)
} as BaseTransactionViewHolder<TransactionView>

Expand Down Expand Up @@ -110,6 +114,8 @@ class TransactionViewHolderFactory : BaseFactory<BaseTransactionViewHolder<Trans
TransactionViewType.STAKE_DEPOSIT_QUEUED.ordinal -> ItemTxQueuedStakeDepositBinding.inflate(layoutInflater, parent, false)
TransactionViewType.STAKE_VALIDATOR_EXIT.ordinal -> ItemTxStakeValidatorExitBinding.inflate(layoutInflater, parent, false)
TransactionViewType.STAKE_VALIDATOR_EXIT_QUEUED.ordinal -> ItemTxQueuedStakeValidatorExitBinding.inflate(layoutInflater, parent, false)
TransactionViewType.STAKE_WITHDRAW.ordinal -> ItemTxStakeWithdrawBinding.inflate(layoutInflater, parent, false)
TransactionViewType.STAKE_WITHDRAW_QUEUED.ordinal -> ItemTxQueuedStakeWithdrawBinding.inflate(layoutInflater, parent, false)
else -> throw UnsupportedViewType(javaClass.name)
}

Expand Down Expand Up @@ -139,6 +145,8 @@ class TransactionViewHolderFactory : BaseFactory<BaseTransactionViewHolder<Trans
is TransactionView.StakeDepositTransactionQueued -> TransactionViewType.STAKE_DEPOSIT_QUEUED
is TransactionView.StakeValidatorExitTransaction -> TransactionViewType.STAKE_VALIDATOR_EXIT
is TransactionView.StakeValidatorExitTransactionQueued -> TransactionViewType.STAKE_VALIDATOR_EXIT_QUEUED
is TransactionView.StakeWithdrawTransaction -> TransactionViewType.STAKE_WITHDRAW
is TransactionView.StakeWithdrawTransactionQueued -> TransactionViewType.STAKE_WITHDRAW_QUEUED
}.ordinal
}

Expand Down Expand Up @@ -633,6 +641,57 @@ class StakeValidatorExitQueuedViewHolder(private val viewBinding: ItemTxQueuedSt
}
}

class StakeWithdrawViewHolder(private val viewBinding: ItemTxStakeWithdrawBinding) :
BaseTransactionViewHolder<TransactionView.StakeWithdrawTransaction>(viewBinding) {

override fun bind(viewTransfer: TransactionView.StakeWithdrawTransaction, payloads: List<Any>) {
val resources = viewBinding.root.context.resources
val theme = viewBinding.root.context.theme

with(viewBinding) {
finalStatus.setText(viewTransfer.statusText)
finalStatus.setTextColor(ResourcesCompat.getColor(resources, viewTransfer.statusColorRes, theme))
dateTime.text = viewTransfer.dateTimeText

txListLabel.text = viewTransfer.displayName
nonce.text = viewTransfer.nonce

finalStatus.alpha = OPACITY_FULL
dateTime.alpha = viewTransfer.alpha
nonce.alpha = viewTransfer.alpha

root.setOnClickListener {
navigateToTxDetails(it, viewTransfer.chain, viewTransfer.id)
}
}
}
}

class StakeWithdrawQueuedViewHolder(private val viewBinding: ItemTxQueuedStakeWithdrawBinding) :
BaseTransactionViewHolder<TransactionView.StakeWithdrawTransactionQueued>(viewBinding) {

@OptIn(ExperimentalTime::class)
override fun bind(viewTransfer: TransactionView.StakeWithdrawTransactionQueued, payloads: List<Any>) {
val resources = viewBinding.root.context.resources
val theme = viewBinding.root.context.theme
with(viewBinding) {
txListLabel.text = viewTransfer.displayName
status.setText(viewTransfer.statusText)
status.setTextColor(ResourcesCompat.getColor(resources, viewTransfer.statusColorRes, theme))
dateTime.text = viewTransfer.dateTime.elapsedIntervalTo(Date.from(Instant.now())).format(resources)

confirmations.setTextColor(ResourcesCompat.getColor(resources, viewTransfer.confirmationsTextColor, theme))
confirmationsIcon.setImageDrawable(ResourcesCompat.getDrawable(resources, viewTransfer.confirmationsIcon, theme))
confirmations.text = resources.getString(R.string.tx_list_confirmations, viewTransfer.confirmations, viewTransfer.threshold)
nonce.text = viewTransfer.nonce

root.setOnClickListener {
navigateToTxDetails(it, viewTransfer.chain, viewTransfer.id)
}
}
}
}

private fun Resources.getAction(methodName: String?, actionCount: Int?): String? =
if (actionCount != null) {
if (actionCount > 0) this.getQuantityString(R.plurals.tx_list_actions, actionCount, actionCount) else methodName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import io.gnosis.safe.ui.base.AppDispatchers
import io.gnosis.safe.ui.base.BaseStateViewModel
import io.gnosis.safe.ui.transactions.details.viewdata.stakeDepositDisplayName
import io.gnosis.safe.ui.transactions.details.viewdata.stakeValidatorExitDisplayName
import io.gnosis.safe.ui.transactions.details.viewdata.stakeWithdrawDisplayName
import io.gnosis.safe.ui.transactions.details.viewdata.swapOrderDisplayname
import io.gnosis.safe.ui.transactions.details.viewdata.swapTransferDisplayName
import io.gnosis.safe.ui.transactions.details.viewdata.twapOrderDisplayName
Expand Down Expand Up @@ -196,7 +197,7 @@ class TransactionListViewModel
is TransactionInfo.TwapOrder -> toTwapOrderTransactionView(chain, txInfo, needsYourConfirmation, isConflict)
is TransactionInfo.StakeDeposit -> toStakeDepositTransactionView(chain, txInfo, needsYourConfirmation, isConflict)
is TransactionInfo.StakeValidatorExit -> toStakeValidatorExitView(chain, txInfo, needsYourConfirmation, isConflict)

is TransactionInfo.StakeWithdraw -> toStakeWithdrawView(chain, txInfo, needsYourConfirmation, isConflict)
TransactionInfo.Unknown -> TransactionView.Unknown
}
}
Expand Down Expand Up @@ -655,7 +656,61 @@ class TransactionListViewModel
)
}

private fun Transaction.toStakeWithdrawView(
chain: Chain,
txInfo: TransactionInfo.StakeWithdraw,
needsYourConfirmation: Boolean,
isConflict: Boolean
): TransactionView =
if (!isCompleted(txStatus)) queuedStakeWithdraw(chain, txInfo, needsYourConfirmation, isConflict)
else historicStakeWithdraw(chain, txInfo)

private fun Transaction.queuedStakeWithdraw(
chain: Chain,
txInfo: TransactionInfo.StakeWithdraw,
needsYourConfirmation: Boolean,
isConflict: Boolean
): TransactionView.StakeWithdrawTransactionQueued {

//FIXME this wouldn't make sense for incoming Ethereum TXs
val threshold = executionInfo?.confirmationsRequired ?: -1
val thresholdMet = checkThreshold(threshold, executionInfo?.confirmationsSubmitted)

return TransactionView.StakeWithdrawTransactionQueued(
chain = chain,
id = id,
status = txStatus,
statusText = displayString(txStatus, needsYourConfirmation),
statusColorRes = statusTextColor(txStatus),
dateTime = timestamp,
confirmations = executionInfo?.confirmationsSubmitted ?: 0,
threshold = threshold,
confirmationsTextColor = if (thresholdMet) R.color.success else R.color.icon,
confirmationsIcon = if (thresholdMet) R.drawable.ic_confirmations_green_16dp else R.drawable.ic_confirmations_grey_16dp,
nonce = if (isConflict) "" else executionInfo?.nonce?.toString() ?: "",
value = txInfo.value,
displayName = stakeWithdrawDisplayName()
)
}

private fun Transaction.historicStakeWithdraw(
chain: Chain,
txInfo: TransactionInfo.StakeWithdraw
): TransactionView.StakeWithdrawTransaction {

return TransactionView.StakeWithdrawTransaction(
chain = chain,
id = id,
status = txStatus,
statusText = displayString(txStatus),
statusColorRes = statusTextColor(txStatus),
dateTimeText = timestamp.formatBackendTimeOfDay(),
alpha = alpha(txStatus),
nonce = executionInfo?.nonce?.toString() ?: "",
value = txInfo.value,
displayName = stakeWithdrawDisplayName()
)
}

private fun Transaction.toRejectionTransactionView(
chain: Chain,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,36 @@ sealed class TransactionView(
) : TransactionView(status, id, chain)



data class StakeWithdrawTransaction(
override val id: String,
override val status: TransactionStatus,
override val chain: Chain,
@StringRes val statusText: Int,
@ColorRes val statusColorRes: Int,
val dateTimeText: String,
val alpha: Float,
val nonce: String,
val value: String,
val displayName: String
) : TransactionView(status, id, chain)

data class StakeWithdrawTransactionQueued(
override val id: String,
override val status: TransactionStatus,
override val chain: Chain,
@StringRes val statusText: Int,
@ColorRes val statusColorRes: Int,
val dateTime: Date,
val confirmations: Int,
val threshold: Int,
@ColorRes val confirmationsTextColor: Int,
@DrawableRes val confirmationsIcon: Int,
val nonce: String,
val value: String,
val displayName: String
) : TransactionView(status, id, chain)

data class Creation(
override val id: String,
override val status: TransactionStatus,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ enum class TxType(@DrawableRes val iconRes: Int, @StringRes val titleRes: Int) {
TWAP_ORDER(R.drawable.ic_code_16dp, R.string.tx_status_type_twap_order),
STAKE_DEPOSIT(R.drawable.ic_stake_16dp, R.string.tx_status_type_stake_deposit),
STAKE_VALIDATOR_EXIT(R.drawable.ic_stake_16dp, R.string.tx_status_type_stake_validator_exit),
STAKE_WITHDRAW(R.drawable.ic_stake_16dp, R.string.tx_status_type_stake_withdraw),
CREATION(R.drawable.ic_settings_change_14dp, R.string.tx_status_type_creation),
REJECTION(R.drawable.ic_circle_cross_red_16dp, R.string.tx_status_type_rejection)
}
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,11 @@ internal fun TransactionInfo.toTransactionInfoViewData(
TransactionInfoViewData.StakeValidatorExit(value, name)
}

is TransactionInfo.StakeWithdraw -> {
val name = stakeWithdrawDisplayName()
TransactionInfoViewData.StakeValidatorExit(value, name)
}

is TransactionInfo.Transfer -> {
val addressInfoData =
if (direction == TransactionDirection.OUTGOING) {
Expand Down Expand Up @@ -381,6 +386,10 @@ internal fun stakeDepositDisplayName(): String {
return "Stake"
}

internal fun stakeWithdrawDisplayName(): String {
return "Claim"
}

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
internal fun SettingsInfo?.toSettingsInfoViewData(
safes: List<Safe>,
Expand Down
146 changes: 146 additions & 0 deletions app/src/main/res/layout/item_tx_queued_stake_withdraw.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/background_secondary"
android:minHeight="@dimen/item_tx_m_height">

<ImageView
android:id="@+id/chevron"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/default_margin"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_chevron_right" />

<ImageView
android:id="@+id/confirmations_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
app:layout_constraintBottom_toBottomOf="@+id/status"
app:layout_constraintEnd_toStartOf="@+id/confirmations"
app:layout_constraintTop_toTopOf="@+id/status"
app:srcCompat="@drawable/ic_confirmations_grey_16dp" />


<!--Revise TableLayout solution when
app:layout_constraintWidth_percent=""
app:layout_constraintWidth_max="wrap"
works as expected
-->
<TableLayout
android:id="@id/address_name_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_small_margin"
android:shrinkColumns="0"
android:stretchColumns="1"
app:layout_constraintBottom_toBottomOf="@+id/address_logo"
app:layout_constraintStart_toEndOf="@+id/address_logo"
app:layout_constraintTop_toTopOf="@+id/address_logo">

<TableRow>

<TextView
android:id="@+id/tx_list_label"
style="@style/Body1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="start"
android:singleLine="true"
tools:text="@string/tx_list_stake_withdraw" />

<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

</TableRow>

</TableLayout>

<TextView
android:id="@+id/nonce"
style="@style/TextMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginTop="@dimen/default_small_margin"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/address_logo"
tools:text="10" />

<TextView
android:id="@+id/date_time"
style="@style/TextMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_small_margin"
app:layout_constraintBottom_toBottomOf="@+id/nonce"
app:layout_constraintStart_toEndOf="@+id/nonce"
app:layout_constraintTop_toTopOf="@+id/nonce"
tools:text="Apr 27, 2020 — 1:01:42PM" />

<TextView
android:id="@+id/status_pending"
style="@style/TextMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_margin"
android:textColor="@color/warning"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/date_time"
app:layout_constraintStart_toEndOf="@+id/date_time"
app:layout_constraintTop_toTopOf="@+id/date_time"
tools:text="\u2022 Pending" />

<TextView
android:id="@+id/status"
style="@style/TextMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_margin"
android:textColor="@color/warning"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/date_time"
tools:text="\u2022 Needs execution" />

<TextView
android:id="@+id/confirmations"
style="@style/TextMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/default_small_margin"
app:layout_constraintBottom_toBottomOf="@+id/confirmations_icon"
app:layout_constraintEnd_toStartOf="@+id/chevron"
app:layout_constraintTop_toTopOf="@+id/confirmations_icon"
tools:text="2 out of 2" />

<androidx.constraintlayout.widget.Group
android:id="@+id/not_pending"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible"
app:constraint_referenced_ids="confirmations_icon,status,confirmations" />

<!-- When making status_pending visible, make group "not_pending" "gone" -->
<io.gnosis.safe.ui.settings.view.KnownAddressLogoView
android:id="@+id/address_logo"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginTop="@dimen/default_margin"
android:src="@drawable/ic_stake_16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.Circle"
app:strokeColor="@color/background_tertiary"
app:strokeWidth="0.01dp" />

</androidx.constraintlayout.widget.ConstraintLayout>
Loading

0 comments on commit 720bd77

Please sign in to comment.