Mobile
MWA Deep Dive

MWA Deep Dive

Цей контент перекладається і буде доступний тут, коли буде готовий.

JSON-RPC Methods Reference

Once a secure session is established, the dApp communicates with the wallet using JSON-RPC 2.0 over the encrypted channel. This lesson documents every method, their parameters, and response formats.

Method Categories

MWA defines two categories of methods:

Non-privileged Methods: Can be called at any time after session establishment.

  • authorize

  • deauthorize

  • get_capabilities

Privileged Methods: Require prior successful authorize call.

  • sign_and_send_transactions

  • sign_messages

  • clone_authorization

authorize

Requests user authorization for the dApp.

Request

json
{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "authorize",
  "params": {
    "identity": {
      "uri": "https://myapp.com",
      "icon": "favicon.ico",
      "name": "My dApp"
    },
    "cluster": "mainnet-beta",
    "auth_token": "previous_token_for_reauthorization",
    "features": ["sign_and_send_transactions:2", "sign_messages"],
    "addresses": ["base64_encoded_addresses"]
  }
}

Parameters

ParameterTypeRequiredDescription
identityobjectYesInformation about the dApp for display
identity.uristringYesURI for identity verification
identity.iconstringNoRelative path to icon from identity.uri
identity.namestringNoDisplay name for the dApp
clusterstringNoSolana cluster: mainnet-beta, testnet, devnet, or custom URL
auth_tokenstringNoPrevious auth token for silent reauthorization
featuresstring[]NoList of features/versions the dApp requires
addressesstring[]NoSpecific account addresses to authorize

Response (Success)

json
{
  "jsonrpc": "2.0",
  "id": "1",
  "result": {
    "accounts": [
      {
        "address": "base64_encoded_pubkey",
        "display_address": "7xKXt...",
        "display_address_format": "base58",
        "label": "Main Wallet",
        "icon": "data:image/png;base64,...",
        "chains": ["solana:mainnet"],
        "features": ["solana:signAndSendTransaction"]
      }
    ],
    "auth_token": "new_or_refreshed_token",
    "wallet_uri_base": "https://phantom.app/ul/v1/",
    "sign_in_result": { /* if sign-in was requested */ }
  }
}

Response Fields

FieldTypeDescription
accountsarrayAuthorized accounts
accounts[].addressstringBase64-encoded public key
accounts[].display_addressstringHuman-readable address
accounts[].display_address_formatstringFormat: base58
accounts[].labelstringOptional account name
accounts[].iconstringOptional account icon (data URI)
accounts[].chainsstring[]Chain identifiers (CAIP-2 format)
accounts[].featuresstring[]Account-supported features
auth_tokenstringToken for future reauthorization
wallet_uri_basestringBase URI for wallet-specific deep links

Reauthorization Flow

If auth_token is provided and still valid, the wallet may skip user interaction:

text
dApp                                     Wallet
  │                                        │
  │ authorize(auth_token="abc123")         │
  │──────────────────────────────────────►│
  │                                        │ Token valid?
  │                                        │ Yes → silent success
  │◄──────────────────────────────────────│
  │ result: { accounts, auth_token }       │

If the token is invalid or expired:

text
  │ authorize(auth_token="expired")        │
  │──────────────────────────────────────►│
  │                                        │ Token invalid
  │                                        │ Show authorization UI
  │                                        │ User approves
  │◄──────────────────────────────────────│
  │ result: { accounts, new_auth_token }   │

deauthorize

Invalidates a previous authorization.

Request

json
{
  "jsonrpc": "2.0",
  "id": "2",
  "method": "deauthorize",
  "params": {
    "auth_token": "token_to_invalidate"
  }
}

Parameters

ParameterTypeRequiredDescription
auth_tokenstringYesThe auth token to invalidate

Response (Success)

json
{
  "jsonrpc": "2.0",
  "id": "2",
  "result": {}
}

Use Cases

  1. User logout: When the user explicitly disconnects their wallet

  2. Security: After detecting suspicious activity

  3. Token rotation: Before requesting fresh authorization

get_capabilities

Queries the wallet's supported features.

Request

json
{
  "jsonrpc": "2.0",
  "id": "3",
  "method": "get_capabilities"
}

No parameters required.

Response

json
{
  "jsonrpc": "2.0",
  "id": "3",
  "result": {
    "supports_clone_authorization": true,
    "supports_sign_and_send_transactions": true,
    "max_transactions_per_request": 10,
    "max_messages_per_request": 10,
    "supported_transaction_versions": ["legacy", 0]
  }
}

Response Fields

FieldTypeDescription
supports_clone_authorizationbooleanWhether clone_authorization is available
supports_sign_and_send_transactionsbooleanWhether the wallet can sign and broadcast
max_transactions_per_requestnumberMaximum transactions in one request
max_messages_per_requestnumberMaximum messages in one request
supported_transaction_versionsarray"legacy", 0 (versioned), etc.

Why Check Capabilities?

Different wallets have different limits and features. Check capabilities before:

  • Sending large transaction batches

  • Using versioned transactions

  • Assuming clone_authorization support

sign_and_send_transactions

Signs transactions and broadcasts them to the network.

Request

json
{
  "jsonrpc": "2.0",
  "id": "4",
  "method": "sign_and_send_transactions",
  "params": {
    "payloads": [
      "base64_encoded_transaction_1",
      "base64_encoded_transaction_2"
    ],
    "options": {
      "min_context_slot": 150000000,
      "commitment": "confirmed",
      "skip_preflight": false,
      "max_retries": 3
    }
  }
}

Parameters

ParameterTypeRequiredDescription
payloadsstring[]YesBase64-encoded serialized transactions
optionsobjectNoTransaction sending options
options.min_context_slotnumberNoMinimum slot for context
options.commitmentstringNoprocessed, confirmed, finalized
options.skip_preflightbooleanNoSkip preflight simulation
options.max_retriesnumberNoNumber of send retries

Transaction Payload Format

Each payload is a Solana transaction, serialized according to its version:

  • Legacy transactions: Standard serialization

  • Versioned transactions (v0): Include version prefix and address lookup tables

The transaction must:

  1. Have recentBlockhash set (or null for the wallet to fill)

  2. Leave the fee payer signature empty (wallet fills this)

  3. Include all other required signatures

Response (Success)

json
{
  "jsonrpc": "2.0",
  "id": "4",
  "result": {
    "signatures": [
      "base64_encoded_signature_1",
      "base64_encoded_signature_2"
    ]
  }
}

Response (Partial Failure)

json
{
  "jsonrpc": "2.0",
  "id": "4",
  "error": {
    "code": -3,
    "message": "Some transactions were not signed",
    "data": {
      "valid": [0],
      "invalid": [1]
    }
  }
}

Error codes for this method:

  • -1: Authorization failed

  • -2: Invalid payloads (malformed transactions)

  • -3: Not all transactions signed (user declined some)

  • -4: Not submitted (broadcast failed)

  • -6: Too many payloads (exceeds max_transactions_per_request)

sign_messages

Signs arbitrary messages (not transactions).

Request

json
{
  "jsonrpc": "2.0",
  "id": "5",
  "method": "sign_messages",
  "params": {
    "payloads": [
      "base64_encoded_message"
    ],
    "addresses": [
      "base64_encoded_pubkey"
    ]
  }
}

Parameters

ParameterTypeRequiredDescription
payloadsstring[]YesBase64-encoded messages to sign
addressesstring[]NoSpecific accounts to sign with (must be authorized)

Response (Success)

json
{
  "jsonrpc": "2.0",
  "id": "5",
  "result": {
    "signed_payloads": [
      "base64_encoded_signed_message"
    ]
  }
}

Message Signing Format

Messages are signed as-is (raw bytes). For human-readable messages, encode as UTF-8 first.

Common patterns:

  • Authentication: Sign a nonce to prove wallet ownership

  • Off-chain data: Sign structured data for protocols like Sign-In With Solana

clone_authorization

Creates a new authorization from an existing one.

Request

json
{
  "jsonrpc": "2.0",
  "id": "6",
  "method": "clone_authorization",
  "params": {}
}

No parameters (uses the current session's authorization).

Response (Success)

json
{
  "jsonrpc": "2.0",
  "id": "6",
  "result": {
    "auth_token": "new_cloned_token"
  }
}

Use Cases

  1. Multi-session apps: Clone authorization to use in background services

  2. Token refresh: Get a new token while the current session is still valid

This method may not be supported by all wallets (check get_capabilities).

Error Response Format

All methods return errors in JSON-RPC format:

json
{
  "jsonrpc": "2.0",
  "id": "1",
  "error": {
    "code": -1,
    "message": "Human-readable error message",
    "data": { /* optional additional data */ }
  }
}

Standard Error Codes

CodeNameDescription
-32700Parse errorInvalid JSON
-32600Invalid requestNot valid JSON-RPC
-32601Method not foundUnknown method name
-32602Invalid paramsInvalid method parameters
-32603Internal errorWallet internal error

MWA-Specific Error Codes

CodeNameDescription
-1ERROR_AUTHORIZATION_FAILEDUser declined or authorization invalid
-2ERROR_INVALID_PAYLOADSTransaction/message payloads malformed
-3ERROR_NOT_SIGNEDUser declined to sign (some or all)
-4ERROR_NOT_SUBMITTEDTransaction send failed
-5ERROR_NOT_CLONEDAuthorization cloning failed
-6ERROR_TOO_MANY_PAYLOADSExceeds wallet limit
-7ERROR_CHAIN_NOT_SUPPORTEDRequested chain not supported by wallet
-100ERROR_ATTEST_ORIGIN_ANDROIDAndroid attestation required but failed

Feature Strings

Feature strings use a namespaced format to identify capabilities and versions:

FeatureDescription
solana:signTransactionsSign transactions without submitting
solana:signAndSendTransactionSign and broadcast a single transaction
solana:signAndSendTransaction:2Version 2 with additional options support
solana:signMessagesMessage signing support
solana:cloneAuthorizationAuthorization cloning support

When calling authorize, specify required features:

json
{
  "method": "authorize",
  "params": {
    "features": ["solana:signAndSendTransaction:2", "solana:signMessages"]
  }
}

The wallet will error if it can't support requested features.

Chain Identifiers

Account responses include chain identifiers in CAIP-2 format:

ChainCAIP-2 Identifier
Mainnet Betasolana:mainnet
Devnetsolana:devnet
Testnetsolana:testnet
Localnetsolana:localnet

Request/Response Flow

A complete session with multiple operations:

text
dApp                                        Wallet
  │                                           │
  │ ──── HELLO_REQ ─────────────────────────► │
  │ ◄─── HELLO_RSP ───────────────────────── │
  │                                           │
  │ ──── authorize ──────────────────────────► │
  │                                           │ [User approves]
  │ ◄─── result: accounts, auth_token ─────── │
  │                                           │
  │ ──── sign_and_send_transactions ─────────► │
  │                                           │ [User reviews]
  │ ◄─── result: signatures ───────────────── │
  │                                           │
  │ ──── deauthorize ────────────────────────► │
  │ ◄─── result: {} ──────────────────────── │
  │                                           │
  │ ──── [WebSocket close] ──────────────────► │

Best Practices

1. Always Check Authorization

Before privileged methods:

typescript
if (!authToken) {
  const authResult = await wallet.authorize(identity);
  authToken = authResult.auth_token;
}

2. Handle Partial Signing

Check for error code -3 which indicates partial signing:

typescript
try {
  const result = await wallet.signAndSendTransactions(payloads);
} catch (error) {
  if (error.code === -3 && error.data) {
    console.log('Signed:', error.data.valid);
    console.log('Declined:', error.data.invalid);
  }
}

3. Respect Wallet Limits

Query capabilities and batch accordingly:

typescript
const caps = await wallet.getCapabilities();
const batchSize = caps.max_transactions_per_request || 1;

for (let i = 0; i < transactions.length; i += batchSize) {
  const batch = transactions.slice(i, i + batchSize);
  await wallet.signAndSendTransactions(batch);
}

4. Use Reauthorization

Store and reuse auth_token:

typescript
// On app start
const savedToken = await AsyncStorage.getItem('auth_token');

// In transact()
const result = await wallet.authorize({
  identity,
  auth_token: savedToken
});

// Save for next time
await AsyncStorage.setItem('auth_token', result.auth_token);

5. Validate Responses

Check response structure before accessing fields:

typescript
if (result.accounts && result.accounts.length > 0) {
  const address = result.accounts[0].address;
  // Use address...
}

In the next lesson, we examine identity verification: how wallets confirm the dApp is who it claims to be.

Blueshift © 2026Commit: 1b8118f