@solana-mobile/mobile-wallet-adapter-protocol 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitignore +2 -0
- package/README.md +69 -62
- package/android/.gitignore +14 -0
- package/android/.gradle/4.4.1/fileChanges/last-build.bin +0 -0
- package/android/.gradle/4.4.1/fileHashes/fileHashes.bin +0 -0
- package/android/.gradle/4.4.1/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/7.1/dependencies-accessors/dependencies-accessors.lock +0 -0
- package/android/.gradle/7.1/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/7.1/fileChanges/last-build.bin +0 -0
- package/android/.gradle/7.1/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/7.1/gc.properties +0 -0
- package/android/.gradle/7.5/checksums/checksums.lock +0 -0
- package/android/.gradle/7.5/dependencies-accessors/dependencies-accessors.lock +0 -0
- package/android/.gradle/7.5/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/7.5/fileChanges/last-build.bin +0 -0
- package/android/.gradle/7.5/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/7.5/gc.properties +0 -0
- package/android/.gradle/7.5.1/checksums/checksums.lock +0 -0
- package/android/.gradle/7.5.1/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/7.5.1/dependencies-accessors/dependencies-accessors.lock +0 -0
- package/android/.gradle/7.5.1/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/7.5.1/fileChanges/last-build.bin +0 -0
- package/android/.gradle/7.5.1/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/7.5.1/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
- package/android/.gradle/checksums/checksums.lock +0 -0
- package/android/.gradle/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/build.gradle +146 -146
- package/android/gradle/wrapper/gradle-wrapper.properties +5 -5
- package/android/src/main/java/com/solanamobile/mobilewalletadapter/reactnative/SolanaMobileWalletAdapterModule.kt +178 -139
- package/lib/cjs/index.browser.js +290 -81
- package/lib/cjs/index.js +290 -81
- package/lib/cjs/index.native.js +180 -28
- package/lib/esm/index.browser.js +288 -82
- package/lib/esm/index.js +288 -82
- package/lib/types/index.browser.d.ts +68 -5
- package/lib/types/index.browser.d.ts.map +1 -1
- package/lib/types/index.d.ts +68 -5
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.native.d.ts +68 -5
- package/lib/types/index.native.d.ts.map +1 -1
- package/package.json +56 -51
- package/src/__forks__/react-native/base64Utils.ts +1 -0
- package/src/__forks__/react-native/transact.ts +92 -0
- package/src/arrayBufferToBase64String.ts +10 -0
- package/src/associationPort.ts +19 -0
- package/src/base64Utils.ts +3 -0
- package/src/createHelloReq.ts +12 -0
- package/src/createMobileWalletProxy.ts +175 -0
- package/src/createSIWSMessage.ts +14 -0
- package/src/createSequenceNumberVector.ts +11 -0
- package/src/encryptedMessage.ts +60 -0
- package/src/errors.ts +95 -0
- package/src/generateAssociationKeypair.ts +10 -0
- package/src/generateECDHKeypair.ts +10 -0
- package/src/getAssociateAndroidIntentURL.ts +57 -0
- package/src/getJWS.ts +19 -0
- package/src/getStringWithURLUnsafeBase64CharactersReplaced.ts +11 -0
- package/src/index.ts +3 -0
- package/src/jsonRpcMessage.ts +38 -0
- package/src/parseHelloRsp.ts +46 -0
- package/src/parseSessionProps.ts +33 -0
- package/src/startSession.ts +94 -0
- package/src/transact.ts +266 -0
- package/src/types.ts +181 -0
- package/tsconfig.cjs.json +7 -0
- package/tsconfig.json +8 -0
package/lib/esm/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createSignInMessageText } from '@solana/wallet-standard-util';
|
|
2
|
+
|
|
1
3
|
// Typescript `enums` thwart tree-shaking. See https://bargsten.org/jsts/enums/
|
|
2
4
|
const SolanaMobileWalletAdapterErrorCode = {
|
|
3
5
|
ERROR_ASSOCIATION_PORT_OUT_OF_RANGE: 'ERROR_ASSOCIATION_PORT_OUT_OF_RANGE',
|
|
@@ -6,6 +8,7 @@ const SolanaMobileWalletAdapterErrorCode = {
|
|
|
6
8
|
ERROR_SESSION_CLOSED: 'ERROR_SESSION_CLOSED',
|
|
7
9
|
ERROR_SESSION_TIMEOUT: 'ERROR_SESSION_TIMEOUT',
|
|
8
10
|
ERROR_WALLET_NOT_FOUND: 'ERROR_WALLET_NOT_FOUND',
|
|
11
|
+
ERROR_INVALID_PROTOCOL_VERSION: 'ERROR_INVALID_PROTOCOL_VERSION',
|
|
9
12
|
};
|
|
10
13
|
class SolanaMobileWalletAdapterError extends Error {
|
|
11
14
|
constructor(...args) {
|
|
@@ -73,6 +76,175 @@ function createHelloReq(ecdhPublicKey, associationKeypairPrivateKey) {
|
|
|
73
76
|
});
|
|
74
77
|
}
|
|
75
78
|
|
|
79
|
+
function encode(input) {
|
|
80
|
+
return window.btoa(input);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function createSIWSMessage(payload) {
|
|
84
|
+
return createSignInMessageText(payload);
|
|
85
|
+
}
|
|
86
|
+
function createSIWSMessageBase64(payload) {
|
|
87
|
+
return encode(createSIWSMessage(payload));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// optional features
|
|
91
|
+
const SolanaSignTransactions = 'solana:signTransactions';
|
|
92
|
+
const SolanaCloneAuthorization = 'solana:cloneAuthorization';
|
|
93
|
+
const SolanaSignInWithSolana = 'solana:signInWithSolana';
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Creates a {@link MobileWallet} proxy that handles backwards compatibility and API to RPC conversion.
|
|
97
|
+
*
|
|
98
|
+
* @param protocolVersion the protocol version in use for this session/request
|
|
99
|
+
* @param protocolRequestHandler callback function that handles sending the RPC request to the wallet endpoint.
|
|
100
|
+
* @returns a {@link MobileWallet} proxy
|
|
101
|
+
*/
|
|
102
|
+
function createMobileWalletProxy(protocolVersion, protocolRequestHandler) {
|
|
103
|
+
return new Proxy({}, {
|
|
104
|
+
get(target, p) {
|
|
105
|
+
if (target[p] == null) {
|
|
106
|
+
target[p] = function (inputParams) {
|
|
107
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
108
|
+
const { method, params } = handleMobileWalletRequest(p, inputParams, protocolVersion);
|
|
109
|
+
const result = yield protocolRequestHandler(method, params);
|
|
110
|
+
// if the request tried to sign in but the wallet did not return a sign in result, fallback on message signing
|
|
111
|
+
if (method === 'authorize' && params.sign_in_payload && !result.sign_in_result) {
|
|
112
|
+
result['sign_in_result'] = yield signInFallback(params.sign_in_payload, result, protocolRequestHandler);
|
|
113
|
+
}
|
|
114
|
+
return handleMobileWalletResponse(p, result, protocolVersion);
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
return target[p];
|
|
119
|
+
},
|
|
120
|
+
defineProperty() {
|
|
121
|
+
return false;
|
|
122
|
+
},
|
|
123
|
+
deleteProperty() {
|
|
124
|
+
return false;
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Handles all {@link MobileWallet} API requests and determines the correct MWA RPC method and params to call.
|
|
130
|
+
* This handles backwards compatibility, based on the provided @protocolVersion.
|
|
131
|
+
*
|
|
132
|
+
* @param methodName the name of {@link MobileWallet} method that was called
|
|
133
|
+
* @param methodParams the parameters that were passed to the method
|
|
134
|
+
* @param protocolVersion the protocol version in use for this session/request
|
|
135
|
+
* @returns the RPC request method and params that should be sent to the wallet endpoint
|
|
136
|
+
*/
|
|
137
|
+
function handleMobileWalletRequest(methodName, methodParams, protocolVersion) {
|
|
138
|
+
let params = methodParams;
|
|
139
|
+
let method = methodName
|
|
140
|
+
.toString()
|
|
141
|
+
.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)
|
|
142
|
+
.toLowerCase();
|
|
143
|
+
switch (methodName) {
|
|
144
|
+
case 'authorize': {
|
|
145
|
+
let { chain } = params;
|
|
146
|
+
if (protocolVersion === 'legacy') {
|
|
147
|
+
switch (chain) {
|
|
148
|
+
case 'solana:testnet': {
|
|
149
|
+
chain = 'testnet';
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case 'solana:devnet': {
|
|
153
|
+
chain = 'devnet';
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
case 'solana:mainnet': {
|
|
157
|
+
chain = 'mainnet-beta';
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
default: {
|
|
161
|
+
chain = params.cluster;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
params.cluster = chain;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
switch (chain) {
|
|
168
|
+
case 'testnet':
|
|
169
|
+
case 'devnet': {
|
|
170
|
+
chain = `solana:${chain}`;
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
case 'mainnet-beta': {
|
|
174
|
+
chain = 'solana:mainnet';
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
params.chain = chain;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
case 'reauthorize': {
|
|
182
|
+
const { auth_token, identity } = params;
|
|
183
|
+
if (auth_token) {
|
|
184
|
+
switch (protocolVersion) {
|
|
185
|
+
case 'legacy': {
|
|
186
|
+
method = 'reauthorize';
|
|
187
|
+
params = { auth_token: auth_token, identity: identity };
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
default: {
|
|
191
|
+
method = 'authorize';
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return { method, params };
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Handles all {@link MobileWallet} API responses and modifies the response for backwards compatibility, if needed
|
|
203
|
+
*
|
|
204
|
+
* @param method the {@link MobileWallet} method that was called
|
|
205
|
+
* @param response the original response that was returned by the method call
|
|
206
|
+
* @param protocolVersion the protocol version in use for this session/request
|
|
207
|
+
* @returns the possibly modified response
|
|
208
|
+
*/
|
|
209
|
+
function handleMobileWalletResponse(method, response, protocolVersion) {
|
|
210
|
+
switch (method) {
|
|
211
|
+
case 'getCapabilities': {
|
|
212
|
+
const capabilities = response;
|
|
213
|
+
switch (protocolVersion) {
|
|
214
|
+
case 'legacy': {
|
|
215
|
+
const features = [SolanaSignTransactions];
|
|
216
|
+
if (capabilities.supports_clone_authorization === true) {
|
|
217
|
+
features.push(SolanaCloneAuthorization);
|
|
218
|
+
}
|
|
219
|
+
return Object.assign(Object.assign({}, capabilities), { features: features });
|
|
220
|
+
}
|
|
221
|
+
case 'v1': {
|
|
222
|
+
return Object.assign(Object.assign({}, capabilities), { supports_sign_and_send_transactions: true, supports_clone_authorization: capabilities.features.includes(SolanaCloneAuthorization) });
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return response;
|
|
228
|
+
}
|
|
229
|
+
function signInFallback(signInPayload, authorizationResult, protocolRequestHandler) {
|
|
230
|
+
var _a;
|
|
231
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
232
|
+
const domain = (_a = signInPayload.domain) !== null && _a !== void 0 ? _a : window.location.host;
|
|
233
|
+
const address = authorizationResult.accounts[0].address;
|
|
234
|
+
const siwsMessage = createSIWSMessageBase64(Object.assign(Object.assign({}, signInPayload), { domain, address }));
|
|
235
|
+
const signMessageResult = yield protocolRequestHandler('sign_messages', {
|
|
236
|
+
addresses: [address],
|
|
237
|
+
payloads: [siwsMessage]
|
|
238
|
+
});
|
|
239
|
+
const signInResult = {
|
|
240
|
+
address: address,
|
|
241
|
+
signed_message: siwsMessage,
|
|
242
|
+
signature: signMessageResult.signed_payloads[0].slice(siwsMessage.length)
|
|
243
|
+
};
|
|
244
|
+
return signInResult;
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
76
248
|
const SEQUENCE_NUMBER_BYTES = 4;
|
|
77
249
|
function createSequenceNumberVector(sequenceNumber) {
|
|
78
250
|
if (sequenceNumber >= 4294967296) {
|
|
@@ -84,29 +256,11 @@ function createSequenceNumberVector(sequenceNumber) {
|
|
|
84
256
|
return new Uint8Array(byteArray);
|
|
85
257
|
}
|
|
86
258
|
|
|
87
|
-
function generateAssociationKeypair() {
|
|
88
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
89
|
-
return yield crypto.subtle.generateKey({
|
|
90
|
-
name: 'ECDSA',
|
|
91
|
-
namedCurve: 'P-256',
|
|
92
|
-
}, false /* extractable */, ['sign'] /* keyUsages */);
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function generateECDHKeypair() {
|
|
97
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
98
|
-
return yield crypto.subtle.generateKey({
|
|
99
|
-
name: 'ECDH',
|
|
100
|
-
namedCurve: 'P-256',
|
|
101
|
-
}, false /* extractable */, ['deriveKey', 'deriveBits'] /* keyUsages */);
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
259
|
const INITIALIZATION_VECTOR_BYTES = 12;
|
|
106
|
-
|
|
260
|
+
const ENCODED_PUBLIC_KEY_LENGTH_BYTES = 65;
|
|
261
|
+
function encryptMessage(plaintext, sequenceNumber, sharedSecret) {
|
|
107
262
|
return __awaiter(this, void 0, void 0, function* () {
|
|
108
|
-
const
|
|
109
|
-
const sequenceNumberVector = createSequenceNumberVector(jsonRpcMessage.id);
|
|
263
|
+
const sequenceNumberVector = createSequenceNumberVector(sequenceNumber);
|
|
110
264
|
const initializationVector = new Uint8Array(INITIALIZATION_VECTOR_BYTES);
|
|
111
265
|
crypto.getRandomValues(initializationVector);
|
|
112
266
|
const ciphertext = yield crypto.subtle.encrypt(getAlgorithmParams(sequenceNumberVector, initializationVector), sharedSecret, new TextEncoder().encode(plaintext));
|
|
@@ -117,18 +271,14 @@ function encryptJsonRpcMessage(jsonRpcMessage, sharedSecret) {
|
|
|
117
271
|
return response;
|
|
118
272
|
});
|
|
119
273
|
}
|
|
120
|
-
function
|
|
274
|
+
function decryptMessage(message, sharedSecret) {
|
|
121
275
|
return __awaiter(this, void 0, void 0, function* () {
|
|
122
276
|
const sequenceNumberVector = message.slice(0, SEQUENCE_NUMBER_BYTES);
|
|
123
277
|
const initializationVector = message.slice(SEQUENCE_NUMBER_BYTES, SEQUENCE_NUMBER_BYTES + INITIALIZATION_VECTOR_BYTES);
|
|
124
278
|
const ciphertext = message.slice(SEQUENCE_NUMBER_BYTES + INITIALIZATION_VECTOR_BYTES);
|
|
125
279
|
const plaintextBuffer = yield crypto.subtle.decrypt(getAlgorithmParams(sequenceNumberVector, initializationVector), sharedSecret, ciphertext);
|
|
126
280
|
const plaintext = getUtf8Decoder().decode(plaintextBuffer);
|
|
127
|
-
|
|
128
|
-
if (Object.hasOwnProperty.call(jsonRpcMessage, 'error')) {
|
|
129
|
-
throw new SolanaMobileWalletAdapterProtocolError(jsonRpcMessage.id, jsonRpcMessage.error.code, jsonRpcMessage.error.message);
|
|
130
|
-
}
|
|
131
|
-
return jsonRpcMessage;
|
|
281
|
+
return plaintext;
|
|
132
282
|
});
|
|
133
283
|
}
|
|
134
284
|
function getAlgorithmParams(sequenceNumber, initializationVector) {
|
|
@@ -147,12 +297,48 @@ function getUtf8Decoder() {
|
|
|
147
297
|
return _utf8Decoder;
|
|
148
298
|
}
|
|
149
299
|
|
|
300
|
+
function generateAssociationKeypair() {
|
|
301
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
302
|
+
return yield crypto.subtle.generateKey({
|
|
303
|
+
name: 'ECDSA',
|
|
304
|
+
namedCurve: 'P-256',
|
|
305
|
+
}, false /* extractable */, ['sign'] /* keyUsages */);
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function generateECDHKeypair() {
|
|
310
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
311
|
+
return yield crypto.subtle.generateKey({
|
|
312
|
+
name: 'ECDH',
|
|
313
|
+
namedCurve: 'P-256',
|
|
314
|
+
}, false /* extractable */, ['deriveKey', 'deriveBits'] /* keyUsages */);
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function encryptJsonRpcMessage(jsonRpcMessage, sharedSecret) {
|
|
319
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
320
|
+
const plaintext = JSON.stringify(jsonRpcMessage);
|
|
321
|
+
const sequenceNumber = jsonRpcMessage.id;
|
|
322
|
+
return encryptMessage(plaintext, sequenceNumber, sharedSecret);
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
function decryptJsonRpcMessage(message, sharedSecret) {
|
|
326
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
327
|
+
const plaintext = yield decryptMessage(message, sharedSecret);
|
|
328
|
+
const jsonRpcMessage = JSON.parse(plaintext);
|
|
329
|
+
if (Object.hasOwnProperty.call(jsonRpcMessage, 'error')) {
|
|
330
|
+
throw new SolanaMobileWalletAdapterProtocolError(jsonRpcMessage.id, jsonRpcMessage.error.code, jsonRpcMessage.error.message);
|
|
331
|
+
}
|
|
332
|
+
return jsonRpcMessage;
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
|
|
150
336
|
function parseHelloRsp(payloadBuffer, // The X9.62-encoded wallet endpoint ephemeral ECDH public keypoint.
|
|
151
337
|
associationPublicKey, ecdhPrivateKey) {
|
|
152
338
|
return __awaiter(this, void 0, void 0, function* () {
|
|
153
339
|
const [associationPublicKeyBuffer, walletPublicKey] = yield Promise.all([
|
|
154
340
|
crypto.subtle.exportKey('raw', associationPublicKey),
|
|
155
|
-
crypto.subtle.importKey('raw', payloadBuffer, { name: 'ECDH', namedCurve: 'P-256' }, false /* extractable */, [] /* keyUsages */),
|
|
341
|
+
crypto.subtle.importKey('raw', payloadBuffer.slice(0, ENCODED_PUBLIC_KEY_LENGTH_BYTES), { name: 'ECDH', namedCurve: 'P-256' }, false /* extractable */, [] /* keyUsages */),
|
|
156
342
|
]);
|
|
157
343
|
const sharedSecret = yield crypto.subtle.deriveBits({ name: 'ECDH', public: walletPublicKey }, ecdhPrivateKey, 256);
|
|
158
344
|
const ecdhSecretKey = yield crypto.subtle.importKey('raw', sharedSecret, 'HKDF', false /* extractable */, ['deriveKey'] /* keyUsages */);
|
|
@@ -166,6 +352,31 @@ associationPublicKey, ecdhPrivateKey) {
|
|
|
166
352
|
});
|
|
167
353
|
}
|
|
168
354
|
|
|
355
|
+
function parseSessionProps(message, sharedSecret) {
|
|
356
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
357
|
+
const plaintext = yield decryptMessage(message, sharedSecret);
|
|
358
|
+
const jsonProperties = JSON.parse(plaintext);
|
|
359
|
+
let protocolVersion = 'legacy';
|
|
360
|
+
if (Object.hasOwnProperty.call(jsonProperties, 'v')) {
|
|
361
|
+
switch (jsonProperties.v) {
|
|
362
|
+
case 1:
|
|
363
|
+
case '1':
|
|
364
|
+
case 'v1':
|
|
365
|
+
protocolVersion = 'v1';
|
|
366
|
+
break;
|
|
367
|
+
case 'legacy':
|
|
368
|
+
protocolVersion = 'legacy';
|
|
369
|
+
break;
|
|
370
|
+
default:
|
|
371
|
+
throw new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_INVALID_PROTOCOL_VERSION, `Unknown/unsupported protocol version: ${jsonProperties.v}`);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return ({
|
|
375
|
+
protocol_version: protocolVersion
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
|
|
169
380
|
function getRandomAssociationPort() {
|
|
170
381
|
return assertAssociationPort(49152 + Math.floor(Math.random() * (65535 - 49152 + 1)));
|
|
171
382
|
}
|
|
@@ -222,7 +433,7 @@ function getIntentURL(methodPathname, intentUrlBase) {
|
|
|
222
433
|
[...getPathParts(baseUrl.pathname), ...getPathParts(methodPathname)].join('/');
|
|
223
434
|
return new URL(pathname, baseUrl);
|
|
224
435
|
}
|
|
225
|
-
function getAssociateAndroidIntentURL(associationPublicKey, putativePort, associationURLBase) {
|
|
436
|
+
function getAssociateAndroidIntentURL(associationPublicKey, putativePort, associationURLBase, protocolVersions = ['v1']) {
|
|
226
437
|
return __awaiter(this, void 0, void 0, function* () {
|
|
227
438
|
const associationPort = assertAssociationPort(putativePort);
|
|
228
439
|
const exportedKey = yield crypto.subtle.exportKey('raw', associationPublicKey);
|
|
@@ -230,6 +441,9 @@ function getAssociateAndroidIntentURL(associationPublicKey, putativePort, associ
|
|
|
230
441
|
const url = getIntentURL('v1/associate/local', associationURLBase);
|
|
231
442
|
url.searchParams.set('association', getStringWithURLUnsafeCharactersReplaced(encodedKey));
|
|
232
443
|
url.searchParams.set('port', `${associationPort}`);
|
|
444
|
+
protocolVersions.forEach((version) => {
|
|
445
|
+
url.searchParams.set('v', version);
|
|
446
|
+
});
|
|
233
447
|
return url;
|
|
234
448
|
});
|
|
235
449
|
}
|
|
@@ -434,59 +648,51 @@ function transact(callback, config) {
|
|
|
434
648
|
break;
|
|
435
649
|
case 'hello_req_sent': {
|
|
436
650
|
const sharedSecret = yield parseHelloRsp(responseBuffer, state.associationPublicKey, state.ecdhPrivateKey);
|
|
437
|
-
|
|
438
|
-
const
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
.toLowerCase();
|
|
445
|
-
target[p] = function (params) {
|
|
446
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
447
|
-
const id = nextJsonRpcMessageId++;
|
|
448
|
-
socket.send(yield encryptJsonRpcMessage({
|
|
449
|
-
id,
|
|
450
|
-
jsonrpc: '2.0',
|
|
451
|
-
method,
|
|
452
|
-
params: params !== null && params !== void 0 ? params : {},
|
|
453
|
-
}, sharedSecret));
|
|
454
|
-
return new Promise((resolve, reject) => {
|
|
455
|
-
jsonRpcResponsePromises[id] = {
|
|
456
|
-
resolve(result) {
|
|
457
|
-
switch (p) {
|
|
458
|
-
case 'authorize':
|
|
459
|
-
case 'reauthorize': {
|
|
460
|
-
const { wallet_uri_base } = result;
|
|
461
|
-
if (wallet_uri_base != null) {
|
|
462
|
-
try {
|
|
463
|
-
assertSecureEndpointSpecificURI(wallet_uri_base);
|
|
464
|
-
}
|
|
465
|
-
catch (e) {
|
|
466
|
-
reject(e);
|
|
467
|
-
return;
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
break;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
resolve(result);
|
|
474
|
-
},
|
|
475
|
-
reject,
|
|
476
|
-
};
|
|
477
|
-
});
|
|
478
|
-
});
|
|
479
|
-
};
|
|
651
|
+
const sessionPropertiesBuffer = responseBuffer.slice(ENCODED_PUBLIC_KEY_LENGTH_BYTES);
|
|
652
|
+
const sessionProperties = sessionPropertiesBuffer.byteLength !== 0
|
|
653
|
+
? yield (() => __awaiter(this, void 0, void 0, function* () {
|
|
654
|
+
const sequenceNumberVector = sessionPropertiesBuffer.slice(0, SEQUENCE_NUMBER_BYTES);
|
|
655
|
+
const sequenceNumber = getSequenceNumberFromByteArray(sequenceNumberVector);
|
|
656
|
+
if (sequenceNumber !== (lastKnownInboundSequenceNumber + 1)) {
|
|
657
|
+
throw new Error('Encrypted message has invalid sequence number');
|
|
480
658
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
659
|
+
lastKnownInboundSequenceNumber = sequenceNumber;
|
|
660
|
+
return parseSessionProps(sessionPropertiesBuffer, sharedSecret);
|
|
661
|
+
}))() : { protocol_version: 'legacy' };
|
|
662
|
+
state = { __type: 'connected', sharedSecret, sessionProperties };
|
|
663
|
+
const wallet = createMobileWalletProxy(sessionProperties.protocol_version, (method, params) => __awaiter(this, void 0, void 0, function* () {
|
|
664
|
+
const id = nextJsonRpcMessageId++;
|
|
665
|
+
socket.send(yield encryptJsonRpcMessage({
|
|
666
|
+
id,
|
|
667
|
+
jsonrpc: '2.0',
|
|
668
|
+
method,
|
|
669
|
+
params: params !== null && params !== void 0 ? params : {},
|
|
670
|
+
}, sharedSecret));
|
|
671
|
+
return new Promise((resolve, reject) => {
|
|
672
|
+
jsonRpcResponsePromises[id] = {
|
|
673
|
+
resolve(result) {
|
|
674
|
+
switch (method) {
|
|
675
|
+
case 'authorize':
|
|
676
|
+
case 'reauthorize': {
|
|
677
|
+
const { wallet_uri_base } = result;
|
|
678
|
+
if (wallet_uri_base != null) {
|
|
679
|
+
try {
|
|
680
|
+
assertSecureEndpointSpecificURI(wallet_uri_base);
|
|
681
|
+
}
|
|
682
|
+
catch (e) {
|
|
683
|
+
reject(e);
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
break;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
resolve(result);
|
|
691
|
+
},
|
|
692
|
+
reject,
|
|
693
|
+
};
|
|
694
|
+
});
|
|
695
|
+
}));
|
|
490
696
|
try {
|
|
491
697
|
resolve(yield callback(wallet));
|
|
492
698
|
}
|
|
@@ -529,4 +735,4 @@ function transact(callback, config) {
|
|
|
529
735
|
});
|
|
530
736
|
}
|
|
531
737
|
|
|
532
|
-
export { SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterProtocolError, SolanaMobileWalletAdapterProtocolErrorCode, transact };
|
|
738
|
+
export { SolanaCloneAuthorization, SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterProtocolError, SolanaMobileWalletAdapterProtocolErrorCode, SolanaSignInWithSolana, SolanaSignTransactions, transact };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { TransactionVersion } from "@solana/web3.js";
|
|
2
|
+
import { SolanaSignInInput } from "@solana/wallet-standard";
|
|
3
|
+
import { IdentifierArray, IdentifierString, WalletAccount, WalletIcon } from "@wallet-standard/core";
|
|
2
4
|
// Typescript `enums` thwart tree-shaking. See https://bargsten.org/jsts/enums/
|
|
3
5
|
declare const SolanaMobileWalletAdapterErrorCode: {
|
|
4
6
|
readonly ERROR_ASSOCIATION_PORT_OUT_OF_RANGE: "ERROR_ASSOCIATION_PORT_OUT_OF_RANGE";
|
|
@@ -7,6 +9,7 @@ declare const SolanaMobileWalletAdapterErrorCode: {
|
|
|
7
9
|
readonly ERROR_SESSION_CLOSED: "ERROR_SESSION_CLOSED";
|
|
8
10
|
readonly ERROR_SESSION_TIMEOUT: "ERROR_SESSION_TIMEOUT";
|
|
9
11
|
readonly ERROR_WALLET_NOT_FOUND: "ERROR_WALLET_NOT_FOUND";
|
|
12
|
+
readonly ERROR_INVALID_PROTOCOL_VERSION: "ERROR_INVALID_PROTOCOL_VERSION";
|
|
10
13
|
};
|
|
11
14
|
type SolanaMobileWalletAdapterErrorCodeEnum = (typeof SolanaMobileWalletAdapterErrorCode)[keyof typeof SolanaMobileWalletAdapterErrorCode];
|
|
12
15
|
type ErrorDataTypeMap = {
|
|
@@ -20,6 +23,7 @@ type ErrorDataTypeMap = {
|
|
|
20
23
|
};
|
|
21
24
|
[SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_TIMEOUT]: undefined;
|
|
22
25
|
[SolanaMobileWalletAdapterErrorCode.ERROR_WALLET_NOT_FOUND]: undefined;
|
|
26
|
+
[SolanaMobileWalletAdapterErrorCode.ERROR_INVALID_PROTOCOL_VERSION]: undefined;
|
|
23
27
|
};
|
|
24
28
|
declare class SolanaMobileWalletAdapterError<TErrorCode extends SolanaMobileWalletAdapterErrorCodeEnum> extends Error {
|
|
25
29
|
data: ErrorDataTypeMap[TErrorCode] | undefined;
|
|
@@ -74,7 +78,10 @@ declare class SolanaMobileWalletAdapterProtocolError<TErrorCode extends SolanaMo
|
|
|
74
78
|
type Account = Readonly<{
|
|
75
79
|
address: Base64EncodedAddress;
|
|
76
80
|
label?: string;
|
|
77
|
-
|
|
81
|
+
icon?: WalletIcon;
|
|
82
|
+
chains?: IdentifierArray;
|
|
83
|
+
features?: IdentifierArray;
|
|
84
|
+
}> | WalletAccount;
|
|
78
85
|
/**
|
|
79
86
|
* Properties that wallets may present to users when an app
|
|
80
87
|
* asks for authorization to execute privileged methods (see
|
|
@@ -91,6 +98,10 @@ type AppIdentity = Readonly<{
|
|
|
91
98
|
* The private key is used during session establishment.
|
|
92
99
|
*/
|
|
93
100
|
type AssociationKeypair = CryptoKeyPair;
|
|
101
|
+
type ProtocolVersion = "v1" | "legacy";
|
|
102
|
+
type SessionProperties = Readonly<{
|
|
103
|
+
protocol_version: ProtocolVersion;
|
|
104
|
+
}>;
|
|
94
105
|
/**
|
|
95
106
|
* The context returned from a wallet after having authorized a given
|
|
96
107
|
* account for use with a given application. You can cache this and
|
|
@@ -100,6 +111,7 @@ type AuthorizationResult = Readonly<{
|
|
|
100
111
|
accounts: Account[];
|
|
101
112
|
auth_token: AuthToken;
|
|
102
113
|
wallet_uri_base: string;
|
|
114
|
+
sign_in_result?: SignInResult;
|
|
103
115
|
}>;
|
|
104
116
|
type AuthToken = string;
|
|
105
117
|
type Base64EncodedAddress = string;
|
|
@@ -108,16 +120,31 @@ type Base64EncodedMessage = string;
|
|
|
108
120
|
type Base64EncodedSignedMessage = string;
|
|
109
121
|
type Base64EncodedSignedTransaction = string;
|
|
110
122
|
type Base64EncodedTransaction = string;
|
|
123
|
+
/**
|
|
124
|
+
* @deprecated Replaced by the 'chain' parameter, which adds multi-chain capability as per MWA 2.0 spec.
|
|
125
|
+
*/
|
|
111
126
|
type Cluster = "devnet" | "testnet" | "mainnet-beta";
|
|
127
|
+
type Chain = IdentifierString | Cluster;
|
|
112
128
|
type Finality = "confirmed" | "finalized" | "processed";
|
|
113
129
|
type WalletAssociationConfig = Readonly<{
|
|
114
130
|
baseUri?: string;
|
|
115
131
|
}>;
|
|
116
132
|
interface AuthorizeAPI {
|
|
133
|
+
/**
|
|
134
|
+
* @deprecated Replaced by updated authorize() method, which adds MWA 2.0 spec support.
|
|
135
|
+
*/
|
|
117
136
|
authorize(params: {
|
|
118
137
|
cluster: Cluster;
|
|
119
138
|
identity: AppIdentity;
|
|
120
139
|
}): Promise<AuthorizationResult>;
|
|
140
|
+
authorize(params: {
|
|
141
|
+
identity: AppIdentity;
|
|
142
|
+
chain?: Chain;
|
|
143
|
+
features?: IdentifierArray;
|
|
144
|
+
addresses?: string[];
|
|
145
|
+
auth_token?: AuthToken;
|
|
146
|
+
sign_in_payload?: SignInPayload;
|
|
147
|
+
}): Promise<AuthorizationResult>;
|
|
121
148
|
}
|
|
122
149
|
interface CloneAuthorizationAPI {
|
|
123
150
|
cloneAuthorization(params: {
|
|
@@ -133,11 +160,18 @@ interface DeauthorizeAPI {
|
|
|
133
160
|
}
|
|
134
161
|
interface GetCapabilitiesAPI {
|
|
135
162
|
getCapabilities(): Promise<Readonly<{
|
|
163
|
+
max_transactions_per_request: number;
|
|
164
|
+
max_messages_per_request: number;
|
|
165
|
+
supported_transaction_versions: ReadonlyArray<TransactionVersion>;
|
|
166
|
+
features: IdentifierArray;
|
|
167
|
+
/**
|
|
168
|
+
* @deprecated Replaced by features array.
|
|
169
|
+
*/
|
|
136
170
|
supports_clone_authorization: boolean;
|
|
171
|
+
/**
|
|
172
|
+
* @deprecated Replaced by features array.
|
|
173
|
+
*/
|
|
137
174
|
supports_sign_and_send_transactions: boolean;
|
|
138
|
-
max_transactions_per_request: boolean;
|
|
139
|
-
max_messages_per_request: boolean;
|
|
140
|
-
supported_transaction_versions: ReadonlyArray<TransactionVersion>;
|
|
141
175
|
}>>;
|
|
142
176
|
}
|
|
143
177
|
interface ReauthorizeAPI {
|
|
@@ -165,6 +199,10 @@ interface SignAndSendTransactionsAPI {
|
|
|
165
199
|
signAndSendTransactions(params: {
|
|
166
200
|
options?: Readonly<{
|
|
167
201
|
min_context_slot?: number;
|
|
202
|
+
commitment?: string;
|
|
203
|
+
skip_preflight?: boolean;
|
|
204
|
+
max_retries?: number;
|
|
205
|
+
wait_for_commitment_to_send_next_transaction?: boolean;
|
|
168
206
|
}>;
|
|
169
207
|
payloads: Base64EncodedTransaction[];
|
|
170
208
|
}): Promise<Readonly<{
|
|
@@ -173,6 +211,31 @@ interface SignAndSendTransactionsAPI {
|
|
|
173
211
|
}
|
|
174
212
|
interface MobileWallet extends AuthorizeAPI, CloneAuthorizationAPI, DeauthorizeAPI, GetCapabilitiesAPI, ReauthorizeAPI, SignMessagesAPI, SignTransactionsAPI, SignAndSendTransactionsAPI {
|
|
175
213
|
}
|
|
214
|
+
// optional features
|
|
215
|
+
declare const SolanaSignTransactions = "solana:signTransactions";
|
|
216
|
+
declare const SolanaCloneAuthorization = "solana:cloneAuthorization";
|
|
217
|
+
declare const SolanaSignInWithSolana = "solana:signInWithSolana";
|
|
218
|
+
type SignInPayload = Readonly<{
|
|
219
|
+
domain?: string;
|
|
220
|
+
address?: string;
|
|
221
|
+
statement?: string;
|
|
222
|
+
uri?: string;
|
|
223
|
+
version?: string;
|
|
224
|
+
chainId?: string;
|
|
225
|
+
nonce?: string;
|
|
226
|
+
issuedAt?: string;
|
|
227
|
+
expirationTime?: string;
|
|
228
|
+
notBefore?: string;
|
|
229
|
+
requestId?: string;
|
|
230
|
+
resources?: readonly string[];
|
|
231
|
+
}> | SolanaSignInInput;
|
|
232
|
+
type SignInPayloadWithRequiredFields = Partial<SignInPayload> & Required<Pick<SignInPayload, "domain" | "address">>;
|
|
233
|
+
type SignInResult = Readonly<{
|
|
234
|
+
address: Base64EncodedAddress;
|
|
235
|
+
signed_message: Base64EncodedSignedMessage;
|
|
236
|
+
signature: Base64EncodedAddress;
|
|
237
|
+
signature_type?: string;
|
|
238
|
+
}>;
|
|
176
239
|
declare function transact<TReturn>(callback: (wallet: MobileWallet) => TReturn, config?: WalletAssociationConfig): Promise<TReturn>;
|
|
177
|
-
export { SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterProtocolErrorCode, SolanaMobileWalletAdapterProtocolError, transact, Account, AppIdentity, AssociationKeypair, AuthorizationResult, AuthToken, Base64EncodedAddress, Base64EncodedTransaction, Cluster, Finality, WalletAssociationConfig, AuthorizeAPI, CloneAuthorizationAPI, DeauthorizeAPI, GetCapabilitiesAPI, ReauthorizeAPI, SignMessagesAPI, SignTransactionsAPI, SignAndSendTransactionsAPI, MobileWallet };
|
|
240
|
+
export { SolanaMobileWalletAdapterErrorCode, SolanaMobileWalletAdapterError, SolanaMobileWalletAdapterProtocolErrorCode, SolanaMobileWalletAdapterProtocolError, transact, Account, AppIdentity, AssociationKeypair, ProtocolVersion, SessionProperties, AuthorizationResult, AuthToken, Base64EncodedAddress, Base64EncodedTransaction, Cluster, Chain, Finality, WalletAssociationConfig, AuthorizeAPI, CloneAuthorizationAPI, DeauthorizeAPI, GetCapabilitiesAPI, ReauthorizeAPI, SignMessagesAPI, SignTransactionsAPI, SignAndSendTransactionsAPI, MobileWallet, SolanaSignTransactions, SolanaCloneAuthorization, SolanaSignInWithSolana, SignInPayload, SignInPayloadWithRequiredFields, SignInResult };
|
|
178
241
|
//# sourceMappingURL=index.browser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.browser.d.ts","sourceRoot":"","sources":["../../src/index.ts","../../src/errors.ts","../../src/createHelloReq.ts","../../src/
|
|
1
|
+
{"version":3,"file":"index.browser.d.ts","sourceRoot":"","sources":["../../src/index.ts","../../src/errors.ts","../../src/createHelloReq.ts","../../src/types.ts","../../src/base64Utils.ts","../../src/createSIWSMessage.ts","../../src/createMobileWalletProxy.ts","../../src/createSequenceNumberVector.ts","../../src/parseHelloRsp.ts","../../src/encryptedMessage.ts","../../src/generateAssociationKeypair.ts","../../src/generateECDHKeypair.ts","../../src/jsonRpcMessage.ts","../../src/parseSessionProps.ts","../../src/associationPort.ts","../../src/arrayBufferToBase64String.ts","../../src/getStringWithURLUnsafeBase64CharactersReplaced.ts","../../src/getAssociateAndroidIntentURL.ts","../../src/startSession.ts","../../src/transact.ts"],"names":[],"mappings":""}
|