Skip to content

Commit

Permalink
walletlib + fakewallet updates (#574)
Browse files Browse the repository at this point in the history
* walletlib + fakewallet updates

* fix test commands

* remove auth token from consumer auth request

* hide protocol version from consumers

* change legacy flavor app name for easier differentiation

* couple small fixes

* resolve merge conflict

* update fakewallet

* update fakewallet

* some cleanup

* clean up reauth, fixes bug with reauth chain
  • Loading branch information
Funkatronics authored Oct 23, 2023
1 parent 0490a1c commit 7f3126e
Show file tree
Hide file tree
Showing 21 changed files with 318 additions and 356 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ jobs:
disable-animations: true
script: |
adb shell am broadcast -a android.intent.action.CLOSE_SYSTEM_DIALOGS
./gradlew :fakewallet:connectedDebugAndroidTest
./gradlew :fakewallet:installDebug :fakedapp:connectedDebugAndroidTest
./gradlew :fakewallet:connectedV1DebugAndroidTest
./gradlew :fakewallet:installV1Debug :fakedapp:connectedDebugAndroidTest
- name: Archive fakewallet test results
if: ${{ success() || failure() }}
uses: actions/upload-artifact@v3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@ public class ProtocolContract {
public static final String RESULT_AUTH_TOKEN = "auth_token"; // type: String
public static final String RESULT_ACCOUNTS = "accounts"; // type: JSON array of Account
public static final String RESULT_ACCOUNTS_ADDRESS = "address"; // type: String (base64-encoded addresses)
public static final String RESULT_ACCOUNTS_DISPLAY_ADDRESS = "display_address"; // type: String
public static final String RESULT_ACCOUNTS_DISPLAY_ADDRESS_FORMAT = "display_address_format"; // type: String
public static final String RESULT_ACCOUNTS_LABEL = "label"; // type: String
public static final String RESULT_ACCOUNTS_ICON = "icon"; // type: String
public static final String RESULT_ACCOUNTS_CHAINS = "chains"; // type: String
// RESULT_ACCOUNTS optionally includes a RESULT_SUPPORTED_FEATURES

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,15 @@ public String toString() {
}
}

public static ProtocolVersion from(String versionString) {
public static ProtocolVersion from(String versionString) throws IllegalArgumentException {
switch (versionString.toLowerCase()) {
case "v1":
case "1":
return V1;
default:
case "legacy":
return LEGACY;
default:
throw new IllegalArgumentException("Unknown/unsupported version: " + versionString);
}
}
}
Expand Down
20 changes: 20 additions & 0 deletions android/fakewallet/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,24 @@ android {
}
}

flavorDimensions = ["protocol_version"]

productFlavors {
v1 {
dimension "protocol_version"
applicationId "com.solana.mobilewalletadapter.fakewallet"
buildConfigField "com.solana.mobilewalletadapter.common.protocol.SessionProperties.ProtocolVersion",
"PROTOCOL_VERSION", "com.solana.mobilewalletadapter.common.protocol.SessionProperties.ProtocolVersion.V1"
}
legacy {
dimension "protocol_version"
applicationId "com.solana.mobilewalletadapter.fakewallet.legacy"
resValue "string", "app_name", "Fake Wallet App (Legacy)"
buildConfigField "com.solana.mobilewalletadapter.common.protocol.SessionProperties.ProtocolVersion",
"PROTOCOL_VERSION", "com.solana.mobilewalletadapter.common.protocol.SessionProperties.ProtocolVersion.LEGACY"
}
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
Expand All @@ -66,6 +84,7 @@ android {

buildFeatures {
viewBinding true
buildConfig true
}
}

Expand Down Expand Up @@ -100,6 +119,7 @@ dependencies {
implementation 'io.coil-kt:coil-svg:2.4.0'
implementation 'org.bouncycastle:bcprov-jdk18on:1.76'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
implementation 'io.github.funkatronics:multimult:0.2.0'
implementation project(path: ':walletlib')
kapt 'androidx.room:room-compiler:2.4.3'
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import android.net.Uri
import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.funkatronics.encoders.Base58
import com.solana.mobilewalletadapter.common.ProtocolContract
import com.solana.mobilewalletadapter.common.protocol.SessionProperties
import com.solana.mobilewalletadapter.fakewallet.usecase.*
import com.solana.mobilewalletadapter.walletlib.association.AssociationUri
import com.solana.mobilewalletadapter.walletlib.association.LocalAssociationUri
Expand Down Expand Up @@ -56,18 +58,34 @@ class MobileWalletAdapterViewModel(application: Application) : AndroidViewModel(
associationUri
)

scenario = associationUri.createScenario(
getApplication<FakeWalletApplication>().applicationContext,
MobileWalletAdapterConfig(
true,
10,
10,
arrayOf(MobileWalletAdapterConfig.LEGACY_TRANSACTION_VERSION, 0),
LOW_POWER_NO_CONNECTION_TIMEOUT_MS,
),
AuthIssuerConfig("fakewallet"),
MobileWalletAdapterScenarioCallbacks()
).also { it.start() }
val config = MobileWalletAdapterConfig(
10,
10,
arrayOf(MobileWalletAdapterConfig.LEGACY_TRANSACTION_VERSION, 0),
LOW_POWER_NO_CONNECTION_TIMEOUT_MS,
arrayOf(ProtocolContract.FEATURE_ID_SIGN_TRANSACTIONS)
)

scenario = if (BuildConfig.PROTOCOL_VERSION == SessionProperties.ProtocolVersion.LEGACY) {
// manually create the scenario here so we can override the association protocol version
// this forces ProtocolVersion.LEGACY to simulate a wallet using walletlib 1.x (for testing)
LocalWebSocketServerScenario(
getApplication<FakeWalletApplication>().applicationContext,
config,
AuthIssuerConfig("fakewallet"),
MobileWalletAdapterScenarioCallbacks(),
associationUri.associationPublicKey,
listOf(SessionProperties.ProtocolVersion.LEGACY),
associationUri.port,
)
} else {
associationUri.createScenario(
getApplication<FakeWalletApplication>().applicationContext,
config,
AuthIssuerConfig("fakewallet"),
MobileWalletAdapterScenarioCallbacks()
)
}.also { it.start() }

return true
}
Expand All @@ -90,12 +108,9 @@ class MobileWalletAdapterViewModel(application: Application) : AndroidViewModel(
val keypair = getApplication<FakeWalletApplication>().keyRepository.generateKeypair()
val publicKey = keypair.public as Ed25519PublicKeyParameters
Log.d(TAG, "Generated a new keypair (pub=${publicKey.encoded.contentToString()}) for authorize request")
request.request.completeWithAuthorize(
publicKey.encoded,
"fakewallet",
null,
request.sourceVerificationState.authorizationScope.encodeToByteArray()
)
val accounts = arrayOf(buildAccount(publicKey.encoded, "fakewallet"))
request.request.completeWithAuthorize(accounts, null,
request.sourceVerificationState.authorizationScope.encodeToByteArray())
} else {
request.request.completeWithDecline()
}
Expand Down Expand Up @@ -258,7 +273,7 @@ class MobileWalletAdapterViewModel(application: Application) : AndroidViewModel(
return
}

Log.d(TAG, "Simulating transactions submitted on cluster=${request.request.cluster}")
Log.d(TAG, "Simulating transactions submitted on cluster=${request.request.chain}")

request.request.completeWithSignatures(request.signatures!!)
}
Expand All @@ -268,7 +283,7 @@ class MobileWalletAdapterViewModel(application: Application) : AndroidViewModel(
return
}

Log.d(TAG, "Simulating transactions NOT submitted on cluster=${request.request.cluster}")
Log.d(TAG, "Simulating transactions NOT submitted on cluster=${request.request.chain}")

val signatures = request.signatures!!
val notSubmittedSignatures = Array(signatures.size) { i ->
Expand Down Expand Up @@ -353,14 +368,25 @@ class MobileWalletAdapterViewModel(application: Application) : AndroidViewModel(
}
}

private fun clusterToRpcUri(cluster: String?): Uri {
return when (cluster) {
private fun buildAccount(publicKey: ByteArray, label: String, icon: Uri? = null,
chains: Array<String>? = null, features: Array<String>? = null ) =
AuthorizedAccount(
publicKey, Base58.encodeToString(publicKey), "base58",
label, icon, chains, features
)

private fun chainOrClusterToRpcUri(chainOrCluster: String?): Uri {
return when (chainOrCluster) {
ProtocolContract.CHAIN_SOLANA_MAINNET,
ProtocolContract.CLUSTER_MAINNET_BETA ->
Uri.parse("https://api.mainnet-beta.solana.com")
ProtocolContract.CHAIN_SOLANA_DEVNET,
ProtocolContract.CLUSTER_DEVNET ->
Uri.parse("https://api.devnet.solana.com")
else ->
ProtocolContract.CHAIN_SOLANA_TESTNET,
ProtocolContract.CLUSTER_TESTNET ->
Uri.parse("https://api.testnet.solana.com")
else -> throw IllegalArgumentException("Unsupported chain/cluster: $chainOrCluster")
}
}

Expand Down Expand Up @@ -457,7 +483,7 @@ class MobileWalletAdapterViewModel(application: Application) : AndroidViewModel(

override fun onSignAndSendTransactionsRequest(request: SignAndSendTransactionsRequest) {
if (verifyPrivilegedMethodSource(request)) {
val endpointUri = clusterToRpcUri(request.cluster)
val endpointUri = chainOrClusterToRpcUri(request.chain)
cancelAndReplaceRequest(MobileWalletAdapterServiceRequest.SignAndSendTransactions(request, endpointUri))
} else {
request.completeWithDecline()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ public abstract class AssociationUri {
public final byte[] associationPublicKey;

@NonNull
public final List<SessionProperties.ProtocolVersion> supportedProtocolVersions;
public final List<SessionProperties.ProtocolVersion> associationProtocolVersions;

protected AssociationUri(@NonNull Uri uri) {
this.uri = uri;
validate(uri);
associationPublicKey = parseAssociationToken(uri);
supportedProtocolVersions = parseSupportedProtocolVersions(uri);
associationProtocolVersions = parseSupportedProtocolVersions(uri);
}

private static void validate(@NonNull Uri uri) {
Expand Down Expand Up @@ -68,9 +68,11 @@ private static List<SessionProperties.ProtocolVersion> parseSupportedProtocolVer
AssociationContract.PARAMETER_PROTOCOL_VERSION)) {
try {
supportedVersions.add(SessionProperties.ProtocolVersion.from(supportVersionStr));
} catch (NumberFormatException e) {
throw new IllegalArgumentException("port parameter must be a number", e);
}
} catch (IllegalArgumentException ignored) {}
}

if (supportedVersions.isEmpty()) {
supportedVersions.add(SessionProperties.ProtocolVersion.LEGACY);
}

return supportedVersions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ public LocalWebSocketServerScenario createScenario(@NonNull Context context,
@NonNull Scenario.Callbacks callbacks) {
if (callbacks instanceof LocalScenario.Callbacks) {
return new LocalWebSocketServerScenario(context, mobileWalletAdapterConfig,
authIssuerConfig, (LocalScenario.Callbacks) callbacks, associationPublicKey, port, supportedProtocolVersions);
authIssuerConfig, (LocalScenario.Callbacks) callbacks,
associationPublicKey, associationProtocolVersions, port);
} else {
throw new IllegalArgumentException("callbacks must implement " + LocalScenario.Callbacks.class.getName());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ public class MobileWalletAdapterConfig {
@Size(min = 1)
public final Object[] supportedTransactionVersions;

@NonNull
public final List<SessionProperties.ProtocolVersion> supportedProtocolVersions;

@NonNull
public final String[] optionalFeatures;

Expand All @@ -49,8 +46,7 @@ public MobileWalletAdapterConfig(boolean supportsSignAndSendTransactions,
@IntRange(from = 0) long noConnectionWarningTimeoutMs) {
this(maxTransactionsPerSigningRequest, maxMessagesPerSigningRequest,
supportedTransactionVersions, noConnectionWarningTimeoutMs,
new String[] { ProtocolContract.FEATURE_ID_SIGN_TRANSACTIONS },
List.of(SessionProperties.ProtocolVersion.LEGACY));
new String[] { ProtocolContract.FEATURE_ID_SIGN_TRANSACTIONS });
if (!supportsSignAndSendTransactions)
throw new IllegalArgumentException("signAndSendTransactions is required in MWA 2.0");
}
Expand All @@ -59,12 +55,10 @@ public MobileWalletAdapterConfig(@IntRange(from = 0) int maxTransactionsPerSigni
@IntRange(from = 0) int maxMessagesPerSigningRequest,
@NonNull @Size(min = 1) Object[] supportedTransactionVersions,
@IntRange(from = 0) long noConnectionWarningTimeoutMs,
@NonNull String[] supportedFeatures,
@NonNull List<SessionProperties.ProtocolVersion> supportedProtocolVersions) {
@NonNull String[] supportedFeatures) {
this.maxTransactionsPerSigningRequest = maxTransactionsPerSigningRequest;
this.maxMessagesPerSigningRequest = maxMessagesPerSigningRequest;
this.noConnectionWarningTimeoutMs = noConnectionWarningTimeoutMs;
this.supportedProtocolVersions = supportedProtocolVersions;
this.optionalFeatures = supportedFeatures;
this.supportsSignAndSendTransactions = true;

Expand All @@ -82,4 +76,4 @@ public MobileWalletAdapterConfig(@IntRange(from = 0) int maxTransactionsPerSigni
}
}
}
}
}
Loading

0 comments on commit 7f3126e

Please sign in to comment.