Skip to content

Commit 1e031fe

Browse files
authored
Merge pull request #713 from code-payments/feat/phantom-sdk-migration
feat(onramp): migrate Phantom integration from manual deeplinks to SDK
2 parents 90b511f + a23ce4d commit 1e031fe

41 files changed

Lines changed: 868 additions & 2031 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/flipcash/app/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ dependencies {
153153
implementation(project(":apps:flipcash:shared:notifications"))
154154
implementation(project(":apps:flipcash:shared:onramp:coinbase"))
155155
implementation(project(":apps:flipcash:shared:onramp:deeplinks"))
156+
implementation(libs.phantom.connect) {
157+
exclude(group = "com.ionspin.kotlin", module = "multiplatform-crypto-libsodium-bindings-android-debug")
158+
}
156159
implementation(project(":apps:flipcash:shared:payments"))
157160
implementation(project(":apps:flipcash:shared:permissions"))
158161
implementation(project(":apps:flipcash:shared:phone"))

apps/flipcash/app/src/main/AndroidManifest.xml

Lines changed: 13 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,6 @@
2828
<action android:name="android.intent.action.VIEW" />
2929
<data android:host="phantom.app" />
3030
</intent>
31-
32-
<intent>
33-
<action android:name="android.intent.action.VIEW" />
34-
<data android:host="backpack.app" />
35-
</intent>
36-
37-
<intent>
38-
<action android:name="android.intent.action.VIEW" />
39-
<data android:host="solflare.com" />
40-
</intent>
4131
</queries>
4232

4333
<application
@@ -82,8 +72,6 @@
8272
<data android:pathPattern="/login.*" />
8373
<data android:pathPattern="/token.*" />
8474
<data android:pathPattern="/verify.*" />
85-
<data android:pathPattern="/external/.*/connected" />
86-
<data android:pathPattern="/external/.*/signed" />
8775
</intent-filter>
8876

8977
<!-- send.flipcash.com App Links -->
@@ -160,29 +148,6 @@
160148
android:scheme="https" />
161149
</intent-filter>
162150

163-
<intent-filter android:autoVerify="true">
164-
<action android:name="android.intent.action.VIEW" />
165-
166-
<category android:name="android.intent.category.DEFAULT" />
167-
<category android:name="android.intent.category.BROWSABLE" />
168-
169-
<data
170-
android:host="app.flipcash.com"
171-
android:pathPattern="/external/.*/connected"
172-
android:scheme="https" />
173-
</intent-filter>
174-
175-
<intent-filter android:autoVerify="true">
176-
<action android:name="android.intent.action.VIEW" />
177-
178-
<category android:name="android.intent.category.DEFAULT" />
179-
<category android:name="android.intent.category.BROWSABLE" />
180-
181-
<data
182-
android:host="app.flipcash.com"
183-
android:pathPattern="/external/.*/signed"
184-
android:scheme="https" />
185-
</intent-filter>
186151

187152
<intent-filter android:autoVerify="true">
188153
<action android:name="android.intent.action.VIEW" />
@@ -232,6 +197,19 @@
232197
</intent-filter>
233198
</activity>
234199

200+
<activity
201+
android:name="dev.bmcreations.phantom.connect.wallet.PhantomWalletCallbackActivity"
202+
android:exported="true"
203+
android:launchMode="singleTask"
204+
android:theme="@android:style/Theme.Translucent.NoTitleBar">
205+
<intent-filter>
206+
<action android:name="android.intent.action.VIEW" />
207+
<category android:name="android.intent.category.DEFAULT" />
208+
<category android:name="android.intent.category.BROWSABLE" />
209+
<data android:scheme="https" android:host="app.flipcash.com" android:path="/phantom-wallet-callback" />
210+
</intent-filter>
211+
</activity>
212+
235213
<!--
236214
Prompt Google Play services to install the backported photo picker module
237215
https://developer.android.com/training/data-storage/shared/photopicker#device-availability

apps/flipcash/app/src/main/kotlin/com/flipcash/app/FlipcashApp.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import com.flipcash.app.auth.AuthManager
1515
import com.flipcash.app.currency.PreferredCurrencyController
1616
import com.getcode.opencode.repositories.EventRepository
1717
import com.getcode.utils.trace
18+
import dev.bmcreations.phantom.connect.PhantomSdk
1819
import dagger.hilt.android.HiltAndroidApp
1920
import javax.inject.Inject
2021

@@ -41,7 +42,7 @@ class FlipcashApp : Application(), Configuration.Provider, SingletonImageLoader.
4142

4243
override fun onCreate() {
4344
super.onCreate()
44-
45+
PhantomSdk.init(this)
4546
authManager.init()
4647

4748
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)

apps/flipcash/app/src/main/kotlin/com/flipcash/app/MainActivity.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ import com.flipcash.app.billing.BillingClient
1919
import com.flipcash.app.core.LocalUserManager
2020
import com.flipcash.app.core.verification.email.EmailCodeChannel
2121
import com.flipcash.app.core.verification.email.LocalEmailCodeChannel
22-
import com.flipcash.app.onramp.ExternalWalletOnRampController
23-
import com.flipcash.app.onramp.LocalExternalWalletOnRampController
2422
import com.flipcash.app.onramp.LocalCoinbaseOnRampController
2523
import com.flipcash.app.onramp.CoinbaseOnRampController
2624
import com.flipcash.app.featureflags.FeatureFlagController
@@ -117,9 +115,6 @@ class MainActivity : FragmentActivity() {
117115
@Inject
118116
lateinit var emailCodeChannel: EmailCodeChannel
119117

120-
@Inject
121-
lateinit var externalWalletOnRampController: ExternalWalletOnRampController
122-
123118
@Inject
124119
lateinit var coinbaseOnRampController: CoinbaseOnRampController
125120

@@ -146,7 +141,6 @@ class MainActivity : FragmentActivity() {
146141
LocalBillPlaygroundController provides billPlaygroundController,
147142
LocalAppUpdater provides appUpdater,
148143
LocalEmailCodeChannel provides emailCodeChannel,
149-
LocalExternalWalletOnRampController provides externalWalletOnRampController,
150144
LocalCoinbaseOnRampController provides coinbaseOnRampController,
151145
LocalUiTesting provides intent.getBooleanExtra(UI_TEST, false),
152146
) {

apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/ui/App.kt

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ import com.flipcash.app.internal.ui.navigation.appEntryProvider
4646
import com.flipcash.app.internal.ui.navigation.decorators.rememberNavBlockingOverlayEntryDecorator
4747
import com.flipcash.app.internal.ui.navigation.decorators.rememberNavMessagingEntryDecorator
4848
import com.flipcash.app.onramp.CoinbaseOnRampHandler
49-
import com.flipcash.app.onramp.ExternalWalletOnRampHandler
50-
import com.flipcash.app.onramp.LocalExternalWalletOnRampController
5149
import com.flipcash.app.router.LocalRouter
5250
import com.flipcash.app.session.LocalSessionController
5351
import com.flipcash.app.theme.FlipcashTheme
@@ -149,7 +147,6 @@ internal fun App(
149147
LocalScrimController provides scrimController,
150148
LocalSharedTransitionScope provides this,
151149
) {
152-
ExternalWalletOnRampHandler(navigator = codeNavigator) {
153150
CoinbaseOnRampHandler {
154151
AppNavHost(
155152
navigator = codeNavigator,
@@ -235,10 +232,8 @@ internal fun App(
235232

236233
ScrimOverlay(scrimController)
237234
}
238-
}
239235

240236
val emailCodeChannel = LocalEmailCodeChannel.current
241-
val externalWalletController = LocalExternalWalletOnRampController.current
242237
LaunchedEffect(deepLink) {
243238
val link = deepLink ?: return@LaunchedEffect
244239

@@ -267,10 +262,6 @@ internal fun App(
267262
}
268263
}
269264

270-
is DeeplinkAction.ExternalWallet -> externalWalletController.handleWalletDeeplink(
271-
action.type
272-
)
273-
274265
is DeeplinkAction.Login -> viewModel.handleLoginEntropy(
275266
action.entropy,
276267
onSwitchAccount = {

apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/ui/navigation/AppScreenContent.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ fun appEntryProvider(
111111
SwapFlowScreen(route = key, resultStateRegistry = resultStateRegistry)
112112
}
113113
annotatedEntry<AppRoute.Token.TxProcessing> { key ->
114-
TokenTxProcessingScreen(key.swapId, key.swapPurpose, key.amount, key.awaitExternalWallet, key.isFundingShortfall)
114+
TokenTxProcessingScreen(key.swapId, key.swapPurpose, key.amount, key.isFundingShortfall)
115115
}
116116
annotatedEntry<AppRoute.Token.Discovery> { TokenDiscoveryScreen() }
117117
annotatedEntry<AppRoute.Token.CurrencyCreator> { key ->

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/AppRoute.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,6 @@ sealed interface AppRoute : NavKey, Parcelable {
153153
val swapId: SwapId,
154154
val swapPurpose: SwapPurpose? = null,
155155
val amount: VerifiedFiat? = null,
156-
val awaitExternalWallet: Boolean = false,
157156
val isFundingShortfall: Boolean = false,
158157
) : Token, NonDismissableRoute, NonDraggableRoute
159158

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/DeeplinkAction.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package com.flipcash.app.core.navigation
22

33
sealed interface DeeplinkAction {
44
data class Navigate(val routes: List<com.flipcash.app.core.AppRoute>) : DeeplinkAction
5-
data class ExternalWallet(val type: DeeplinkType) : DeeplinkAction
65
data class Login(val entropy: String) : DeeplinkAction
76
data class OpenCashLink(val entropy: String) : DeeplinkAction
87
data object None : DeeplinkAction

apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/DeeplinkType.kt

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,7 @@ package com.flipcash.app.core.navigation
22

33
import android.net.Uri
44
import android.os.Parcelable
5-
import com.flipcash.app.core.onramp.deeplinks.WalletDeeplinkConnectionResult
6-
import com.flipcash.app.core.onramp.deeplinks.ExternalWalletDeeplinkError
7-
import com.flipcash.app.core.onramp.deeplinks.OnRampDeeplinkOrigin
8-
import com.flipcash.app.core.onramp.deeplinks.WalletDeeplinkSigningResult
9-
import com.getcode.ed25519.Ed25519
105
import com.getcode.solana.keys.Mint
11-
import com.getcode.vendor.Base58
126
import kotlinx.parcelize.Parcelize
137
import kotlinx.serialization.Serializable
148

@@ -21,24 +15,6 @@ sealed interface DeeplinkType: Parcelable {
2115

2216
@Serializable data class TokenInfo(val mint: Mint): DeeplinkType, Navigatable
2317

24-
sealed interface ExternalWalletStep {
25-
val origin: OnRampDeeplinkOrigin
26-
}
27-
28-
@Serializable
29-
data class ExternalWalletConnection(
30-
override val origin: OnRampDeeplinkOrigin,
31-
val result: WalletDeeplinkConnectionResult?,
32-
val error: ExternalWalletDeeplinkError? = null
33-
): DeeplinkType, ExternalWalletStep, Navigatable
34-
35-
@Serializable
36-
data class ExternalWalletSignedTransaction(
37-
override val origin: OnRampDeeplinkOrigin,
38-
val result: WalletDeeplinkSigningResult?,
39-
val error: ExternalWalletDeeplinkError? = null
40-
): DeeplinkType, ExternalWalletStep, Navigatable
41-
4218
@Serializable
4319
data class EmailVerification(
4420
val email: String,
@@ -88,4 +64,4 @@ sealed interface Key {
8864
}
8965

9066
private operator fun Regex.contains(text: String?): Boolean =
91-
text?.let { this.matches(it) } ?: false
67+
text?.let { this.matches(it) } ?: false
Lines changed: 0 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,7 @@
11
package com.flipcash.app.core.onramp.deeplinks
22

33
import android.os.Parcelable
4-
import com.flipcash.app.core.AppRoute
5-
import com.getcode.ed25519.Ed25519
6-
import com.getcode.opencode.model.core.ID
7-
import com.getcode.opencode.utils.base64
8-
import com.getcode.opencode.utils.base64UrlSafe
9-
import com.getcode.solana.keys.Mint
104
import com.getcode.solana.keys.PublicKey
11-
import com.getcode.solana.keys.base58
12-
import com.getcode.utils.base58
13-
import com.getcode.utils.decodeBase58
14-
import com.getcode.utils.decodeBase64
15-
import com.getcode.utils.serializer.ByteListAsBase64Serializer
165
import kotlinx.parcelize.Parcelize
176
import kotlinx.serialization.SerialName
187
import kotlinx.serialization.Serializable
@@ -31,101 +20,3 @@ data class ExternallySignedTransaction(
3120
@SerialName("transaction")
3221
val serializedTransaction: String,
3322
): Parcelable
34-
35-
@Serializable
36-
@Parcelize
37-
sealed class OnRampDeeplinkOrigin: Parcelable {
38-
@Serializable @Parcelize
39-
data object Menu : OnRampDeeplinkOrigin()
40-
41-
@Serializable @Parcelize
42-
data class Give(val tokenAddress: Mint?) : OnRampDeeplinkOrigin()
43-
44-
@Serializable @Parcelize
45-
data object Wallet: OnRampDeeplinkOrigin()
46-
47-
@Serializable @Parcelize
48-
data class TokenInfo(val mint: Mint): OnRampDeeplinkOrigin()
49-
50-
@Serializable @Parcelize
51-
data object Reserves: OnRampDeeplinkOrigin()
52-
53-
@Serializable @Parcelize
54-
data object CurrencyCreator: OnRampDeeplinkOrigin()
55-
56-
57-
fun forUri(): String {
58-
return when(this) {
59-
Menu -> "menu"
60-
is Give -> "give-${tokenAddress?.base58()?.base64UrlSafe}"
61-
Wallet -> "wallet"
62-
is TokenInfo -> "token-${mint.base58().base64UrlSafe}"
63-
Reserves -> "reserves"
64-
CurrencyCreator -> "currency-creator"
65-
}.lowercase()
66-
}
67-
68-
companion object Companion {
69-
fun fromRoute(route: AppRoute?): OnRampDeeplinkOrigin? {
70-
return when (route) {
71-
is AppRoute.Sheets.Menu -> Menu
72-
is AppRoute.Sheets.Give -> Give(route.mint)
73-
is AppRoute.Sheets.Wallet -> Wallet
74-
is AppRoute.Token.Info -> {
75-
if (route.mint == Mint.usdf) Reserves else TokenInfo(route.mint)
76-
}
77-
is AppRoute.Token.CurrencyCreator -> CurrencyCreator
78-
79-
else -> null
80-
}
81-
}
82-
83-
fun fromString(value: String?): OnRampDeeplinkOrigin? {
84-
return when {
85-
value == "menu" -> Menu
86-
value?.startsWith("give-") == true -> {
87-
val tokenAddress = value.removePrefix("give-").decodeBase64().base58
88-
val mint = runCatching {
89-
Mint(tokenAddress)
90-
}.getOrNull() ?: return null
91-
Give(mint)
92-
}
93-
value == "wallet" -> Wallet
94-
value == "reserves" -> Reserves
95-
value == "currency-creator" -> CurrencyCreator
96-
value?.startsWith("token-") == true -> {
97-
val mintString = value.removePrefix("token-").decodeBase64().base58
98-
val mint = runCatching {
99-
Mint(mintString)
100-
}.onFailure { it.printStackTrace() }.getOrNull() ?: return null
101-
102-
TokenInfo(mint)
103-
}
104-
105-
else -> return null
106-
}
107-
}
108-
}
109-
}
110-
111-
@Serializable
112-
@Parcelize
113-
data class WalletDeeplinkConnectionResult(
114-
@Serializable(with = ByteListAsBase64Serializer::class) val encryptionPublicKey: List<Byte>,
115-
@Serializable(with = ByteListAsBase64Serializer::class) val nonce: List<Byte>,
116-
@Serializable(with = ByteListAsBase64Serializer::class) val encryptedData: List<Byte>
117-
): Parcelable
118-
119-
@Serializable
120-
@Parcelize
121-
data class WalletDeeplinkSigningResult(
122-
@Serializable(with = ByteListAsBase64Serializer::class) val nonce: List<Byte>,
123-
@Serializable(with = ByteListAsBase64Serializer::class) val encryptedData: List<Byte>,
124-
): Parcelable
125-
126-
@Serializable
127-
@Parcelize
128-
data class ExternalWalletDeeplinkError(
129-
val errorCode: String,
130-
val errorMessage: String,
131-
): Parcelable

0 commit comments

Comments
 (0)