}
}
}
- async function createWallet (elm, type) {
- const label = elm.firstElementChild
+
+ async function updateWallet () {
+ const wallet = document.getElementById('wallet').value
+ if (wallet !== '_new' && wallet !== '_import' && wallet !== '_ledger') {
+ return await updateAccount()
+ }
+ if (wallet === '_ledger') {
+ return await LedgerWallet.create()
+ }
+ const form = document.getElementById('wallet-form')
+ const walletType = document.getElementById('wallet-form-wallet-type')
+ const importType = document.getElementById('wallet-form-import-type')
+ const importValue = document.getElementById('wallet-form-import-value')
+ const salt = document.getElementById('wallet-form-salt')
+ walletType.querySelector('x-radios').value = null
+ importType.querySelector('x-select').value = null
+ importValue.querySelector('x-input').value = null
+ salt.querySelector('x-input').value = null
+ if (wallet.value === '_new') {
+ importType.classList.add('hide')
+ importValue.classList.add('hide')
+ salt.classList.remove('hide')
+ }
+ if (wallet.value === '_import') {
+ importType.classList.remove('hide')
+ importValue.classList.remove('hide')
+ salt.classList.add('hide')
+ }
+ return await form.showModal()
+ }
+
+ function spinner (btn) {
+ const label = btn.firstElementChild
const spinner = document.createElement('x-throbber')
spinner.size = 'small'
spinner.style.width = `${label.scrollWidth}px`
- elm.replaceChildren(spinner)
+ btn.replaceChildren(spinner)
+ // at some point then...
+ // btn.replaceChildren(label)
+ }
+
+ async function createWallet () {
+ const walletSelect = document.getElementById('wallet')
+ const form = document.getElementById('wallet-form')
+ const name = form.querySelector('#wallet-form-name x-input').value
+ if (name === '_new' || name === '_import' || name === '_ledger') {
+ walletSelect.value = null
+ notify.warn(`Invalid wallet name "${name}".`)
+ return
+ }
+ const type = form.querySelector('#wallet-form-wallet-type x-radios').value
const walletType = getWalletType(type)
+ const salt = form.querySelector('#wallet-form-salt x-input')?.value
+ const password = form.querySelector('#wallet-form-password x-input')?.value
+ if (!password) {
+ walletSelect.value = null
+ notify.error('Password is required')
+ return
+ }
let wallet
try {
- wallet = await walletType.create('password')
+ wallet = await walletType.create(password, salt)
const walletData = {
id: wallet.id,
+ name: name || wallet.id,
type
}
- addToStorage(`wallets`, JSON.stringify(walletData))
+ await addToStorage(`wallets`, JSON.stringify(walletData))
+
+ const menu = document.querySelector('#wallet > x-menu')
+ const menuitem = document.createElement('x-menuitem')
+ menuitem.value = walletData.id
+ if (menu.childElementCount >= 0) {
+ menu.appendChild(menuitem)
+ }
+ const label = document.createElement('x-label')
+ label.innerText = walletData.name
+ menuitem.appendChild(label)
+ walletSelect.value = walletData.id
} catch (err) {
+ label?.remove()
+ menuitem?.remove()
+ walletSelect.value = null
notify.error(err.msg)
} finally {
- elm.replaceChildren(label)
+ await form.close()
return wallet
}
}
+
function addToStorage (key, value) {
if (typeof value !== 'string') {
throw new TypeError(`Cannot add ${typeof value} to storage`)
throw new TypeError(`Storage item is not an array`)
}
item.push(value)
- sessionStorage.setItem(key, JSON.stringify(item))
+ return new Promise((resolve, reject) => {
+ try {
+ sessionStorage.setItem(key, JSON.stringify(item))
+ resolve()
+ } catch (err) {
+ console.error(err)
+ reject(err)
+ }
+ })
+ }
+ function updateWalletForm () {
+ const form = document.getElementById('wallet-form')
+ const walletTypeContainer = document.getElementById('wallet-form-wallet-type')
+ const walletType = walletTypeContainer.firstChild
+ const importTypeContainer = document.getElementById('wallet-form-import-type')
+ const importType = importTypeContainer.firstChild
+ const saltContainer = document.getElementById('wallet-form-salt')
+ if (walletType.value === 'bip44' && importType.value === 'mnemonic') {
+ saltContainer.classList.remove('hide')
+ } else {
+ saltContainer.classList.add('hide')
+ }
+ document.querySelector('#wallet-form-import-value x-label').innerText = importType.value
}
async function showWallets () {
const card = document.getElementById('walletCard')
for (const walletData of storedWalletData) {
const w = JSON.parse(walletData)
console.dir(w)
- if (w.id && w.type) {
+ if (w.id && w.name && w.type) {
const walletType = getWalletType(w.type)
wallets.push(await walletType.restore(w.id))
}
for (const wallet of wallets) {
const walletElement = document.createElement('x-label')
await wallet.unlock('password')
- walletElement.innerText = wallet.mnemonic
+ walletElement.innerText = `${wallet.name}: ${wallet.mnemonic}`
await wallet.lock('password')
walletElements.push(walletElement)
}
card.replaceChildren(...walletElements)
}
+
+ async function deriveAccounts () {
+ const wallet = document.querySelector('#wallet').value
+ const form = btn.querySelector('#account-form')
+ await console.log('deriveAccounts')
+ }
async function clearStorage () {
sessionStorage.clear()
notify.info(`Session storage cleared`)
<meta name="xel-theme" content="https://unpkg.com/xel@latest/themes/adwaita-dark.css" />
<meta name="xel-accent-color" content="blue" />
<meta name="xel-icons" content="https://unpkg.com/bootstrap-icons@latest/bootstrap-icons.svg" />
- <link rel="preload" as="image" href="https://unpkg.com/bootstrap-icons@latest/bootstrap-icons.svg" />
-
<style>
body {
background-color: slategrey;
.page.show {
display: initial;
}
+ h1 {
+ text-align: center;
+ }
+ dialog {
+ padding: 1rem !important;
+ }
+ dialog .hide {
+ display: none;
+ }
nav {
align-items: flex-end;
bottom: 0;
<header>
<x-box id="notifications"></x-box>
<x-box id="wallets">
- <x-select>
- <x-icon href="#wallet2"></x-icon>
+ <x-select id="wallet" style="width:100%;" onchange="updateWallet()">
<x-menu>
- <x-menuitem value="new">
- <x-button>
- <x-label>New Wallet</x-label>
- <dialog>
- <x-input type="text">Name</x-input>
- <x-radios>
- <x-label>Type</x-label>
- <x-radio value="bip44" toggled><x-label>BIP-44</x-label></x-radio>
- <x-radio value="blake2b"><x-label>BLAKE2b</x-label></x-radio>
- </x-radios>
- <x-input type="password" required="true">Password</x-input>
- <x-button
- onclick="createWallet(this, this.closest('dialog').querySelector('x-radios').value).then(w => { console.log(w);showWallets() })"></x-button>
- </dialog>
- </x-button>
+ <x-menuitem value="_new">
+ <x-label>New</x-label>
+ </x-menuitem>
+ <x-menuitem value="_import">
+ <x-label>Import</x-label>
</x-menuitem>
- <x-menuitem value="import">
- <x-label>Import Wallet</x-label>
- <dialog>
- </dialog>
+ <hr />
+ <x-menuitem value="_ledger">
+ <x-label>Ledger</x-label>
</x-menuitem>
- <hr>
+ <hr />
</x-menu>
</x-select>
+ <dialog id="wallet-form">
+ <x-box vertical>
+ <x-box id="wallet-form-name">
+ <x-label>Name</x-label>
+ <x-input type="text"></x-input>
+ </x-box>
+ <x-box id="wallet-form-wallet-type">
+ <x-radios required onchange="updateWalletForm()">
+ <x-radio value="bip44"><x-label>BIP-44</x-label></x-radio>
+ <x-radio value="blake2b"><x-label>BLAKE2b</x-label></x-radio>
+ </x-radios>
+ </x-box>
+ <x-box id="wallet-form-import-type" class="hide">
+ <x-select onchange="updateWalletForm()">
+ <x-menu>
+ <x-menuitem value="mnemonic"><x-label>Import mnemonic</x-label></x-menuitem>
+ <x-menuitem value="seed"><x-label>Import seed</x-label></x-menuitem>
+ </x-menu>
+ </x-select>
+ </x-box>
+ <x-box id="wallet-form-import-value" class="hide">
+ <x-label style="text-transform:capitalize"></x-label>
+ <x-input type="password"></x-input>
+ </x-box>
+ <x-box id="wallet-form-salt" class="hide">
+ <x-label>Salt</x-label>
+ <x-input type="password">Optional</x-input>
+ </x-box>
+ <x-box id="wallet-form-password">
+ <x-label>Lock</x-label>
+ <x-input type="password" required><x-label>Password</x-label></x-input>
+ </x-box>
+ <x-box>
+ <x-buttons>
+ <x-button onclick="document.getElementById('wallet-form').close()">
+ Cancel
+ </x-button>
+ <x-button onclick="createWallet().then(w => { console.log(w);showWallets() })">
+ OK
+ </x-button>
+ </x-buttons>
+ </x-box>
+ </x-box>
+ </dialog>
</x-box><!-- end #wallets-->
<x-box id="accounts">
- <x-select>
- <x-icon href="#cash-stack"></x-icon>
+ <x-select id="account" style="width:100%;" onchange="updateAccount()">
<x-menu>
- <x-menuitem value="new">
- <x-label>New Account</x-label>
+ <x-menuitem value="_new">
+ <x-label>New</x-label>
</x-menuitem>
- <x-menuitem value="import">
- <x-label>Derive</x-label>
- <dialog>
- </dialog>
+ <x-menuitem value="_import">
+ <x-label>Import</x-label>
</x-menuitem>
- <hr>
+ <hr />
</x-menu>
</x-select>
+ <x-button>
+ <x-icon href="#cash-stack"></x-icon>
+ <x-label>New Account</x-label>
+ <dialog id="account-form">
+ <x-box vertical>
+ <x-box>
+ <x-label>Name</x-label>
+ <x-input type="text"></x-input>
+ </x-box>
+ <x-box>
+ <x-label>Index (optional)</x-label>
+ <x-numberinput min="0" max="2147483647"></x-numberinput>
+ </x-box>
+ <x-buttons>
+ <x-button onclick="document.getElementById('account-form').close()">
+ Cancel
+ </x-button>
+ <x-button onclick="deriveAccounts(this).then(w => { console.log(w);showWallets() })">
+ OK
+ </x-button>
+ </x-buttons>
+ </x-box>
+ </dialog>
+ </x-button>
</x-box><!-- end #accounts -->
</header>
<main>
<x-box id="exchange" class="page">
- Exchange
+ <h1>Exchange</h1>
</x-box><!-- end #exchange -->
<x-box id="history" class="page">
- History
+ <h1>History</h1>
</x-box><!-- end #history -->
<x-box id="transact" class="page">
- Transact
+ <h1>Transact</h1>
<x-card id="walletCard">
</x-card>
</x-box><!-- end #transact -->
<x-box id="rolodex" class="page">
- Rolodex
+ <h1>Rolodex</h1>
</x-box><!-- end #rolodex -->
<x-box id="settings" class="page">
<h1>Settings</h1>