Skip to content

Commit e370f52

Browse files
committed
fix(ocp): properly support passthrough of verifiedState from grab => give while bill is still active
Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent 13f20f5 commit e370f52

8 files changed

Lines changed: 64 additions & 24 deletions

File tree

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/bill/BillState.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import androidx.compose.ui.graphics.painter.Painter
55
import androidx.compose.ui.res.painterResource
66
import androidx.compose.ui.res.stringResource
77
import com.flipcash.core.R
8+
import com.getcode.opencode.internal.manager.VerifiedState
89
import com.getcode.opencode.model.financial.Fiat
910
import com.getcode.opencode.model.financial.LocalFiat
1011
import com.getcode.opencode.model.financial.Token
@@ -122,6 +123,7 @@ sealed interface Bill {
122123
override val confirmationDelay: Duration = Duration.ZERO,
123124
override val data: List<Byte> = emptyList(),
124125
val kind: Kind = Kind.cash,
126+
val verifiedState: VerifiedState? = null,
125127
) : Bill {
126128
override val canFlip: Boolean = false
127129
}

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/internal/bill/BillController.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.flipcash.app.core.internal.bill
22

33
import com.flipcash.app.core.bill.BillState
44
import com.flipcash.services.user.UserManager
5+
import com.getcode.opencode.internal.manager.VerifiedState
56
import com.getcode.opencode.model.accounts.AccountCluster
67
import com.getcode.opencode.managers.BillTransactionManager
78
import com.getcode.opencode.model.accounts.GiftCardAccount
@@ -39,6 +40,7 @@ class BillController @Inject constructor(
3940
amount: LocalFiat,
4041
token: Token,
4142
owner: AccountCluster,
43+
verifiedState: VerifiedState?,
4244
present: (List<Byte>) -> Unit,
4345
onGrabbed: suspend (LocalFiat) -> Unit,
4446
onTimeout: () -> Unit,
@@ -47,6 +49,7 @@ class BillController @Inject constructor(
4749
token = token,
4850
amount = amount,
4951
owner = owner,
52+
verifiedState = verifiedState,
5053
billExchangeDataTimeout = userManager.userFlags?.billExchangeDataTimeout,
5154
present = present,
5255
onGrabbed = onGrabbed,
@@ -59,7 +62,7 @@ class BillController @Inject constructor(
5962
fun attemptGrab(
6063
owner: AccountCluster,
6164
payload: OpenCodePayload,
62-
onGrabbed: suspend (Token, LocalFiat) -> Unit,
65+
onGrabbed: suspend (Token, LocalFiat, VerifiedState?) -> Unit,
6366
onError: (Throwable) -> Unit,
6467
) = transactionManager.attemptGrabFromSender(owner, payload, onGrabbed, onError)
6568

@@ -76,7 +79,7 @@ class BillController @Inject constructor(
7679
entropy: String,
7780
owner: AccountCluster,
7881
claimIfOwned: Boolean,
79-
onReceived: suspend (Token, LocalFiat) -> Unit,
82+
onReceived: suspend (Token, LocalFiat,) -> Unit,
8083
onError: (Throwable) -> Unit,
8184
) = transactionManager.receiveGiftCard(owner, entropy, claimIfOwned, onReceived, onError)
8285
}

apps/flipcash/shared/session/src/main/kotlin/com/flipcash/app/session/internal/RealSessionController.kt

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ class RealSessionController @Inject constructor(
237237
* Specifically, it clears the bottom bar, cancels any pending bill grab actions, and cancels
238238
* any ongoing send operations if:
239239
* - The share sheet is not currently checking for a share action, OR
240-
* - There is an active bill and it has not yet been received.
240+
* - There is an active bill, and it has not yet been received.
241241
*/
242242
override fun onAppInBackground() {
243243
stopPolling()
@@ -414,6 +414,7 @@ class RealSessionController @Inject constructor(
414414
billController.awaitGrab(
415415
amount = bill.amount,
416416
token = bill.token,
417+
verifiedState = (bill as? Bill.Cash)?.verifiedState,
417418
owner = owner,
418419
onGrabbed = { amount ->
419420
tokenCoordinator.subtract(bill.token, amount)
@@ -425,11 +426,6 @@ class RealSessionController @Inject constructor(
425426
},
426427
onTimeout = {
427428
dismissBill(action = PutInWallet)
428-
// analytics.billTimeoutReached(
429-
// bill.amount.kin,
430-
// bill.amount.rate.currency,
431-
// CodeAnalyticsManager.BillPresentationStyle.Slide
432-
// )
433429
},
434430
onError = {
435431
analytics.transfer(
@@ -733,7 +729,11 @@ class RealSessionController @Inject constructor(
733729
analytics.transfer(Analytics.Transfer.ClaimedCashLink, amount = amount)
734730
toastController.enqueue(amount, isDeposit = true)
735731
showBill(
736-
bill = Bill.Cash(amount = amount, token = token, didReceive = true),
732+
bill = Bill.Cash(
733+
amount = amount,
734+
token = token,
735+
didReceive = true,
736+
),
737737
)
738738
checkPendingItemsInFeed()
739739
bringActivityFeedCurrent()
@@ -819,15 +819,20 @@ class RealSessionController @Inject constructor(
819819
billController.attemptGrab(
820820
owner = owner,
821821
payload = payload,
822-
onGrabbed = { token, amount ->
822+
onGrabbed = { token, amount, verifiedState ->
823823
tokenCoordinator.add(token, amount)
824824
val grabStart = scannedRendezvous[payload.rendezvous.publicKey]
825825
val grabTime = grabStart?.let {
826826
Clock.System.now().toEpochMilliseconds() - it
827827
}
828828

829829
showBill(
830-
bill = Bill.Cash(amount = amount, token = token, didReceive = true),
830+
bill = Bill.Cash(
831+
amount = amount,
832+
token = token,
833+
didReceive = true,
834+
verifiedState = verifiedState
835+
),
831836
)
832837

833838
analytics.transfer(Analytics.Transfer.GrabBill(grabTime), amount)
@@ -860,6 +865,7 @@ class RealSessionController @Inject constructor(
860865
didReceive = bill.didReceive,
861866
confirmationDelay = bill.confirmationDelay,
862867
token = bill.token,
868+
verifiedState = (bill as? Bill.Cash)?.verifiedState,
863869
),
864870
valuation = PaymentValuation(bill.amount.nativeAmount),
865871
)

services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/extensions/ProtobufToLocal.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.codeinc.opencode.gen.common.v1.Model
44
import com.codeinc.opencode.gen.currency.v1.CurrencyService
55
import com.codeinc.opencode.gen.messaging.v1.MessagingService
66
import com.codeinc.opencode.gen.transaction.v1.TransactionService
7+
import com.codeinc.opencode.gen.transaction.v1.clientExchangeDataOrNull
78
import com.codeinc.opencode.gen.transaction.v1.destinationOrNull
89
import com.getcode.opencode.internal.extensions.toHash
910
import com.getcode.opencode.internal.extensions.toMint
@@ -102,6 +103,7 @@ internal fun TransactionService.Metadata.toMetadata(): TransactionMetadata {
102103
destination = sendPublicPayment.destination.toPublicKey(),
103104
destinationOwner = sendPublicPayment.destinationOrNull?.toPublicKey(),
104105
exchangeData = sendPublicPayment.serverExchangeData.toModel(),
106+
verifiedExchangeData = sendPublicPayment.clientExchangeDataOrNull?.toModel(),
105107
isRemoteSend = sendPublicPayment.isRemoteSend,
106108
isWithdrawal = sendPublicPayment.isWithdrawal,
107109
)

services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/GiveBillTransactor.kt

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.getcode.opencode.controllers.TransactionController
66
import com.getcode.opencode.internal.extensions.exchangeDataFor
77
import com.getcode.opencode.internal.extensions.toPublicKey
88
import com.getcode.opencode.internal.manager.VerifiedProtoManager
9+
import com.getcode.opencode.internal.manager.VerifiedState
910
import com.getcode.opencode.internal.network.extensions.asProtobufMessage
1011
import com.getcode.opencode.model.accounts.AccountCluster
1112
import com.getcode.opencode.model.core.OpenCodePayload
@@ -28,7 +29,7 @@ internal class GiveBillTransactor(
2829
private val transactionController: TransactionController,
2930
private val scope: CoroutineScope,
3031
private val verifiedProtoManager: VerifiedProtoManager,
31-
): Transactor<GiveBillTransactor.GiveTransactorError>("Transactor::Give") {
32+
) : Transactor<GiveBillTransactor.GiveTransactorError>("Transactor::Give") {
3233
private var token: Token? = null
3334
private var amount: LocalFiat? = null
3435
private var exchangeDataTimeout: Duration? = null
@@ -37,15 +38,24 @@ internal class GiveBillTransactor(
3738
private var rendezvousKey: KeyPair? = null
3839
private var receivingAccount: PublicKey? = null
3940

41+
private var providedVerifiedState: VerifiedState? = null
42+
4043
private var payload: OpenCodePayload = OpenCodePayload.Empty
4144
var data: List<Byte> = emptyList()
4245
private set
4346

44-
fun with(token: Token, amount: LocalFiat, owner: AccountCluster, billExchangeDataTimeout: Duration?) {
47+
fun with(
48+
token: Token,
49+
amount: LocalFiat,
50+
owner: AccountCluster,
51+
billExchangeDataTimeout: Duration?,
52+
verifiedState: VerifiedState?
53+
) {
4554
this.token = token
4655
this.amount = amount
4756
this.exchangeDataTimeout = billExchangeDataTimeout
4857
this.owner = owner
58+
this.providedVerifiedState = verifiedState
4959

5060
receivingAccount = null
5161

@@ -70,11 +80,20 @@ internal class GiveBillTransactor(
7080
val sendingAmount = amount
7181
?: return logAndFail(GiveTransactorError.Other(message = "No amount. Did you call with() first?"))
7282

73-
val verifiedState = verifiedProtoManager.getVerifiedStateFor(sendingAmount.rate.currency, desiredToken.address)
74-
?: return logAndFail(GiveTransactorError.Other(message = "No verified state found"))
75-
76-
val exchangeData = verifiedState.exchangeDataFor(amount = sendingAmount, mint = desiredToken.address, billExchangeDataTimeout = exchangeDataTimeout)
77-
?: return logAndFail(GiveTransactorError.ExchangeRateExpiredException())
83+
val verifiedState = if (providedVerifiedState != null) {
84+
providedVerifiedState
85+
} else {
86+
verifiedProtoManager.getVerifiedStateFor(
87+
sendingAmount.rate.currency,
88+
desiredToken.address
89+
)
90+
} ?: return logAndFail(GiveTransactorError.Other(message = "No verified state found"))
91+
92+
val exchangeData = verifiedState.exchangeDataFor(
93+
amount = sendingAmount,
94+
mint = desiredToken.address,
95+
billExchangeDataTimeout = exchangeDataTimeout
96+
) ?: return logAndFail(GiveTransactorError.ExchangeRateExpiredException())
7897

7998
// 1. Send request to "give" the bill to the recipient
8099
// This provides the recipient with the desired token mint of the cash

services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/GrabBillTransactor.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ internal class GrabBillTransactor(
6464
private suspend fun handleMultiMintScan(
6565
ownerKey: AccountCluster,
6666
data: OpenCodePayload
67-
): Result<TransactionMetadata.PublicPayment> {
67+
): Result<TransactionMetadata.SendPublicPayment> {
6868
// 1. Wait for the give request from the sender so we can determine what mint we are operating on
6969
val (messageId, giveRequestMint, exchangeData) = messagingController.pollForGiveRequest(data.rendezvous)
7070
.getOrNull()
@@ -97,11 +97,14 @@ internal class GrabBillTransactor(
9797
}.fold(
9898
onSuccess = {
9999
// 5. Wait for confirmation
100-
transactionController.pollIntentMetadata<TransactionMetadata.PublicPayment>(
100+
transactionController.pollIntentMetadata<TransactionMetadata.SendPublicPayment>(
101101
owner = tokenizedCluster.authority.keyPair,
102102
intentId = data.rendezvous.toPublicKey(),
103103
debugLogs = true
104-
).onSuccess {
104+
).map {
105+
// copy in exchange data we received from querying for give request
106+
it.copy(verifiedExchangeData = exchangeData)
107+
}.onSuccess {
105108
// 6. Ack the receipt of the give request to clear it from the stream
106109
messagingController.ackMessages(data.rendezvous, listOf(messageId))
107110
}

services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/ReceiveGiftCardTransactor.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.getcode.crypt.DerivedKey
55
import com.getcode.crypt.MnemonicPhrase
66
import com.getcode.opencode.controllers.AccountController
77
import com.getcode.opencode.controllers.TransactionController
8+
import com.getcode.opencode.internal.manager.VerifiedState
89
import com.getcode.opencode.managers.GiftCardManager
910
import com.getcode.opencode.managers.MnemonicManager
1011
import com.getcode.opencode.model.accounts.AccountCluster

services/opencode/src/main/kotlin/com/getcode/opencode/managers/BillTransactionManager.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.getcode.opencode.controllers.AccountController
44
import com.getcode.opencode.controllers.MessagingController
55
import com.getcode.opencode.controllers.TransactionController
66
import com.getcode.opencode.internal.manager.VerifiedProtoManager
7+
import com.getcode.opencode.internal.manager.VerifiedState
78
import com.getcode.opencode.internal.transactors.GiveBillTransactor
89
import com.getcode.opencode.internal.transactors.GrabBillTransactor
910
import com.getcode.opencode.internal.transactors.ReceiveGiftCardTransactor
@@ -55,6 +56,7 @@ class BillTransactionManager @Inject constructor(
5556
token: Token,
5657
amount: LocalFiat,
5758
owner: AccountCluster,
59+
verifiedState: VerifiedState?,
5860
billExchangeDataTimeout: Duration?,
5961
present: (List<Byte>) -> Unit,
6062
onGrabbed: suspend (LocalFiat) -> Unit,
@@ -72,7 +74,7 @@ class BillTransactionManager @Inject constructor(
7274
childScope,
7375
verifiedProtoManager,
7476
).apply {
75-
with(token, amount, owner, billExchangeDataTimeout)
77+
with(token, amount, owner, billExchangeDataTimeout, verifiedState)
7678
}
7779

7880
giveTransactor = transactor
@@ -95,7 +97,7 @@ class BillTransactionManager @Inject constructor(
9597
fun attemptGrabFromSender(
9698
owner: AccountCluster,
9799
payload: OpenCodePayload,
98-
onGrabbed: suspend (Token, LocalFiat) -> Unit,
100+
onGrabbed: suspend (Token, LocalFiat, VerifiedState?) -> Unit,
99101
onError: (Throwable) -> Unit,
100102
) {
101103
grabTransactor?.dispose()
@@ -136,7 +138,9 @@ class BillTransactionManager @Inject constructor(
136138
tag = "Bill",
137139
message = "Grabbed ${amount.nativeAmount.formatted()} of ${token.symbol} from sender"
138140
)
139-
onGrabbed(token, amount)
141+
142+
val verifiedState = metadata.verifiedExchangeData?.verifiedState
143+
onGrabbed(token, amount, verifiedState)
140144
sharedScope.launch {
141145
transactionController.updateLimits(owner, force = true)
142146
}

0 commit comments

Comments
 (0)