|
1 | 1 | <template> |
2 | | - <div class="group"> |
3 | | - <div> |
4 | | - <label> |
5 | | - <input v-model="connectMethod" type="radio" value="default" /> |
6 | | - Iframe or WebExtension |
7 | | - </label> |
8 | | - </div> |
9 | | - <div> |
10 | | - <label> |
11 | | - <input v-model="connectMethod" type="radio" value="reverse-iframe" /> |
12 | | - Reverse iframe |
13 | | - </label> |
14 | | - <div><input v-model="reverseIframeWalletUrl" /></div> |
15 | | - </div> |
16 | | - |
17 | | - <button v-if="walletConnected" @click="disconnect">Disconnect</button> |
18 | | - <button v-else-if="connectMethod" :disabled="walletConnecting" @click="connect">Connect</button> |
19 | | - |
20 | | - <button v-if="cancelWalletDetection" @click="cancelWalletDetection">Cancel detection</button> |
21 | | - |
22 | | - <template v-if="walletConnected"> |
23 | | - <br /> |
24 | | - <button @click="getAccounts">Get accounts</button> |
25 | | - <button @click="subscribeAccounts('subscribe', 'current')">Subscribe current</button> |
26 | | - <button @click="subscribeAccounts('unsubscribe', 'current')">Unsubscribe current</button> |
27 | | - <button @click="subscribeAccounts('subscribe', 'connected')">Subscribe connected</button> |
28 | | - <button @click="subscribeAccounts('unsubscribe', 'connected')">Unsubscribe connected</button> |
29 | | - |
30 | | - <div> |
31 | | - <div>RPC Accounts</div> |
32 | | - <div>{{ rpcAccounts.map((account) => account.address.slice(0, 8)).join(', ') }}</div> |
33 | | - </div> |
34 | | - </template> |
35 | | - </div> |
36 | | - |
37 | | - <SelectNetwork :select="(network) => this.walletConnector.askToSelectNetwork(network)" /> |
38 | | - |
39 | | - <h2>Ledger Hardware Wallet</h2> |
40 | | - <div class="group"> |
41 | | - <template v-if="ledgerStatus"> |
42 | | - <div> |
43 | | - <div>Connection status</div> |
44 | | - <div>{{ ledgerStatus }}</div> |
45 | | - </div> |
46 | | - </template> |
47 | | - <button v-else-if="!ledgerAccountFactory" @click="connectLedger">Connect</button> |
48 | | - <template v-else> |
49 | | - <button @click="disconnectLedger">Disconnect</button> |
50 | | - <button @click="addLedgerAccount">Add Account</button> |
51 | | - <button v-if="ledgerAccounts.length > 1" @click="switchLedgerAccount">Switch Account</button> |
52 | | - <button @click="switchNode">Switch Node</button> |
53 | | - <div v-if="ledgerAccounts.length"> |
54 | | - <div>Ledger Accounts</div> |
55 | | - <div>{{ ledgerAccounts.map((account) => account.address.slice(0, 8)).join(', ') }}</div> |
56 | | - </div> |
57 | | - </template> |
| 2 | + <div class="nav"> |
| 3 | + <a href="#" :class="{ active: view === 'Frame' }" @click="view = 'Frame'">Frame</a> |
| 4 | + <a href="#" :class="{ active: view === 'Ledger' }" @click="view = 'Ledger'">Ledger HW</a> |
| 5 | + <a href="#" :class="{ active: view === 'Metamask' }" @click="view = 'Metamask'">MetaMask</a> |
58 | 6 | </div> |
59 | 7 |
|
60 | | - <div class="group"> |
61 | | - <div> |
62 | | - <div>SDK status</div> |
63 | | - <div> |
64 | | - {{ |
65 | | - (walletConnected && 'Wallet connected') || |
66 | | - (cancelWalletDetection && 'Wallet detection') || |
67 | | - (walletConnecting && 'Wallet connecting') || |
68 | | - 'Ready to connect to wallet' |
69 | | - }} |
70 | | - </div> |
71 | | - </div> |
72 | | - <div> |
73 | | - <div>Wallet name</div> |
74 | | - <div>{{ walletName }}</div> |
75 | | - </div> |
76 | | - </div> |
| 8 | + <Component v-if="view" :is="view" /> |
77 | 9 | </template> |
78 | 10 |
|
79 | 11 | <script> |
80 | | -import { |
81 | | - walletDetector, |
82 | | - BrowserWindowMessageConnection, |
83 | | - RpcConnectionDenyError, |
84 | | - RpcRejectedByUserError, |
85 | | - WalletConnectorFrame, |
86 | | - AccountLedgerFactory, |
87 | | -} from '@aeternity/aepp-sdk'; |
88 | | -import { mapState } from 'vuex'; |
89 | | -import TransportWebUSB from '@ledgerhq/hw-transport-webusb'; |
90 | | -import SelectNetwork from './components/SelectNetwork.vue'; |
| 12 | +import Frame from './components/ConnectFrame.vue'; |
| 13 | +import Ledger from './components/ConnectLedger.vue'; |
| 14 | +import Metamask from './components/ConnectMetamask.vue'; |
91 | 15 |
|
92 | 16 | export default { |
93 | | - components: { SelectNetwork }, |
94 | | - data: () => ({ |
95 | | - connectMethod: 'default', |
96 | | - walletConnected: false, |
97 | | - walletConnecting: null, |
98 | | - reverseIframe: null, |
99 | | - reverseIframeWalletUrl: process.env.VUE_APP_WALLET_URL ?? `http://${location.hostname}:9000`, |
100 | | - walletInfo: null, |
101 | | - cancelWalletDetection: null, |
102 | | - rpcAccounts: [], |
103 | | - ledgerStatus: '', |
104 | | - ledgerAccountFactory: null, |
105 | | - ledgerAccounts: [], |
106 | | - }), |
107 | | - computed: { |
108 | | - ...mapState(['aeSdk']), |
109 | | - walletName() { |
110 | | - if (!this.walletConnected) return 'Wallet is not connected'; |
111 | | - return this.walletInfo.name; |
112 | | - }, |
113 | | - }, |
114 | | - methods: { |
115 | | - async connectLedger() { |
116 | | - try { |
117 | | - this.ledgerStatus = 'Waiting for Ledger response'; |
118 | | - const transport = await TransportWebUSB.create(); |
119 | | - this.ledgerAccountFactory = new AccountLedgerFactory(transport); |
120 | | - } catch (error) { |
121 | | - if (error.name === 'TransportOpenUserCancelled') return; |
122 | | - throw error; |
123 | | - } finally { |
124 | | - this.ledgerStatus = ''; |
125 | | - } |
126 | | - }, |
127 | | - async disconnectLedger() { |
128 | | - this.ledgerAccountFactory = null; |
129 | | - this.ledgerAccounts = []; |
130 | | - this.$store.commit('setAddress', undefined); |
131 | | - if (Object.keys(this.aeSdk.accounts).length) this.aeSdk.removeAccount(this.aeSdk.address); |
132 | | - }, |
133 | | - async addLedgerAccount() { |
134 | | - try { |
135 | | - this.ledgerStatus = 'Waiting for Ledger response'; |
136 | | - const idx = this.ledgerAccounts.length; |
137 | | - const account = await this.ledgerAccountFactory.initialize(idx); |
138 | | - this.ledgerStatus = `Ensure that ${account.address} is displayed on Ledger HW screen`; |
139 | | - await this.ledgerAccountFactory.getAddress(idx, true); |
140 | | - this.ledgerAccounts.push(account); |
141 | | - this.setAccount(this.ledgerAccounts[0]); |
142 | | - } catch (error) { |
143 | | - if (error.statusCode === 0x6985) return; |
144 | | - throw error; |
145 | | - } finally { |
146 | | - this.ledgerStatus = ''; |
147 | | - } |
148 | | - }, |
149 | | - switchLedgerAccount() { |
150 | | - this.ledgerAccounts.push(this.ledgerAccounts.shift()); |
151 | | - this.setAccount(this.ledgerAccounts[0]); |
152 | | - }, |
153 | | - async switchNode() { |
154 | | - await this.setNode(this.$store.state.networkId === 'ae_mainnet' ? 'ae_uat' : 'ae_mainnet'); |
155 | | - }, |
156 | | - async getAccounts() { |
157 | | - this.rpcAccounts = await this.walletConnector.getAccounts(); |
158 | | - if (this.rpcAccounts.length) this.setAccount(this.rpcAccounts[0]); |
159 | | - }, |
160 | | - async subscribeAccounts(type, value) { |
161 | | - await this.walletConnector.subscribeAccounts(type, value); |
162 | | - }, |
163 | | - async detectWallets() { |
164 | | - if (this.connectMethod === 'reverse-iframe') { |
165 | | - this.reverseIframe = document.createElement('iframe'); |
166 | | - this.reverseIframe.src = this.reverseIframeWalletUrl; |
167 | | - this.reverseIframe.style.display = 'none'; |
168 | | - document.body.appendChild(this.reverseIframe); |
169 | | - } |
170 | | - const connection = new BrowserWindowMessageConnection(); |
171 | | - return new Promise((resolve, reject) => { |
172 | | - const stopDetection = walletDetector(connection, async ({ newWallet }) => { |
173 | | - if ( |
174 | | - confirm( |
175 | | - `Do you want to connect to wallet ${newWallet.info.name} with id ${newWallet.info.id}`, |
176 | | - ) |
177 | | - ) { |
178 | | - stopDetection(); |
179 | | - resolve(newWallet.getConnection()); |
180 | | - this.cancelWalletDetection = null; |
181 | | - this.walletInfo = newWallet.info; |
182 | | - } |
183 | | - }); |
184 | | - this.cancelWalletDetection = () => { |
185 | | - reject(new Error('Wallet detection cancelled')); |
186 | | - stopDetection(); |
187 | | - this.cancelWalletDetection = null; |
188 | | - if (this.reverseIframe) this.reverseIframe.remove(); |
189 | | - }; |
190 | | - }); |
191 | | - }, |
192 | | - async setNode(networkId) { |
193 | | - const [{ name }] = (await this.aeSdk.getNodesInPool()).filter( |
194 | | - (node) => node.nodeNetworkId === networkId, |
195 | | - ); |
196 | | - this.aeSdk.selectNode(name); |
197 | | - this.$store.commit('setNetworkId', networkId); |
198 | | - }, |
199 | | - setAccount(account) { |
200 | | - if (Object.keys(this.aeSdk.accounts).length) this.aeSdk.removeAccount(this.aeSdk.address); |
201 | | - this.aeSdk.addAccount(account, { select: true }); |
202 | | - this.$store.commit('setAddress', account.address); |
203 | | - }, |
204 | | - async connect() { |
205 | | - this.walletConnecting = true; |
206 | | - try { |
207 | | - const connection = await this.detectWallets(); |
208 | | - try { |
209 | | - this.walletConnector = await WalletConnectorFrame.connect('Simple æpp', connection); |
210 | | - } catch (error) { |
211 | | - if (error instanceof RpcConnectionDenyError) connection.disconnect(); |
212 | | - throw error; |
213 | | - } |
214 | | - this.walletConnector.on('disconnect', () => { |
215 | | - this.walletConnected = false; |
216 | | - this.walletInfo = null; |
217 | | - this.rpcAccounts = []; |
218 | | - this.$store.commit('setAddress', undefined); |
219 | | - if (this.reverseIframe) this.reverseIframe.remove(); |
220 | | - }); |
221 | | - this.walletConnected = true; |
222 | | -
|
223 | | - this.setNode(this.walletConnector.networkId); |
224 | | - this.walletConnector.on('networkIdChange', (networkId) => this.setNode(networkId)); |
225 | | -
|
226 | | - this.walletConnector.on('accountsChange', (accounts) => { |
227 | | - this.rpcAccounts = accounts; |
228 | | - if (accounts.length) this.setAccount(accounts[0]); |
229 | | - }); |
230 | | - } catch (error) { |
231 | | - if ( |
232 | | - error.message === 'Wallet detection cancelled' || |
233 | | - error instanceof RpcConnectionDenyError || |
234 | | - error instanceof RpcRejectedByUserError |
235 | | - ) |
236 | | - return; |
237 | | - throw error; |
238 | | - } finally { |
239 | | - this.walletConnecting = false; |
240 | | - } |
241 | | - }, |
242 | | - disconnect() { |
243 | | - this.walletConnector.disconnect(); |
244 | | - }, |
245 | | - }, |
| 17 | + components: { Frame, Ledger, Metamask }, |
| 18 | + data: () => ({ view: 'Frame' }), |
246 | 19 | }; |
247 | 20 | </script> |
0 commit comments