@0xsequence/provider 1.0.5 → 1.1.0
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/dist/0xsequence-provider.cjs.dev.js +1742 -1678
- package/dist/0xsequence-provider.cjs.prod.js +1742 -1678
- package/dist/0xsequence-provider.esm.js +1735 -1676
- package/dist/declarations/src/client.d.ts +74 -0
- package/dist/declarations/src/index.d.ts +3 -1
- package/dist/declarations/src/init.d.ts +25 -0
- package/dist/declarations/src/provider.d.ts +127 -63
- package/dist/declarations/src/signer.d.ts +87 -0
- package/dist/declarations/src/transports/mux-transport/mux-message-provider.d.ts +21 -0
- package/dist/declarations/src/transports/wallet-request-handler.d.ts +0 -1
- package/dist/declarations/src/types.d.ts +25 -9
- package/dist/declarations/src/utils/index.d.ts +10 -7
- package/dist/declarations/src/utils.d.ts +21 -15
- package/package.json +19 -12
- package/src/client.ts +423 -0
- package/src/extended.ts +4 -0
- package/src/index.ts +3 -1
- package/src/init.ts +134 -0
- package/src/provider.ts +447 -424
- package/src/signer.ts +316 -0
- package/src/transports/base-wallet-transport.ts +3 -8
- package/src/transports/mux-transport/mux-message-provider.ts +86 -2
- package/src/transports/proxy-transport/proxy-message-provider.ts +1 -1
- package/src/transports/wallet-request-handler.ts +3 -33
- package/src/transports/window-transport/window-message-provider.ts +4 -2
- package/src/types.ts +41 -10
- package/src/utils/index.ts +16 -76
- package/src/utils.ts +81 -51
- package/dist/declarations/src/extended.d.ts +0 -6
- package/dist/declarations/src/wallet.d.ts +0 -105
- package/src/wallet.ts +0 -770
|
@@ -8,7 +8,6 @@ var ethers = require('ethers');
|
|
|
8
8
|
var network = require('@0xsequence/network');
|
|
9
9
|
var core = require('@0xsequence/core');
|
|
10
10
|
var auth = require('@0xsequence/auth');
|
|
11
|
-
var wallet = require('@0xsequence/wallet');
|
|
12
11
|
|
|
13
12
|
function _extends() {
|
|
14
13
|
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
@@ -25,6 +24,10 @@ function _extends() {
|
|
|
25
24
|
return _extends.apply(this, arguments);
|
|
26
25
|
}
|
|
27
26
|
|
|
27
|
+
function isProviderTransport(transport) {
|
|
28
|
+
return transport && typeof transport === 'object' && typeof transport.register === 'function' && typeof transport.unregister === 'function' && typeof transport.openWallet === 'function' && typeof transport.closeWallet === 'function' && typeof transport.isOpened === 'function' && typeof transport.isConnected === 'function' && typeof transport.on === 'function';
|
|
29
|
+
}
|
|
30
|
+
|
|
28
31
|
// ProviderMessageCallback is used to respond to ProviderMessage requests. The error
|
|
29
32
|
// argument is for exceptions during the execution, and response is the response payload
|
|
30
33
|
// which may contain the result or an error payload from the wallet.
|
|
@@ -76,6 +79,8 @@ const ErrSignedInRequired = new ProviderError('Wallet is not signed in. Connect
|
|
|
76
79
|
|
|
77
80
|
// TODO: lets build some nice error handling tools, prob in /utils ...
|
|
78
81
|
|
|
82
|
+
// This is required by viem, it expects a provider to have an EIP-1193 compliant `request` attribute.
|
|
83
|
+
|
|
79
84
|
const PROVIDER_OPEN_TIMEOUT = 30000; // in ms
|
|
80
85
|
|
|
81
86
|
let _messageIdx = 0;
|
|
@@ -613,59 +618,87 @@ const isUnityPlugin = () => !!navigator.userAgent.match(/UnitySequence/i);
|
|
|
613
618
|
const isWalletUpToDate = status => {
|
|
614
619
|
return status.onChain.deployed && status.fullyMigrated;
|
|
615
620
|
};
|
|
621
|
+
class MemoryItemStore {
|
|
622
|
+
constructor() {
|
|
623
|
+
this.callbacks = [];
|
|
624
|
+
this.store = {};
|
|
625
|
+
}
|
|
626
|
+
getItem(key) {
|
|
627
|
+
return this.store[key] || null;
|
|
628
|
+
}
|
|
629
|
+
setItem(key, value) {
|
|
630
|
+
this.store[key] = value;
|
|
631
|
+
this.callbacks.filter(c => c.key === key).forEach(c => c.cb(value));
|
|
632
|
+
}
|
|
633
|
+
removeItem(key) {
|
|
634
|
+
delete this.store[key];
|
|
635
|
+
}
|
|
636
|
+
onItemChange(key, cb) {
|
|
637
|
+
this.callbacks.push({
|
|
638
|
+
key,
|
|
639
|
+
cb
|
|
640
|
+
});
|
|
641
|
+
return () => {
|
|
642
|
+
this.callbacks = this.callbacks.filter(c => c.cb !== cb);
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
}
|
|
616
646
|
class LocalStorage {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
removeItem: key => Promise.resolve(window.localStorage.removeItem(key))
|
|
625
|
-
};
|
|
626
|
-
}
|
|
627
|
-
} else {
|
|
628
|
-
// noop local storage if window is not defined
|
|
629
|
-
// TODO: perhaps add an in-memory local storage if we need?
|
|
630
|
-
if (!LocalStorage._instance) {
|
|
631
|
-
LocalStorage._instance = {
|
|
632
|
-
getItem: key => Promise.resolve(null),
|
|
633
|
-
setItem: (key, value) => Promise.resolve(),
|
|
634
|
-
removeItem: key => Promise.resolve()
|
|
635
|
-
};
|
|
636
|
-
}
|
|
647
|
+
static isAvailable() {
|
|
648
|
+
return typeof window === 'object' && typeof window.localStorage === 'object';
|
|
649
|
+
}
|
|
650
|
+
constructor() {
|
|
651
|
+
this.callbacks = [];
|
|
652
|
+
if (!LocalStorage.isAvailable()) {
|
|
653
|
+
throw new Error('LocalStorage is not available');
|
|
637
654
|
}
|
|
638
|
-
|
|
655
|
+
window.addEventListener('storage', e => {
|
|
656
|
+
const {
|
|
657
|
+
key
|
|
658
|
+
} = e;
|
|
659
|
+
const cb = this.callbacks.filter(c => c.key === key);
|
|
660
|
+
cb.forEach(c => c.cb(this.getItem(key)));
|
|
661
|
+
});
|
|
639
662
|
}
|
|
640
|
-
|
|
641
|
-
|
|
663
|
+
getItem(key) {
|
|
664
|
+
return window.localStorage.getItem(key);
|
|
642
665
|
}
|
|
643
|
-
|
|
666
|
+
setItem(key, value) {
|
|
667
|
+
window.localStorage.setItem(key, value);
|
|
644
668
|
|
|
645
|
-
//
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
this.def = def;
|
|
649
|
-
this.key = key;
|
|
669
|
+
// Trigger callbacks
|
|
670
|
+
// NOTICE: the event is not triggered on the same window
|
|
671
|
+
this.callbacks.filter(c => c.key === key).forEach(c => c.cb(value));
|
|
650
672
|
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
673
|
+
removeItem(key) {
|
|
674
|
+
window.localStorage.removeItem(key);
|
|
675
|
+
|
|
676
|
+
// Trigger callbacks
|
|
677
|
+
// NOTICE: the event is not triggered on the same window
|
|
678
|
+
this.callbacks.filter(c => c.key === key).forEach(c => c.cb(null));
|
|
679
|
+
}
|
|
680
|
+
onItemChange(key, cb) {
|
|
681
|
+
this.callbacks.push({
|
|
682
|
+
key,
|
|
683
|
+
cb
|
|
684
|
+
});
|
|
685
|
+
return () => {
|
|
686
|
+
this.callbacks = this.callbacks.filter(c => c.cb !== cb);
|
|
687
|
+
};
|
|
662
688
|
}
|
|
663
|
-
|
|
664
|
-
|
|
689
|
+
}
|
|
690
|
+
function useBestStore() {
|
|
691
|
+
if (LocalStorage.isAvailable()) {
|
|
692
|
+
return new LocalStorage();
|
|
665
693
|
}
|
|
666
|
-
|
|
667
|
-
|
|
694
|
+
return new MemoryItemStore();
|
|
695
|
+
}
|
|
696
|
+
async function resolveArrayProperties(object) {
|
|
697
|
+
if (Array.isArray(object)) {
|
|
698
|
+
// T must include array type
|
|
699
|
+
return Promise.all(object.map(o => ethers.ethers.utils.resolveProperties(o)));
|
|
668
700
|
}
|
|
701
|
+
return ethers.ethers.utils.resolveProperties(object);
|
|
669
702
|
}
|
|
670
703
|
|
|
671
704
|
const TRANSPORT_SESSION_LS_KEY = '@sequence.transportSession';
|
|
@@ -806,11 +839,6 @@ class BaseWalletTransport {
|
|
|
806
839
|
// Set connect options on the walletRequestHandler as our primary
|
|
807
840
|
// wallet controller, and fall back to networkId if necessary
|
|
808
841
|
_this.walletRequestHandler.setConnectOptions(connectOptions);
|
|
809
|
-
if (connectOptions.networkId) {
|
|
810
|
-
networkId = connectOptions.networkId;
|
|
811
|
-
} else if (networkId) {
|
|
812
|
-
connectOptions.networkId = networkId;
|
|
813
|
-
}
|
|
814
842
|
} else {
|
|
815
843
|
_this.walletRequestHandler.setConnectOptions(undefined);
|
|
816
844
|
}
|
|
@@ -880,10 +908,10 @@ class BaseWalletTransport {
|
|
|
880
908
|
return true;
|
|
881
909
|
};
|
|
882
910
|
this.saveTransportSession = session => {
|
|
883
|
-
|
|
911
|
+
useBestStore().setItem(TRANSPORT_SESSION_LS_KEY, JSON.stringify(session));
|
|
884
912
|
};
|
|
885
913
|
this.getCachedTransportSession = async function () {
|
|
886
|
-
const session =
|
|
914
|
+
const session = useBestStore().getItem(TRANSPORT_SESSION_LS_KEY);
|
|
887
915
|
try {
|
|
888
916
|
return session ? JSON.parse(session) : null;
|
|
889
917
|
} catch (err) {
|
|
@@ -1237,203 +1265,84 @@ class ProxyMessageHandler extends BaseWalletTransport {
|
|
|
1237
1265
|
}
|
|
1238
1266
|
}
|
|
1239
1267
|
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
// REVIEW/NOTE: ........ this method does not work for the chrome-extension. The issue becomes
|
|
1251
|
-
// when the browser quits or restarts, the "open" event is never triggered. Perhaps the code here is fine,
|
|
1252
|
-
// or maybe its not. What should happen is when a dapp makes a request, it will call openWallet
|
|
1253
|
-
// below, in which case one of the events will register. So perhaps this is fine.
|
|
1254
|
-
this.messageProviders.forEach(m => {
|
|
1255
|
-
m.register();
|
|
1256
|
-
m.once('open', () => {
|
|
1257
|
-
// the first one to open is the winner, and others will be unregistered
|
|
1258
|
-
if (!this.provider) {
|
|
1259
|
-
this.provider = m;
|
|
1260
|
-
|
|
1261
|
-
// unregister other providers
|
|
1262
|
-
this.messageProviders.forEach(m => {
|
|
1263
|
-
if (this.provider !== m) {
|
|
1264
|
-
m.unregister();
|
|
1265
|
-
}
|
|
1266
|
-
});
|
|
1267
|
-
}
|
|
1268
|
-
});
|
|
1269
|
-
});
|
|
1270
|
-
};
|
|
1271
|
-
this.unregister = () => {
|
|
1272
|
-
this.messageProviders.forEach(m => m.unregister());
|
|
1273
|
-
this.provider = undefined;
|
|
1274
|
-
};
|
|
1275
|
-
this.openWallet = (path, intent, networkId) => {
|
|
1276
|
-
if (this.provider) {
|
|
1277
|
-
this.provider.openWallet(path, intent, networkId);
|
|
1278
|
-
return;
|
|
1279
|
-
}
|
|
1280
|
-
this.messageProviders.forEach(m => m.openWallet(path, intent, networkId));
|
|
1281
|
-
};
|
|
1282
|
-
this.sendAsync = async function (request, callback, chainId) {
|
|
1283
|
-
if (_this.provider) {
|
|
1284
|
-
_this.provider.sendAsync(request, callback, chainId);
|
|
1285
|
-
return;
|
|
1286
|
-
}
|
|
1287
|
-
throw new Error('impossible state, wallet must be opened first');
|
|
1288
|
-
};
|
|
1289
|
-
this.sendMessageRequest = async function (message) {
|
|
1290
|
-
if (_this.provider) {
|
|
1291
|
-
return _this.provider.sendMessageRequest(message);
|
|
1292
|
-
}
|
|
1293
|
-
throw new Error('impossible state, wallet must be opened first');
|
|
1268
|
+
/**
|
|
1269
|
+
* This will redirect console logs from Sequence.js & the wallet to the Unreal console, for debugging purposes.
|
|
1270
|
+
*/
|
|
1271
|
+
function overrideLogs(side) {
|
|
1272
|
+
var _window$ue;
|
|
1273
|
+
if ((_window$ue = window.ue) != null && _window$ue.sequencewallettransport && !window.logsOverriddenForUnreal) {
|
|
1274
|
+
var _window$ue2;
|
|
1275
|
+
const t = (_window$ue2 = window.ue) == null ? void 0 : _window$ue2.sequencewallettransport;
|
|
1276
|
+
console.log = (...args) => {
|
|
1277
|
+
t.logfromjs(`${side}: ${stringify(args)}`);
|
|
1294
1278
|
};
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
return _this.provider.waitUntilOpened();
|
|
1298
|
-
}
|
|
1299
|
-
return Promise.race(_this.messageProviders.map(p => p.waitUntilOpened()));
|
|
1279
|
+
console.warn = (...args) => {
|
|
1280
|
+
t.warnfromjs(`${side}: ${stringify(args)}`);
|
|
1300
1281
|
};
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
return _this.provider.waitUntilConnected();
|
|
1304
|
-
}
|
|
1305
|
-
throw new Error('impossible state, wallet must be opened first');
|
|
1282
|
+
console.error = (...args) => {
|
|
1283
|
+
t.errorfromjs(`${side}: ${stringify(args)}`);
|
|
1306
1284
|
};
|
|
1307
|
-
|
|
1308
|
-
this.provider = undefined;
|
|
1309
|
-
}
|
|
1310
|
-
add(...messageProviders) {
|
|
1311
|
-
this.messageProviders.push(...messageProviders);
|
|
1312
|
-
}
|
|
1313
|
-
closeWallet() {
|
|
1314
|
-
if (this.provider) {
|
|
1315
|
-
this.provider.closeWallet();
|
|
1316
|
-
}
|
|
1317
|
-
}
|
|
1318
|
-
isOpened() {
|
|
1319
|
-
if (this.provider) {
|
|
1320
|
-
return this.provider.isOpened();
|
|
1321
|
-
}
|
|
1322
|
-
return false;
|
|
1323
|
-
}
|
|
1324
|
-
isConnected() {
|
|
1325
|
-
if (this.provider) {
|
|
1326
|
-
return this.provider.isConnected();
|
|
1327
|
-
}
|
|
1328
|
-
return false;
|
|
1329
|
-
}
|
|
1330
|
-
on(event, fn) {
|
|
1331
|
-
if (this.provider) {
|
|
1332
|
-
this.provider.on(event, fn);
|
|
1333
|
-
return;
|
|
1334
|
-
}
|
|
1335
|
-
this.messageProviders.forEach(m => {
|
|
1336
|
-
m.on(event, fn);
|
|
1337
|
-
});
|
|
1338
|
-
}
|
|
1339
|
-
once(event, fn) {
|
|
1340
|
-
if (this.provider) {
|
|
1341
|
-
this.provider.once(event, fn);
|
|
1342
|
-
return;
|
|
1343
|
-
}
|
|
1344
|
-
this.messageProviders.forEach(m => {
|
|
1345
|
-
m.once(event, fn);
|
|
1346
|
-
});
|
|
1347
|
-
}
|
|
1348
|
-
emit(event, ...args) {
|
|
1349
|
-
if (this.provider) {
|
|
1350
|
-
return this.provider.emit(event, ...args);
|
|
1351
|
-
}
|
|
1352
|
-
for (let i = 0; i < this.messageProviders.length; i++) {
|
|
1353
|
-
this.messageProviders[i].emit(event, ...args);
|
|
1354
|
-
}
|
|
1355
|
-
return true;
|
|
1356
|
-
}
|
|
1357
|
-
sendMessage(message) {
|
|
1358
|
-
if (!message.idx || message.idx <= 0) {
|
|
1359
|
-
throw new Error('message idx is empty');
|
|
1360
|
-
}
|
|
1361
|
-
if (this.provider) {
|
|
1362
|
-
this.provider.sendMessage(message);
|
|
1363
|
-
} else {
|
|
1364
|
-
throw new Error('impossible state, wallet must be opened first');
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
handleMessage(message) {
|
|
1368
|
-
if (this.provider) {
|
|
1369
|
-
this.provider.handleMessage(message);
|
|
1370
|
-
return;
|
|
1371
|
-
}
|
|
1372
|
-
throw new Error('impossible state, wallet must be opened first');
|
|
1285
|
+
window.logsOverriddenForUnreal = true;
|
|
1373
1286
|
}
|
|
1374
1287
|
}
|
|
1288
|
+
function stringify(things) {
|
|
1289
|
+
return things.map(a => typeof a === 'object' ? a instanceof Error ? a.message : JSON.stringify(a) : String(a)).join(' ');
|
|
1290
|
+
}
|
|
1375
1291
|
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1292
|
+
let registeredUnrealMessageProvider;
|
|
1293
|
+
|
|
1294
|
+
// all lowercase is an annoying limitation of Unreal CEF BindUObject
|
|
1295
|
+
|
|
1296
|
+
/**
|
|
1297
|
+
* Initialized on dApp side
|
|
1298
|
+
*/
|
|
1299
|
+
class UnrealMessageProvider extends BaseProviderTransport {
|
|
1379
1300
|
constructor(walletAppURL) {
|
|
1380
1301
|
super();
|
|
1381
1302
|
this.register = () => {
|
|
1382
|
-
|
|
1303
|
+
var _window$ue;
|
|
1304
|
+
overrideLogs('dapp');
|
|
1305
|
+
if (registeredUnrealMessageProvider) {
|
|
1383
1306
|
// overriding the registered message provider
|
|
1384
|
-
|
|
1385
|
-
|
|
1307
|
+
registeredUnrealMessageProvider.unregister();
|
|
1308
|
+
registeredUnrealMessageProvider = this;
|
|
1386
1309
|
}
|
|
1387
1310
|
|
|
1388
1311
|
// listen for incoming messages from wallet
|
|
1389
|
-
window.
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
this.on('open', () => {
|
|
1394
|
-
// Heartbeat to track if window closed
|
|
1395
|
-
const popup = this.walletWindow;
|
|
1396
|
-
const interval = setInterval(() => {
|
|
1397
|
-
if (popup && popup.closed) {
|
|
1398
|
-
clearInterval(interval);
|
|
1399
|
-
this.close();
|
|
1400
|
-
}
|
|
1401
|
-
}, 500);
|
|
1402
|
-
});
|
|
1403
|
-
|
|
1404
|
-
// close clean up
|
|
1405
|
-
this.on('close', () => {
|
|
1406
|
-
if (this.walletWindow) {
|
|
1407
|
-
this.walletWindow.close();
|
|
1408
|
-
this.walletWindow = null;
|
|
1409
|
-
}
|
|
1410
|
-
});
|
|
1312
|
+
if ((_window$ue = window.ue) != null && _window$ue.sequencewallettransport) {
|
|
1313
|
+
window.ue.sequencewallettransport.onmessagefromwallet = this.onUnrealCallback;
|
|
1314
|
+
}
|
|
1315
|
+
registeredUnrealMessageProvider = this;
|
|
1411
1316
|
this._registered = true;
|
|
1317
|
+
console.log('registering transport!');
|
|
1412
1318
|
};
|
|
1413
1319
|
this.unregister = () => {
|
|
1320
|
+
var _window$ue2, _window$ue2$sequencew;
|
|
1414
1321
|
this._registered = false;
|
|
1415
1322
|
this.closeWallet();
|
|
1416
1323
|
|
|
1417
1324
|
// disable message listener
|
|
1418
|
-
if (
|
|
1419
|
-
|
|
1325
|
+
if (registeredUnrealMessageProvider === this) {
|
|
1326
|
+
registeredUnrealMessageProvider = undefined;
|
|
1327
|
+
}
|
|
1328
|
+
if (((_window$ue2 = window.ue) == null ? void 0 : (_window$ue2$sequencew = _window$ue2.sequencewallettransport) == null ? void 0 : _window$ue2$sequencew.onmessagefromwallet) === this.onUnrealCallback) {
|
|
1329
|
+
delete window.ue.sequencewallettransport.onmessagefromwallet;
|
|
1420
1330
|
}
|
|
1421
|
-
window.removeEventListener('message', this.onWindowEvent);
|
|
1422
1331
|
|
|
1423
1332
|
// clear event listeners
|
|
1424
1333
|
this.events.removeAllListeners();
|
|
1425
1334
|
};
|
|
1426
1335
|
this.openWallet = (path, intent, networkId) => {
|
|
1427
|
-
if (this.
|
|
1428
|
-
// TODO
|
|
1429
|
-
|
|
1336
|
+
if (this.isOpened()) {
|
|
1337
|
+
// TODO focus wallet
|
|
1338
|
+
console.log('wallet already open!');
|
|
1430
1339
|
return;
|
|
1431
1340
|
}
|
|
1432
|
-
|
|
1341
|
+
console.log('opening wallet!');
|
|
1433
1342
|
// Instantiate new walletURL for this call
|
|
1434
1343
|
const walletURL = new URL(this.walletURL.href);
|
|
1435
1344
|
const windowSessionParams = new WindowSessionParams();
|
|
1436
|
-
if (path
|
|
1345
|
+
if (path) {
|
|
1437
1346
|
walletURL.pathname = path.toLowerCase();
|
|
1438
1347
|
}
|
|
1439
1348
|
|
|
@@ -1442,80 +1351,19 @@ class WindowMessageProvider extends BaseProviderTransport {
|
|
|
1442
1351
|
this._sessionId = `${performance.now()}`;
|
|
1443
1352
|
windowSessionParams.set('sid', this._sessionId);
|
|
1444
1353
|
if (intent) {
|
|
1445
|
-
// for the window-transport, we eagerly/optimistically set the origin host
|
|
1446
|
-
// when connecting to the wallet, however, this will be verified and enforced
|
|
1447
|
-
// on the wallet-side, so if a dapp provides the wrong origin, it will be dropped.
|
|
1448
|
-
if (intent.type === 'connect') {
|
|
1449
|
-
if (!intent.options) intent.options = {};
|
|
1450
|
-
|
|
1451
|
-
// skip setting origin host if we're in an browser extension execution context
|
|
1452
|
-
// allow origin that is passed in
|
|
1453
|
-
if (!isBrowserExtension() && !isUnityPlugin()) {
|
|
1454
|
-
intent.options.origin = window.location.origin;
|
|
1455
|
-
}
|
|
1456
|
-
}
|
|
1457
1354
|
// encode intent as base64 url-encoded param
|
|
1458
1355
|
windowSessionParams.set('intent', utils.base64EncodeObject(intent));
|
|
1459
1356
|
}
|
|
1460
1357
|
if (networkId) {
|
|
1461
1358
|
windowSessionParams.set('net', `${networkId}`);
|
|
1462
1359
|
}
|
|
1463
|
-
|
|
1464
|
-
// Open popup window on center of the app window
|
|
1465
|
-
let windowSize;
|
|
1466
|
-
let windowPos;
|
|
1467
|
-
if (isBrowserExtension()) {
|
|
1468
|
-
windowSize = [450, 750];
|
|
1469
|
-
windowPos = [Math.abs(window.screen.width / 2 - windowSize[0] / 2), Math.abs(window.screen.height / 2 - windowSize[1] / 2)];
|
|
1470
|
-
} else {
|
|
1471
|
-
windowSize = [450, 750];
|
|
1472
|
-
windowPos = [Math.abs(window.screenX + window.innerWidth / 2 - windowSize[0] / 2), Math.abs(window.screenY + window.innerHeight / 2 - windowSize[1] / 2)];
|
|
1473
|
-
}
|
|
1474
|
-
const windowFeatures = `toolbar=0,location=0,menubar=0,scrollbars=yes,status=yes` + `,width=${windowSize[0]},height=${windowSize[1]}` + `,left=${windowPos[0]},top=${windowPos[1]}`;
|
|
1475
|
-
|
|
1476
1360
|
// serialize params
|
|
1477
1361
|
walletURL.search = windowSessionParams.toString();
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
// TODO: move this somewhere else
|
|
1481
|
-
// TODO: perhaps we trigger a .on('openTimeout') event..? maybe.. could help.
|
|
1482
|
-
|
|
1483
|
-
// Popup blocking detection and notice
|
|
1484
|
-
// let warned = false
|
|
1485
|
-
// const warnPopupBlocked = () => {
|
|
1486
|
-
// if (warned) return
|
|
1487
|
-
// warned = true
|
|
1488
|
-
// // alert('popup is blocked! hey yo') // NOTE: for debug purposes only
|
|
1489
|
-
// throw new Error('popup is blocked')
|
|
1490
|
-
// }
|
|
1491
|
-
|
|
1492
|
-
// const popupCheck = setTimeout(() => {
|
|
1493
|
-
// if (!popup || popup.closed || typeof popup.closed === 'undefined') {
|
|
1494
|
-
// // popup is definitely blocked if we reach here.
|
|
1495
|
-
// warnPopupBlocked()
|
|
1496
|
-
// }
|
|
1497
|
-
// }, 1000)
|
|
1498
|
-
|
|
1499
|
-
// const popupBlocked = popup === null || popup === undefined
|
|
1500
|
-
// if (popupBlocked) {
|
|
1501
|
-
// warnPopupBlocked()
|
|
1502
|
-
// return
|
|
1503
|
-
// }
|
|
1362
|
+
console.log('opening wallet to', walletURL.href);
|
|
1363
|
+
window.open(walletURL.href);
|
|
1504
1364
|
};
|
|
1505
|
-
// onmessage, receives ProviderMessageResponse from the wallet
|
|
1506
|
-
this.
|
|
1507
|
-
// Security check, ensure message is coming from wallet origin url
|
|
1508
|
-
if (event.origin !== this.walletURL.origin) {
|
|
1509
|
-
// Safetly can skip events not from the wallet
|
|
1510
|
-
return;
|
|
1511
|
-
}
|
|
1512
|
-
let message;
|
|
1513
|
-
try {
|
|
1514
|
-
message = JSON.parse(event.data);
|
|
1515
|
-
} catch (err) {
|
|
1516
|
-
// event is not a ProviderMessage JSON object, skip
|
|
1517
|
-
return;
|
|
1518
|
-
}
|
|
1365
|
+
// onmessage, receives ProviderMessageResponse from the wallet unreal transport
|
|
1366
|
+
this.onUnrealCallback = message => {
|
|
1519
1367
|
if (!message) {
|
|
1520
1368
|
throw new Error('ProviderMessage object is empty');
|
|
1521
1369
|
}
|
|
@@ -1526,62 +1374,36 @@ class WindowMessageProvider extends BaseProviderTransport {
|
|
|
1526
1374
|
this.walletURL = new URL(walletAppURL);
|
|
1527
1375
|
}
|
|
1528
1376
|
closeWallet() {
|
|
1529
|
-
var _this$walletWindow;
|
|
1530
1377
|
this.close();
|
|
1531
|
-
(_this$walletWindow = this.walletWindow) == null ? void 0 : _this$walletWindow.close();
|
|
1532
1378
|
}
|
|
1379
|
+
// all lowercase is an annoying limitation of Unreal CEF BindUObject
|
|
1533
1380
|
sendMessage(message) {
|
|
1534
|
-
|
|
1535
|
-
utils.logger.warn('WindowMessageProvider: sendMessage failed as walletWindow is unavailable');
|
|
1536
|
-
return;
|
|
1537
|
-
}
|
|
1381
|
+
var _window$ue3, _window$ue3$sequencew;
|
|
1538
1382
|
const postedMessage = typeof message !== 'string' ? JSON.stringify(message) : message;
|
|
1539
|
-
|
|
1383
|
+
console.log('Sending message to wallet:', postedMessage);
|
|
1384
|
+
(_window$ue3 = window.ue) == null ? void 0 : (_window$ue3$sequencew = _window$ue3.sequencewallettransport) == null ? void 0 : _window$ue3$sequencew.sendmessagetowallet(postedMessage);
|
|
1540
1385
|
}
|
|
1541
1386
|
}
|
|
1542
1387
|
|
|
1543
|
-
|
|
1388
|
+
// all lowercase is an annoying limitation of Unreal CEF BindUObject
|
|
1389
|
+
|
|
1390
|
+
/**
|
|
1391
|
+
* Initialized on Wallet side
|
|
1392
|
+
*/
|
|
1393
|
+
class UnrealMessageHandler extends BaseWalletTransport {
|
|
1544
1394
|
constructor(walletRequestHandler) {
|
|
1545
|
-
var _this;
|
|
1546
1395
|
super(walletRequestHandler);
|
|
1547
|
-
_this = this;
|
|
1548
|
-
this._isPopup = false;
|
|
1549
1396
|
// onmessage is called when (the wallet) receives request messages from the dapp
|
|
1550
|
-
// over the
|
|
1551
|
-
this.
|
|
1552
|
-
if (!event.origin || event.origin === '') {
|
|
1553
|
-
// skip same-origin or when event.origin is empty/undefined
|
|
1554
|
-
return;
|
|
1555
|
-
}
|
|
1556
|
-
if (_this.appOrigin && event.origin !== _this.appOrigin) {
|
|
1557
|
-
// skip message as not from expected app origin
|
|
1558
|
-
return;
|
|
1559
|
-
}
|
|
1560
|
-
|
|
1397
|
+
// over the unreal json-messaging transport
|
|
1398
|
+
this.onMessageFromUnreal = request => {
|
|
1561
1399
|
// Wallet always expects json-rpc request messages from a dapp
|
|
1562
|
-
let request;
|
|
1563
|
-
try {
|
|
1564
|
-
request = JSON.parse(event.data);
|
|
1565
|
-
} catch (err) {
|
|
1566
|
-
// event is not a ProviderMessage JSON object, skip
|
|
1567
|
-
return;
|
|
1568
|
-
}
|
|
1569
|
-
utils.logger.debug('RECEIVED MESSAGE', request);
|
|
1570
1400
|
|
|
1571
|
-
|
|
1572
|
-
if (_this._init !== InitState.OK && _this.isValidInitAck(request)) {
|
|
1573
|
-
_this.appOrigin = event.origin;
|
|
1574
|
-
}
|
|
1575
|
-
if (_this._init === InitState.OK && (!_this.appOrigin || _this.appOrigin.length < 8)) {
|
|
1576
|
-
// impossible state
|
|
1577
|
-
utils.logger.error('impossible state, init.OK and appOrigin required');
|
|
1578
|
-
return;
|
|
1579
|
-
}
|
|
1401
|
+
utils.logger.debug('RECEIVED MESSAGE', request);
|
|
1580
1402
|
|
|
1581
1403
|
// Handle message via the base transport
|
|
1582
|
-
|
|
1404
|
+
this.handleMessage(request);
|
|
1583
1405
|
};
|
|
1584
|
-
this.
|
|
1406
|
+
this.getUnrealTransportSession = windowParams => {
|
|
1585
1407
|
const params = new WindowSessionParams(windowParams);
|
|
1586
1408
|
return {
|
|
1587
1409
|
sessionId: params.get('sid'),
|
|
@@ -1592,18 +1414,17 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1592
1414
|
this._init = InitState.NIL;
|
|
1593
1415
|
}
|
|
1594
1416
|
async register(windowHref) {
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
if (isPopup !== true) {
|
|
1417
|
+
var _window$ue;
|
|
1418
|
+
if (((_window$ue = window.ue) == null ? void 0 : _window$ue.sequencewallettransport) === undefined) {
|
|
1598
1419
|
return;
|
|
1599
1420
|
}
|
|
1421
|
+
overrideLogs('wallet');
|
|
1600
1422
|
|
|
1601
1423
|
// record open details (sessionId + default network) from the window url
|
|
1602
1424
|
const {
|
|
1603
|
-
pathname,
|
|
1604
1425
|
search: rawParams
|
|
1605
1426
|
} = new URL(windowHref || window.location.href);
|
|
1606
|
-
let session = this.
|
|
1427
|
+
let session = this.getUnrealTransportSession(rawParams);
|
|
1607
1428
|
|
|
1608
1429
|
// provider should always include sid when opening a new window
|
|
1609
1430
|
const isNewWindowSession = !!session.sessionId;
|
|
@@ -1613,15 +1434,12 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1613
1434
|
session = await this.getCachedTransportSession();
|
|
1614
1435
|
}
|
|
1615
1436
|
if (!session) {
|
|
1616
|
-
utils.logger.error('
|
|
1437
|
+
utils.logger.error('unreal session is undefined');
|
|
1617
1438
|
return;
|
|
1618
1439
|
}
|
|
1619
1440
|
|
|
1620
|
-
// record parent window instance for communication
|
|
1621
|
-
this.parentWindow = parent.window.opener;
|
|
1622
|
-
|
|
1623
1441
|
// listen for window-transport requests
|
|
1624
|
-
window.
|
|
1442
|
+
window.ue.sequencewallettransport.onmessagefromsequencejs = this.onMessageFromUnreal;
|
|
1625
1443
|
this._registered = true;
|
|
1626
1444
|
|
|
1627
1445
|
// send open event to the app which opened us
|
|
@@ -1646,79 +1464,670 @@ class WindowMessageHandler extends BaseWalletTransport {
|
|
|
1646
1464
|
});
|
|
1647
1465
|
}
|
|
1648
1466
|
unregister() {
|
|
1649
|
-
|
|
1467
|
+
var _window$ue2, _window$ue2$sequencew;
|
|
1468
|
+
if (((_window$ue2 = window.ue) == null ? void 0 : (_window$ue2$sequencew = _window$ue2.sequencewallettransport) == null ? void 0 : _window$ue2$sequencew.onmessagefromsequencejs) === this.onMessageFromUnreal) {
|
|
1469
|
+
delete window.ue.sequencewallettransport.onmessagefromsequencejs;
|
|
1470
|
+
}
|
|
1650
1471
|
this._registered = false;
|
|
1651
1472
|
}
|
|
1652
|
-
//
|
|
1473
|
+
// sendMessage sends message to the dapp window
|
|
1653
1474
|
sendMessage(message) {
|
|
1475
|
+
var _window$ue3, _window$ue3$sequencew;
|
|
1476
|
+
if (message.type !== EventType.INIT && this._init !== InitState.OK) {
|
|
1477
|
+
utils.logger.error('impossible state, should not be calling postMessage until inited');
|
|
1478
|
+
return;
|
|
1479
|
+
}
|
|
1654
1480
|
// prepare payload
|
|
1655
1481
|
const payload = JSON.stringify(message);
|
|
1656
1482
|
|
|
1657
1483
|
// post-message to app.
|
|
1658
|
-
|
|
1659
|
-
if (message.type === EventType.INIT) {
|
|
1660
|
-
this.postMessage(payload, true);
|
|
1661
|
-
} else {
|
|
1662
|
-
this.postMessage(payload);
|
|
1663
|
-
}
|
|
1484
|
+
(_window$ue3 = window.ue) == null ? void 0 : (_window$ue3$sequencew = _window$ue3.sequencewallettransport) == null ? void 0 : _window$ue3$sequencew.sendmessagetosequencejs(payload);
|
|
1664
1485
|
}
|
|
1665
|
-
|
|
1666
|
-
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
const CHANNEL_ID = 'sequence-extension-message-handler';
|
|
1489
|
+
class ExtensionMessageHandler extends BaseWalletTransport {
|
|
1490
|
+
constructor(walletRequestHandler, runtime) {
|
|
1491
|
+
super(walletRequestHandler);
|
|
1492
|
+
this.runtime = runtime;
|
|
1493
|
+
this._init = InitState.OK;
|
|
1667
1494
|
}
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
// open message transmission
|
|
1678
|
-
if (this.appOrigin && this.appOrigin.length > 4) {
|
|
1679
|
-
// just above '.com'
|
|
1680
|
-
this.parentWindow.postMessage(message, this.appOrigin);
|
|
1681
|
-
} else {
|
|
1682
|
-
utils.logger.error('unable to postMessage as parentOrigin is invalid');
|
|
1683
|
-
}
|
|
1684
|
-
}
|
|
1495
|
+
register() {
|
|
1496
|
+
this._registered = true;
|
|
1497
|
+
this.port = this.runtime.connect({
|
|
1498
|
+
name: CHANNEL_ID
|
|
1499
|
+
});
|
|
1500
|
+
}
|
|
1501
|
+
sendMessage(message) {
|
|
1502
|
+
utils.logger.info('[ExtensionMessageHandler send]', message);
|
|
1503
|
+
this.port.postMessage(message);
|
|
1685
1504
|
}
|
|
1686
1505
|
}
|
|
1687
1506
|
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1507
|
+
class ExtensionMessageProvider extends BaseProviderTransport {
|
|
1508
|
+
constructor(runtime) {
|
|
1509
|
+
super();
|
|
1510
|
+
this.register = () => {
|
|
1511
|
+
this._registered = true;
|
|
1512
|
+
};
|
|
1513
|
+
runtime.onConnect.addListener(port => {
|
|
1514
|
+
if (port.name === CHANNEL_ID) {
|
|
1515
|
+
this._init = InitState.OK;
|
|
1516
|
+
port.onMessage.addListener(message => {
|
|
1517
|
+
this.handleMessage(message);
|
|
1518
|
+
});
|
|
1519
|
+
}
|
|
1520
|
+
});
|
|
1521
|
+
}
|
|
1522
|
+
sendMessage(message) {
|
|
1523
|
+
//noop
|
|
1524
|
+
}
|
|
1525
|
+
unregister() {
|
|
1526
|
+
//noop
|
|
1527
|
+
}
|
|
1528
|
+
openWallet(path, intent, networkId) {
|
|
1529
|
+
//noop
|
|
1530
|
+
}
|
|
1531
|
+
closeWallet() {
|
|
1532
|
+
//noop
|
|
1691
1533
|
}
|
|
1692
|
-
const [first, ...rest] = transactions;
|
|
1693
|
-
return _extends({}, first, {
|
|
1694
|
-
auxiliary: rest
|
|
1695
|
-
});
|
|
1696
|
-
}
|
|
1697
|
-
function fromExtended(transaction) {
|
|
1698
|
-
return [transaction, ...(transaction.auxiliary || [])];
|
|
1699
1534
|
}
|
|
1700
1535
|
|
|
1701
|
-
|
|
1702
|
-
class
|
|
1703
|
-
constructor(
|
|
1704
|
-
var _this
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
this.
|
|
1709
|
-
this.
|
|
1710
|
-
this.
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
// this is an unexpected state and should not happen
|
|
1714
|
-
throw new Error('prompter connect options are empty');
|
|
1536
|
+
// to be used on injected window.ethereum EIP1193 proxy
|
|
1537
|
+
class BaseInjectedTransport extends eventemitter2.EventEmitter2 {
|
|
1538
|
+
constructor(stream) {
|
|
1539
|
+
var _this;
|
|
1540
|
+
super();
|
|
1541
|
+
_this = this;
|
|
1542
|
+
this.responseCallbacks = new Map();
|
|
1543
|
+
this._messageIdx = 0;
|
|
1544
|
+
this.nextMessageIdx = () => ++this._messageIdx;
|
|
1545
|
+
this.handleMessage = message => {
|
|
1546
|
+
if (!message.type || !message.data) {
|
|
1547
|
+
return;
|
|
1715
1548
|
}
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1549
|
+
utils.logger.info('[received message]', message);
|
|
1550
|
+
const requestIdx = message.idx;
|
|
1551
|
+
const responseCallback = this.responseCallbacks.get(requestIdx);
|
|
1552
|
+
if (requestIdx) {
|
|
1553
|
+
this.responseCallbacks.delete(requestIdx);
|
|
1719
1554
|
}
|
|
1720
|
-
|
|
1721
|
-
|
|
1555
|
+
switch (message.type) {
|
|
1556
|
+
case EventType.MESSAGE:
|
|
1557
|
+
if (responseCallback) {
|
|
1558
|
+
this.emit(EventType.MESSAGE, message);
|
|
1559
|
+
responseCallback(message.data.error, message);
|
|
1560
|
+
} else {
|
|
1561
|
+
// NOTE: this would occur if 'idx' isn't set, which should never happen
|
|
1562
|
+
// or when we register two handler, or duplicate messages with the same idx are sent,
|
|
1563
|
+
// all of which should be prevented prior to getting to this point
|
|
1564
|
+
throw new Error('impossible state');
|
|
1565
|
+
}
|
|
1566
|
+
break;
|
|
1567
|
+
case EventType.DISCONNECT:
|
|
1568
|
+
case EventType.ACCOUNTS_CHANGED:
|
|
1569
|
+
case EventType.CHAIN_CHANGED:
|
|
1570
|
+
this.emit(message.type, message.data);
|
|
1571
|
+
break;
|
|
1572
|
+
default:
|
|
1573
|
+
console.error('unknown message type', message);
|
|
1574
|
+
break;
|
|
1575
|
+
}
|
|
1576
|
+
};
|
|
1577
|
+
this.sendMessageRequest = async function (message) {
|
|
1578
|
+
return new Promise((resolve, reject) => {
|
|
1579
|
+
if (!message.idx || message.idx <= 0) {
|
|
1580
|
+
reject(new Error('message idx not set'));
|
|
1581
|
+
}
|
|
1582
|
+
const responseCallback = (error, response) => {
|
|
1583
|
+
if (error) {
|
|
1584
|
+
reject(error);
|
|
1585
|
+
} else if (response) {
|
|
1586
|
+
resolve(response);
|
|
1587
|
+
} else {
|
|
1588
|
+
throw new Error('no valid response to return');
|
|
1589
|
+
}
|
|
1590
|
+
};
|
|
1591
|
+
const {
|
|
1592
|
+
idx
|
|
1593
|
+
} = message;
|
|
1594
|
+
if (!_this.responseCallbacks.get(idx)) {
|
|
1595
|
+
_this.responseCallbacks.set(idx, responseCallback);
|
|
1596
|
+
} else {
|
|
1597
|
+
reject(new Error('duplicate message idx, should never happen'));
|
|
1598
|
+
}
|
|
1599
|
+
_this.sendMessage(message);
|
|
1600
|
+
});
|
|
1601
|
+
};
|
|
1602
|
+
this.stream = stream;
|
|
1603
|
+
this.stream.on('data', this.handleMessage);
|
|
1604
|
+
}
|
|
1605
|
+
sendMessage(message) {
|
|
1606
|
+
if (!this.stream.writable) {
|
|
1607
|
+
console.error('window post message stream is not writable');
|
|
1608
|
+
}
|
|
1609
|
+
this.stream.write(message);
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
// ..
|
|
1614
|
+
let registeredWindowMessageProvider;
|
|
1615
|
+
class WindowMessageProvider extends BaseProviderTransport {
|
|
1616
|
+
constructor(walletAppURL) {
|
|
1617
|
+
super();
|
|
1618
|
+
this.register = () => {
|
|
1619
|
+
if (registeredWindowMessageProvider) {
|
|
1620
|
+
// overriding the registered message provider
|
|
1621
|
+
registeredWindowMessageProvider.unregister();
|
|
1622
|
+
registeredWindowMessageProvider = this;
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
// listen for incoming messages from wallet
|
|
1626
|
+
window.addEventListener('message', this.onWindowEvent);
|
|
1627
|
+
registeredWindowMessageProvider = this;
|
|
1628
|
+
|
|
1629
|
+
// open heartbeat
|
|
1630
|
+
this.on('open', () => {
|
|
1631
|
+
// Heartbeat to track if window closed
|
|
1632
|
+
const popup = this.walletWindow;
|
|
1633
|
+
const interval = setInterval(() => {
|
|
1634
|
+
if (popup && popup.closed) {
|
|
1635
|
+
clearInterval(interval);
|
|
1636
|
+
this.close();
|
|
1637
|
+
}
|
|
1638
|
+
}, 500);
|
|
1639
|
+
});
|
|
1640
|
+
|
|
1641
|
+
// close clean up
|
|
1642
|
+
this.on('close', () => {
|
|
1643
|
+
if (this.walletWindow) {
|
|
1644
|
+
this.walletWindow.close();
|
|
1645
|
+
this.walletWindow = null;
|
|
1646
|
+
}
|
|
1647
|
+
});
|
|
1648
|
+
this._registered = true;
|
|
1649
|
+
};
|
|
1650
|
+
this.unregister = () => {
|
|
1651
|
+
this._registered = false;
|
|
1652
|
+
this.closeWallet();
|
|
1653
|
+
|
|
1654
|
+
// disable message listener
|
|
1655
|
+
if (registeredWindowMessageProvider === this) {
|
|
1656
|
+
registeredWindowMessageProvider = undefined;
|
|
1657
|
+
}
|
|
1658
|
+
window.removeEventListener('message', this.onWindowEvent);
|
|
1659
|
+
|
|
1660
|
+
// clear event listeners
|
|
1661
|
+
this.events.removeAllListeners();
|
|
1662
|
+
};
|
|
1663
|
+
this.openWallet = (path, intent, networkId) => {
|
|
1664
|
+
if (this.walletWindow && this.isOpened()) {
|
|
1665
|
+
// TODO: update the location of window to path
|
|
1666
|
+
this.walletWindow.focus();
|
|
1667
|
+
return;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
// Instantiate new walletURL for this call
|
|
1671
|
+
const walletURL = new URL(this.walletURL.href);
|
|
1672
|
+
const windowSessionParams = new WindowSessionParams();
|
|
1673
|
+
if (path && path !== '') {
|
|
1674
|
+
walletURL.pathname = path.toLowerCase();
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
// Set session, intent and network id on walletURL
|
|
1678
|
+
this._init = InitState.NIL;
|
|
1679
|
+
this._sessionId = `${performance.now()}`;
|
|
1680
|
+
windowSessionParams.set('sid', this._sessionId);
|
|
1681
|
+
if (intent) {
|
|
1682
|
+
// for the window-transport, we eagerly/optimistically set the origin host
|
|
1683
|
+
// when connecting to the wallet, however, this will be verified and enforced
|
|
1684
|
+
// on the wallet-side, so if a dapp provides the wrong origin, it will be dropped.
|
|
1685
|
+
if (intent.type === 'connect') {
|
|
1686
|
+
if (!intent.options) intent.options = {
|
|
1687
|
+
app: window.location.origin
|
|
1688
|
+
};
|
|
1689
|
+
|
|
1690
|
+
// skip setting origin host if we're in an browser extension execution context
|
|
1691
|
+
// allow origin that is passed in
|
|
1692
|
+
if (!isBrowserExtension() && !isUnityPlugin() && intent.options) {
|
|
1693
|
+
intent.options.origin = window.location.origin;
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
// encode intent as base64 url-encoded param
|
|
1697
|
+
windowSessionParams.set('intent', utils.base64EncodeObject(intent));
|
|
1698
|
+
}
|
|
1699
|
+
if (networkId) {
|
|
1700
|
+
windowSessionParams.set('net', `${networkId}`);
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
// Open popup window on center of the app window
|
|
1704
|
+
let windowSize;
|
|
1705
|
+
let windowPos;
|
|
1706
|
+
if (isBrowserExtension()) {
|
|
1707
|
+
windowSize = [450, 750];
|
|
1708
|
+
windowPos = [Math.abs(window.screen.width / 2 - windowSize[0] / 2), Math.abs(window.screen.height / 2 - windowSize[1] / 2)];
|
|
1709
|
+
} else {
|
|
1710
|
+
windowSize = [450, 750];
|
|
1711
|
+
windowPos = [Math.abs(window.screenX + window.innerWidth / 2 - windowSize[0] / 2), Math.abs(window.screenY + window.innerHeight / 2 - windowSize[1] / 2)];
|
|
1712
|
+
}
|
|
1713
|
+
const windowFeatures = `toolbar=0,location=0,menubar=0,scrollbars=yes,status=yes` + `,width=${windowSize[0]},height=${windowSize[1]}` + `,left=${windowPos[0]},top=${windowPos[1]}`;
|
|
1714
|
+
|
|
1715
|
+
// serialize params
|
|
1716
|
+
walletURL.search = windowSessionParams.toString();
|
|
1717
|
+
this.walletWindow = window.open(walletURL.href, 'sequence.app', windowFeatures);
|
|
1718
|
+
|
|
1719
|
+
// TODO: move this somewhere else
|
|
1720
|
+
// TODO: perhaps we trigger a .on('openTimeout') event..? maybe.. could help.
|
|
1721
|
+
|
|
1722
|
+
// Popup blocking detection and notice
|
|
1723
|
+
// let warned = false
|
|
1724
|
+
// const warnPopupBlocked = () => {
|
|
1725
|
+
// if (warned) return
|
|
1726
|
+
// warned = true
|
|
1727
|
+
// // alert('popup is blocked! hey yo') // NOTE: for debug purposes only
|
|
1728
|
+
// throw new Error('popup is blocked')
|
|
1729
|
+
// }
|
|
1730
|
+
|
|
1731
|
+
// const popupCheck = setTimeout(() => {
|
|
1732
|
+
// if (!popup || popup.closed || typeof popup.closed === 'undefined') {
|
|
1733
|
+
// // popup is definitely blocked if we reach here.
|
|
1734
|
+
// warnPopupBlocked()
|
|
1735
|
+
// }
|
|
1736
|
+
// }, 1000)
|
|
1737
|
+
|
|
1738
|
+
// const popupBlocked = popup === null || popup === undefined
|
|
1739
|
+
// if (popupBlocked) {
|
|
1740
|
+
// warnPopupBlocked()
|
|
1741
|
+
// return
|
|
1742
|
+
// }
|
|
1743
|
+
};
|
|
1744
|
+
// onmessage, receives ProviderMessageResponse from the wallet post-message transport
|
|
1745
|
+
this.onWindowEvent = event => {
|
|
1746
|
+
// Security check, ensure message is coming from wallet origin url
|
|
1747
|
+
if (event.origin !== this.walletURL.origin) {
|
|
1748
|
+
// Safetly can skip events not from the wallet
|
|
1749
|
+
return;
|
|
1750
|
+
}
|
|
1751
|
+
let message;
|
|
1752
|
+
try {
|
|
1753
|
+
message = JSON.parse(event.data);
|
|
1754
|
+
} catch (err) {
|
|
1755
|
+
// event is not a ProviderMessage JSON object, skip
|
|
1756
|
+
return;
|
|
1757
|
+
}
|
|
1758
|
+
if (!message) {
|
|
1759
|
+
throw new Error('ProviderMessage object is empty');
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
// handle message with base message provider
|
|
1763
|
+
this.handleMessage(message);
|
|
1764
|
+
};
|
|
1765
|
+
this.walletURL = new URL(walletAppURL);
|
|
1766
|
+
}
|
|
1767
|
+
closeWallet() {
|
|
1768
|
+
var _this$walletWindow;
|
|
1769
|
+
this.close();
|
|
1770
|
+
(_this$walletWindow = this.walletWindow) == null ? void 0 : _this$walletWindow.close();
|
|
1771
|
+
}
|
|
1772
|
+
sendMessage(message) {
|
|
1773
|
+
if (!this.walletWindow) {
|
|
1774
|
+
utils.logger.warn('WindowMessageProvider: sendMessage failed as walletWindow is unavailable');
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1777
|
+
const postedMessage = typeof message !== 'string' ? JSON.stringify(message) : message;
|
|
1778
|
+
this.walletWindow.postMessage(postedMessage, this.walletURL.origin);
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
class WindowMessageHandler extends BaseWalletTransport {
|
|
1783
|
+
constructor(walletRequestHandler) {
|
|
1784
|
+
var _this;
|
|
1785
|
+
super(walletRequestHandler);
|
|
1786
|
+
_this = this;
|
|
1787
|
+
this._isPopup = false;
|
|
1788
|
+
// onmessage is called when (the wallet) receives request messages from the dapp
|
|
1789
|
+
// over the window post-messaging transport
|
|
1790
|
+
this.onWindowEvent = async function (event) {
|
|
1791
|
+
if (!event.origin || event.origin === '') {
|
|
1792
|
+
// skip same-origin or when event.origin is empty/undefined
|
|
1793
|
+
return;
|
|
1794
|
+
}
|
|
1795
|
+
if (_this.appOrigin && event.origin !== _this.appOrigin) {
|
|
1796
|
+
// skip message as not from expected app origin
|
|
1797
|
+
return;
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
// Wallet always expects json-rpc request messages from a dapp
|
|
1801
|
+
let request;
|
|
1802
|
+
try {
|
|
1803
|
+
request = JSON.parse(event.data);
|
|
1804
|
+
} catch (err) {
|
|
1805
|
+
// event is not a ProviderMessage JSON object, skip
|
|
1806
|
+
return;
|
|
1807
|
+
}
|
|
1808
|
+
utils.logger.debug('RECEIVED MESSAGE', request);
|
|
1809
|
+
|
|
1810
|
+
// Record event origin for valid init ack
|
|
1811
|
+
if (_this._init !== InitState.OK && _this.isValidInitAck(request)) {
|
|
1812
|
+
_this.appOrigin = event.origin;
|
|
1813
|
+
}
|
|
1814
|
+
if (_this._init === InitState.OK && (!_this.appOrigin || _this.appOrigin.length < 8)) {
|
|
1815
|
+
// impossible state
|
|
1816
|
+
utils.logger.error('impossible state, init.OK and appOrigin required');
|
|
1817
|
+
return;
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
// Handle message via the base transport
|
|
1821
|
+
_this.handleMessage(request);
|
|
1822
|
+
};
|
|
1823
|
+
this.getWindowTransportSession = windowParams => {
|
|
1824
|
+
const params = new WindowSessionParams(windowParams);
|
|
1825
|
+
return {
|
|
1826
|
+
sessionId: params.get('sid'),
|
|
1827
|
+
networkId: params.get('net'),
|
|
1828
|
+
intent: utils.base64DecodeObject(params.get('intent'))
|
|
1829
|
+
};
|
|
1830
|
+
};
|
|
1831
|
+
this._init = InitState.NIL;
|
|
1832
|
+
}
|
|
1833
|
+
async register(windowHref) {
|
|
1834
|
+
const isPopup = parent.window.opener !== null;
|
|
1835
|
+
this._isPopup = isPopup;
|
|
1836
|
+
if (isPopup !== true) {
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
// record open details (sessionId + default network) from the window url
|
|
1841
|
+
const {
|
|
1842
|
+
pathname,
|
|
1843
|
+
search: rawParams
|
|
1844
|
+
} = new URL(windowHref || window.location.href);
|
|
1845
|
+
let session = this.getWindowTransportSession(rawParams);
|
|
1846
|
+
|
|
1847
|
+
// provider should always include sid when opening a new window
|
|
1848
|
+
const isNewWindowSession = !!session.sessionId;
|
|
1849
|
+
|
|
1850
|
+
// attempt to restore previous session in the case of a redirect or window reload
|
|
1851
|
+
if (!isNewWindowSession) {
|
|
1852
|
+
session = await this.getCachedTransportSession();
|
|
1853
|
+
}
|
|
1854
|
+
if (!session) {
|
|
1855
|
+
utils.logger.error('window session is undefined');
|
|
1856
|
+
return;
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
// record parent window instance for communication
|
|
1860
|
+
this.parentWindow = parent.window.opener;
|
|
1861
|
+
|
|
1862
|
+
// listen for window-transport requests
|
|
1863
|
+
window.addEventListener('message', this.onWindowEvent, false);
|
|
1864
|
+
this._registered = true;
|
|
1865
|
+
|
|
1866
|
+
// send open event to the app which opened us
|
|
1867
|
+
this.open(session).then(opened => {
|
|
1868
|
+
if (!opened) {
|
|
1869
|
+
var _session;
|
|
1870
|
+
const err = `failed to open to network ${(_session = session) == null ? void 0 : _session.networkId}`;
|
|
1871
|
+
utils.logger.error(err);
|
|
1872
|
+
this.notifyClose({
|
|
1873
|
+
message: err
|
|
1874
|
+
});
|
|
1875
|
+
window.close();
|
|
1876
|
+
}
|
|
1877
|
+
}).catch(e => {
|
|
1878
|
+
var _session2;
|
|
1879
|
+
const err = `failed to open to network ${(_session2 = session) == null ? void 0 : _session2.networkId}, due to: ${e}`;
|
|
1880
|
+
utils.logger.error(err);
|
|
1881
|
+
this.notifyClose({
|
|
1882
|
+
message: err
|
|
1883
|
+
});
|
|
1884
|
+
window.close();
|
|
1885
|
+
});
|
|
1886
|
+
}
|
|
1887
|
+
unregister() {
|
|
1888
|
+
window.removeEventListener('message', this.onWindowEvent);
|
|
1889
|
+
this._registered = false;
|
|
1890
|
+
}
|
|
1891
|
+
// postMessage sends message to the dapp window
|
|
1892
|
+
sendMessage(message) {
|
|
1893
|
+
// prepare payload
|
|
1894
|
+
const payload = JSON.stringify(message);
|
|
1895
|
+
|
|
1896
|
+
// post-message to app.
|
|
1897
|
+
// only for init requests, we send to '*' origin
|
|
1898
|
+
if (message.type === EventType.INIT) {
|
|
1899
|
+
this.postMessage(payload, true);
|
|
1900
|
+
} else {
|
|
1901
|
+
this.postMessage(payload);
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
get isPopup() {
|
|
1905
|
+
return this._isPopup;
|
|
1906
|
+
}
|
|
1907
|
+
postMessage(message, init = false) {
|
|
1908
|
+
if (init !== true && this._init !== InitState.OK) {
|
|
1909
|
+
utils.logger.error('impossible state, should not be calling postMessage until inited');
|
|
1910
|
+
return;
|
|
1911
|
+
}
|
|
1912
|
+
if (init) {
|
|
1913
|
+
// init message transmission to global target -- for 'init' payloads only
|
|
1914
|
+
this.parentWindow.postMessage(message, '*');
|
|
1915
|
+
} else {
|
|
1916
|
+
// open message transmission
|
|
1917
|
+
if (this.appOrigin && this.appOrigin.length > 4) {
|
|
1918
|
+
// just above '.com'
|
|
1919
|
+
this.parentWindow.postMessage(message, this.appOrigin);
|
|
1920
|
+
} else {
|
|
1921
|
+
utils.logger.error('unable to postMessage as parentOrigin is invalid');
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
function isMuxTransportTemplate(obj) {
|
|
1928
|
+
return obj && typeof obj === 'object' && (obj.windowTransport && typeof obj.windowTransport === 'object' || obj.proxyTransport && typeof obj.proxyTransport === 'object' || obj.extensionTransport && typeof obj.extensionTransport === 'object' || obj.unrealTransport && typeof obj.unrealTransport === 'object') && (
|
|
1929
|
+
// One of the transports must be enabled
|
|
1930
|
+
obj.windowTransport && obj.windowTransport.enabled || obj.proxyTransport && obj.proxyTransport.enabled || obj.extensionTransport && obj.extensionTransport.enabled || obj.unrealTransport && obj.unrealTransport.enabled);
|
|
1931
|
+
}
|
|
1932
|
+
class MuxMessageProvider {
|
|
1933
|
+
constructor(...messageProviders) {
|
|
1934
|
+
var _this = this;
|
|
1935
|
+
this.register = () => {
|
|
1936
|
+
if (this.messageProviders.length === 1) {
|
|
1937
|
+
this.provider = this.messageProviders[0];
|
|
1938
|
+
this.provider.register();
|
|
1939
|
+
return;
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1942
|
+
// REVIEW/NOTE: ........ this method does not work for the chrome-extension. The issue becomes
|
|
1943
|
+
// when the browser quits or restarts, the "open" event is never triggered. Perhaps the code here is fine,
|
|
1944
|
+
// or maybe its not. What should happen is when a dapp makes a request, it will call openWallet
|
|
1945
|
+
// below, in which case one of the events will register. So perhaps this is fine.
|
|
1946
|
+
this.messageProviders.forEach(m => {
|
|
1947
|
+
m.register();
|
|
1948
|
+
m.once('open', () => {
|
|
1949
|
+
// the first one to open is the winner, and others will be unregistered
|
|
1950
|
+
if (!this.provider) {
|
|
1951
|
+
this.provider = m;
|
|
1952
|
+
|
|
1953
|
+
// unregister other providers
|
|
1954
|
+
this.messageProviders.forEach(m => {
|
|
1955
|
+
if (this.provider !== m) {
|
|
1956
|
+
m.unregister();
|
|
1957
|
+
}
|
|
1958
|
+
});
|
|
1959
|
+
}
|
|
1960
|
+
});
|
|
1961
|
+
});
|
|
1962
|
+
};
|
|
1963
|
+
this.unregister = () => {
|
|
1964
|
+
this.messageProviders.forEach(m => m.unregister());
|
|
1965
|
+
this.provider = undefined;
|
|
1966
|
+
};
|
|
1967
|
+
this.openWallet = (path, intent, networkId) => {
|
|
1968
|
+
if (this.provider) {
|
|
1969
|
+
this.provider.openWallet(path, intent, networkId);
|
|
1970
|
+
return;
|
|
1971
|
+
}
|
|
1972
|
+
this.messageProviders.forEach(m => m.openWallet(path, intent, networkId));
|
|
1973
|
+
};
|
|
1974
|
+
this.sendAsync = async function (request, callback, chainId) {
|
|
1975
|
+
if (_this.provider) {
|
|
1976
|
+
_this.provider.sendAsync(request, callback, chainId);
|
|
1977
|
+
return;
|
|
1978
|
+
}
|
|
1979
|
+
throw new Error('impossible state, wallet must be opened first');
|
|
1980
|
+
};
|
|
1981
|
+
this.sendMessageRequest = async function (message) {
|
|
1982
|
+
if (_this.provider) {
|
|
1983
|
+
return _this.provider.sendMessageRequest(message);
|
|
1984
|
+
}
|
|
1985
|
+
throw new Error('impossible state, wallet must be opened first');
|
|
1986
|
+
};
|
|
1987
|
+
this.waitUntilOpened = async function () {
|
|
1988
|
+
if (_this.provider) {
|
|
1989
|
+
return _this.provider.waitUntilOpened();
|
|
1990
|
+
}
|
|
1991
|
+
return Promise.race(_this.messageProviders.map(p => p.waitUntilOpened()));
|
|
1992
|
+
};
|
|
1993
|
+
this.waitUntilConnected = async function () {
|
|
1994
|
+
if (_this.provider) {
|
|
1995
|
+
return _this.provider.waitUntilConnected();
|
|
1996
|
+
}
|
|
1997
|
+
throw new Error('impossible state, wallet must be opened first');
|
|
1998
|
+
};
|
|
1999
|
+
this.messageProviders = messageProviders;
|
|
2000
|
+
this.provider = undefined;
|
|
2001
|
+
}
|
|
2002
|
+
static new(template) {
|
|
2003
|
+
var _template$windowTrans, _template$proxyTransp, _template$extensionTr, _template$unrealTrans;
|
|
2004
|
+
const muxMessageProvider = new MuxMessageProvider();
|
|
2005
|
+
if ((_template$windowTrans = template.windowTransport) != null && _template$windowTrans.enabled && typeof window === 'object' && template.walletAppURL) {
|
|
2006
|
+
const windowMessageProvider = new WindowMessageProvider(template.walletAppURL);
|
|
2007
|
+
muxMessageProvider.add(windowMessageProvider);
|
|
2008
|
+
}
|
|
2009
|
+
if ((_template$proxyTransp = template.proxyTransport) != null && _template$proxyTransp.enabled) {
|
|
2010
|
+
const proxyMessageProvider = new ProxyMessageProvider(template.proxyTransport.appPort);
|
|
2011
|
+
muxMessageProvider.add(proxyMessageProvider);
|
|
2012
|
+
}
|
|
2013
|
+
if ((_template$extensionTr = template.extensionTransport) != null && _template$extensionTr.enabled) {
|
|
2014
|
+
const extensionMessageProvider = new ExtensionMessageProvider(template.extensionTransport.runtime);
|
|
2015
|
+
muxMessageProvider.add(extensionMessageProvider);
|
|
2016
|
+
|
|
2017
|
+
// NOTE/REVIEW: see note in mux-message-provider
|
|
2018
|
+
//
|
|
2019
|
+
// We don't add the extensionMessageProvider here because we don't send requests to it anyways, we seem to
|
|
2020
|
+
// send all requests to the WindowMessageProvider anyways. By allowing it, if browser restarts, it will break
|
|
2021
|
+
// the entire extension because messageProvider.provider will be undefined. So this is a hack to fix it.
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
if ((_template$unrealTrans = template.unrealTransport) != null && _template$unrealTrans.enabled && template.windowTransport && template.walletAppURL) {
|
|
2025
|
+
const unrealMessageProvider = new UnrealMessageProvider(template.walletAppURL);
|
|
2026
|
+
muxMessageProvider.add(unrealMessageProvider);
|
|
2027
|
+
}
|
|
2028
|
+
muxMessageProvider.register();
|
|
2029
|
+
return muxMessageProvider;
|
|
2030
|
+
}
|
|
2031
|
+
add(...messageProviders) {
|
|
2032
|
+
this.messageProviders.push(...messageProviders);
|
|
2033
|
+
}
|
|
2034
|
+
closeWallet() {
|
|
2035
|
+
if (this.provider) {
|
|
2036
|
+
this.provider.closeWallet();
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
isOpened() {
|
|
2040
|
+
if (this.provider) {
|
|
2041
|
+
return this.provider.isOpened();
|
|
2042
|
+
}
|
|
2043
|
+
return false;
|
|
2044
|
+
}
|
|
2045
|
+
isConnected() {
|
|
2046
|
+
if (this.provider) {
|
|
2047
|
+
return this.provider.isConnected();
|
|
2048
|
+
}
|
|
2049
|
+
return false;
|
|
2050
|
+
}
|
|
2051
|
+
on(event, fn) {
|
|
2052
|
+
if (this.provider) {
|
|
2053
|
+
this.provider.on(event, fn);
|
|
2054
|
+
return;
|
|
2055
|
+
}
|
|
2056
|
+
this.messageProviders.forEach(m => {
|
|
2057
|
+
m.on(event, fn);
|
|
2058
|
+
});
|
|
2059
|
+
}
|
|
2060
|
+
once(event, fn) {
|
|
2061
|
+
if (this.provider) {
|
|
2062
|
+
this.provider.once(event, fn);
|
|
2063
|
+
return;
|
|
2064
|
+
}
|
|
2065
|
+
this.messageProviders.forEach(m => {
|
|
2066
|
+
m.once(event, fn);
|
|
2067
|
+
});
|
|
2068
|
+
}
|
|
2069
|
+
emit(event, ...args) {
|
|
2070
|
+
if (this.provider) {
|
|
2071
|
+
return this.provider.emit(event, ...args);
|
|
2072
|
+
}
|
|
2073
|
+
for (let i = 0; i < this.messageProviders.length; i++) {
|
|
2074
|
+
this.messageProviders[i].emit(event, ...args);
|
|
2075
|
+
}
|
|
2076
|
+
return true;
|
|
2077
|
+
}
|
|
2078
|
+
sendMessage(message) {
|
|
2079
|
+
if (!message.idx || message.idx <= 0) {
|
|
2080
|
+
throw new Error('message idx is empty');
|
|
2081
|
+
}
|
|
2082
|
+
if (this.provider) {
|
|
2083
|
+
this.provider.sendMessage(message);
|
|
2084
|
+
} else {
|
|
2085
|
+
throw new Error('impossible state, wallet must be opened first');
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
handleMessage(message) {
|
|
2089
|
+
if (this.provider) {
|
|
2090
|
+
this.provider.handleMessage(message);
|
|
2091
|
+
return;
|
|
2092
|
+
}
|
|
2093
|
+
throw new Error('impossible state, wallet must be opened first');
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
function toExtended(transactions) {
|
|
2098
|
+
if (transactions.length === 0) {
|
|
2099
|
+
throw new Error("No transaction provided");
|
|
2100
|
+
}
|
|
2101
|
+
const [first, ...rest] = transactions;
|
|
2102
|
+
return _extends({}, first, {
|
|
2103
|
+
auxiliary: rest
|
|
2104
|
+
});
|
|
2105
|
+
}
|
|
2106
|
+
function fromExtended(transaction) {
|
|
2107
|
+
return [transaction, ...(transaction.auxiliary || [])];
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
const SIGNER_READY_TIMEOUT = 10000;
|
|
2111
|
+
class WalletRequestHandler {
|
|
2112
|
+
constructor(_account, prompter, networks) {
|
|
2113
|
+
var _this = this;
|
|
2114
|
+
// signer interface of the wallet. A null value means there is no signer (ie. user not signed in). An undefined
|
|
2115
|
+
// value means the signer state is unknown, usually meaning the wallet app is booting up and initializing. Of course
|
|
2116
|
+
// a Signer value is the actually interface to a signed-in account
|
|
2117
|
+
this.signerReadyCallbacks = [];
|
|
2118
|
+
this.events = new eventemitter2.EventEmitter2();
|
|
2119
|
+
this.onConnectOptionsChange = undefined;
|
|
2120
|
+
this.promptConnect = async function (options) {
|
|
2121
|
+
if (!options && !_this._connectOptions) {
|
|
2122
|
+
// this is an unexpected state and should not happen
|
|
2123
|
+
throw new Error('prompter connect options are empty');
|
|
2124
|
+
}
|
|
2125
|
+
if (!_this.prompter) {
|
|
2126
|
+
// if prompter is null, we'll auto connect
|
|
2127
|
+
return _this.connect(options);
|
|
2128
|
+
}
|
|
2129
|
+
const promptConnectDetails = await _this.prompter.promptConnect(options || _this._connectOptions).catch(_ => {
|
|
2130
|
+
return {
|
|
1722
2131
|
connected: false
|
|
1723
2132
|
};
|
|
1724
2133
|
});
|
|
@@ -2155,16 +2564,6 @@ class WalletRequestHandler {
|
|
|
2155
2564
|
var _this$prompter$getDef, _this$prompter;
|
|
2156
2565
|
return (_this$prompter$getDef = (_this$prompter = this.prompter) == null ? void 0 : _this$prompter.getDefaultChainId()) != null ? _this$prompter$getDef : this.networks[0].chainId;
|
|
2157
2566
|
}
|
|
2158
|
-
findNetworkID(network) {
|
|
2159
|
-
const lnet = typeof network === 'string' ? network.toLowerCase() : network;
|
|
2160
|
-
const networkId = this.networks.find(n => {
|
|
2161
|
-
return n.name.toLowerCase() === lnet || n.chainId.toString() === lnet || n.chainId === lnet;
|
|
2162
|
-
});
|
|
2163
|
-
if (!networkId) {
|
|
2164
|
-
throw new Error(`Network ${network} not found`);
|
|
2165
|
-
}
|
|
2166
|
-
return networkId.chainId;
|
|
2167
|
-
}
|
|
2168
2567
|
async signIn(account, options = {}) {
|
|
2169
2568
|
this.setAccount(account);
|
|
2170
2569
|
const {
|
|
@@ -2233,24 +2632,7 @@ class WalletRequestHandler {
|
|
|
2233
2632
|
error: 'unable to connect without signed in account'
|
|
2234
2633
|
};
|
|
2235
2634
|
}
|
|
2236
|
-
|
|
2237
|
-
switch (typeof (options == null ? void 0 : options.networkId)) {
|
|
2238
|
-
case 'string':
|
|
2239
|
-
// First see if it matches the name of a network
|
|
2240
|
-
try {
|
|
2241
|
-
chainId = this.findNetworkID(options.networkId);
|
|
2242
|
-
} catch (err) {
|
|
2243
|
-
// If not, try to parse it as a big number
|
|
2244
|
-
chainId = network.getChainId(options.networkId);
|
|
2245
|
-
}
|
|
2246
|
-
break;
|
|
2247
|
-
case 'number':
|
|
2248
|
-
chainId = options.networkId;
|
|
2249
|
-
break;
|
|
2250
|
-
default:
|
|
2251
|
-
chainId = (_this$prompter$getDef2 = (_this$prompter4 = this.prompter) == null ? void 0 : _this$prompter4.getDefaultChainId()) != null ? _this$prompter$getDef2 : 1;
|
|
2252
|
-
break;
|
|
2253
|
-
}
|
|
2635
|
+
const chainId = (_this$prompter$getDef2 = (_this$prompter4 = this.prompter) == null ? void 0 : _this$prompter4.getDefaultChainId()) != null ? _this$prompter$getDef2 : 1;
|
|
2254
2636
|
const connectDetails = {
|
|
2255
2637
|
connected: true,
|
|
2256
2638
|
chainId: ethers.ethers.BigNumber.from(chainId).toHexString()
|
|
@@ -2362,6 +2744,7 @@ class WalletRequestHandler {
|
|
|
2362
2744
|
}
|
|
2363
2745
|
notifyConnect(connectDetails, origin) {
|
|
2364
2746
|
var _connectDetails$sessi;
|
|
2747
|
+
console.log('emit connect', connectDetails);
|
|
2365
2748
|
this.events.emit('connect', connectDetails);
|
|
2366
2749
|
if ((_connectDetails$sessi = connectDetails.session) != null && _connectDetails$sessi.accountAddress) {
|
|
2367
2750
|
var _connectDetails$sessi2;
|
|
@@ -2447,1412 +2830,1089 @@ function getLegacyWalletState(chainId, status) {
|
|
|
2447
2830
|
}
|
|
2448
2831
|
const permittedJsonRpcMethods = ['net_version', 'eth_chainId', 'eth_getBalance', 'eth_getTransactionCount', 'eth_blockNumber', 'eth_getBlockByNumber', 'eth_getBlockByHash', 'eth_getTransactionByHash', 'eth_getCode', 'eth_estimateGas', 'eth_gasPrice', 'sequence_getWalletContext', 'sequence_getNetworks', 'sequence_setDefaultNetwork'];
|
|
2449
2832
|
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
this.
|
|
2833
|
+
class SequenceSigner {
|
|
2834
|
+
get utils() {
|
|
2835
|
+
return this.provider.utils;
|
|
2836
|
+
}
|
|
2837
|
+
constructor(client, provider) {
|
|
2838
|
+
this.singleNetworkSigners = {};
|
|
2839
|
+
this._isSigner = true;
|
|
2840
|
+
this._isSequenceSigner = true;
|
|
2841
|
+
this.client = client;
|
|
2842
|
+
this.provider = provider;
|
|
2843
|
+
}
|
|
2844
|
+
async getAddress() {
|
|
2845
|
+
return this.client.getAddress();
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2848
|
+
// This method shouldn't be used directly
|
|
2849
|
+
// it exists to maintain compatibility with ethers.Signer
|
|
2850
|
+
connect(provider) {
|
|
2851
|
+
if (!SequenceProvider.is(provider)) {
|
|
2852
|
+
throw new Error("SequenceSigner can only be connected to a SequenceProvider");
|
|
2853
|
+
}
|
|
2854
|
+
return new SequenceSigner(this.client, provider);
|
|
2855
|
+
}
|
|
2856
|
+
getSigner(chainId) {
|
|
2857
|
+
// The signer for the default network is this signer
|
|
2858
|
+
if (!chainId) {
|
|
2859
|
+
return this;
|
|
2860
|
+
}
|
|
2861
|
+
const useChainId = this.provider.toChainId(chainId);
|
|
2862
|
+
if (!this.singleNetworkSigners[useChainId]) {
|
|
2863
|
+
this.singleNetworkSigners[useChainId] = new SingleNetworkSequenceSigner(this.client, this.provider, useChainId);
|
|
2864
|
+
}
|
|
2865
|
+
return this.singleNetworkSigners[useChainId];
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2868
|
+
/**
|
|
2869
|
+
* Resolves the chainId to use for the given request. If no chainId is provided,
|
|
2870
|
+
* it uses the chainId defined by the client (default chainId). This can be
|
|
2871
|
+
* overriden to build a single-network SequenceProvider.
|
|
2872
|
+
*/
|
|
2873
|
+
useChainId(chainId) {
|
|
2874
|
+
return this.provider.toChainId(chainId) || this.client.getChainId();
|
|
2875
|
+
}
|
|
2876
|
+
async signMessage(message, options) {
|
|
2877
|
+
const {
|
|
2878
|
+
eip6492 = true
|
|
2879
|
+
} = options || {};
|
|
2880
|
+
const chainId = this.useChainId(options == null ? void 0 : options.chainId);
|
|
2881
|
+
return this.client.signMessage(message, {
|
|
2882
|
+
eip6492,
|
|
2883
|
+
chainId
|
|
2884
|
+
});
|
|
2885
|
+
}
|
|
2886
|
+
async signTypedData(domain, types, message, options) {
|
|
2887
|
+
const {
|
|
2888
|
+
eip6492 = true
|
|
2889
|
+
} = options || {};
|
|
2890
|
+
const chainId = this.useChainId(options == null ? void 0 : options.chainId);
|
|
2891
|
+
return this.client.signTypedData({
|
|
2892
|
+
domain,
|
|
2893
|
+
types,
|
|
2894
|
+
message
|
|
2895
|
+
}, {
|
|
2896
|
+
eip6492,
|
|
2897
|
+
chainId
|
|
2898
|
+
});
|
|
2899
|
+
}
|
|
2900
|
+
getProvider(chainId) {
|
|
2901
|
+
return this.provider.getProvider(chainId);
|
|
2902
|
+
}
|
|
2903
|
+
async sendTransaction(transaction, options) {
|
|
2904
|
+
const chainId = this.useChainId(options == null ? void 0 : options.chainId);
|
|
2905
|
+
const resolved = await resolveArrayProperties(transaction);
|
|
2906
|
+
const txHash = await this.client.sendTransaction(resolved, {
|
|
2907
|
+
chainId
|
|
2908
|
+
});
|
|
2909
|
+
const provider = this.getProvider(chainId);
|
|
2910
|
+
try {
|
|
2911
|
+
return await ethers.ethers.utils.poll(async function () {
|
|
2912
|
+
const tx = await provider.getTransaction(txHash);
|
|
2913
|
+
return tx ? provider._wrapTransaction(tx, txHash) : undefined;
|
|
2914
|
+
}, {
|
|
2915
|
+
onceBlock: provider
|
|
2916
|
+
});
|
|
2917
|
+
} catch (err) {
|
|
2918
|
+
err.transactionHash = txHash;
|
|
2919
|
+
throw err;
|
|
2920
|
+
}
|
|
2456
2921
|
}
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2922
|
+
async getWalletConfig(chainId) {
|
|
2923
|
+
const useChainId = this.useChainId(chainId);
|
|
2924
|
+
return this.client.getOnchainWalletConfig({
|
|
2925
|
+
chainId: useChainId
|
|
2461
2926
|
});
|
|
2462
2927
|
}
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
this.port.postMessage(message);
|
|
2928
|
+
getNetworks() {
|
|
2929
|
+
return this.client.getNetworks();
|
|
2466
2930
|
}
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
constructor(runtime) {
|
|
2471
|
-
super();
|
|
2472
|
-
this.register = () => {
|
|
2473
|
-
this._registered = true;
|
|
2474
|
-
};
|
|
2475
|
-
runtime.onConnect.addListener(port => {
|
|
2476
|
-
if (port.name === CHANNEL_ID) {
|
|
2477
|
-
this._init = InitState.OK;
|
|
2478
|
-
port.onMessage.addListener(message => {
|
|
2479
|
-
this.handleMessage(message);
|
|
2480
|
-
});
|
|
2481
|
-
}
|
|
2482
|
-
});
|
|
2931
|
+
async getBalance(blockTag, optionals) {
|
|
2932
|
+
const provider = this.getProvider(optionals == null ? void 0 : optionals.chainId);
|
|
2933
|
+
return provider.getBalance(this.getAddress(), blockTag);
|
|
2483
2934
|
}
|
|
2484
|
-
|
|
2485
|
-
|
|
2935
|
+
async estimateGas(transaction, optionals) {
|
|
2936
|
+
return this.getProvider(optionals == null ? void 0 : optionals.chainId).estimateGas(transaction);
|
|
2486
2937
|
}
|
|
2487
|
-
|
|
2488
|
-
|
|
2938
|
+
async call(transaction, blockTag, optionals) {
|
|
2939
|
+
return this.getProvider(optionals == null ? void 0 : optionals.chainId).call(transaction, blockTag);
|
|
2489
2940
|
}
|
|
2490
|
-
|
|
2491
|
-
|
|
2941
|
+
getChainId() {
|
|
2942
|
+
return Promise.resolve(this.client.getChainId());
|
|
2492
2943
|
}
|
|
2493
|
-
|
|
2494
|
-
|
|
2944
|
+
async getGasPrice(optionals) {
|
|
2945
|
+
return this.getProvider(optionals == null ? void 0 : optionals.chainId).getGasPrice();
|
|
2495
2946
|
}
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
// to be used on injected window.ethereum EIP1193 proxy
|
|
2499
|
-
class BaseInjectedTransport extends eventemitter2.EventEmitter2 {
|
|
2500
|
-
constructor(stream) {
|
|
2501
|
-
var _this;
|
|
2502
|
-
super();
|
|
2503
|
-
_this = this;
|
|
2504
|
-
this.responseCallbacks = new Map();
|
|
2505
|
-
this._messageIdx = 0;
|
|
2506
|
-
this.nextMessageIdx = () => ++this._messageIdx;
|
|
2507
|
-
this.handleMessage = message => {
|
|
2508
|
-
if (!message.type || !message.data) {
|
|
2509
|
-
return;
|
|
2510
|
-
}
|
|
2511
|
-
utils.logger.info('[received message]', message);
|
|
2512
|
-
const requestIdx = message.idx;
|
|
2513
|
-
const responseCallback = this.responseCallbacks.get(requestIdx);
|
|
2514
|
-
if (requestIdx) {
|
|
2515
|
-
this.responseCallbacks.delete(requestIdx);
|
|
2516
|
-
}
|
|
2517
|
-
switch (message.type) {
|
|
2518
|
-
case EventType.MESSAGE:
|
|
2519
|
-
if (responseCallback) {
|
|
2520
|
-
this.emit(EventType.MESSAGE, message);
|
|
2521
|
-
responseCallback(message.data.error, message);
|
|
2522
|
-
} else {
|
|
2523
|
-
// NOTE: this would occur if 'idx' isn't set, which should never happen
|
|
2524
|
-
// or when we register two handler, or duplicate messages with the same idx are sent,
|
|
2525
|
-
// all of which should be prevented prior to getting to this point
|
|
2526
|
-
throw new Error('impossible state');
|
|
2527
|
-
}
|
|
2528
|
-
break;
|
|
2529
|
-
case EventType.DISCONNECT:
|
|
2530
|
-
case EventType.ACCOUNTS_CHANGED:
|
|
2531
|
-
case EventType.CHAIN_CHANGED:
|
|
2532
|
-
this.emit(message.type, message.data);
|
|
2533
|
-
break;
|
|
2534
|
-
default:
|
|
2535
|
-
console.error('unknown message type', message);
|
|
2536
|
-
break;
|
|
2537
|
-
}
|
|
2538
|
-
};
|
|
2539
|
-
this.sendMessageRequest = async function (message) {
|
|
2540
|
-
return new Promise((resolve, reject) => {
|
|
2541
|
-
if (!message.idx || message.idx <= 0) {
|
|
2542
|
-
reject(new Error('message idx not set'));
|
|
2543
|
-
}
|
|
2544
|
-
const responseCallback = (error, response) => {
|
|
2545
|
-
if (error) {
|
|
2546
|
-
reject(error);
|
|
2547
|
-
} else if (response) {
|
|
2548
|
-
resolve(response);
|
|
2549
|
-
} else {
|
|
2550
|
-
throw new Error('no valid response to return');
|
|
2551
|
-
}
|
|
2552
|
-
};
|
|
2553
|
-
const {
|
|
2554
|
-
idx
|
|
2555
|
-
} = message;
|
|
2556
|
-
if (!_this.responseCallbacks.get(idx)) {
|
|
2557
|
-
_this.responseCallbacks.set(idx, responseCallback);
|
|
2558
|
-
} else {
|
|
2559
|
-
reject(new Error('duplicate message idx, should never happen'));
|
|
2560
|
-
}
|
|
2561
|
-
_this.sendMessage(message);
|
|
2562
|
-
});
|
|
2563
|
-
};
|
|
2564
|
-
this.stream = stream;
|
|
2565
|
-
this.stream.on('data', this.handleMessage);
|
|
2947
|
+
async getFeeData(optionals) {
|
|
2948
|
+
return this.getProvider(optionals == null ? void 0 : optionals.chainId).getFeeData();
|
|
2566
2949
|
}
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2950
|
+
async resolveName(name) {
|
|
2951
|
+
const res = await this.provider.resolveName(name);
|
|
2952
|
+
|
|
2953
|
+
// For some reason ethers.Signer expects this to return `string`
|
|
2954
|
+
// but ethers.providers.Provider expects this to return `string | null`.
|
|
2955
|
+
// The signer doesn't have any other source of information, so we'll
|
|
2956
|
+
// fail if the provider doesn't return a result.
|
|
2957
|
+
if (res === null) {
|
|
2958
|
+
throw new Error(`ENS name not found: ${name}`);
|
|
2570
2959
|
}
|
|
2571
|
-
|
|
2960
|
+
return res;
|
|
2572
2961
|
}
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
/**
|
|
2576
|
-
* This will redirect console logs from Sequence.js & the wallet to the Unreal console, for debugging purposes.
|
|
2577
|
-
*/
|
|
2578
|
-
function overrideLogs(side) {
|
|
2579
|
-
var _window$ue;
|
|
2580
|
-
if ((_window$ue = window.ue) != null && _window$ue.sequencewallettransport && !window.logsOverriddenForUnreal) {
|
|
2581
|
-
var _window$ue2;
|
|
2582
|
-
const t = (_window$ue2 = window.ue) == null ? void 0 : _window$ue2.sequencewallettransport;
|
|
2583
|
-
console.log = (...args) => {
|
|
2584
|
-
t.logfromjs(`${side}: ${stringify(args)}`);
|
|
2585
|
-
};
|
|
2586
|
-
console.warn = (...args) => {
|
|
2587
|
-
t.warnfromjs(`${side}: ${stringify(args)}`);
|
|
2588
|
-
};
|
|
2589
|
-
console.error = (...args) => {
|
|
2590
|
-
t.errorfromjs(`${side}: ${stringify(args)}`);
|
|
2591
|
-
};
|
|
2592
|
-
window.logsOverriddenForUnreal = true;
|
|
2962
|
+
_checkProvider(_operation) {
|
|
2963
|
+
// We always have a provider, so this is a noop
|
|
2593
2964
|
}
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
return things.map(a => typeof a === 'object' ? a instanceof Error ? a.message : JSON.stringify(a) : String(a)).join(' ');
|
|
2597
|
-
}
|
|
2598
|
-
|
|
2599
|
-
let registeredUnrealMessageProvider;
|
|
2600
|
-
|
|
2601
|
-
// all lowercase is an annoying limitation of Unreal CEF BindUObject
|
|
2602
|
-
|
|
2603
|
-
/**
|
|
2604
|
-
* Initialized on dApp side
|
|
2605
|
-
*/
|
|
2606
|
-
class UnrealMessageProvider extends BaseProviderTransport {
|
|
2607
|
-
constructor(walletAppURL) {
|
|
2608
|
-
super();
|
|
2609
|
-
this.register = () => {
|
|
2610
|
-
var _window$ue;
|
|
2611
|
-
overrideLogs('dapp');
|
|
2612
|
-
if (registeredUnrealMessageProvider) {
|
|
2613
|
-
// overriding the registered message provider
|
|
2614
|
-
registeredUnrealMessageProvider.unregister();
|
|
2615
|
-
registeredUnrealMessageProvider = this;
|
|
2616
|
-
}
|
|
2617
|
-
|
|
2618
|
-
// listen for incoming messages from wallet
|
|
2619
|
-
if ((_window$ue = window.ue) != null && _window$ue.sequencewallettransport) {
|
|
2620
|
-
window.ue.sequencewallettransport.onmessagefromwallet = this.onUnrealCallback;
|
|
2621
|
-
}
|
|
2622
|
-
registeredUnrealMessageProvider = this;
|
|
2623
|
-
this._registered = true;
|
|
2624
|
-
console.log('registering transport!');
|
|
2625
|
-
};
|
|
2626
|
-
this.unregister = () => {
|
|
2627
|
-
var _window$ue2, _window$ue2$sequencew;
|
|
2628
|
-
this._registered = false;
|
|
2629
|
-
this.closeWallet();
|
|
2630
|
-
|
|
2631
|
-
// disable message listener
|
|
2632
|
-
if (registeredUnrealMessageProvider === this) {
|
|
2633
|
-
registeredUnrealMessageProvider = undefined;
|
|
2634
|
-
}
|
|
2635
|
-
if (((_window$ue2 = window.ue) == null ? void 0 : (_window$ue2$sequencew = _window$ue2.sequencewallettransport) == null ? void 0 : _window$ue2$sequencew.onmessagefromwallet) === this.onUnrealCallback) {
|
|
2636
|
-
delete window.ue.sequencewallettransport.onmessagefromwallet;
|
|
2637
|
-
}
|
|
2638
|
-
|
|
2639
|
-
// clear event listeners
|
|
2640
|
-
this.events.removeAllListeners();
|
|
2641
|
-
};
|
|
2642
|
-
this.openWallet = (path, intent, networkId) => {
|
|
2643
|
-
if (this.isOpened()) {
|
|
2644
|
-
// TODO focus wallet
|
|
2645
|
-
console.log('wallet already open!');
|
|
2646
|
-
return;
|
|
2647
|
-
}
|
|
2648
|
-
console.log('opening wallet!');
|
|
2649
|
-
// Instantiate new walletURL for this call
|
|
2650
|
-
const walletURL = new URL(this.walletURL.href);
|
|
2651
|
-
const windowSessionParams = new WindowSessionParams();
|
|
2652
|
-
if (path) {
|
|
2653
|
-
walletURL.pathname = path.toLowerCase();
|
|
2654
|
-
}
|
|
2655
|
-
|
|
2656
|
-
// Set session, intent and network id on walletURL
|
|
2657
|
-
this._init = InitState.NIL;
|
|
2658
|
-
this._sessionId = `${performance.now()}`;
|
|
2659
|
-
windowSessionParams.set('sid', this._sessionId);
|
|
2660
|
-
if (intent) {
|
|
2661
|
-
// encode intent as base64 url-encoded param
|
|
2662
|
-
windowSessionParams.set('intent', utils.base64EncodeObject(intent));
|
|
2663
|
-
}
|
|
2664
|
-
if (networkId) {
|
|
2665
|
-
windowSessionParams.set('net', `${networkId}`);
|
|
2666
|
-
}
|
|
2667
|
-
// serialize params
|
|
2668
|
-
walletURL.search = windowSessionParams.toString();
|
|
2669
|
-
console.log('opening wallet to', walletURL.href);
|
|
2670
|
-
window.open(walletURL.href);
|
|
2671
|
-
};
|
|
2672
|
-
// onmessage, receives ProviderMessageResponse from the wallet unreal transport
|
|
2673
|
-
this.onUnrealCallback = message => {
|
|
2674
|
-
if (!message) {
|
|
2675
|
-
throw new Error('ProviderMessage object is empty');
|
|
2676
|
-
}
|
|
2677
|
-
|
|
2678
|
-
// handle message with base message provider
|
|
2679
|
-
this.handleMessage(message);
|
|
2680
|
-
};
|
|
2681
|
-
this.walletURL = new URL(walletAppURL);
|
|
2965
|
+
populateTransaction(_transaction) {
|
|
2966
|
+
throw new Error("SequenceSigner does not support populateTransaction");
|
|
2682
2967
|
}
|
|
2683
|
-
|
|
2684
|
-
|
|
2968
|
+
checkTransaction(_transaction) {
|
|
2969
|
+
throw new Error("SequenceSigner does not support checkTransaction");
|
|
2685
2970
|
}
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
console.log('Sending message to wallet:', postedMessage);
|
|
2691
|
-
(_window$ue3 = window.ue) == null ? void 0 : (_window$ue3$sequencew = _window$ue3.sequencewallettransport) == null ? void 0 : _window$ue3$sequencew.sendmessagetowallet(postedMessage);
|
|
2971
|
+
getTransactionCount(_blockTag) {
|
|
2972
|
+
// We could try returning the sequence nonce here
|
|
2973
|
+
// but we aren't sure how ethers will use this nonce
|
|
2974
|
+
throw new Error("SequenceSigner does not support getTransactionCount");
|
|
2692
2975
|
}
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
//
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
super(walletRequestHandler);
|
|
2703
|
-
// onmessage is called when (the wallet) receives request messages from the dapp
|
|
2704
|
-
// over the unreal json-messaging transport
|
|
2705
|
-
this.onMessageFromUnreal = request => {
|
|
2706
|
-
// Wallet always expects json-rpc request messages from a dapp
|
|
2707
|
-
|
|
2708
|
-
utils.logger.debug('RECEIVED MESSAGE', request);
|
|
2709
|
-
|
|
2710
|
-
// Handle message via the base transport
|
|
2711
|
-
this.handleMessage(request);
|
|
2712
|
-
};
|
|
2713
|
-
this.getUnrealTransportSession = windowParams => {
|
|
2714
|
-
const params = new WindowSessionParams(windowParams);
|
|
2715
|
-
return {
|
|
2716
|
-
sessionId: params.get('sid'),
|
|
2717
|
-
networkId: params.get('net'),
|
|
2718
|
-
intent: utils.base64DecodeObject(params.get('intent'))
|
|
2719
|
-
};
|
|
2720
|
-
};
|
|
2721
|
-
this._init = InitState.NIL;
|
|
2976
|
+
signTransaction(_transaction) {
|
|
2977
|
+
// We could implement signTransaction/sendTransaction here
|
|
2978
|
+
// but first we need a way of serializing these signed transactions
|
|
2979
|
+
// and it could lead to more trouble, because the dapp could try to send this transaction
|
|
2980
|
+
// using a different provider, which would fail.
|
|
2981
|
+
throw new Error("SequenceWallet does not support signTransaction, use sendTransaction instead.");
|
|
2982
|
+
}
|
|
2983
|
+
static is(cand) {
|
|
2984
|
+
return cand && typeof cand === "object" && cand._isSequenceSigner === true;
|
|
2722
2985
|
}
|
|
2723
|
-
|
|
2724
|
-
var _window$ue;
|
|
2725
|
-
if (((_window$ue = window.ue) == null ? void 0 : _window$ue.sequencewallettransport) === undefined) {
|
|
2726
|
-
return;
|
|
2727
|
-
}
|
|
2728
|
-
overrideLogs('wallet');
|
|
2729
|
-
|
|
2730
|
-
// record open details (sessionId + default network) from the window url
|
|
2731
|
-
const {
|
|
2732
|
-
search: rawParams
|
|
2733
|
-
} = new URL(windowHref || window.location.href);
|
|
2734
|
-
let session = this.getUnrealTransportSession(rawParams);
|
|
2986
|
+
}
|
|
2735
2987
|
|
|
2736
|
-
|
|
2737
|
-
|
|
2988
|
+
/**
|
|
2989
|
+
* This is the same provider, but it only allows a single network at a time.
|
|
2990
|
+
* the network defined by the constructor is the only one that can be used.
|
|
2991
|
+
*
|
|
2992
|
+
* Attempting to call any method with a different network will throw an error.
|
|
2993
|
+
* Attempting to change the network of this provider will throw an error.
|
|
2994
|
+
*
|
|
2995
|
+
* NOTICE: These networks won't support ENS unless they are the mainnet.
|
|
2996
|
+
*/
|
|
2997
|
+
class SingleNetworkSequenceSigner extends SequenceSigner {
|
|
2998
|
+
constructor(client, provider, chainId) {
|
|
2999
|
+
super(client, provider.getProvider(chainId));
|
|
3000
|
+
this._isSingleNetworkSequenceSigner = true;
|
|
3001
|
+
this.chainId = chainId;
|
|
3002
|
+
}
|
|
3003
|
+
_useChainId(chainId) {
|
|
3004
|
+
const provided = this.provider.toChainId(chainId);
|
|
3005
|
+
if (provided && provided !== this.chainId) {
|
|
3006
|
+
throw new Error(`This signer only supports the network ${this.chainId}, but ${provided} was requested.`);
|
|
3007
|
+
}
|
|
3008
|
+
return provided || this.provider.toChainId(this.chainId);
|
|
3009
|
+
}
|
|
3010
|
+
useChainId(chainId) {
|
|
3011
|
+
return this._useChainId(chainId);
|
|
3012
|
+
}
|
|
3013
|
+
getChainId() {
|
|
3014
|
+
return Promise.resolve(this.provider.toChainId(this.chainId));
|
|
3015
|
+
}
|
|
2738
3016
|
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
3017
|
+
/**
|
|
3018
|
+
* Override getProvider and getSigner so they always use `useChainId`
|
|
3019
|
+
* this way they can't return providers and signers that can switch networks,
|
|
3020
|
+
* or that don't match the chainId of this signer.
|
|
3021
|
+
*/
|
|
3022
|
+
getProvider(chainId) {
|
|
3023
|
+
return super.getProvider(this._useChainId(chainId));
|
|
3024
|
+
}
|
|
3025
|
+
getSigner(chainId) {
|
|
3026
|
+
if (this._useChainId(chainId) !== this.chainId) {
|
|
3027
|
+
throw new Error(`Unreachable code`);
|
|
2742
3028
|
}
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
3029
|
+
return this;
|
|
3030
|
+
}
|
|
3031
|
+
static is(cand) {
|
|
3032
|
+
return cand && typeof cand === "object" && cand._isSingleNetworkSequenceSigner === true;
|
|
3033
|
+
}
|
|
3034
|
+
}
|
|
3035
|
+
|
|
3036
|
+
/**
|
|
3037
|
+
* This class is redundant with the SequenceSigner class, but it is here for now to
|
|
3038
|
+
* maintain compatibility with the old wallet API. Eventually we should move these
|
|
3039
|
+
* methods to the SequenceSigner class and deprecate this class.
|
|
3040
|
+
*/
|
|
3041
|
+
class WalletUtils {
|
|
3042
|
+
constructor(signer) {
|
|
3043
|
+
this.signer = signer;
|
|
3044
|
+
if (SingleNetworkSequenceSigner.is(signer)) {
|
|
3045
|
+
throw new Error('WalletUtils does not support SingleNetworkSequenceSigner');
|
|
2746
3046
|
}
|
|
3047
|
+
}
|
|
2747
3048
|
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
this.
|
|
3049
|
+
// Sign message on a specified chain, or DefaultChain by default
|
|
3050
|
+
signMessage(message, chainId, eip6492) {
|
|
3051
|
+
return this.signer.signMessage(message, {
|
|
3052
|
+
chainId,
|
|
3053
|
+
eip6492
|
|
3054
|
+
});
|
|
3055
|
+
}
|
|
2751
3056
|
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
utils.logger.error(err);
|
|
2758
|
-
this.notifyClose({
|
|
2759
|
-
message: err
|
|
2760
|
-
});
|
|
2761
|
-
window.close();
|
|
2762
|
-
}
|
|
2763
|
-
}).catch(e => {
|
|
2764
|
-
var _session2;
|
|
2765
|
-
const err = `failed to open to network ${(_session2 = session) == null ? void 0 : _session2.networkId}, due to: ${e}`;
|
|
2766
|
-
utils.logger.error(err);
|
|
2767
|
-
this.notifyClose({
|
|
2768
|
-
message: err
|
|
2769
|
-
});
|
|
2770
|
-
window.close();
|
|
3057
|
+
// Sign EIP-712 TypedData on a specified chain, or DefaultChain by default
|
|
3058
|
+
signTypedData(domain, types, message, chainId, eip6492) {
|
|
3059
|
+
return this.signer.signTypedData(domain, types, message, {
|
|
3060
|
+
chainId,
|
|
3061
|
+
eip6492
|
|
2771
3062
|
});
|
|
2772
3063
|
}
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
}
|
|
2778
|
-
this._registered = false;
|
|
3064
|
+
|
|
3065
|
+
// Verify signature of a digest, one of a message, typedData or other
|
|
3066
|
+
async isValidSignature(address, digest, signature, chainId) {
|
|
3067
|
+
return isValidSignature(address, digest, signature, this.signer.getProvider(chainId));
|
|
2779
3068
|
}
|
|
2780
|
-
// sendMessage sends message to the dapp window
|
|
2781
|
-
sendMessage(message) {
|
|
2782
|
-
var _window$ue3, _window$ue3$sequencew;
|
|
2783
|
-
if (message.type !== EventType.INIT && this._init !== InitState.OK) {
|
|
2784
|
-
utils.logger.error('impossible state, should not be calling postMessage until inited');
|
|
2785
|
-
return;
|
|
2786
|
-
}
|
|
2787
|
-
// prepare payload
|
|
2788
|
-
const payload = JSON.stringify(message);
|
|
2789
3069
|
|
|
2790
|
-
|
|
2791
|
-
|
|
3070
|
+
// Verify message signature
|
|
3071
|
+
async isValidMessageSignature(address, message, signature, chainId) {
|
|
3072
|
+
const provider = this.signer.getProvider(chainId);
|
|
3073
|
+
const prefixed = prefixEIP191Message(message);
|
|
3074
|
+
const digest = utils.encodeMessageDigest(prefixed);
|
|
3075
|
+
return isValidSignature(address, digest, signature, provider);
|
|
2792
3076
|
}
|
|
2793
|
-
}
|
|
2794
3077
|
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
return
|
|
3078
|
+
// Verify typedData signature
|
|
3079
|
+
isValidTypedDataSignature(address, typedData, signature, chainId) {
|
|
3080
|
+
return this.isValidSignature(address, utils.encodeTypedDataDigest(typedData), signature, chainId);
|
|
2798
3081
|
}
|
|
2799
3082
|
|
|
2800
|
-
//
|
|
2801
|
-
//
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
3083
|
+
// sendTransaction()
|
|
3084
|
+
// sendTransactions()
|
|
3085
|
+
|
|
3086
|
+
// sendETH()
|
|
3087
|
+
// sendToken()
|
|
3088
|
+
// sendCoin() -- sugar for sendToken()
|
|
3089
|
+
// sendCollectible() -- sugar for sendToken()
|
|
3090
|
+
// callContract()
|
|
3091
|
+
|
|
3092
|
+
// transactionHistory()
|
|
3093
|
+
// getReceipt()
|
|
3094
|
+
// getLogs()
|
|
3095
|
+
// // ..
|
|
3096
|
+
|
|
3097
|
+
// validateSignature()
|
|
3098
|
+
// recoverWalletConfig()
|
|
3099
|
+
// recoverAddress()
|
|
3100
|
+
}
|
|
3101
|
+
|
|
3102
|
+
class SequenceProvider extends ethers.ethers.providers.BaseProvider {
|
|
3103
|
+
constructor(client, providerFor, networks = network.allNetworks) {
|
|
3104
|
+
// We support a lot of networks
|
|
3105
|
+
// but we start with the default one
|
|
3106
|
+
super(client.getChainId());
|
|
3107
|
+
|
|
3108
|
+
// Emit events as defined by EIP-1193
|
|
3109
|
+
this.singleNetworkProviders = {};
|
|
2807
3110
|
this._isSequenceProvider = true;
|
|
2808
|
-
this.
|
|
3111
|
+
this.client = client;
|
|
3112
|
+
this.providerFor = providerFor;
|
|
3113
|
+
this.networks = networks;
|
|
3114
|
+
client.onConnect(details => {
|
|
3115
|
+
this.emit('connect', details);
|
|
3116
|
+
});
|
|
3117
|
+
client.onDisconnect(error => {
|
|
3118
|
+
this.emit('disconnect', error);
|
|
3119
|
+
});
|
|
3120
|
+
client.onDefaultChainIdChanged(chainId => {
|
|
3121
|
+
this.emit('chainChanged', chainId);
|
|
3122
|
+
});
|
|
3123
|
+
client.onAccountsChanged(accounts => {
|
|
3124
|
+
this.emit('accountsChanged', accounts);
|
|
3125
|
+
});
|
|
3126
|
+
|
|
3127
|
+
// NOTICE: We don't emit 'open' and 'close' events
|
|
3128
|
+
// because these are handled by the library, and they
|
|
3129
|
+
// are not part of EIP-1193
|
|
3130
|
+
|
|
3131
|
+
// devs can still access them using
|
|
3132
|
+
// client.onOpen()
|
|
3133
|
+
// client.onClose()
|
|
3134
|
+
|
|
3135
|
+
// Create a Sequence signer too
|
|
3136
|
+
this.signer = new SequenceSigner(this.client, this);
|
|
3137
|
+
|
|
3138
|
+
// Create a utils instance
|
|
3139
|
+
this.utils = new WalletUtils(this.signer);
|
|
2809
3140
|
}
|
|
2810
|
-
|
|
2811
|
-
this.
|
|
3141
|
+
getSigner(chainId) {
|
|
3142
|
+
return this.signer.getSigner(chainId);
|
|
2812
3143
|
}
|
|
2813
|
-
|
|
2814
|
-
return this.
|
|
3144
|
+
connect(options) {
|
|
3145
|
+
return this.client.connect(options);
|
|
2815
3146
|
}
|
|
2816
|
-
|
|
2817
|
-
return this.
|
|
3147
|
+
disconnect() {
|
|
3148
|
+
return this.client.disconnect();
|
|
2818
3149
|
}
|
|
2819
|
-
|
|
2820
|
-
return
|
|
3150
|
+
isConnected() {
|
|
3151
|
+
return this.client.isConnected();
|
|
3152
|
+
}
|
|
3153
|
+
getSession() {
|
|
3154
|
+
return this.client.getSession();
|
|
3155
|
+
}
|
|
3156
|
+
listAccounts() {
|
|
3157
|
+
return [this.client.getAddress()];
|
|
2821
3158
|
}
|
|
2822
|
-
async getChainId() {
|
|
2823
|
-
// If we already have a default chainId, then we can just return it
|
|
2824
|
-
const defaultChainId = this._defaultChainId;
|
|
2825
|
-
if (defaultChainId) return defaultChainId;
|
|
2826
3159
|
|
|
2827
|
-
|
|
2828
|
-
|
|
3160
|
+
// @deprecated use getSigner() instead
|
|
3161
|
+
getAddress() {
|
|
3162
|
+
return this.client.getAddress();
|
|
2829
3163
|
}
|
|
2830
3164
|
getNetworks() {
|
|
2831
|
-
return this.
|
|
3165
|
+
return this.client.getNetworks();
|
|
2832
3166
|
}
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
const cand = provider;
|
|
2836
|
-
return cand && cand.send !== undefined && cand._isSequenceProvider === true;
|
|
2837
|
-
}
|
|
2838
|
-
class LocalWeb3Provider extends Web3Provider {
|
|
2839
|
-
constructor(account, networks) {
|
|
2840
|
-
const walletRequestHandler = new WalletRequestHandler(account, null, networks || []);
|
|
2841
|
-
super(walletRequestHandler);
|
|
3167
|
+
getChainId() {
|
|
3168
|
+
return this.client.getChainId();
|
|
2842
3169
|
}
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
this.
|
|
2851
|
-
|
|
2852
|
-
|
|
3170
|
+
setDefaultChainId(chainId) {
|
|
3171
|
+
return this.client.setDefaultChainId(this.toChainId(chainId));
|
|
3172
|
+
}
|
|
3173
|
+
isOpened() {
|
|
3174
|
+
return this.client.isOpened();
|
|
3175
|
+
}
|
|
3176
|
+
closeWallet() {
|
|
3177
|
+
return this.client.closeWallet();
|
|
3178
|
+
}
|
|
3179
|
+
getWalletContext() {
|
|
3180
|
+
return this.client.getWalletContext();
|
|
2853
3181
|
}
|
|
2854
3182
|
|
|
2855
|
-
//
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
if (this._address) return this._address;
|
|
2862
|
-
const accounts = await this.provider.send('eth_accounts', []);
|
|
2863
|
-
this._address = accounts[0];
|
|
2864
|
-
this._index = 0;
|
|
2865
|
-
return ethers.ethers.utils.getAddress(this._address);
|
|
3183
|
+
// @deprecated use getSigner() instead
|
|
3184
|
+
async getWalletConfig(chainId) {
|
|
3185
|
+
const useChainId = await this.useChainId(chainId);
|
|
3186
|
+
return this.client.getOnchainWalletConfig({
|
|
3187
|
+
chainId: useChainId
|
|
3188
|
+
});
|
|
2866
3189
|
}
|
|
2867
|
-
|
|
2868
|
-
//
|
|
2869
|
-
|
|
3190
|
+
authorize(options) {
|
|
3191
|
+
// Just an alias for connect with authorize: true
|
|
3192
|
+
return this.client.connect(_extends({}, options, {
|
|
3193
|
+
authorize: true
|
|
3194
|
+
}));
|
|
2870
3195
|
}
|
|
2871
|
-
|
|
2872
|
-
|
|
3196
|
+
async openWallet(path, intent) {
|
|
3197
|
+
await this.client.openWallet(path, intent);
|
|
3198
|
+
return true;
|
|
3199
|
+
}
|
|
3200
|
+
toChainId(chainId) {
|
|
3201
|
+
if (chainId === undefined) {
|
|
3202
|
+
return undefined;
|
|
3203
|
+
}
|
|
3204
|
+
const resolved = network.findNetworkConfig(this.networks, chainId);
|
|
3205
|
+
if (!resolved) {
|
|
3206
|
+
throw new Error(`Unsupported network ${chainId}`);
|
|
3207
|
+
}
|
|
3208
|
+
return resolved.chainId;
|
|
2873
3209
|
}
|
|
2874
3210
|
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
3211
|
+
/**
|
|
3212
|
+
* Resolves the chainId to use for the given request. If no chainId is provided,
|
|
3213
|
+
* it uses the chainId defined by the client (default chainId). This can be
|
|
3214
|
+
* overriden to build a single-network SequenceProvider.
|
|
3215
|
+
*/
|
|
3216
|
+
async useChainId(chainId) {
|
|
3217
|
+
return this.toChainId(chainId) || this.client.getChainId();
|
|
3218
|
+
}
|
|
2878
3219
|
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
3220
|
+
/**
|
|
3221
|
+
* This generates a provider that ONLY works for the given chainId.
|
|
3222
|
+
* the generated provider can't switch networks, and can't handle requests
|
|
3223
|
+
* for other networks.
|
|
3224
|
+
*/
|
|
3225
|
+
|
|
3226
|
+
getProvider(chainId) {
|
|
3227
|
+
// The provider without a chainId is... this one
|
|
3228
|
+
if (!chainId) {
|
|
3229
|
+
return this;
|
|
2888
3230
|
}
|
|
2889
|
-
|
|
3231
|
+
const useChainId = this.toChainId(chainId);
|
|
3232
|
+
if (!this.singleNetworkProviders[useChainId]) {
|
|
3233
|
+
this.singleNetworkProviders[useChainId] = new SingleNetworkSequenceProvider(this.client, this.providerFor, useChainId);
|
|
3234
|
+
}
|
|
3235
|
+
return this.singleNetworkProviders[useChainId];
|
|
2890
3236
|
}
|
|
2891
3237
|
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
this._providers[chainId] = new Web3Provider(new network.JsonRpcSender(this.provider, chainId), chainId);
|
|
3238
|
+
/**
|
|
3239
|
+
* This returns a subprovider, this is a regular non-sequence provider that
|
|
3240
|
+
* can be used to fulfill read only requests on a given network.
|
|
3241
|
+
*/
|
|
3242
|
+
async _getSubprovider(chainId) {
|
|
3243
|
+
const useChainId = await this.useChainId(chainId);
|
|
3244
|
+
|
|
3245
|
+
// Whoever implements providerFrom should memoize the generated provider
|
|
3246
|
+
// otherwise every instance of SequenceProvider will create a new subprovider
|
|
3247
|
+
const provider = this.providerFor(useChainId);
|
|
3248
|
+
if (!provider) {
|
|
3249
|
+
throw new Error(`Unsupported network ${useChainId}`);
|
|
2905
3250
|
}
|
|
2906
|
-
return
|
|
3251
|
+
return provider;
|
|
2907
3252
|
}
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
//
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
3253
|
+
async perform(method, params) {
|
|
3254
|
+
var _provider$prepareRequ;
|
|
3255
|
+
// First we check if the method should be handled by the client
|
|
3256
|
+
if (method === 'eth_chainId') {
|
|
3257
|
+
return this.useChainId();
|
|
3258
|
+
}
|
|
3259
|
+
if (method === 'eth_accounts') {
|
|
3260
|
+
return [this.client.getAddress()];
|
|
3261
|
+
}
|
|
3262
|
+
if (method === 'wallet_switchEthereumChain') {
|
|
3263
|
+
const args = params[0];
|
|
3264
|
+
const chainId = normalizeChainId(args);
|
|
3265
|
+
return this.setDefaultChainId(chainId);
|
|
3266
|
+
}
|
|
3267
|
+
|
|
3268
|
+
// Usually these methods aren't used by calling the provider
|
|
3269
|
+
// but to maximize compatibility we support them too.
|
|
3270
|
+
// The correct way of accessing these methods is by using .getSigner()
|
|
3271
|
+
if (method === 'eth_sendTransaction' || method === 'eth_sign' || method === 'eth_signTypedData' || method === 'eth_signTypedData_v4' || method === 'personal_sign' ||
|
|
3272
|
+
// These methods will use EIP-6492
|
|
3273
|
+
// but this is handled directly by the wallet
|
|
3274
|
+
method === 'sequence_sign' || method === 'sequence_signTypedData_v4') {
|
|
3275
|
+
// We pass the chainId to the client, if we don't pass one
|
|
3276
|
+
// the client will use its own default chainId
|
|
3277
|
+
return this.client.send({
|
|
3278
|
+
method,
|
|
3279
|
+
params
|
|
3280
|
+
}, this.getChainId());
|
|
3281
|
+
}
|
|
3282
|
+
|
|
3283
|
+
// Forward call to the corresponding provider
|
|
3284
|
+
// we use the provided chainId, or the default one provided by the client
|
|
3285
|
+
const provider = await this._getSubprovider();
|
|
3286
|
+
const prepared = (_provider$prepareRequ = provider.prepareRequest(method, params)) != null ? _provider$prepareRequ : [method, params];
|
|
3287
|
+
return provider.send(prepared[0], prepared[1]);
|
|
3288
|
+
}
|
|
3289
|
+
send(method, params) {
|
|
3290
|
+
return this.perform(method, params);
|
|
2914
3291
|
}
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
3292
|
+
request(request) {
|
|
3293
|
+
return this.perform(request.method, request.params);
|
|
3294
|
+
}
|
|
3295
|
+
async detectNetwork() {
|
|
3296
|
+
const chainId = this.client.getChainId();
|
|
3297
|
+
const network$1 = network.findNetworkConfig(this.networks, chainId);
|
|
3298
|
+
if (!network$1) {
|
|
3299
|
+
throw new Error(`Unknown network ${chainId}`);
|
|
2918
3300
|
}
|
|
2919
|
-
return
|
|
3301
|
+
return network$1;
|
|
2920
3302
|
}
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
3303
|
+
|
|
3304
|
+
// Override most of the methods, so we add support for an optional chainId
|
|
3305
|
+
// argument, which is used to select the provider to use.
|
|
3306
|
+
//
|
|
3307
|
+
// NOTICE: We could use generics to avoid repeating the same code
|
|
3308
|
+
// but this would make the code harder to read, and it's not worth it
|
|
3309
|
+
// since we only have a few methods to override.
|
|
3310
|
+
|
|
3311
|
+
async waitForTransaction(transactionHash, confirmations, timeout, optionals) {
|
|
3312
|
+
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3313
|
+
return provider.waitForTransaction(transactionHash, confirmations, timeout);
|
|
2925
3314
|
}
|
|
2926
|
-
async
|
|
2927
|
-
const
|
|
2928
|
-
|
|
2929
|
-
return (await this.provider.send('sequence_getWalletState', [reqChainId], reqChainId))[0].status;
|
|
3315
|
+
async getBlockNumber(optionals) {
|
|
3316
|
+
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3317
|
+
return provider.getBlockNumber();
|
|
2930
3318
|
}
|
|
2931
|
-
async
|
|
2932
|
-
|
|
2933
|
-
return
|
|
3319
|
+
async getGasPrice(optionals) {
|
|
3320
|
+
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3321
|
+
return provider.getGasPrice();
|
|
2934
3322
|
}
|
|
2935
|
-
async
|
|
2936
|
-
const
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
3323
|
+
async getBalance(addressOrName, blockTag, optionals) {
|
|
3324
|
+
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3325
|
+
return provider.getBalance(addressOrName, blockTag);
|
|
3326
|
+
}
|
|
3327
|
+
async getTransactionCount(addressOrName, blockTag, optionals) {
|
|
3328
|
+
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3329
|
+
return provider.getTransactionCount(addressOrName, blockTag);
|
|
3330
|
+
}
|
|
3331
|
+
async getCode(addressOrName, blockTag, optionals) {
|
|
3332
|
+
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3333
|
+
return provider.getCode(addressOrName, blockTag);
|
|
3334
|
+
}
|
|
3335
|
+
async getStorageAt(addressOrName, position, blockTag, optionals) {
|
|
3336
|
+
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3337
|
+
return provider.getStorageAt(addressOrName, position, blockTag);
|
|
3338
|
+
}
|
|
3339
|
+
async call(transaction, blockTag, optionals) {
|
|
3340
|
+
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3341
|
+
return provider.call(transaction, blockTag);
|
|
3342
|
+
}
|
|
3343
|
+
async estimateGas(transaction, optionals) {
|
|
3344
|
+
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3345
|
+
return provider.estimateGas(transaction);
|
|
3346
|
+
}
|
|
3347
|
+
async getBlock(blockHashOrBlockTag, optionals) {
|
|
3348
|
+
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3349
|
+
return provider.getBlock(blockHashOrBlockTag);
|
|
3350
|
+
}
|
|
3351
|
+
async getTransaction(transactionHash, optionals) {
|
|
3352
|
+
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3353
|
+
return provider.getTransaction(transactionHash);
|
|
3354
|
+
}
|
|
3355
|
+
async getLogs(filter, optionals) {
|
|
3356
|
+
const provider = await this._getSubprovider(optionals == null ? void 0 : optionals.chainId);
|
|
3357
|
+
return provider.getLogs(filter);
|
|
2944
3358
|
}
|
|
2945
3359
|
|
|
2946
|
-
//
|
|
2947
|
-
// multi-chain support.
|
|
2948
|
-
async signMessage(message, chainId, sequenceVerified = true) {
|
|
2949
|
-
const provider = await this.getSender(network.maybeChainId(chainId) || this.defaultChainId);
|
|
2950
|
-
const data = typeof message === 'string' ? ethers.ethers.utils.toUtf8Bytes(message) : message;
|
|
2951
|
-
const address = await this.getAddress();
|
|
3360
|
+
// ENS methods
|
|
2952
3361
|
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
return provider.send(sequenceVerified ? 'sequence_sign' : 'personal_sign', [ethers.ethers.utils.hexlify(data), address]);
|
|
3362
|
+
async supportsENS() {
|
|
3363
|
+
const networks = await this.getNetworks();
|
|
3364
|
+
return networks.some(n => n.chainId === 1);
|
|
2957
3365
|
}
|
|
3366
|
+
async getResolver(name) {
|
|
3367
|
+
if (!(await this.supportsENS())) {
|
|
3368
|
+
return null;
|
|
3369
|
+
}
|
|
2958
3370
|
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
3371
|
+
// Resolver is always on the chainId 1
|
|
3372
|
+
const provider = await this._getSubprovider(1);
|
|
3373
|
+
return provider.getResolver(name);
|
|
3374
|
+
}
|
|
3375
|
+
async resolveName(name) {
|
|
3376
|
+
if (ethers.ethers.utils.isAddress(await name)) {
|
|
3377
|
+
return name;
|
|
3378
|
+
}
|
|
3379
|
+
if (!(await this.supportsENS())) {
|
|
3380
|
+
return null;
|
|
3381
|
+
}
|
|
2966
3382
|
|
|
2967
|
-
|
|
3383
|
+
// Resolver is always on the chainId 1
|
|
3384
|
+
const provider = await this._getSubprovider(1);
|
|
3385
|
+
return provider.resolveName(name);
|
|
2968
3386
|
}
|
|
3387
|
+
async lookupAddress(address) {
|
|
3388
|
+
if (!(await this.supportsENS())) {
|
|
3389
|
+
return null;
|
|
3390
|
+
}
|
|
2969
3391
|
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
3392
|
+
// Resolver is always on the chainId 1
|
|
3393
|
+
const provider = await this._getSubprovider(1);
|
|
3394
|
+
return provider.lookupAddress(address);
|
|
3395
|
+
}
|
|
3396
|
+
async getAvatar(nameOrAddress) {
|
|
3397
|
+
if (!(await this.supportsENS())) {
|
|
3398
|
+
return null;
|
|
3399
|
+
}
|
|
3400
|
+
const provider = await this._getSubprovider(1);
|
|
3401
|
+
return provider.getAvatar(nameOrAddress);
|
|
3402
|
+
}
|
|
3403
|
+
}
|
|
3404
|
+
SequenceProvider.is = provider => {
|
|
3405
|
+
return provider && typeof provider === 'object' && provider._isSequenceProvider === true;
|
|
3406
|
+
};
|
|
3407
|
+
function normalizeChainId(chainId) {
|
|
3408
|
+
if (typeof chainId === 'object') return normalizeChainId(chainId.chainId);
|
|
3409
|
+
return ethers.ethers.BigNumber.from(chainId).toNumber();
|
|
3410
|
+
}
|
|
2989
3411
|
|
|
2990
|
-
|
|
2991
|
-
|
|
3412
|
+
/**
|
|
3413
|
+
* This is the same provider, but it only allows a single network at a time.
|
|
3414
|
+
* the network defined by the constructor is the only one that can be used.
|
|
3415
|
+
*
|
|
3416
|
+
* Attempting to call any method with a different network will throw an error.
|
|
3417
|
+
* Attempting to change the network of this provider will throw an error.
|
|
3418
|
+
*
|
|
3419
|
+
* NOTICE: These networks won't support ENS unless they are the mainnet.
|
|
3420
|
+
*/
|
|
3421
|
+
class SingleNetworkSequenceProvider extends SequenceProvider {
|
|
3422
|
+
constructor(client, providerFor, chainId) {
|
|
3423
|
+
super(client, providerFor);
|
|
3424
|
+
this._isSingleNetworkSequenceProvider = true;
|
|
3425
|
+
this.chainId = chainId;
|
|
3426
|
+
}
|
|
3427
|
+
_useChainId(chainId) {
|
|
3428
|
+
const provided = this.toChainId(chainId);
|
|
3429
|
+
if (provided && provided !== this.chainId) {
|
|
3430
|
+
throw new Error(`This provider only supports the network ${this.chainId}, but ${provided} was requested.`);
|
|
3431
|
+
}
|
|
3432
|
+
return provided || super.toChainId(this.chainId);
|
|
3433
|
+
}
|
|
3434
|
+
useChainId(chainId) {
|
|
3435
|
+
return Promise.resolve(this._useChainId(chainId));
|
|
3436
|
+
}
|
|
3437
|
+
getChainId() {
|
|
3438
|
+
return super.toChainId(this.chainId);
|
|
3439
|
+
}
|
|
3440
|
+
async getNetwork() {
|
|
3441
|
+
const networks = await this.client.getNetworks();
|
|
3442
|
+
const res = network.findNetworkConfig(networks, this.chainId);
|
|
3443
|
+
if (!res) {
|
|
3444
|
+
throw new Error(`Unsupported network ${this.chainId}`);
|
|
3445
|
+
}
|
|
3446
|
+
return res;
|
|
2992
3447
|
}
|
|
2993
3448
|
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3449
|
+
/**
|
|
3450
|
+
* Override getProvider and getSigner so they always use `useChainId`
|
|
3451
|
+
* this way they can't return providers and signers that can switch networks,
|
|
3452
|
+
* or that don't match the chainId of this signer.
|
|
3453
|
+
*/
|
|
3454
|
+
getProvider(chainId) {
|
|
3455
|
+
if (this._useChainId(chainId) !== this.chainId) {
|
|
3456
|
+
throw new Error(`Unreachable code`);
|
|
3000
3457
|
}
|
|
3458
|
+
return this;
|
|
3459
|
+
}
|
|
3460
|
+
getSigner(chainId) {
|
|
3461
|
+
return super.getSigner(this._useChainId(chainId));
|
|
3462
|
+
}
|
|
3463
|
+
setDefaultChainId(_chainId) {
|
|
3464
|
+
throw new Error(`This provider only supports the network ${this.chainId}; use the parent provider to switch networks.`);
|
|
3465
|
+
}
|
|
3466
|
+
static is(cand) {
|
|
3467
|
+
return cand && typeof cand === 'object' && cand._isSingleNetworkSequenceProvider === true;
|
|
3468
|
+
}
|
|
3469
|
+
}
|
|
3001
3470
|
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3471
|
+
/**
|
|
3472
|
+
* This session class is meant to persist the state of the wallet connection
|
|
3473
|
+
* whitin the dapp. This enables the client to retain the wallet address (and some more)
|
|
3474
|
+
* even if the user refreshes the page. Otherwise we would have to open the popup again.
|
|
3475
|
+
*/
|
|
3476
|
+
class SequenceClientSession {
|
|
3477
|
+
constructor(store) {
|
|
3478
|
+
this.store = store;
|
|
3479
|
+
}
|
|
3480
|
+
connectedSession() {
|
|
3481
|
+
const session = this.getSession();
|
|
3482
|
+
if (session && session.accountAddress && session.walletContext && session.networks) {
|
|
3483
|
+
return {
|
|
3484
|
+
accountAddress: session.accountAddress,
|
|
3485
|
+
walletContext: session.walletContext,
|
|
3486
|
+
networks: session.networks
|
|
3487
|
+
};
|
|
3488
|
+
}
|
|
3489
|
+
throw new Error('Sequence session not connected');
|
|
3490
|
+
}
|
|
3491
|
+
hasSession() {
|
|
3492
|
+
var _this$getSession;
|
|
3493
|
+
return ((_this$getSession = this.getSession()) == null ? void 0 : _this$getSession.accountAddress) !== undefined;
|
|
3494
|
+
}
|
|
3495
|
+
setSession(session) {
|
|
3496
|
+
return this.store.setItem(SequenceClientSession.SESSION_LOCALSTORE_KEY, JSON.stringify(session));
|
|
3497
|
+
}
|
|
3498
|
+
getSession() {
|
|
3499
|
+
const session = this.store.getItem(SequenceClientSession.SESSION_LOCALSTORE_KEY);
|
|
3500
|
+
if (session) {
|
|
3501
|
+
return JSON.parse(session);
|
|
3005
3502
|
}
|
|
3006
|
-
|
|
3007
|
-
|
|
3503
|
+
return undefined;
|
|
3504
|
+
}
|
|
3505
|
+
async clearSession() {
|
|
3506
|
+
return this.store.removeItem(SequenceClientSession.SESSION_LOCALSTORE_KEY);
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
|
|
3510
|
+
/**
|
|
3511
|
+
* The wallet webapp doesn't really care what's the "default chain" for the user.
|
|
3512
|
+
* so we don't even bother to send this information to the wallet. Instead, we
|
|
3513
|
+
* track it locally using storage, that way the data stays always in sync.
|
|
3514
|
+
*/
|
|
3515
|
+
SequenceClientSession.SESSION_LOCALSTORE_KEY = '@sequence.session';
|
|
3516
|
+
class DefaultChainIdTracker {
|
|
3517
|
+
constructor(store, startingChainId = 1) {
|
|
3518
|
+
this.callbacks = [];
|
|
3519
|
+
this.store = store;
|
|
3520
|
+
this.startingChainId = startingChainId;
|
|
3521
|
+
store.onItemChange(DefaultChainIdTracker.SESSION_CHAIN_ID_KEY, value => {
|
|
3522
|
+
if (value) {
|
|
3523
|
+
const chainId = parseInt(value);
|
|
3524
|
+
this.callbacks.forEach(cb => cb(chainId));
|
|
3525
|
+
}
|
|
3526
|
+
});
|
|
3527
|
+
}
|
|
3528
|
+
onDefaultChainIdChanged(callback) {
|
|
3529
|
+
this.callbacks.push(callback);
|
|
3530
|
+
return () => {
|
|
3531
|
+
this.callbacks = this.callbacks.filter(cb => cb !== callback);
|
|
3532
|
+
};
|
|
3008
3533
|
}
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
return this.provider.send('eth_signTransaction', [transaction], network.maybeChainId(chainId) || this.defaultChainId);
|
|
3534
|
+
setDefaultChainId(chainId) {
|
|
3535
|
+
if (chainId !== this.getDefaultChainId()) {
|
|
3536
|
+
this.store.setItem(DefaultChainIdTracker.SESSION_CHAIN_ID_KEY, chainId.toString());
|
|
3537
|
+
}
|
|
3014
3538
|
}
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3539
|
+
getDefaultChainId() {
|
|
3540
|
+
const read = this.store.getItem(DefaultChainIdTracker.SESSION_CHAIN_ID_KEY);
|
|
3541
|
+
if (!read || read.length === 0) {
|
|
3542
|
+
return this.startingChainId;
|
|
3543
|
+
}
|
|
3544
|
+
return parseInt(read);
|
|
3018
3545
|
}
|
|
3546
|
+
}
|
|
3547
|
+
|
|
3548
|
+
/**
|
|
3549
|
+
* This is a wallet client for sequence wallet-webapp. It connects using *some* transport
|
|
3550
|
+
* and it allows to perform all sequence specific (or write) operations related to the wallet.
|
|
3551
|
+
*
|
|
3552
|
+
* It doesn't implement a full ethereum Provider, it doesn't include read-only methods.
|
|
3553
|
+
*/
|
|
3554
|
+
DefaultChainIdTracker.SESSION_CHAIN_ID_KEY = '@sequence.session.defaultChainId';
|
|
3555
|
+
class SequenceClient {
|
|
3556
|
+
constructor(transport, store, defaultChainId) {
|
|
3557
|
+
this.callbacks = {};
|
|
3558
|
+
if (isMuxTransportTemplate(transport)) {
|
|
3559
|
+
this.transport = MuxMessageProvider.new(transport);
|
|
3560
|
+
} else if (isProviderTransport(transport)) {
|
|
3561
|
+
this.transport = transport;
|
|
3562
|
+
} else {
|
|
3563
|
+
throw new Error('Invalid transport');
|
|
3564
|
+
}
|
|
3565
|
+
this.session = new SequenceClientSession(store);
|
|
3566
|
+
this.defaultChainId = new DefaultChainIdTracker(store, defaultChainId);
|
|
3567
|
+
this.transport.on('accountsChanged', accounts => {
|
|
3568
|
+
var _this$callbacks$accou;
|
|
3569
|
+
if (accounts.length > 1) {
|
|
3570
|
+
console.warn('SequenceClient: wallet-webapp returned more than one account');
|
|
3571
|
+
}
|
|
3572
|
+
(_this$callbacks$accou = this.callbacks.accountsChanged) == null ? void 0 : _this$callbacks$accou.forEach(cb => cb(accounts));
|
|
3573
|
+
});
|
|
3574
|
+
this.transport.on('connect', response => {
|
|
3575
|
+
var _this$callbacks$conne;
|
|
3576
|
+
const chainIdHex = ethers.ethers.BigNumber.from(this.getChainId()).toHexString();
|
|
3577
|
+
(_this$callbacks$conne = this.callbacks.connect) == null ? void 0 : _this$callbacks$conne.forEach(cb => cb(_extends({}, response, {
|
|
3578
|
+
// Ignore the full connect response
|
|
3579
|
+
// use the chainId defined locally
|
|
3580
|
+
chainId: chainIdHex
|
|
3581
|
+
})));
|
|
3582
|
+
});
|
|
3583
|
+
this.transport.on('disconnect', error => {
|
|
3584
|
+
var _this$callbacks$disco;
|
|
3585
|
+
(_this$callbacks$disco = this.callbacks.disconnect) == null ? void 0 : _this$callbacks$disco.forEach(cb => cb(error));
|
|
3586
|
+
});
|
|
3587
|
+
this.transport.on('networks', networks => {
|
|
3588
|
+
var _this$callbacks$netwo;
|
|
3589
|
+
(_this$callbacks$netwo = this.callbacks.networks) == null ? void 0 : _this$callbacks$netwo.forEach(cb => cb(networks));
|
|
3590
|
+
});
|
|
3591
|
+
this.transport.on('walletContext', context => {
|
|
3592
|
+
var _this$callbacks$walle;
|
|
3593
|
+
(_this$callbacks$walle = this.callbacks.walletContext) == null ? void 0 : _this$callbacks$walle.forEach(cb => cb(context));
|
|
3594
|
+
});
|
|
3595
|
+
this.transport.on('open', info => {
|
|
3596
|
+
var _this$callbacks$open;
|
|
3597
|
+
(_this$callbacks$open = this.callbacks.open) == null ? void 0 : _this$callbacks$open.forEach(cb => cb(info));
|
|
3598
|
+
});
|
|
3599
|
+
this.transport.on('close', () => {
|
|
3600
|
+
var _this$callbacks$close;
|
|
3601
|
+
(_this$callbacks$close = this.callbacks.close) == null ? void 0 : _this$callbacks$close.forEach(cb => cb());
|
|
3602
|
+
});
|
|
3019
3603
|
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
}
|
|
3028
|
-
const provider = await this.getSender(this.defaultChainId);
|
|
3029
|
-
return [config, provider._wrapTransaction(tx, tx.hash)];
|
|
3604
|
+
// We don't listen for the transport chainChanged event
|
|
3605
|
+
// instead we handle it locally, so we listen for changes in the store
|
|
3606
|
+
this.defaultChainId.onDefaultChainIdChanged(chainId => {
|
|
3607
|
+
var _this$callbacks$chain;
|
|
3608
|
+
const chainIdHex = ethers.ethers.BigNumber.from(chainId).toHexString();
|
|
3609
|
+
(_this$callbacks$chain = this.callbacks.chainChanged) == null ? void 0 : _this$callbacks$chain.forEach(cb => cb(chainIdHex));
|
|
3610
|
+
});
|
|
3030
3611
|
}
|
|
3031
3612
|
|
|
3032
|
-
//
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
if (tx === null) {
|
|
3038
|
-
return undefined;
|
|
3613
|
+
// Callbacks
|
|
3614
|
+
|
|
3615
|
+
registerCallback(eventName, callback) {
|
|
3616
|
+
if (!this.callbacks[eventName]) {
|
|
3617
|
+
this.callbacks[eventName] = [];
|
|
3039
3618
|
}
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
const walletCode = await provider.getCode(await this.getAddress());
|
|
3045
|
-
return !!walletCode && walletCode !== '0x';
|
|
3619
|
+
this.callbacks[eventName].push(callback);
|
|
3620
|
+
return () => {
|
|
3621
|
+
this.callbacks[eventName] = this.callbacks[eventName].filter(c => c !== callback);
|
|
3622
|
+
};
|
|
3046
3623
|
}
|
|
3047
3624
|
|
|
3048
|
-
//
|
|
3049
|
-
// ethers JsonRpcSigner methods
|
|
3050
|
-
//
|
|
3051
|
-
|
|
3052
|
-
async _legacySignMessage(message, chainId) {
|
|
3053
|
-
const provider = await this.getSender(network.maybeChainId(chainId) || this.defaultChainId);
|
|
3054
|
-
const data = typeof message === 'string' ? ethers.ethers.utils.toUtf8Bytes(message) : message;
|
|
3055
|
-
const address = await this.getAddress();
|
|
3625
|
+
// Individual callbacks lead to more idiomatic code
|
|
3056
3626
|
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
return await provider.send('eth_sign', [address, ethers.ethers.utils.hexlify(data)]);
|
|
3627
|
+
onOpen(callback) {
|
|
3628
|
+
return this.registerCallback('open', callback);
|
|
3060
3629
|
}
|
|
3061
|
-
|
|
3062
|
-
return this.
|
|
3630
|
+
onClose(callback) {
|
|
3631
|
+
return this.registerCallback('close', callback);
|
|
3063
3632
|
}
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
const fromAddress = this.getAddress();
|
|
3067
|
-
|
|
3068
|
-
// NOTE: we do not use provider estimation, and instead rely on our relayer to determine the gasLimit and gasPrice
|
|
3069
|
-
//
|
|
3070
|
-
// TODO: alternatively/one day, we could write a provider middleware to eth_estimateGas
|
|
3071
|
-
// and send it to our relayer url instead for estimation..
|
|
3072
|
-
//
|
|
3073
|
-
// if (!transaction.gasLimit) {
|
|
3074
|
-
// const estimate = shallowCopy(transaction)
|
|
3075
|
-
// estimate.from = fromAddress
|
|
3076
|
-
// transaction.gasLimit = this.provider.estimateGas(estimate)
|
|
3077
|
-
// }
|
|
3078
|
-
|
|
3079
|
-
const provider = await this.getSender(network.maybeChainId(chainId) || this.defaultChainId);
|
|
3080
|
-
return utils.resolveProperties({
|
|
3081
|
-
tx: utils.resolveProperties(transaction),
|
|
3082
|
-
sender: await fromAddress
|
|
3083
|
-
}).then(({
|
|
3084
|
-
tx,
|
|
3085
|
-
sender
|
|
3086
|
-
}) => {
|
|
3087
|
-
if (tx.from != null) {
|
|
3088
|
-
if (ethers.ethers.utils.getAddress(tx.from) !== sender) {
|
|
3089
|
-
// logger.throwArgumentError("from address mismatch", "transaction", transaction)
|
|
3090
|
-
throw new Error(`from address mismatch for transaction ${transaction}`);
|
|
3091
|
-
}
|
|
3092
|
-
} else {
|
|
3093
|
-
tx.from = sender;
|
|
3094
|
-
}
|
|
3095
|
-
const hexTx = hexlifyTransaction(tx);
|
|
3096
|
-
return provider.send('eth_sendTransaction', [hexTx]).then(hash => {
|
|
3097
|
-
return hash;
|
|
3098
|
-
}, error => {
|
|
3099
|
-
// return checkError("sendTransaction", error, hexTx)
|
|
3100
|
-
throw error;
|
|
3101
|
-
});
|
|
3102
|
-
});
|
|
3633
|
+
onConnect(callback) {
|
|
3634
|
+
return this.registerCallback('connect', callback);
|
|
3103
3635
|
}
|
|
3104
|
-
|
|
3105
|
-
return
|
|
3636
|
+
onDisconnect(callback) {
|
|
3637
|
+
return this.registerCallback('disconnect', callback);
|
|
3106
3638
|
}
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
return this.provider.send('personal_unlockAccount', [address, password, null]);
|
|
3639
|
+
onNetworks(callback) {
|
|
3640
|
+
return this.registerCallback('networks', callback);
|
|
3110
3641
|
}
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
// NOTE: method has been copied + modified from ethers.js JsonRpcProvider
|
|
3114
|
-
// Convert an ethers.js transaction into a JSON-RPC transaction
|
|
3115
|
-
|
|
3116
|
-
const allowedTransactionKeys = {
|
|
3117
|
-
chainId: true,
|
|
3118
|
-
data: true,
|
|
3119
|
-
gasLimit: true,
|
|
3120
|
-
gasPrice: true,
|
|
3121
|
-
nonce: true,
|
|
3122
|
-
to: true,
|
|
3123
|
-
value: true,
|
|
3124
|
-
from: true,
|
|
3125
|
-
auxiliary: true,
|
|
3126
|
-
expiration: true,
|
|
3127
|
-
afterNonce: true,
|
|
3128
|
-
delegateCall: true,
|
|
3129
|
-
revertOnError: true
|
|
3130
|
-
};
|
|
3131
|
-
const hexlifyTransaction = (transaction, allowExtra) => {
|
|
3132
|
-
// Check only allowed properties are given
|
|
3133
|
-
const allowed = utils.shallowCopy(allowedTransactionKeys);
|
|
3134
|
-
if (allowExtra) {
|
|
3135
|
-
for (const key in allowExtra) {
|
|
3136
|
-
if (allowExtra[key]) {
|
|
3137
|
-
allowed[key] = true;
|
|
3138
|
-
}
|
|
3139
|
-
}
|
|
3642
|
+
onAccountsChanged(callback) {
|
|
3643
|
+
return this.registerCallback('accountsChanged', callback);
|
|
3140
3644
|
}
|
|
3141
|
-
ethers.ethers.utils.checkProperties(transaction, allowed);
|
|
3142
|
-
const result = {}
|
|
3143
3645
|
|
|
3144
|
-
//
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
const value = transaction[key];
|
|
3148
|
-
if (value === null || value === undefined) {
|
|
3149
|
-
return;
|
|
3150
|
-
}
|
|
3151
|
-
const hexValue = ethers.ethers.utils.hexValue(value);
|
|
3152
|
-
if (key === 'gasLimit') {
|
|
3153
|
-
key = 'gas';
|
|
3154
|
-
}
|
|
3155
|
-
result[key] = hexValue;
|
|
3156
|
-
});
|
|
3157
|
-
['from', 'to', 'data'].forEach(key => {
|
|
3158
|
-
if (!transaction[key]) {
|
|
3159
|
-
return;
|
|
3160
|
-
}
|
|
3161
|
-
result[key] = ethers.ethers.utils.hexlify(transaction[key]);
|
|
3162
|
-
});
|
|
3163
|
-
['delegateCall', 'revertOnError'].forEach(key => {
|
|
3164
|
-
const value = transaction[key];
|
|
3165
|
-
if (value !== undefined && value !== null) {
|
|
3166
|
-
result[key] = value;
|
|
3167
|
-
}
|
|
3168
|
-
});
|
|
3169
|
-
const auxiliary = transaction['auxiliary'];
|
|
3170
|
-
if (auxiliary && auxiliary.length > 0) {
|
|
3171
|
-
result['auxiliary'] = [];
|
|
3172
|
-
auxiliary.forEach(a => {
|
|
3173
|
-
result['auxiliary'].push(hexlifyTransaction(a));
|
|
3174
|
-
});
|
|
3646
|
+
// @deprecated
|
|
3647
|
+
onWalletContext(callback) {
|
|
3648
|
+
return this.registerCallback('walletContext', callback);
|
|
3175
3649
|
}
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
class UncheckedJsonRpcSigner extends Web3Signer {
|
|
3179
|
-
sendTransaction(transaction) {
|
|
3180
|
-
return this.sendUncheckedTransaction(transaction).then(hash => {
|
|
3181
|
-
return {
|
|
3182
|
-
chainId: 0,
|
|
3183
|
-
confirmations: 0,
|
|
3184
|
-
data: '',
|
|
3185
|
-
from: '',
|
|
3186
|
-
gasLimit: ethers.ethers.constants.Zero,
|
|
3187
|
-
gasPrice: ethers.ethers.constants.Zero,
|
|
3188
|
-
hash,
|
|
3189
|
-
nonce: 0,
|
|
3190
|
-
value: ethers.ethers.constants.Zero,
|
|
3191
|
-
wait: confirmations => this.provider.waitForTransaction(hash, confirmations)
|
|
3192
|
-
};
|
|
3193
|
-
});
|
|
3650
|
+
onDefaultChainIdChanged(callback) {
|
|
3651
|
+
return this.registerCallback('chainChanged', callback);
|
|
3194
3652
|
}
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
class WalletUtils {
|
|
3198
|
-
constructor(walletProvider) {
|
|
3199
|
-
this.wallet = walletProvider;
|
|
3653
|
+
getChainId() {
|
|
3654
|
+
return this.defaultChainId.getDefaultChainId();
|
|
3200
3655
|
}
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
signMessage(message, chainId, allSigners) {
|
|
3204
|
-
const signer = this.wallet.getSigner();
|
|
3205
|
-
if (!signer) throw new Error('unable to get signer');
|
|
3206
|
-
return signer.signMessage(message, chainId, allSigners);
|
|
3656
|
+
setDefaultChainId(chainId) {
|
|
3657
|
+
return this.defaultChainId.setDefaultChainId(chainId);
|
|
3207
3658
|
}
|
|
3208
3659
|
|
|
3209
|
-
//
|
|
3210
|
-
async signAuthMessage(message, allSigners) {
|
|
3211
|
-
const signer = this.wallet.getSigner();
|
|
3212
|
-
if (!signer) throw new Error('unable to get AuthChain signer');
|
|
3213
|
-
return signer.signMessage(message, await signer.getChainId(), allSigners);
|
|
3214
|
-
}
|
|
3660
|
+
// Proxy transport methods
|
|
3215
3661
|
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
return signer.signTypedData(domain, types, message, chainId, allSigners);
|
|
3662
|
+
async openWallet(path, intent) {
|
|
3663
|
+
this.transport.openWallet(path, intent, this.getChainId());
|
|
3664
|
+
await this.transport.waitUntilOpened();
|
|
3665
|
+
return this.isOpened();
|
|
3221
3666
|
}
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
async signAuthTypedData(domain, types, message, allSigners) {
|
|
3225
|
-
const signer = this.wallet.getSigner();
|
|
3226
|
-
if (!signer) throw new Error('unable to get AuthChain signer');
|
|
3227
|
-
return signer.signTypedData(domain, types, message, await signer.getChainId(), allSigners);
|
|
3667
|
+
closeWallet() {
|
|
3668
|
+
return this.transport.closeWallet();
|
|
3228
3669
|
}
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
async isValidSignature(address, digest, signature, chainId) {
|
|
3232
|
-
const provider = this.wallet.getProvider(chainId);
|
|
3233
|
-
if (!provider) throw new Error(`unable to get provider for chainId ${chainId}`);
|
|
3234
|
-
return isValidSignature(address, digest, signature, provider);
|
|
3670
|
+
isOpened() {
|
|
3671
|
+
return this.transport.isOpened();
|
|
3235
3672
|
}
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
async isValidMessageSignature(address, message, signature, chainId) {
|
|
3239
|
-
const provider = this.wallet.getProvider(chainId);
|
|
3240
|
-
if (!provider) throw new Error(`unable to get provider for chainId ${chainId}`);
|
|
3241
|
-
const prefixed = prefixEIP191Message(message);
|
|
3242
|
-
const digest = utils.encodeMessageDigest(prefixed);
|
|
3243
|
-
return isValidSignature(address, digest, signature, provider);
|
|
3673
|
+
isConnected() {
|
|
3674
|
+
return this.session.hasSession();
|
|
3244
3675
|
}
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
isValidTypedDataSignature(address, typedData, signature, chainId) {
|
|
3248
|
-
return this.isValidSignature(address, utils.encodeTypedDataDigest(typedData), signature, chainId);
|
|
3676
|
+
getSession() {
|
|
3677
|
+
return this.session.getSession();
|
|
3249
3678
|
}
|
|
3250
3679
|
|
|
3251
|
-
//
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
// chainId: BigNumberish,
|
|
3269
|
-
// walletContext?: WalletContext
|
|
3270
|
-
// ): Promise<WalletConfig> => {
|
|
3271
|
-
// walletContext = walletContext || (await this.wallet.getWalletContext())
|
|
3272
|
-
// return recoverWalletConfig(address, encodeMessageDigest(prefixEIP191Message(message)), signature, chainId, walletContext)
|
|
3273
|
-
// }
|
|
3274
|
-
|
|
3275
|
-
// // Recover the WalletConfig from a signature of a typedData object
|
|
3276
|
-
// recoverWalletConfigFromTypedData = async (
|
|
3277
|
-
// address: string,
|
|
3278
|
-
// typedData: TypedData,
|
|
3279
|
-
// signature: string | DecodedSignature,
|
|
3280
|
-
// chainId: BigNumberish,
|
|
3281
|
-
// walletContext?: WalletContext
|
|
3282
|
-
// ): Promise<WalletConfig> => {
|
|
3283
|
-
// walletContext = walletContext || (await this.wallet.getWalletContext())
|
|
3284
|
-
// return recoverWalletConfig(address, encodeTypedDataDigest(typedData), signature, chainId, walletContext)
|
|
3285
|
-
// }
|
|
3286
|
-
|
|
3287
|
-
// sendTransaction()
|
|
3288
|
-
// sendTransactions()
|
|
3289
|
-
|
|
3290
|
-
// sendETH()
|
|
3291
|
-
// sendToken()
|
|
3292
|
-
// sendCoin() -- sugar for sendToken()
|
|
3293
|
-
// sendCollectible() -- sugar for sendToken()
|
|
3294
|
-
// callContract()
|
|
3295
|
-
|
|
3296
|
-
// transactionHistory()
|
|
3297
|
-
// getReceipt()
|
|
3298
|
-
// getLogs()
|
|
3299
|
-
// // ..
|
|
3300
|
-
|
|
3301
|
-
// isWalletDeployed()
|
|
3302
|
-
// deployWallet()
|
|
3303
|
-
|
|
3304
|
-
// validateSignature()
|
|
3305
|
-
// recoverWalletConfig()
|
|
3306
|
-
// recoverAddress()
|
|
3307
|
-
}
|
|
3308
|
-
|
|
3309
|
-
const SESSION_LOCALSTORE_KEY = '@sequence.session';
|
|
3310
|
-
class Wallet {
|
|
3311
|
-
constructor(_network, config) {
|
|
3312
|
-
var _this = this;
|
|
3313
|
-
this.init = () => {
|
|
3314
|
-
var _this$config$transpor, _this$config$transpor2, _this$config$transpor3, _this$config$transpor4, _this$config$transpor5, _this$config$transpor6, _this$config$transpor7, _this$config$transpor8, _findSupportedNetwork;
|
|
3315
|
-
if (this.transport.provider) {
|
|
3316
|
-
// init must have already been called
|
|
3317
|
-
return;
|
|
3318
|
-
}
|
|
3319
|
-
|
|
3320
|
-
// Setup provider
|
|
3321
|
-
|
|
3322
|
-
this.transport.messageProvider = new MuxMessageProvider();
|
|
3323
|
-
|
|
3324
|
-
// multiple message provider setup, first one to connect will be the main transport
|
|
3325
|
-
if ((_this$config$transpor = this.config.transports) != null && (_this$config$transpor2 = _this$config$transpor.windowTransport) != null && _this$config$transpor2.enabled && typeof window === 'object') {
|
|
3326
|
-
this.transport.windowMessageProvider = new WindowMessageProvider(this.config.walletAppURL);
|
|
3327
|
-
this.transport.messageProvider.add(this.transport.windowMessageProvider);
|
|
3328
|
-
}
|
|
3329
|
-
if ((_this$config$transpor3 = this.config.transports) != null && (_this$config$transpor4 = _this$config$transpor3.proxyTransport) != null && _this$config$transpor4.enabled) {
|
|
3330
|
-
this.transport.proxyMessageProvider = new ProxyMessageProvider(this.config.transports.proxyTransport.appPort);
|
|
3331
|
-
this.transport.messageProvider.add(this.transport.proxyMessageProvider);
|
|
3332
|
-
}
|
|
3333
|
-
if ((_this$config$transpor5 = this.config.transports) != null && (_this$config$transpor6 = _this$config$transpor5.extensionTransport) != null && _this$config$transpor6.enabled) {
|
|
3334
|
-
this.transport.extensionMessageProvider = new ExtensionMessageProvider(this.config.transports.extensionTransport.runtime);
|
|
3335
|
-
// this.transport.extensionMessageProvider.register()
|
|
3336
|
-
this.transport.messageProvider.add(this.transport.extensionMessageProvider);
|
|
3337
|
-
|
|
3338
|
-
// NOTE/REVIEW: see note in mux-message-provider
|
|
3339
|
-
//
|
|
3340
|
-
// We don't add the extensionMessageProvider here because we don't send requests to it anyways, we seem to
|
|
3341
|
-
// send all requests to the WindowMessageProvider anyways. By allowing it, if browser restarts, it will break
|
|
3342
|
-
// the entire extension because messageProvider.provider will be undefined. So this is a hack to fix it.
|
|
3343
|
-
//
|
|
3344
|
-
// this.transport.messageProvider.add(this.transport.extensionMessageProvider)
|
|
3345
|
-
}
|
|
3346
|
-
|
|
3347
|
-
if ((_this$config$transpor7 = this.config.transports) != null && (_this$config$transpor8 = _this$config$transpor7.unrealTransport) != null && _this$config$transpor8.enabled) {
|
|
3348
|
-
this.transport.unrealMessageProvider = new UnrealMessageProvider(this.config.walletAppURL);
|
|
3349
|
-
this.transport.messageProvider.add(this.transport.unrealMessageProvider);
|
|
3350
|
-
}
|
|
3351
|
-
this.transport.messageProvider.register();
|
|
3352
|
-
|
|
3353
|
-
// .....
|
|
3354
|
-
this.transport.allowProvider = network.allowProviderMiddleware(request => {
|
|
3355
|
-
if (request.method === 'sequence_setDefaultNetwork') return true;
|
|
3356
|
-
const isConnected = this.isConnected();
|
|
3357
|
-
if (!isConnected) {
|
|
3358
|
-
throw new Error('Sequence: wallet not connected');
|
|
3359
|
-
}
|
|
3360
|
-
return isConnected;
|
|
3361
|
-
});
|
|
3362
|
-
|
|
3363
|
-
// ...
|
|
3364
|
-
this.transport.networkProvider = network.networkProviderMiddleware(request => {
|
|
3365
|
-
// return stub chainId of 0 when not connected to any
|
|
3366
|
-
if (!this.networks || this.networks.length === 0) return 0;
|
|
3367
|
-
|
|
3368
|
-
// return the default chainId as we're connected
|
|
3369
|
-
return network.findNetworkConfig(this.networks, this.config.defaultNetworkId).chainId;
|
|
3370
|
-
});
|
|
3371
|
-
|
|
3372
|
-
// Provider proxy to support middleware stack of logging, caching and read-only rpc calls
|
|
3373
|
-
this.transport.cachedProvider = new network.CachedProvider();
|
|
3374
|
-
this.transport.cachedProvider.onUpdate(() => {
|
|
3375
|
-
if (!this.session) this.session = {
|
|
3376
|
-
providerCache: {}
|
|
3377
|
-
};
|
|
3378
|
-
this.session.providerCache = this.transport.cachedProvider.getCache();
|
|
3379
|
-
this.saveSession(this.session);
|
|
3380
|
-
});
|
|
3381
|
-
|
|
3382
|
-
// ..
|
|
3383
|
-
this.transport.router = new network.JsonRpcRouter([network.loggingProviderMiddleware, this.transport.networkProvider, this.transport.allowProvider, network.exceptionProviderMiddleware, this.transport.cachedProvider], this.transport.messageProvider);
|
|
3384
|
-
|
|
3385
|
-
// TODO: Move finding this config to upper in the stack
|
|
3386
|
-
this.transport.provider = new Web3Provider(this.transport.router, (_findSupportedNetwork = network.findSupportedNetwork(this.config.defaultNetworkId)) == null ? void 0 : _findSupportedNetwork.chainId);
|
|
3387
|
-
|
|
3388
|
-
// NOTE: we don't listen on 'connect' even here as we handle it within connect() method
|
|
3389
|
-
// in more synchronous flow.
|
|
3390
|
-
|
|
3391
|
-
// below will update the wallet session object and persist it. In case the session
|
|
3392
|
-
// is undefined, we consider the session to have been removed by the user, so we clear it.
|
|
3393
|
-
this.transport.messageProvider.on('open', openInfo => {
|
|
3394
|
-
const {
|
|
3395
|
-
session
|
|
3396
|
-
} = openInfo;
|
|
3397
|
-
if (!session) {
|
|
3398
|
-
if (this.session && this.session.accountAddress) {
|
|
3399
|
-
// emit disconnect even if previously we had a session, and now we don't.
|
|
3400
|
-
this.transport.messageProvider.emit('disconnect');
|
|
3401
|
-
}
|
|
3402
|
-
this.clearSession();
|
|
3403
|
-
} else {
|
|
3404
|
-
this.useSession(session, true);
|
|
3405
|
-
}
|
|
3406
|
-
});
|
|
3407
|
-
|
|
3408
|
-
// below will update the account upon wallet connect/disconnect - aka, login/logout.
|
|
3409
|
-
// if an origin is provided, this operation should be performed only on that origin
|
|
3410
|
-
// and shouldn't affect the session of the wallet.
|
|
3411
|
-
this.transport.messageProvider.on('accountsChanged', (accounts, origin) => {
|
|
3412
|
-
if (origin) {
|
|
3413
|
-
if (accounts.length > 0) {
|
|
3414
|
-
this.useSession({
|
|
3415
|
-
accountAddress: accounts[0]
|
|
3416
|
-
}, true);
|
|
3417
|
-
}
|
|
3418
|
-
return;
|
|
3419
|
-
}
|
|
3420
|
-
if (!accounts || accounts.length === 0 || accounts[0] === '') {
|
|
3421
|
-
this.clearSession();
|
|
3422
|
-
} else {
|
|
3423
|
-
this.useSession({
|
|
3424
|
-
accountAddress: accounts[0]
|
|
3425
|
-
}, true);
|
|
3680
|
+
// Basic API
|
|
3681
|
+
getAddress() {
|
|
3682
|
+
const session = this.session.connectedSession();
|
|
3683
|
+
return session.accountAddress;
|
|
3684
|
+
}
|
|
3685
|
+
async connect(options) {
|
|
3686
|
+
if ((options == null ? void 0 : options.authorizeVersion) === undefined) {
|
|
3687
|
+
// Populate default authorize version if not provided
|
|
3688
|
+
options.authorizeVersion = 2;
|
|
3689
|
+
}
|
|
3690
|
+
if ((options == null ? void 0 : options.refresh) === true) {
|
|
3691
|
+
this.disconnect();
|
|
3692
|
+
}
|
|
3693
|
+
if (options) {
|
|
3694
|
+
if (options.authorize) {
|
|
3695
|
+
if (!options.app) {
|
|
3696
|
+
throw new Error(`connecting with 'authorize' option also requires 'app' to be set`);
|
|
3426
3697
|
}
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
// below will update the networks automatically when the wallet networks change
|
|
3430
|
-
this.transport.messageProvider.on('networks', networks => {
|
|
3431
|
-
this.useSession({
|
|
3432
|
-
networks: networks
|
|
3433
|
-
}, true);
|
|
3434
|
-
});
|
|
3435
|
-
|
|
3436
|
-
// below will update the wallet context automatically
|
|
3437
|
-
this.transport.messageProvider.on('walletContext', walletContext => {
|
|
3438
|
-
this.useSession({
|
|
3439
|
-
walletContext: walletContext
|
|
3440
|
-
}, true);
|
|
3441
|
-
});
|
|
3442
|
-
};
|
|
3443
|
-
this.loadSession = async function (preferredNetwork) {
|
|
3444
|
-
const data = await LocalStorage.getInstance().getItem(SESSION_LOCALSTORE_KEY);
|
|
3445
|
-
if (!data || data === '') {
|
|
3446
|
-
return undefined;
|
|
3447
|
-
}
|
|
3448
|
-
try {
|
|
3449
|
-
const session = JSON.parse(data);
|
|
3450
|
-
if (session) {
|
|
3451
|
-
// Setting preferredNetwork as default network if it's in session.networks
|
|
3452
|
-
if (preferredNetwork !== undefined) {
|
|
3453
|
-
var _session$networks;
|
|
3454
|
-
const preferredNetworkIdNum = typeof preferredNetwork === 'string' ? parseInt(preferredNetwork) : preferredNetwork;
|
|
3455
|
-
const isPreferredNetwork = n => n.name === preferredNetwork || n.chainId === preferredNetworkIdNum;
|
|
3456
|
-
const preferredNetworkInConfig = (_session$networks = session.networks) == null ? void 0 : _session$networks.find(isPreferredNetwork);
|
|
3457
|
-
const isAlreadyDefaultChain = preferredNetworkInConfig == null ? void 0 : preferredNetworkInConfig.isDefaultChain;
|
|
3458
|
-
if (session.networks && preferredNetworkInConfig && !isAlreadyDefaultChain) {
|
|
3459
|
-
const updatedNetworks = session.networks.map(n => _extends({}, n, {
|
|
3460
|
-
isDefaultChain: isPreferredNetwork(n)
|
|
3461
|
-
}));
|
|
3462
|
-
session.networks = network.sortNetworks(updatedNetworks);
|
|
3463
|
-
session.providerCache = undefined;
|
|
3464
|
-
}
|
|
3465
|
-
}
|
|
3466
|
-
_this.useSession(session, true);
|
|
3698
|
+
if (options.authorizeVersion === undefined) {
|
|
3699
|
+
options.authorizeVersion = 2;
|
|
3467
3700
|
}
|
|
3468
|
-
return session;
|
|
3469
|
-
} catch (err) {
|
|
3470
|
-
utils.logger.warn('loadSession failed, unable to parse session payload from storage.');
|
|
3471
|
-
return undefined;
|
|
3472
3701
|
}
|
|
3473
|
-
}
|
|
3474
|
-
this.
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
}
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
if (_this.isConnected() && (await _this.isSiteConnected(options == null ? void 0 : options.origin)) && !!_this.session && !(options != null && options.authorize) && !(options != null && options.askForEmail)) {
|
|
3702
|
+
}
|
|
3703
|
+
await this.openWallet(undefined, {
|
|
3704
|
+
type: 'connect',
|
|
3705
|
+
options: _extends({}, options, {
|
|
3706
|
+
networkId: this.getChainId()
|
|
3707
|
+
})
|
|
3708
|
+
});
|
|
3709
|
+
const connectDetails = await this.transport.waitUntilConnected().catch(error => {
|
|
3710
|
+
if (error instanceof Error) {
|
|
3483
3711
|
return {
|
|
3484
|
-
connected:
|
|
3485
|
-
|
|
3486
|
-
chainId: ethers.ethers.utils.hexlify(await _this.getChainId())
|
|
3712
|
+
connected: false,
|
|
3713
|
+
error: error.message
|
|
3487
3714
|
};
|
|
3488
|
-
}
|
|
3489
|
-
if (options) {
|
|
3490
|
-
if (options.authorize) {
|
|
3491
|
-
if (!options.app) {
|
|
3492
|
-
throw new Error(`connecting with 'authorize' option also requires 'app' to be set`);
|
|
3493
|
-
}
|
|
3494
|
-
if (options.authorizeVersion === undefined) {
|
|
3495
|
-
options.authorizeVersion = 2;
|
|
3496
|
-
}
|
|
3497
|
-
}
|
|
3498
|
-
}
|
|
3499
|
-
await _this.openWallet(undefined, {
|
|
3500
|
-
type: 'connect',
|
|
3501
|
-
options
|
|
3502
|
-
});
|
|
3503
|
-
const connectDetails = await _this.transport.messageProvider.waitUntilConnected().catch(error => {
|
|
3504
|
-
if (error instanceof Error) {
|
|
3505
|
-
return {
|
|
3506
|
-
connected: false,
|
|
3507
|
-
error: error.message
|
|
3508
|
-
};
|
|
3509
|
-
} else {
|
|
3510
|
-
return {
|
|
3511
|
-
connected: false,
|
|
3512
|
-
error: JSON.stringify(error)
|
|
3513
|
-
};
|
|
3514
|
-
}
|
|
3515
|
-
});
|
|
3516
|
-
if (connectDetails.connected) {
|
|
3517
|
-
if (!!connectDetails.session) {
|
|
3518
|
-
_this.useSession(connectDetails.session, true);
|
|
3519
|
-
_this.addConnectedSite(options == null ? void 0 : options.origin);
|
|
3520
|
-
} else {
|
|
3521
|
-
throw new Error('impossible state, connect response is missing session');
|
|
3522
|
-
}
|
|
3523
|
-
}
|
|
3524
|
-
return connectDetails;
|
|
3525
|
-
};
|
|
3526
|
-
this.authorize = async function (options) {
|
|
3527
|
-
return _this.connect(_extends({}, options, {
|
|
3528
|
-
authorize: true
|
|
3529
|
-
}));
|
|
3530
|
-
};
|
|
3531
|
-
this.getSession = () => {
|
|
3532
|
-
if (!this.isConnected()) {
|
|
3533
|
-
return undefined;
|
|
3534
|
-
}
|
|
3535
|
-
return this.session;
|
|
3536
|
-
};
|
|
3537
|
-
this.getAddress = async function () {
|
|
3538
|
-
if (!_this.isConnected()) {
|
|
3539
|
-
throw new Error('connect first');
|
|
3540
|
-
}
|
|
3541
|
-
const session = _this.getSession();
|
|
3542
|
-
return session.accountAddress;
|
|
3543
|
-
};
|
|
3544
|
-
this.getNetworks = async function (chainId) {
|
|
3545
|
-
if (!_this.isConnected() || !_this.networks) {
|
|
3546
|
-
throw new Error('connect first');
|
|
3547
|
-
}
|
|
3548
|
-
if (chainId) {
|
|
3549
|
-
// filter list to just the specific chain requested
|
|
3550
|
-
const network$1 = network.findNetworkConfig(_this.networks, chainId);
|
|
3551
|
-
return network$1 ? [network$1] : [];
|
|
3552
|
-
}
|
|
3553
|
-
return _this.networks;
|
|
3554
|
-
};
|
|
3555
|
-
// getChainId returns the default chain id
|
|
3556
|
-
this.getChainId = async function () {
|
|
3557
|
-
if (!_this.networks || _this.networks.length < 1) {
|
|
3558
|
-
throw new Error('networks have not been set by session. connect first.');
|
|
3559
|
-
}
|
|
3560
|
-
const network$1 = network.findNetworkConfig(_this.networks, _this.config.defaultNetworkId);
|
|
3561
|
-
if (!network$1) {
|
|
3562
|
-
throw new Error('networks must have a default chain specified');
|
|
3563
|
-
}
|
|
3564
|
-
return network$1.chainId;
|
|
3565
|
-
};
|
|
3566
|
-
this.openWallet = async function (path, intent, networkId) {
|
|
3567
|
-
if ((intent == null ? void 0 : intent.type) !== 'connect' && !_this.isConnected()) {
|
|
3568
|
-
throw new Error('connect first');
|
|
3569
|
-
}
|
|
3570
|
-
let currentNetworkId;
|
|
3571
|
-
if (!_this.networks || _this.networks.length < 1) {
|
|
3572
|
-
currentNetworkId = _this.config.defaultNetworkId;
|
|
3573
|
-
} else {
|
|
3574
|
-
currentNetworkId = await _this.getChainId();
|
|
3575
|
-
}
|
|
3576
|
-
_this.transport.messageProvider.openWallet(path, intent, networkId || currentNetworkId);
|
|
3577
|
-
await _this.transport.messageProvider.waitUntilOpened();
|
|
3578
|
-
return true;
|
|
3579
|
-
};
|
|
3580
|
-
this.closeWallet = () => {
|
|
3581
|
-
this.transport.messageProvider.closeWallet();
|
|
3582
|
-
};
|
|
3583
|
-
this.unregister = () => {
|
|
3584
|
-
var _this$transport$messa;
|
|
3585
|
-
this.disconnect();
|
|
3586
|
-
(_this$transport$messa = this.transport.messageProvider) == null ? void 0 : _this$transport$messa.unregister();
|
|
3587
|
-
};
|
|
3588
|
-
this.saveSession = async function (session) {
|
|
3589
|
-
utils.logger.debug('wallet provider: saving session');
|
|
3590
|
-
const data = JSON.stringify(session);
|
|
3591
|
-
await LocalStorage.getInstance().setItem(SESSION_LOCALSTORE_KEY, data);
|
|
3592
|
-
};
|
|
3593
|
-
this.useSession = async function (session, autoSave = true) {
|
|
3594
|
-
if (!_this.session) _this.session = {};
|
|
3595
|
-
|
|
3596
|
-
// setup wallet context
|
|
3597
|
-
if (_this.config.walletContext) {
|
|
3598
|
-
_this.session.walletContext = _this.config.walletContext;
|
|
3599
|
-
} else if (session.walletContext) {
|
|
3600
|
-
_this.session.walletContext = session.walletContext;
|
|
3601
|
-
}
|
|
3602
|
-
|
|
3603
|
-
// setup account
|
|
3604
|
-
if (session.accountAddress) {
|
|
3605
|
-
_this.useAccountAddress(session.accountAddress);
|
|
3606
|
-
}
|
|
3607
|
-
|
|
3608
|
-
// setup networks
|
|
3609
|
-
if (session.networks) {
|
|
3610
|
-
_this.useNetworks(session.networks);
|
|
3611
|
-
}
|
|
3612
|
-
|
|
3613
|
-
// setup provider cache
|
|
3614
|
-
if (session.providerCache) {
|
|
3615
|
-
_this.transport.cachedProvider.setCache(session.providerCache);
|
|
3616
3715
|
} else {
|
|
3617
|
-
|
|
3716
|
+
return {
|
|
3717
|
+
connected: false,
|
|
3718
|
+
error: JSON.stringify(error)
|
|
3719
|
+
};
|
|
3618
3720
|
}
|
|
3721
|
+
});
|
|
3619
3722
|
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
};
|
|
3625
|
-
// config is a Partial, so that we may intersect it with the DefaultProviderConfig,
|
|
3626
|
-
// which allows easy overriding and control of the config.
|
|
3627
|
-
this.config = _extends({}, DefaultProviderConfig);
|
|
3628
|
-
if (config) {
|
|
3629
|
-
this.config = _extends({}, this.config, config);
|
|
3630
|
-
}
|
|
3631
|
-
if (_network) {
|
|
3632
|
-
this.config.defaultNetworkId = _network;
|
|
3633
|
-
} else if (!this.config.defaultNetworkId) {
|
|
3634
|
-
this.config.defaultNetworkId = 'mainnet';
|
|
3635
|
-
}
|
|
3636
|
-
if (config != null && config.localStorage) {
|
|
3637
|
-
LocalStorage.use(config.localStorage);
|
|
3638
|
-
}
|
|
3639
|
-
this.transport = {};
|
|
3640
|
-
this.networks = [];
|
|
3641
|
-
this.providers = {};
|
|
3642
|
-
this.connectedSites = new LocalStore('@sequence.connectedSites', []);
|
|
3643
|
-
this.utils = new WalletUtils(this);
|
|
3644
|
-
this.init();
|
|
3645
|
-
}
|
|
3646
|
-
async addConnectedSite(origin) {
|
|
3647
|
-
origin = origin || window.location.origin;
|
|
3648
|
-
const connectedSites = await this.connectedSites.get();
|
|
3649
|
-
if (connectedSites) {
|
|
3650
|
-
if (connectedSites.includes(origin)) {
|
|
3651
|
-
return;
|
|
3652
|
-
}
|
|
3653
|
-
this.connectedSites.set([...connectedSites, origin]);
|
|
3654
|
-
} else {
|
|
3655
|
-
this.connectedSites.set([origin]);
|
|
3723
|
+
// Normalize chainId into a decimal string
|
|
3724
|
+
// TODO: Remove this once wallet-webapp returns chainId as a string
|
|
3725
|
+
if (connectDetails.chainId) {
|
|
3726
|
+
connectDetails.chainId = ethers.ethers.BigNumber.from(connectDetails.chainId).toString();
|
|
3656
3727
|
}
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
this.
|
|
3728
|
+
if (connectDetails.connected) {
|
|
3729
|
+
if (!connectDetails.session) {
|
|
3730
|
+
throw new Error('impossible state, connect response is missing session');
|
|
3731
|
+
}
|
|
3732
|
+
this.session.setSession(connectDetails.session);
|
|
3662
3733
|
}
|
|
3663
|
-
|
|
3664
|
-
getConnectedSites() {
|
|
3665
|
-
return this.connectedSites.get();
|
|
3666
|
-
}
|
|
3667
|
-
async isSiteConnected(origin) {
|
|
3668
|
-
const authorized = await this.connectedSites.get();
|
|
3669
|
-
return !!authorized && authorized.includes(origin || window.location.origin);
|
|
3734
|
+
return connectDetails;
|
|
3670
3735
|
}
|
|
3671
3736
|
disconnect() {
|
|
3672
3737
|
if (this.isOpened()) {
|
|
3673
3738
|
this.closeWallet();
|
|
3674
3739
|
}
|
|
3675
|
-
return this.clearSession();
|
|
3740
|
+
return this.session.clearSession();
|
|
3676
3741
|
}
|
|
3677
3742
|
|
|
3678
|
-
//
|
|
3679
|
-
// and on successful response, will update the provider info here, etc.
|
|
3743
|
+
// Higher level API
|
|
3680
3744
|
|
|
3681
|
-
|
|
3682
|
-
|
|
3745
|
+
// Working with sendAsync is less idiomatic
|
|
3746
|
+
// but transport uses it instead of send, so we wrap it
|
|
3747
|
+
send(request, chainId) {
|
|
3748
|
+
return new Promise((resolve, reject) => {
|
|
3749
|
+
this.transport.sendAsync(request, (error, response) => {
|
|
3750
|
+
if (error) {
|
|
3751
|
+
reject(error);
|
|
3752
|
+
} else if (response === undefined) {
|
|
3753
|
+
reject(new Error(`Got undefined response for request: ${request}`));
|
|
3754
|
+
} else if (typeof response === 'object' && response.error) {
|
|
3755
|
+
reject(response.error);
|
|
3756
|
+
} else if (typeof response === 'object' && response.result) {
|
|
3757
|
+
resolve(response.result);
|
|
3758
|
+
} else {
|
|
3759
|
+
reject(new Error(`Got invalid response for request: ${request}`));
|
|
3760
|
+
}
|
|
3761
|
+
}, chainId || this.getChainId());
|
|
3762
|
+
});
|
|
3683
3763
|
}
|
|
3684
|
-
|
|
3685
|
-
|
|
3764
|
+
async getNetworks(pull) {
|
|
3765
|
+
const connectedSession = this.session.connectedSession();
|
|
3766
|
+
if (pull) {
|
|
3767
|
+
connectedSession.networks = await this.send({
|
|
3768
|
+
method: 'sequence_getNetworks'
|
|
3769
|
+
});
|
|
3770
|
+
this.session.setSession(connectedSession);
|
|
3771
|
+
}
|
|
3772
|
+
return connectedSession.networks;
|
|
3686
3773
|
}
|
|
3687
|
-
|
|
3688
|
-
|
|
3774
|
+
async signMessage(message, options) {
|
|
3775
|
+
const method = options != null && options.eip6492 ? 'sequence_sign' : 'personal_sign';
|
|
3776
|
+
|
|
3777
|
+
// Address is ignored by the wallet webapp
|
|
3778
|
+
return this.send({
|
|
3779
|
+
method,
|
|
3780
|
+
params: [message, this.getAddress()]
|
|
3781
|
+
}, options == null ? void 0 : options.chainId);
|
|
3689
3782
|
}
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
// and user has not logged in
|
|
3693
|
-
if (!this.isConnected()) {
|
|
3694
|
-
if (chainId) {
|
|
3695
|
-
throw new Error(`session is empty. connect and try again.`);
|
|
3696
|
-
} else {
|
|
3697
|
-
return this.transport.provider;
|
|
3698
|
-
}
|
|
3699
|
-
}
|
|
3700
|
-
let network$1 = network.findNetworkConfig(this.networks, this.config.defaultNetworkId);
|
|
3701
|
-
if (chainId) {
|
|
3702
|
-
network$1 = network.findNetworkConfig(this.networks, chainId);
|
|
3703
|
-
if (!network$1) {
|
|
3704
|
-
throw new Error(`network ${chainId} is not in the network list`);
|
|
3705
|
-
}
|
|
3706
|
-
}
|
|
3783
|
+
async signTypedData(typedData, options) {
|
|
3784
|
+
const method = options != null && options.eip6492 ? 'sequence_signTypedData_v4' : 'eth_signTypedData_v4';
|
|
3707
3785
|
|
|
3708
|
-
//
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
}
|
|
3786
|
+
// TODO: Stop using ethers for this, this is the only place where we use it
|
|
3787
|
+
// and it makes the client depend on ethers.
|
|
3788
|
+
const encoded = ethers.ethers.utils._TypedDataEncoder.getPayload(typedData.domain, typedData.types, typedData.message);
|
|
3712
3789
|
|
|
3713
|
-
//
|
|
3714
|
-
|
|
3790
|
+
// The sign typed data will use one of the following chainIds, in order:
|
|
3791
|
+
// - The one provided in the options
|
|
3792
|
+
// - The one provided in the typedData.domain.chainId
|
|
3793
|
+
// - The default chainId
|
|
3715
3794
|
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
const router = new network.JsonRpcRouter([network.loggingProviderMiddleware, network.exceptionProviderMiddleware, new network.EagerProvider({
|
|
3721
|
-
accountAddress: this.session.accountAddress,
|
|
3722
|
-
walletContext: this.session.walletContext
|
|
3723
|
-
}), new network.SigningProvider(this.transport.provider), this.transport.cachedProvider], new network.JsonRpcSender(rpcProvider));
|
|
3724
|
-
provider = new Web3Provider(router, network$1.chainId);
|
|
3725
|
-
} else {
|
|
3726
|
-
// communicating with another chain will bind to that network, but will forward
|
|
3727
|
-
// any signing-related requests to the wallet message transport
|
|
3728
|
-
const router = new network.JsonRpcRouter([network.loggingProviderMiddleware, network.exceptionProviderMiddleware, new network.EagerProvider({
|
|
3729
|
-
accountAddress: this.session.accountAddress,
|
|
3730
|
-
walletContext: this.session.walletContext,
|
|
3731
|
-
chainId: network$1.chainId
|
|
3732
|
-
}), new network.SigningProvider(this.transport.provider), new network.CachedProvider({
|
|
3733
|
-
defaultChainId: network$1.chainId
|
|
3734
|
-
})], new network.JsonRpcSender(rpcProvider));
|
|
3735
|
-
provider = new Web3Provider(router, network$1.chainId);
|
|
3736
|
-
}
|
|
3737
|
-
this.providers[network$1.chainId] = provider;
|
|
3738
|
-
return provider;
|
|
3739
|
-
}
|
|
3740
|
-
getAllProviders() {
|
|
3741
|
-
return this.providers;
|
|
3742
|
-
}
|
|
3743
|
-
getSigner(chainId) {
|
|
3744
|
-
return this.getProvider(chainId).getSigner();
|
|
3745
|
-
}
|
|
3746
|
-
getWalletConfig(chainId) {
|
|
3747
|
-
return this.getSigner().getWalletConfig(chainId);
|
|
3748
|
-
}
|
|
3749
|
-
getWalletState(chainId) {
|
|
3750
|
-
return this.getSigner().getWalletState(chainId);
|
|
3751
|
-
}
|
|
3752
|
-
getWalletContext() {
|
|
3753
|
-
return this.getSigner().getWalletContext();
|
|
3754
|
-
}
|
|
3755
|
-
isDeployed(chainId) {
|
|
3756
|
-
return this.getSigner(chainId).isDeployed();
|
|
3795
|
+
return this.send({
|
|
3796
|
+
method,
|
|
3797
|
+
params: [this.getAddress(), encoded]
|
|
3798
|
+
}, (options == null ? void 0 : options.chainId) || typedData.domain.chainId && ethers.ethers.BigNumber.from(typedData.domain.chainId).toNumber() || this.getChainId());
|
|
3757
3799
|
}
|
|
3758
|
-
|
|
3759
|
-
|
|
3800
|
+
async sendTransaction(tx, options) {
|
|
3801
|
+
const sequenceTxs = Array.isArray(tx) ? tx : [tx];
|
|
3802
|
+
const extendedTxs = toExtended(sequenceTxs);
|
|
3803
|
+
return this.send({
|
|
3804
|
+
method: 'eth_sendTransaction',
|
|
3805
|
+
params: [extendedTxs]
|
|
3806
|
+
}, options == null ? void 0 : options.chainId);
|
|
3760
3807
|
}
|
|
3761
|
-
|
|
3762
|
-
this.
|
|
3808
|
+
async getWalletContext() {
|
|
3809
|
+
return this.send({
|
|
3810
|
+
method: 'sequence_getWalletContext'
|
|
3811
|
+
});
|
|
3763
3812
|
}
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3813
|
+
async getOnchainWalletConfig(options) {
|
|
3814
|
+
// NOTICE: sequence_getWalletConfig sends the chainId as a param
|
|
3815
|
+
const res = await this.send({
|
|
3816
|
+
method: 'sequence_getWalletConfig',
|
|
3817
|
+
params: [(options == null ? void 0 : options.chainId) || this.getChainId()]
|
|
3818
|
+
}, options == null ? void 0 : options.chainId);
|
|
3819
|
+
return Array.isArray(res) ? res[0] : res;
|
|
3767
3820
|
}
|
|
3768
|
-
useNetworks(networks) {
|
|
3769
|
-
// set networks in the session
|
|
3770
|
-
if (!this.session) this.session = {};
|
|
3771
|
-
|
|
3772
|
-
// set networks on session object
|
|
3773
|
-
this.session.networks = networks;
|
|
3774
|
-
|
|
3775
|
-
// short-circuit if setting empty network list (aka logged out state)
|
|
3776
|
-
if (!this.session.networks || this.session.networks.length === 0) {
|
|
3777
|
-
return;
|
|
3778
|
-
}
|
|
3779
|
-
|
|
3780
|
-
// check if any custom network settings, otherwise return early
|
|
3781
|
-
if (!this.config.networks && !this.config.networkRpcUrl) {
|
|
3782
|
-
this.networks = networks;
|
|
3783
|
-
return;
|
|
3784
|
-
}
|
|
3785
|
-
|
|
3786
|
-
// init networks
|
|
3787
|
-
this.networks = networks;
|
|
3788
|
-
|
|
3789
|
-
// combine custom network config with networks in the session
|
|
3790
|
-
if (this.config.networks) {
|
|
3791
|
-
this.networks = networks.map(n => _extends({}, n)); // copy
|
|
3792
|
-
this.config.networks.forEach(n => {
|
|
3793
|
-
const network$1 = network.findNetworkConfig(this.networks, n.chainId || n.name);
|
|
3794
|
-
if (!network$1) return;
|
|
3795
|
-
network.updateNetworkConfig(n, network$1);
|
|
3796
|
-
});
|
|
3797
|
-
network.ensureValidNetworks(this.networks, true);
|
|
3798
|
-
}
|
|
3799
3821
|
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
network.rpcUrl = this.config.networkRpcUrl;
|
|
3805
|
-
}
|
|
3806
|
-
}
|
|
3807
|
-
}
|
|
3808
|
-
async clearSession() {
|
|
3809
|
-
var _this$transport$cache;
|
|
3810
|
-
utils.logger.debug('wallet provider: clearing session');
|
|
3811
|
-
await LocalStorage.getInstance().removeItem(SESSION_LOCALSTORE_KEY);
|
|
3812
|
-
this.session = undefined;
|
|
3813
|
-
this.networks = [];
|
|
3814
|
-
this.providers = {};
|
|
3815
|
-
(_this$transport$cache = this.transport.cachedProvider) == null ? void 0 : _this$transport$cache.clearCache();
|
|
3816
|
-
}
|
|
3822
|
+
// NOTICE: We are leaving out all the "regular" methods os a tipical
|
|
3823
|
+
// JSON RPC Provider (eth_getBlockByNumber, eth_call, etc)
|
|
3824
|
+
// wallet-webapp does implement them, but this client is meant to be
|
|
3825
|
+
// exclusively used for Sequence specific methods
|
|
3817
3826
|
}
|
|
3818
|
-
const DefaultProviderConfig = {
|
|
3819
|
-
walletAppURL: 'https://sequence.app',
|
|
3820
|
-
// walletSessionURL: 'https://session.sequence.app',
|
|
3821
3827
|
|
|
3828
|
+
const DefaultProviderConfig = {
|
|
3822
3829
|
transports: {
|
|
3830
|
+
walletAppURL: 'https://sequence.app',
|
|
3823
3831
|
windowTransport: {
|
|
3824
3832
|
enabled: true
|
|
3825
3833
|
},
|
|
3826
3834
|
proxyTransport: {
|
|
3827
3835
|
enabled: false
|
|
3828
3836
|
}
|
|
3829
|
-
}
|
|
3837
|
+
},
|
|
3838
|
+
defaultNetwork: 1
|
|
3830
3839
|
};
|
|
3831
|
-
let
|
|
3832
|
-
const initWallet =
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3840
|
+
let sequenceWalletProvider;
|
|
3841
|
+
const initWallet = partialConfig => {
|
|
3842
|
+
var _config$networks$filt, _config$networks, _findNetworkConfig;
|
|
3843
|
+
if (sequenceWalletProvider) {
|
|
3844
|
+
return sequenceWalletProvider;
|
|
3845
|
+
}
|
|
3846
|
+
|
|
3847
|
+
// Combine both the provided config and the default config
|
|
3848
|
+
const config = _extends({}, DefaultProviderConfig, partialConfig, {
|
|
3849
|
+
transports: _extends({}, DefaultProviderConfig.transports, partialConfig == null ? void 0 : partialConfig.transports)
|
|
3850
|
+
});
|
|
3851
|
+
const rpcProviders = {};
|
|
3852
|
+
|
|
3853
|
+
// Find any new networks that aren't already defined in sequence.js
|
|
3854
|
+
// and add them to the list of networks, (they must have a rpcUrl and chainId)
|
|
3855
|
+
const newNetworks = (_config$networks$filt = (_config$networks = config.networks) == null ? void 0 : _config$networks.filter(n => {
|
|
3856
|
+
n.rpcUrl !== undefined && n.chainId !== undefined && !network.allNetworks.find(an => an.chainId === n.chainId);
|
|
3857
|
+
})) != null ? _config$networks$filt : [];
|
|
3858
|
+
|
|
3859
|
+
// Override any information about the networks using the config
|
|
3860
|
+
const combinedNetworks = network.allNetworks.map(n => {
|
|
3861
|
+
var _config$networks2;
|
|
3862
|
+
const network = (_config$networks2 = config.networks) == null ? void 0 : _config$networks2.find(cn => cn.chainId === n.chainId);
|
|
3863
|
+
return network ? _extends({}, n, network) : n;
|
|
3864
|
+
}).concat(newNetworks);
|
|
3865
|
+
|
|
3866
|
+
// This build a "public rpc" on demand, we build them on demand because we don't want to
|
|
3867
|
+
// generate a bunch of providers for networks that aren't used.
|
|
3868
|
+
const providerForChainId = chainId => {
|
|
3869
|
+
if (!rpcProviders[chainId]) {
|
|
3870
|
+
var _combinedNetworks$fin;
|
|
3871
|
+
const rpcUrl = (_combinedNetworks$fin = combinedNetworks.find(n => n.chainId === chainId)) == null ? void 0 : _combinedNetworks$fin.rpcUrl;
|
|
3872
|
+
if (!rpcUrl) {
|
|
3873
|
+
throw new Error(`no rpcUrl found for chainId: ${chainId}`);
|
|
3874
|
+
}
|
|
3875
|
+
const baseProvider = new ethers.ethers.providers.JsonRpcProvider(rpcUrl);
|
|
3876
|
+
const router = new network.JsonRpcRouter([network.loggingProviderMiddleware, network.exceptionProviderMiddleware, new network.CachedProvider()], new network.JsonRpcSender(baseProvider));
|
|
3877
|
+
rpcProviders[chainId] = new ethers.ethers.providers.Web3Provider(router, chainId);
|
|
3878
|
+
}
|
|
3879
|
+
return rpcProviders[chainId];
|
|
3880
|
+
};
|
|
3881
|
+
|
|
3882
|
+
// This is the starting default network (as defined by the config)
|
|
3883
|
+
// it can be later be changed using `wallet_switchEthereumChain` or some
|
|
3884
|
+
// of the other methods on the provider.
|
|
3885
|
+
const defaultNetwork = config.defaultNetwork ? (_findNetworkConfig = network.findNetworkConfig(combinedNetworks, config.defaultNetwork)) == null ? void 0 : _findNetworkConfig.chainId : undefined;
|
|
3886
|
+
if (!defaultNetwork && config.defaultNetwork) {
|
|
3887
|
+
throw new Error(`defaultNetwork not found for chainId: ${config.defaultNetwork}`);
|
|
3888
|
+
}
|
|
3889
|
+
|
|
3890
|
+
// Generate ItemStore
|
|
3891
|
+
const itemStore = config.localStorage || useBestStore();
|
|
3892
|
+
|
|
3893
|
+
// Create client, provider and return signer
|
|
3894
|
+
const client = new SequenceClient(config.transports, itemStore, defaultNetwork);
|
|
3895
|
+
sequenceWalletProvider = new SequenceProvider(client, providerForChainId);
|
|
3896
|
+
return sequenceWalletProvider;
|
|
3839
3897
|
};
|
|
3840
3898
|
const unregisterWallet = () => {
|
|
3841
|
-
if (!
|
|
3842
|
-
|
|
3843
|
-
|
|
3899
|
+
if (!sequenceWalletProvider) return;
|
|
3900
|
+
sequenceWalletProvider.client.closeWallet();
|
|
3901
|
+
sequenceWalletProvider.client.transport.unregister();
|
|
3902
|
+
sequenceWalletProvider = undefined;
|
|
3844
3903
|
};
|
|
3845
3904
|
const getWallet = () => {
|
|
3846
|
-
if (!
|
|
3847
|
-
throw new Error('Wallet has not been initialized, call sequence.initWallet(
|
|
3905
|
+
if (!sequenceWalletProvider) {
|
|
3906
|
+
throw new Error('Wallet has not been initialized, call sequence.initWallet(config) first.');
|
|
3848
3907
|
}
|
|
3849
|
-
return
|
|
3908
|
+
return sequenceWalletProvider;
|
|
3850
3909
|
};
|
|
3851
3910
|
|
|
3852
3911
|
exports.BaseInjectedTransport = BaseInjectedTransport;
|
|
3853
3912
|
exports.BaseProviderTransport = BaseProviderTransport;
|
|
3854
3913
|
exports.BaseWalletTransport = BaseWalletTransport;
|
|
3855
3914
|
exports.CHANNEL_ID = CHANNEL_ID;
|
|
3915
|
+
exports.DefaultChainIdTracker = DefaultChainIdTracker;
|
|
3856
3916
|
exports.DefaultProviderConfig = DefaultProviderConfig;
|
|
3857
3917
|
exports.ErrSignedInRequired = ErrSignedInRequired;
|
|
3858
3918
|
exports.EventType = EventType;
|
|
@@ -3860,8 +3920,7 @@ exports.ExtensionMessageHandler = ExtensionMessageHandler;
|
|
|
3860
3920
|
exports.ExtensionMessageProvider = ExtensionMessageProvider;
|
|
3861
3921
|
exports.InitState = InitState;
|
|
3862
3922
|
exports.LocalStorage = LocalStorage;
|
|
3863
|
-
exports.
|
|
3864
|
-
exports.LocalWeb3Provider = LocalWeb3Provider;
|
|
3923
|
+
exports.MemoryItemStore = MemoryItemStore;
|
|
3865
3924
|
exports.MuxMessageProvider = MuxMessageProvider;
|
|
3866
3925
|
exports.OpenState = OpenState;
|
|
3867
3926
|
exports.PROVIDER_OPEN_TIMEOUT = PROVIDER_OPEN_TIMEOUT;
|
|
@@ -3870,20 +3929,23 @@ exports.ProxyMessageChannel = ProxyMessageChannel;
|
|
|
3870
3929
|
exports.ProxyMessageChannelPort = ProxyMessageChannelPort;
|
|
3871
3930
|
exports.ProxyMessageHandler = ProxyMessageHandler;
|
|
3872
3931
|
exports.ProxyMessageProvider = ProxyMessageProvider;
|
|
3873
|
-
exports.
|
|
3932
|
+
exports.SequenceClient = SequenceClient;
|
|
3933
|
+
exports.SequenceClientSession = SequenceClientSession;
|
|
3934
|
+
exports.SequenceProvider = SequenceProvider;
|
|
3935
|
+
exports.SequenceSigner = SequenceSigner;
|
|
3936
|
+
exports.SingleNetworkSequenceProvider = SingleNetworkSequenceProvider;
|
|
3937
|
+
exports.SingleNetworkSequenceSigner = SingleNetworkSequenceSigner;
|
|
3874
3938
|
exports.UnrealMessageHandler = UnrealMessageHandler;
|
|
3875
3939
|
exports.UnrealMessageProvider = UnrealMessageProvider;
|
|
3876
|
-
exports.Wallet = Wallet;
|
|
3877
3940
|
exports.WalletRequestHandler = WalletRequestHandler;
|
|
3878
|
-
exports.Web3Provider = Web3Provider;
|
|
3879
|
-
exports.Web3Signer = Web3Signer;
|
|
3880
3941
|
exports.WindowMessageHandler = WindowMessageHandler;
|
|
3881
3942
|
exports.WindowMessageProvider = WindowMessageProvider;
|
|
3882
3943
|
exports.WindowSessionParams = WindowSessionParams;
|
|
3883
3944
|
exports.getWallet = getWallet;
|
|
3884
3945
|
exports.initWallet = initWallet;
|
|
3885
3946
|
exports.isBrowserExtension = isBrowserExtension;
|
|
3886
|
-
exports.
|
|
3947
|
+
exports.isMuxTransportTemplate = isMuxTransportTemplate;
|
|
3948
|
+
exports.isProviderTransport = isProviderTransport;
|
|
3887
3949
|
exports.isUnityPlugin = isUnityPlugin;
|
|
3888
3950
|
exports.isValidMessageSignature = isValidMessageSignature;
|
|
3889
3951
|
exports.isValidSignature = isValidSignature;
|
|
@@ -3892,5 +3954,7 @@ exports.isWalletUpToDate = isWalletUpToDate;
|
|
|
3892
3954
|
exports.messageToBytes = messageToBytes;
|
|
3893
3955
|
exports.nextMessageIdx = nextMessageIdx;
|
|
3894
3956
|
exports.prefixEIP191Message = prefixEIP191Message;
|
|
3957
|
+
exports.resolveArrayProperties = resolveArrayProperties;
|
|
3895
3958
|
exports.trimEIP191Prefix = trimEIP191Prefix;
|
|
3896
3959
|
exports.unregisterWallet = unregisterWallet;
|
|
3960
|
+
exports.useBestStore = useBestStore;
|