Skip to content

Commit 105f416

Browse files
committed
fix(mwa): send CAIP-2 chain on reauthorize so signing stays on the right network
The chain fix only covered authorize. Every sign re-establishes the session via reauthorize, which omitted chain — so MWA 2.0 wallets (Seeker Seed Vault) defaulted the re-established session to solana:mainnet and rejected devnet transactions with 'Network mismatch', even though the original authorize was devnet. Per the MWA 2.0 spec, reauthorize is deprecated in favour of authorize carrying an auth_token, and chain defaults to solana:mainnet when absent. So: - MobileWalletAdapterClient.Reauthorize now emits an 'authorize' request with the auth_token plus cluster + chain. When the chain matches the token's binding the wallet silently reuses the token (no extra prompt). - IAdapterOperations.Reauthorize / ReauthorizeOperation thread rpcCluster + chain; RunPrivileged passes them through. - Tests: contract test updated for the new Reauthorize signature; client tests assert chain is forwarded on reauthorize and that it now uses the authorize method. Verified on a physical Seeker (Seed Vault, devnet): authorize and reauthorize both send chain=solana:devnet and the wallet establishes a devnet session.
1 parent 4d6dc69 commit 105f416

5 files changed

Lines changed: 53 additions & 16 deletions

File tree

Runtime/codebase/SolanaMobileStack/Interfaces/IAdapterOperations.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ public interface IAdapterOperations
1212
// chain: optional CAIP-2 identifier (e.g. "solana:devnet") for MWA 2.0 wallets.
1313
public Task<AuthorizationResult> Authorize(Uri identityUri, Uri iconUri, string identityName, string rpcCluster, string chain = null);
1414
[Preserve]
15-
public Task<AuthorizationResult> Reauthorize(Uri identityUri, Uri iconUri, string identityName, string authToken);
15+
// rpcCluster/chain: MWA 2.0 requires the network identifier on reauthorize too.
16+
// The spec deprecates the standalone reauthorize in favour of authorize carrying an
17+
// auth_token; when chain is absent the wallet (e.g. Seeker Seed Vault) defaults the
18+
// re-established session to solana:mainnet, causing a "Network mismatch" at sign time.
19+
public Task<AuthorizationResult> Reauthorize(Uri identityUri, Uri iconUri, string identityName, string authToken, string rpcCluster = null, string chain = null);
1620
[Preserve]
1721
public Task Deauthorize(string authToken);
1822
[Preserve]

Runtime/codebase/SolanaMobileStack/MobileWalletAdapterClient.cs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,22 @@ public Task<AuthorizationResult> Authorize(Uri identityUri, Uri iconUri, string
3434
return SendRequest<AuthorizationResult>(request);
3535
}
3636

37-
public Task<AuthorizationResult> Reauthorize(Uri identityUri, Uri iconUri, string identityName, string authToken)
37+
public Task<AuthorizationResult> Reauthorize(Uri identityUri, Uri iconUri, string identityName, string authToken, string cluster = null, string chain = null)
3838
{
39+
// MWA 2.0 deprecated the standalone `reauthorize` method in favour of `authorize`
40+
// carrying an `auth_token`. The `chain` MUST be re-sent here: when it is absent the
41+
// wallet (e.g. Seeker Seed Vault) defaults the re-established session to
42+
// solana:mainnet, producing a "Network mismatch" at sign time even though the
43+
// original authorize was devnet. When the chain matches the token's binding the
44+
// wallet silently reuses the existing auth_token (no extra user prompt).
3945
var request = PrepareAuthRequest(
4046
identityUri,
41-
iconUri,
42-
identityName,
43-
null,
44-
"reauthorize");
45-
47+
iconUri,
48+
identityName,
49+
cluster,
50+
"authorize",
51+
chain);
52+
4653
request.Params.AuthToken = authToken;
4754

4855
return SendRequest<AuthorizationResult>(request);

Runtime/codebase/SolanaMobileStack/SolanaMobileWalletAdapter.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ private async Task RunPrivileged(Action<IAdapterOperations> privilegedAction, st
189189
// operation in one session, so only the operation itself prompts.
190190
if (!_authToken.IsNullOrEmpty())
191191
{
192-
var reauthorize = new ReauthorizeOperation(_walletOptions, _authToken);
192+
var reauthorize = new ReauthorizeOperation(
193+
_walletOptions, _authToken, RPCNameMap[(int)RpcCluster], ChainNameMap[(int)RpcCluster]);
193194
using (var scenario = await CreateTargetedScenario())
194195
{
195196
var actions = reauthorize.BuildActions();
@@ -609,13 +610,17 @@ internal sealed class ReauthorizeOperation
609610
{
610611
private readonly SolanaMobileWalletAdapterOptions _opts;
611612
private readonly string _authToken;
612-
613+
private readonly string _cluster;
614+
private readonly string _chain;
615+
613616
public AuthorizationResult Authorization { get; private set; }
614617

615-
public ReauthorizeOperation(SolanaMobileWalletAdapterOptions opts, string authToken)
618+
public ReauthorizeOperation(SolanaMobileWalletAdapterOptions opts, string authToken, string cluster = null, string chain = null)
616619
{
617620
_opts = opts;
618621
_authToken = authToken;
622+
_cluster = cluster;
623+
_chain = chain;
619624
}
620625

621626
public List<Action<IAdapterOperations>> BuildActions()
@@ -627,7 +632,7 @@ public List<Action<IAdapterOperations>> BuildActions()
627632
Authorization = await client.Reauthorize(
628633
new Uri(_opts.identityUri),
629634
new Uri(_opts.iconUri, UriKind.Relative),
630-
_opts.name, _authToken);
635+
_opts.name, _authToken, _cluster, _chain);
631636
}
632637
};
633638
}

Tests/EditMode/Contracts/IAdapterOperationsContractTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ public void Interface_Has_Reauthorize_WithExpectedSignature()
6060
Assert.IsNotNull(method, "IAdapterOperations.Reauthorize must exist");
6161
Assert.AreEqual(typeof(Task<AuthorizationResult>), method.ReturnType,
6262
"Reauthorize must return Task<AuthorizationResult>");
63-
Assert.IsTrue(HasParams(method, typeof(Uri), typeof(Uri), typeof(string), typeof(string)),
64-
"Reauthorize params must be (Uri identityUri, Uri iconUri, string identityName, string authToken)");
63+
Assert.IsTrue(HasParams(method, typeof(Uri), typeof(Uri), typeof(string), typeof(string), typeof(string), typeof(string)),
64+
"Reauthorize params must be (Uri identityUri, Uri iconUri, string identityName, string authToken, string rpcCluster, string chain)");
6565
}
6666

6767

Tests/EditMode/MwaClient/MobileWalletAdapterClientTests.cs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,10 @@ public void Authorize_ThrowsArgumentException_WhenIconUri_IsAbsolute()
210210

211211
// Reauthorize
212212
[Test]
213-
public void Reauthorize_SendsJsonRpc_WithCorrectMethod()
213+
public void Reauthorize_SendsJsonRpc_AsAuthorizeWithAuthToken()
214214
{
215+
// MWA 2.0 deprecated the standalone `reauthorize` method; reauthorization is
216+
// performed via `authorize` carrying an auth_token.
215217
// Arrange
216218
var identityUri = new Uri("https://example.com");
217219
const string authToken = "test-auth-token-abc123";
@@ -221,8 +223,8 @@ public void Reauthorize_SendsJsonRpc_WithCorrectMethod()
221223

222224
// Assert
223225
var request = DecodeLastRequest();
224-
Assert.AreEqual("reauthorize", request.Method,
225-
"Method must be 'reauthorize'");
226+
Assert.AreEqual("authorize", request.Method,
227+
"Method must be 'authorize' (MWA 2.0 reauthorize-via-authorize)");
226228
}
227229

228230
[Test]
@@ -240,5 +242,24 @@ public void Reauthorize_SendsJsonRpc_WithAuthToken()
240242
Assert.AreEqual(authToken, request.Params.AuthToken,
241243
"Params.AuthToken must match the supplied auth token");
242244
}
245+
246+
[Test]
247+
public void Reauthorize_SendsJsonRpc_WithChain()
248+
{
249+
// The chain MUST be forwarded on reauthorize, or the wallet defaults the
250+
// re-established session to solana:mainnet (Network mismatch at sign time).
251+
// Arrange
252+
var identityUri = new Uri("https://example.com");
253+
const string authToken = "test-auth-token-abc123";
254+
const string chain = "solana:devnet";
255+
256+
// Act
257+
_ = _client.Reauthorize(identityUri, null, "TestApp", authToken, "devnet", chain);
258+
259+
// Assert
260+
var request = DecodeLastRequest();
261+
Assert.AreEqual(chain, request.Params.Chain,
262+
"Params.Chain must match the supplied CAIP-2 chain string on reauthorize");
263+
}
243264
}
244265
}

0 commit comments

Comments
 (0)