Skip to content

Commit

Permalink
Merge branch 'dashpay-voting' of https://github.com/dashevo/dash-wallet
Browse files Browse the repository at this point in the history
… into dashpay-design-improvments
  • Loading branch information
HashEngineering committed Oct 30, 2024
2 parents a70ae80 + f419160 commit 435d958
Show file tree
Hide file tree
Showing 13 changed files with 62 additions and 26 deletions.
5 changes: 3 additions & 2 deletions wallet/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,9 @@ android {
compileSdk 34
minSdkVersion 24
targetSdkVersion 34
versionCode project.hasProperty('versionCode') ? project.property('versionCode') as int : 110060
versionName project.hasProperty('versionName') ? project.property('versionName') : "11.0.1"
// version code: MMmmppbb; MM = Major Version, mm = minor version, pp == patch version, bb = build
versionCode project.hasProperty('versionCode') ? project.property('versionCode') as int : 11000201
versionName project.hasProperty('versionName') ? project.property('versionName') : "11.0.2"
multiDexEnabled true
generatedDensities = ['hdpi', 'xhdpi']
vectorDrawables.useSupportLibrary = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ package de.schildbach.wallet.database.entity

import androidx.room.Entity
import androidx.room.PrimaryKey
import de.schildbach.wallet.Constants
import org.bitcoinj.core.NetworkParameters
import java.util.concurrent.TimeUnit
import org.bitcoinj.core.Base58
import org.bitcoinj.core.Sha256Hash
import org.dashj.platform.sdk.platform.Names
Expand All @@ -37,6 +40,8 @@ data class UsernameRequest(
val isApproved: Boolean
) {
companion object {
val VOTING_PERIOD_MILLIS = if (Constants.NETWORK_PARAMETERS.id == NetworkParameters.ID_MAINNET) TimeUnit.DAYS.toMillis(14) else TimeUnit.MINUTES.toMillis(90)
val SUBMIT_PERIOD_MILLIS = VOTING_PERIOD_MILLIS / 2
fun getRequestId(identity: String, username: String): String {
return String.format("%s-%s", identity, Names.normalizeString(username))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package de.schildbach.wallet.payments

import androidx.annotation.VisibleForTesting
import com.google.firebase.installations.FirebaseInstallations
import de.schildbach.wallet.WalletApplication
import de.schildbach.wallet.data.CoinJoinConfig
import de.schildbach.wallet.data.PaymentIntent
Expand Down Expand Up @@ -79,7 +78,6 @@ class SendCoinsTaskRunner @Inject constructor(
}
private var coinJoinSend = false
private val coroutineScope = CoroutineScope(Dispatchers.IO)
private var firebaseInstallationId: String = ""
init {
coinJoinConfig
.observeMode()
Expand All @@ -88,10 +86,6 @@ class SendCoinsTaskRunner @Inject constructor(
coinJoinSend = mode != CoinJoinMode.NONE
}
.launchIn(coroutineScope)

FirebaseInstallations.getInstance().id.addOnCompleteListener { task ->
firebaseInstallationId = if (task.isSuccessful) task.result else ""
}
}

@Throws(LeftoverBalanceException::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ class PlatformSynchronizationService @Inject constructor(
if (blockchainIdentityData.creationState < BlockchainIdentityData.CreationState.DONE) {
// Is the Voting Period complete?
if (blockchainIdentityData.creationState == BlockchainIdentityData.CreationState.VOTING) {
val timeWindow = if (Constants.NETWORK_PARAMETERS.id == NetworkParameters.ID_MAINNET) TimeUnit.DAYS.toMillis(14) else TimeUnit.MINUTES.toMillis(90)
val timeWindow = UsernameRequest.VOTING_PERIOD_MILLIS
if (System.currentTimeMillis() - blockchainIdentityData.votingPeriodStart!! >= timeWindow) {
val resource = platformRepo.getUsername(blockchainIdentityData.username!!)
if (resource.status == Status.SUCCESS && resource.data != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,12 @@ class CreateIdentityService : LifecycleService() {
if (blockchainIdentityData.creationStateErrorMessage?.contains("preorderDocument was not found with a salted domain hash") == true) {
blockchainIdentityData.creationState = CreationState.PREORDER_REGISTERING
platformRepo.updateBlockchainIdentityData(blockchainIdentityData)
} else if (retryWithNewUserName) {
// lets rewind the state to allow for a new username registration or request
// it may have failed later in the process
if (blockchainIdentityData.creationState > CreationState.USERNAME_REGISTERING) {
blockchainIdentityData.creationState = CreationState.USERNAME_REGISTERING
}
}
}
}
Expand Down Expand Up @@ -707,7 +713,7 @@ class CreateIdentityService : LifecycleService() {
platformRepo.updateBlockchainIdentityData(blockchainIdentityData, blockchainIdentity)

blockchainIdentityData.verificationLink?.let { verificationLink ->
if (verificationLink.startsWith("https://") || verificationLink.startsWith("http://")) {
if (verificationLink.matches(Regex("^https?:\\/\\/.+\$"))) {
IdentityVerify(platformRepo.platform.platform).createForDashDomain(
blockchainIdentityData.username!!,
verificationLink,
Expand Down Expand Up @@ -919,7 +925,18 @@ class CreateIdentityService : LifecycleService() {
false
)
)
val usernameInfo = blockchainIdentity.usernameStatuses[blockchainIdentity.currentUsername!!]!!
// what if usernameInfo would have been null, we should create it.

var usernameInfo = blockchainIdentity.usernameStatuses[blockchainIdentity.currentUsername!!]
if (usernameInfo == null) {
usernameInfo = UsernameInfo(
null,
UsernameStatus.CONFIRMED,
blockchainIdentity.currentUsername!!,
UsernameRequestStatus.VOTING
)
blockchainIdentity.usernameStatuses[blockchainIdentity.currentUsername!!] = usernameInfo
}

// determine when voting started by finding the minimum timestamp
val earliestCreatedAt = voteContenders.map.values.minOf {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,10 @@ class HistoryHeaderAdapter(

if (blockchainIdentityData.creationStateErrorMessage != null) {
if (blockchainIdentityData.creationState == BlockchainIdentityData.CreationState.USERNAME_REGISTERING &&
blockchainIdentityData.creationStateErrorMessage.contains("Document transitions with duplicate unique properties")) {
(blockchainIdentityData.creationStateErrorMessage.contains("Document transitions with duplicate unique properties") ||
blockchainIdentityData.creationStateErrorMessage.contains("Document Contest for vote_poll ContestedDocumentResourceVotePoll")) ||
blockchainIdentityData.creationStateErrorMessage.contains(Regex("does not have .* as a contender"))
) {
binding.identityCreation.title.text = binding.root.context.getString(R.string.processing_username_unavailable_title)
binding.identityCreation.subtitle.visibility = View.VISIBLE
binding.identityCreation.icon.setImageResource(R.drawable.ic_username_unavailable)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import android.annotation.SuppressLint
import android.app.Application
import androidx.work.*
import de.schildbach.wallet.Constants
import de.schildbach.wallet.database.entity.UsernameRequest
import org.bitcoinj.core.NetworkParameters
import org.slf4j.LoggerFactory
import java.text.DateFormat
Expand Down Expand Up @@ -49,11 +50,7 @@ class GetUsernameVotingResultOperation(val application: Application) {
@SuppressLint("EnqueueWork")
fun create(username: String, identityId: String, votingStartedAt: Long): WorkContinuation {
log.info("scheduling work to check username voting status")
val delay = System.currentTimeMillis() - if (Constants.NETWORK_PARAMETERS.id != NetworkParameters.ID_MAINNET) {
TimeUnit.MINUTES.toMillis(90)
} else {
TimeUnit.DAYS.toMillis(14)
} + votingStartedAt + TimeUnit.MINUTES.toMillis(2)
val delay = System.currentTimeMillis() - UsernameRequest.VOTING_PERIOD_MILLIS + votingStartedAt + TimeUnit.MINUTES.toMillis(2)
log.info("scheduling work to check username voting status on {}",
DateFormat.getDateInstance(DateFormat.FULL).format(
Date(System.currentTimeMillis() + delay)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,8 @@ class WalletTransactionsFragment : Fragment(R.layout.wallet_transactions_fragmen
private fun openIdentityCreation() {
viewModel.blockchainIdentity.value?.let { blockchainIdentityData ->
if (blockchainIdentityData.creationStateErrorMessage != null) {
if (blockchainIdentityData.creationState == BlockchainIdentityData.CreationState.USERNAME_REGISTERING) {
if (blockchainIdentityData.creationState == BlockchainIdentityData.CreationState.USERNAME_REGISTERING ||
blockchainIdentityData.creationState == BlockchainIdentityData.CreationState.REQUESTED_NAME_CHECKING) {
startActivity(CreateUsernameActivity.createIntentReuseTransaction(requireActivity(), blockchainIdentityData))
} else {
Toast.makeText(requireContext(), blockchainIdentityData.creationStateErrorMessage, Toast.LENGTH_LONG).show()
Expand Down
6 changes: 4 additions & 2 deletions wallet/src/de/schildbach/wallet/ui/more/MoreFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import de.schildbach.wallet.Constants
import de.schildbach.wallet.WalletApplication
import de.schildbach.wallet.database.entity.BlockchainIdentityData
import de.schildbach.wallet.database.entity.DashPayProfile
import de.schildbach.wallet.database.entity.UsernameRequest
import de.schildbach.wallet.livedata.Status
import de.schildbach.wallet.service.PackageInfoProvider
import de.schildbach.wallet.ui.CreateUsernameActivity
Expand Down Expand Up @@ -237,7 +238,7 @@ class MoreFragment : Fragment(R.layout.fragment_more) {
binding.joinDashpayContainer.visibility = View.GONE
binding.requestedUsernameContainer.visibility = View.VISIBLE
val votingPeriod = it.votingPeriodStart?.let { startTime ->
val endTime = startTime + if (Constants.NETWORK_PARAMETERS.id == NetworkParameters.ID_MAINNET) TimeUnit.DAYS.toMillis(14) else TimeUnit.MINUTES.toMillis(90)
val endTime = startTime + UsernameRequest.VOTING_PERIOD_MILLIS
val dateFormat = DateFormat.getMediumDateFormat(requireContext())
String.format("%s", dateFormat.format(endTime))
} ?: "Voting Period not found"
Expand Down Expand Up @@ -283,7 +284,8 @@ class MoreFragment : Fragment(R.layout.fragment_more) {
}

binding.retryRequestButton.setOnClickListener {
// TODO: restart CreateIdentityService
mainActivityViewModel.logEvent(AnalyticsConstants.UsersContacts.CREATE_USERNAME_TRYAGAIN)
createIdentityViewModel.retryCreateIdentity()
}

initViewModel()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import org.dashj.platform.dashpay.UsernameRequestStatus
import org.dashj.platform.dpp.identifier.Identifier
import org.dashj.platform.sdk.platform.DomainDocument
import org.dashj.platform.sdk.platform.Names
import org.slf4j.LoggerFactory
import javax.inject.Inject
import kotlin.math.max

Expand All @@ -82,13 +83,16 @@ data class RequestUserNameUIState(
@HiltViewModel
class RequestUserNameViewModel @Inject constructor(
val walletApplication: WalletApplication,
val identityConfig: BlockchainIdentityConfig,
private val identityConfig: BlockchainIdentityConfig,
val walletData: WalletDataProvider,
val platformRepo: PlatformRepo,
val usernameRequestDao: UsernameRequestDao,
val coinJoinConfig: CoinJoinConfig,
val analytics: AnalyticsService
) : ViewModel() {
companion object {
private val log = LoggerFactory.getLogger(RequestUserNameViewModel::class.java)
}
private val workerJob = SupervisorJob()
private val viewModelWorkerScope = CoroutineScope(Dispatchers.IO + workerJob)
private val _uiState = MutableStateFlow(RequestUserNameUIState())
Expand Down Expand Up @@ -144,6 +148,7 @@ class RequestUserNameViewModel @Inject constructor(
identityBalance = identity?.let { identity ->
platformRepo.getIdentityBalance(Identifier.from(identity.userId)).balance
} ?: 0
log.info("identity balance: {}", identityBalance)
if (requestedUserName == null) {
requestedUserName = identityConfig.get(USERNAME)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.google.android.material.textfield.TextInputLayout
import dagger.hilt.android.AndroidEntryPoint
import de.schildbach.wallet.Constants
import de.schildbach.wallet.database.entity.BlockchainIdentityData
import de.schildbach.wallet.database.entity.UsernameRequest
import de.schildbach.wallet.ui.dashpay.DashPayViewModel
import de.schildbach.wallet_test.R
import de.schildbach.wallet_test.databinding.FragmentRequestUsernameBinding
Expand Down Expand Up @@ -135,8 +136,10 @@ class RequestUsernameFragment : Fragment(R.layout.fragment_request_username) {
binding.walletBalanceContainer.isVisible = !it.enoughBalance
if (it.usernameContestable || it.usernameContested) {
val startDate = Date(it.votingPeriodStart)
val endDate = Date(startDate.time + if (Constants.NETWORK_PARAMETERS.id == NetworkParameters.ID_MAINNET) TimeUnit.DAYS.toMillis(14) else TimeUnit.MINUTES.toMillis(90))
if (it.votingPeriodStart == -1L && System.currentTimeMillis() - it.votingPeriodStart > TimeUnit.DAYS.toMillis(7)) {
val endDate = Date(startDate.time + UsernameRequest.VOTING_PERIOD_MILLIS)
if (it.votingPeriodStart == -1L && System.currentTimeMillis() - it.votingPeriodStart > UsernameRequest.VOTING_PERIOD_MILLIS) {
binding.votingPeriodContainer.isVisible = false
} else if (it.votingPeriodStart == -1L && System.currentTimeMillis() - it.votingPeriodStart > UsernameRequest.SUBMIT_PERIOD_MILLIS) {
binding.votingPeriodContainer.isVisible = false
} else {
val dateFormat = DateFormat.getMediumDateFormat(context)
Expand All @@ -162,6 +165,12 @@ class RequestUsernameFragment : Fragment(R.layout.fragment_request_username) {
binding.checkAvailable.setImageResource(getCheckMarkImage(false, false))
binding.votingPeriodContainer.isVisible = false
}
it.usernameContestable && (it.votingPeriodStart == -1L && System.currentTimeMillis() - it.votingPeriodStart > UsernameRequest.VOTING_PERIOD_MILLIS) -> {
// the submission period has ended, let us just say the username is taken
binding.usernameAvailableMessage.text = getString(R.string.request_username_taken)
binding.checkAvailable.setImageResource(getCheckMarkImage(false, false))
binding.votingPeriodContainer.isVisible = false
}
it.usernameContestable -> {
// voting period container will be visible
binding.usernameAvailableContainer.isVisible = false
Expand Down Expand Up @@ -197,7 +206,8 @@ class RequestUsernameFragment : Fragment(R.layout.fragment_request_username) {
return@observe
}
if (it?.creationStateErrorMessage != null) {
requireActivity().finish()
//why are we closing, we should allow the user to chose a new name
//requireActivity().finish()
} else if ((it?.creationState?.ordinal ?: 0) > BlockchainIdentityData.CreationState.NONE.ordinal) {
// completeUsername = it.username ?: ""
// showCompleteState()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class VerifyIdentityFragment : Fragment(R.layout.fragment_verfiy_identity) {

binding.linkInput.doOnTextChanged { text, _, _, _ ->
val link = text.toString()
val isValidLink = link.startsWith("https://") || link.startsWith("http://")
val isValidLink = link.matches(Regex("^https?:\\/\\/.+\$"))
binding.verifyBtn.isEnabled = isValidLink
if (!text.isNullOrEmpty()) {
binding.linkInputLayout.hint = getString(R.string.link)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import de.schildbach.wallet.Constants
import de.schildbach.wallet.database.entity.UsernameRequest
import de.schildbach.wallet_test.R
import de.schildbach.wallet_test.databinding.FragmentVotingRequestDetailsBinding
import org.bitcoinj.core.NetworkParameters
Expand Down Expand Up @@ -58,7 +59,7 @@ class VotingRequestDetailsFragment : Fragment(R.layout.fragment_voting_request_d
binding.identity.text = myUsernameRequest?.identity
var isVotingOver = false
val votingResults = myUsernameRequest?.createdAt?.let { startTime ->
val endTime = startTime + if (Constants.NETWORK_PARAMETERS.id == NetworkParameters.ID_MAINNET) TimeUnit.DAYS.toMillis(14) else TimeUnit.MINUTES.toMillis(90)
val endTime = startTime + UsernameRequest.VOTING_PERIOD_MILLIS
val dateFormat = DateFormat.getMediumDateFormat(requireContext())
isVotingOver = endTime < System.currentTimeMillis()
if (isVotingOver) {
Expand Down

0 comments on commit 435d958

Please sign in to comment.