34
34
>
35
35
Cancel detection
36
36
</button >
37
+
38
+ <template v-if =" walletConnected " >
39
+ <br >
40
+ <button @click =" getAccounts" >
41
+ Get accounts
42
+ </button >
43
+ <button @click =" subscribeAccounts('subscribe', 'current')" >
44
+ Subscribe current
45
+ </button >
46
+ <button @click =" subscribeAccounts('unsubscribe', 'current')" >
47
+ Unsubscribe current
48
+ </button >
49
+ <button @click =" subscribeAccounts('subscribe', 'connected')" >
50
+ Subscribe connected
51
+ </button >
52
+ <button @click =" subscribeAccounts('unsubscribe', 'connected')" >
53
+ Unsubscribe connected
54
+ </button >
55
+
56
+ <div >
57
+ <div >RPC Accounts</div >
58
+ <div >{{ rpcAccounts.map((account) => account.address.slice(0, 8)).join(', ') }}</div >
59
+ </div >
60
+ </template >
61
+ </div >
62
+
63
+ <h2 >Ledger Hardware Wallet</h2 >
64
+ <div class =" group" >
65
+ <template v-if =" ledgerStatus " >
66
+ <div >
67
+ <div >Connection status</div >
68
+ <div >{{ ledgerStatus }}</div >
69
+ </div >
70
+ </template >
71
+ <button
72
+ v-else-if =" !ledgerAccountFactory"
73
+ @click =" connectLedger"
74
+ >
75
+ Connect
76
+ </button >
77
+ <template v-else >
78
+ <button @click =" disconnectLedger" >
79
+ Disconnect
80
+ </button >
81
+ <button @click =" addLedgerAccount" >
82
+ Add Account
83
+ </button >
84
+ <button
85
+ v-if =" ledgerAccounts.length > 1"
86
+ @click =" switchLedgerAccount"
87
+ >
88
+ Switch Account
89
+ </button >
90
+ <button @click =" switchNode" >
91
+ Switch Node
92
+ </button >
93
+ <div v-if =" ledgerAccounts.length" >
94
+ <div >Ledger Accounts</div >
95
+ <div >{{ ledgerAccounts.map((account) => account.address.slice(0, 8)).join(', ') }}</div >
96
+ </div >
97
+ </template >
37
98
</div >
38
99
39
100
<div class =" group" >
58
119
<script >
59
120
import {
60
121
walletDetector , BrowserWindowMessageConnection , RpcConnectionDenyError , RpcRejectedByUserError ,
122
+ WalletConnectorFrame , AccountLedgerFactory ,
61
123
} from ' @aeternity/aepp-sdk' ;
62
124
import { mapState } from ' vuex' ;
125
+ import TransportWebUSB from ' @ledgerhq/hw-transport-webusb' ;
63
126
64
127
export default {
65
128
data : () => ({
@@ -70,6 +133,10 @@ export default {
70
133
reverseIframeWalletUrl: process .env .VUE_APP_WALLET_URL ?? ` http://${ location .hostname } :9000` ,
71
134
walletInfo: null ,
72
135
cancelWalletDetection: null ,
136
+ rpcAccounts: [],
137
+ ledgerStatus: ' ' ,
138
+ ledgerAccountFactory: null ,
139
+ ledgerAccounts: [],
73
140
}),
74
141
computed: {
75
142
... mapState ([' aeSdk' ]),
@@ -79,6 +146,54 @@ export default {
79
146
},
80
147
},
81
148
methods: {
149
+ async connectLedger () {
150
+ try {
151
+ this .ledgerStatus = ' Waiting for Ledger response' ;
152
+ const transport = await TransportWebUSB .create ();
153
+ this .ledgerAccountFactory = new AccountLedgerFactory (transport);
154
+ } catch (error) {
155
+ if (error .name === ' TransportOpenUserCancelled' ) return ;
156
+ throw error;
157
+ } finally {
158
+ this .ledgerStatus = ' ' ;
159
+ }
160
+ },
161
+ async disconnectLedger () {
162
+ this .ledgerAccountFactory = null ;
163
+ this .ledgerAccounts = [];
164
+ this .$store .commit (' setAddress' , undefined );
165
+ if (Object .keys (this .aeSdk .accounts ).length ) this .aeSdk .removeAccount (this .aeSdk .address );
166
+ },
167
+ async addLedgerAccount () {
168
+ try {
169
+ this .ledgerStatus = ' Waiting for Ledger response' ;
170
+ const idx = this .ledgerAccounts .length ;
171
+ const account = await this .ledgerAccountFactory .initialize (idx);
172
+ this .ledgerStatus = ` Ensure that ${ account .address } is displayed on Ledger HW screen` ;
173
+ await this .ledgerAccountFactory .getAddress (idx, true );
174
+ this .ledgerAccounts .push (account);
175
+ this .setAccount (this .ledgerAccounts [0 ]);
176
+ } catch (error) {
177
+ if (error .statusCode === 0x6985 ) return ;
178
+ throw error;
179
+ } finally {
180
+ this .ledgerStatus = ' ' ;
181
+ }
182
+ },
183
+ switchLedgerAccount () {
184
+ this .ledgerAccounts .push (this .ledgerAccounts .shift ());
185
+ this .setAccount (this .ledgerAccounts [0 ]);
186
+ },
187
+ async switchNode () {
188
+ await this .setNode (this .$store .state .networkId === ' ae_mainnet' ? ' ae_uat' : ' ae_mainnet' );
189
+ },
190
+ async getAccounts () {
191
+ this .rpcAccounts = await this .walletConnector .getAccounts ();
192
+ if (this .rpcAccounts .length ) this .setAccount (this .rpcAccounts [0 ]);
193
+ },
194
+ async subscribeAccounts (type , value ) {
195
+ await this .walletConnector .subscribeAccounts (type, value);
196
+ },
82
197
async detectWallets () {
83
198
if (this .connectMethod === ' reverse-iframe' ) {
84
199
this .reverseIframe = document .createElement (' iframe' );
@@ -93,6 +208,7 @@ export default {
93
208
stopDetection ();
94
209
resolve (newWallet .getConnection ());
95
210
this .cancelWalletDetection = null ;
211
+ this .walletInfo = newWallet .info ;
96
212
}
97
213
});
98
214
this .cancelWalletDetection = () => {
@@ -103,25 +219,43 @@ export default {
103
219
};
104
220
});
105
221
},
222
+ async setNode (networkId ) {
223
+ const [{ name }] = (await this .aeSdk .getNodesInPool ())
224
+ .filter ((node ) => node .nodeNetworkId === networkId);
225
+ this .aeSdk .selectNode (name);
226
+ this .$store .commit (' setNetworkId' , networkId);
227
+ },
228
+ setAccount (account ) {
229
+ if (Object .keys (this .aeSdk .accounts ).length ) this .aeSdk .removeAccount (this .aeSdk .address );
230
+ this .aeSdk .addAccount (account, { select: true });
231
+ this .$store .commit (' setAddress' , account .address );
232
+ },
106
233
async connect () {
107
234
this .walletConnecting = true ;
108
- this .aeSdk .onDisconnect = () => {
109
- this .walletConnected = false ;
110
- this .walletInfo = null ;
111
- this .$store .commit (' setAddress' , undefined );
112
- if (this .reverseIframe ) this .reverseIframe .remove ();
113
- };
114
235
try {
115
236
const connection = await this .detectWallets ();
116
237
try {
117
- this .walletInfo = await this . aeSdk . connectToWallet ( connection);
238
+ this .walletConnector = await WalletConnectorFrame . connect ( ' Simple æpp ' , connection);
118
239
} catch (error) {
119
240
if (error instanceof RpcConnectionDenyError) connection .disconnect ();
120
241
throw error;
121
242
}
243
+ this .walletConnector .on (' disconnect' , () => {
244
+ this .walletConnected = false ;
245
+ this .walletInfo = null ;
246
+ this .rpcAccounts = [];
247
+ this .$store .commit (' setAddress' , undefined );
248
+ if (this .reverseIframe ) this .reverseIframe .remove ();
249
+ });
122
250
this .walletConnected = true ;
123
- const { address: { current } } = await this .aeSdk .subscribeAddress (' subscribe' , ' connected' );
124
- this .$store .commit (' setAddress' , Object .keys (current)[0 ]);
251
+
252
+ this .setNode (this .walletConnector .networkId );
253
+ this .walletConnector .on (' networkIdChange' , (networkId ) => this .setNode (networkId));
254
+
255
+ this .walletConnector .on (' accountsChange' , (accounts ) => {
256
+ this .rpcAccounts = accounts;
257
+ if (accounts .length ) this .setAccount (accounts[0 ]);
258
+ });
125
259
} catch (error) {
126
260
if (
127
261
error .message === ' Wallet detection cancelled'
@@ -134,7 +268,7 @@ export default {
134
268
}
135
269
},
136
270
disconnect () {
137
- this .aeSdk . disconnectWallet ();
271
+ this .walletConnector . disconnect ();
138
272
},
139
273
},
140
274
};
0 commit comments