Skip to content

feat: add GetCapabilities MWA 2.0 method#277

Open
mstevens843 wants to merge 1 commit intomagicblock-labs:mainfrom
mstevens843:feature/get-capabilities
Open

feat: add GetCapabilities MWA 2.0 method#277
mstevens843 wants to merge 1 commit intomagicblock-labs:mainfrom
mstevens843:feature/get-capabilities

Conversation

@mstevens843
Copy link
Copy Markdown

@mstevens843 mstevens843 commented Apr 14, 2026

The MWA 2.0 spec defines get_capabilities as a non-privileged method that queries wallet capabilities. This method did not exist in the SDK.

Added GetCapabilities() to the MWA client layer:

  • IAdapterOperations.cs: added GetCapabilities() interface method
  • MobileWalletAdapterClient.cs: sends get_capabilities JSON-RPC request
  • SolanaMobileWalletAdapter.cs: async wrapper via LocalAssociationScenario
  • CapabilitiesResult.cs: response model (MaxTransactionsPerRequest, MaxMessagesPerRequest, SupportedTransactionVersions, Features)

Tested on Solana Seeker with Phantom — returns real values: maxTransactions=10, maxMessages=1, supportedVersions=[legacy, 0], features=[supports_sign_and_send_transactions]

⚠️ NOTE: This is a new MWA 2.0 method that was missing from the SDK. No existing methods were changed. Non-breaking addition.

Status Type ⚠️ Core Change Issue
Ready Feature Yes #273

Problem

The MWA 2.0 spec defines get_capabilities as a non-privileged method for querying wallet limits and supported features. Without it, developers have no way to check how many transactions or messages a wallet can handle per request. Sending more than the wallet supports fails the entire request with
ERROR_TOO_MANY_PAYLOADS and there is no way to prevent it ahead of time.

Solution

Added GetCapabilities() across the MWA client layer following the same pattern as existing methods (authorize, signTransactions, signMessages):

  • IAdapterOperations.cs: added GetCapabilities() to the interface
  • MobileWalletAdapterClient.cs: sends get_capabilities JSON-RPC request over the encrypted session channel
  • SolanaMobileWalletAdapter.cs: async wrapper that handles LocalAssociationScenario lifecycle
  • CapabilitiesResult.cs: new response model with MaxTransactionsPerRequest, MaxMessagesPerRequest, SupportedTransactionVersions, Features

Before & After Screenshots

BEFORE:
No method exists to query wallet capabilities. Developers must guess batch sizes or hardcode limits.

AFTER:
Tested on Solana Seeker with Phantom wallet:

  • MaxTransactionsPerRequest = 10
  • MaxMessagesPerRequest = 1
  • SupportedTransactionVersions = [legacy, 0]
  • Features = [supports_sign_and_send_transactions]

Other changes (e.g. bug fixes, small refactors)

None. Self-contained addition.

Deploy Notes

No new dependencies, scripts, or configuration changes. Pure C# addition to the existing MWA client layer.

New scripts:

  • None

New dependencies:

  • None

Summary by CodeRabbit

  • New Features
    • Added new capability to retrieve wallet adapter information, including transaction and message request limits, supported transaction versions, and available features. Enables developers to query adapter constraints and feature support before executing operations.

The MWA 2.0 spec defines get_capabilities as a non-privileged method
that queries wallet capabilities. This method did not exist in the SDK.

Added GetCapabilities() to the MWA client layer:
- IAdapterOperations.cs: added GetCapabilities() interface method
- MobileWalletAdapterClient.cs: sends get_capabilities JSON-RPC request
- SolanaMobileWalletAdapter.cs: async wrapper via LocalAssociationScenario
- CapabilitiesResult.cs: response model (MaxTransactionsPerRequest,
  MaxMessagesPerRequest, SupportedTransactionVersions, Features)

Tested on Solana Seeker with Phantom — returns real values:
maxTransactions=10, maxMessages=1, supportedVersions=[legacy, 0],
features=[supports_sign_and_send_transactions]

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 14, 2026

Walkthrough

A new GetCapabilities() method is added across the Solana Mobile Stack adapter layer. The method is defined in the IAdapterOperations interface, implemented in MobileWalletAdapterClient and SolanaMobileWalletAdapter, and supported by a new CapabilitiesResult response model class.

Changes

Cohort / File(s) Summary
Interface Contract
Runtime/codebase/SolanaMobileStack/Interfaces/IAdapterOperations.cs
Added GetCapabilities() method signature returning Task<CapabilitiesResult> to the adapter interface.
Response Model
Runtime/codebase/SolanaMobileStack/JsonRpcClient/Responses/CapabilitiesResult.cs, CapabilitiesResult.cs.meta
Added new CapabilitiesResult class with four properties (MaxTransactionsPerRequest, MaxMessagesPerRequest, SupportedTransactionVersions, Features), each decorated with JsonProperty mappings. Includes Unity AOT preservation and required member annotations. Added corresponding Unity metadata file.
Client Implementation
Runtime/codebase/SolanaMobileStack/MobileWalletAdapterClient.cs
Implemented GetCapabilities() method that constructs and sends a JSON-RPC request with method "get_capabilities" and returns CapabilitiesResult.
Adapter Implementation
Runtime/codebase/SolanaMobileStack/SolanaMobileWalletAdapter.cs
Implemented GetCapabilities() async method that executes a LocalAssociationScenario, invokes the adapter client method, and returns the result. Includes error handling that logs and throws exceptions on scenario failure.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add GetCapabilities MWA 2.0 method' directly and clearly summarizes the main change—adding a new GetCapabilities method for MWA 2.0 specification compliance.
Description check ✅ Passed The description is comprehensive, addressing all template sections: Problem (querying wallet capabilities), Solution (implementation across client layers), Before & After (practical examples from testing), and Deploy Notes (no new dependencies).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@Runtime/codebase/SolanaMobileStack/JsonRpcClient/Responses/CapabilitiesResult.cs`:
- Around line 18-24: CapabilitiesResult's collection properties
SupportedTransactionVersions and Features can be deserialized as null and cause
NREs; update the property declarations in the CapabilitiesResult class to
initialize both SupportedTransactionVersions and Features to empty List<string>
instances (e.g., new List<string>()) so consumers can safely iterate without
null checks and keep the existing JsonProperty/RequiredMember attributes intact.

In `@Runtime/codebase/SolanaMobileStack/SolanaMobileWalletAdapter.cs`:
- Around line 191-208: The method captures a CapabilitiesResult into the local
variable capabilities via LocalAssociationScenario.StartAndExecute/
GetCapabilities but may return null even when result.WasSuccessful; after the
call to StartAndExecute and the success check, add a null guard for the
capabilities variable (from this method's local “capabilities”) and handle it
consistently—either throw a descriptive Exception or log an error with
Debug.LogError and throw (e.g., "Capabilities payload was null after successful
association")—so callers never receive a null CapabilitiesResult.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4e9512e0-7855-4ee6-a1a5-218cc1c3b5a7

📥 Commits

Reviewing files that changed from the base of the PR and between 054503e and 28f0757.

📒 Files selected for processing (5)
  • Runtime/codebase/SolanaMobileStack/Interfaces/IAdapterOperations.cs
  • Runtime/codebase/SolanaMobileStack/JsonRpcClient/Responses/CapabilitiesResult.cs
  • Runtime/codebase/SolanaMobileStack/JsonRpcClient/Responses/CapabilitiesResult.cs.meta
  • Runtime/codebase/SolanaMobileStack/MobileWalletAdapterClient.cs
  • Runtime/codebase/SolanaMobileStack/SolanaMobileWalletAdapter.cs

Comment on lines +18 to +24
[JsonProperty("supported_transaction_versions")]
[RequiredMember]
public List<string> SupportedTransactionVersions { get; set; }

[JsonProperty("features", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public List<string> Features { get; set; }
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Initialize collection properties to avoid null-driven crashes.

On Line 20 and Line 24, both lists can deserialize as null, which makes downstream iteration fragile. Prefer non-null defaults.

💡 Proposed fix
     [JsonProperty("supported_transaction_versions")]
     [RequiredMember]
-    public List<string> SupportedTransactionVersions { get; set; }
+    public List<string> SupportedTransactionVersions { get; set; } = new();

     [JsonProperty("features", NullValueHandling = NullValueHandling.Ignore)]
     [RequiredMember]
-    public List<string> Features { get; set; }
+    public List<string> Features { get; set; } = new();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
[JsonProperty("supported_transaction_versions")]
[RequiredMember]
public List<string> SupportedTransactionVersions { get; set; }
[JsonProperty("features", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public List<string> Features { get; set; }
[JsonProperty("supported_transaction_versions")]
[RequiredMember]
public List<string> SupportedTransactionVersions { get; set; } = new();
[JsonProperty("features", NullValueHandling = NullValueHandling.Ignore)]
[RequiredMember]
public List<string> Features { get; set; } = new();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Runtime/codebase/SolanaMobileStack/JsonRpcClient/Responses/CapabilitiesResult.cs`
around lines 18 - 24, CapabilitiesResult's collection properties
SupportedTransactionVersions and Features can be deserialized as null and cause
NREs; update the property declarations in the CapabilitiesResult class to
initialize both SupportedTransactionVersions and Features to empty List<string>
instances (e.g., new List<string>()) so consumers can safely iterate without
null checks and keep the existing JsonProperty/RequiredMember attributes intact.

Comment on lines +191 to +208
CapabilitiesResult capabilities = null;
var localAssociationScenario = new LocalAssociationScenario();
var result = await localAssociationScenario.StartAndExecute(
new List<Action<IAdapterOperations>>
{
async client =>
{
capabilities = await client.GetCapabilities();
}
}
);
if (!result.WasSuccessful)
{
Debug.LogError(result.Error.Message);
throw new Exception(result.Error.Message);
}
return capabilities;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard against null capabilities payload before returning.

On Line 207, capabilities may still be null even when the scenario itself reports success, which can lead to downstream null dereferences.

🛡️ Proposed fix
         if (!result.WasSuccessful)
         {
             Debug.LogError(result.Error.Message);
             throw new Exception(result.Error.Message);
         }
+        if (capabilities == null)
+        {
+            throw new Exception("get_capabilities returned an empty result.");
+        }
         return capabilities;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
CapabilitiesResult capabilities = null;
var localAssociationScenario = new LocalAssociationScenario();
var result = await localAssociationScenario.StartAndExecute(
new List<Action<IAdapterOperations>>
{
async client =>
{
capabilities = await client.GetCapabilities();
}
}
);
if (!result.WasSuccessful)
{
Debug.LogError(result.Error.Message);
throw new Exception(result.Error.Message);
}
return capabilities;
}
CapabilitiesResult capabilities = null;
var localAssociationScenario = new LocalAssociationScenario();
var result = await localAssociationScenario.StartAndExecute(
new List<Action<IAdapterOperations>>
{
async client =>
{
capabilities = await client.GetCapabilities();
}
}
);
if (!result.WasSuccessful)
{
Debug.LogError(result.Error.Message);
throw new Exception(result.Error.Message);
}
if (capabilities == null)
{
throw new Exception("get_capabilities returned an empty result.");
}
return capabilities;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Runtime/codebase/SolanaMobileStack/SolanaMobileWalletAdapter.cs` around lines
191 - 208, The method captures a CapabilitiesResult into the local variable
capabilities via LocalAssociationScenario.StartAndExecute/ GetCapabilities but
may return null even when result.WasSuccessful; after the call to
StartAndExecute and the success check, add a null guard for the capabilities
variable (from this method's local “capabilities”) and handle it
consistently—either throw a descriptive Exception or log an error with
Debug.LogError and throw (e.g., "Capabilities payload was null after successful
association")—so callers never receive a null CapabilitiesResult.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant