feat: Add Bitcoin support, BTC chips, and improve UX
Some checks failed
Workflow push to Dappbundle / Build (push) Has been cancelled

- Implement Bitcoin address generation (Bech32) and WIF display.
- Add BTC chips to searched addresses list.
- Add input validation: reject FLO/BTC addresses with clear intent messages.
- Update search placeholder and errors to use 'MNT'.
- Fix desktop notification panel positioning.
This commit is contained in:
void-57 2026-01-24 04:19:30 +05:30
parent 72351dd5b8
commit 6be4402f6f

View File

@ -468,9 +468,10 @@
const apply = () => {
if (window.matchMedia('(min-width: 640px)').matches) {
Object.assign(panel.style, {
left: 'calc(10rem + 1rem)',
bottom: '1rem',
top: 'auto',
// Desktop: top-right to avoid overlapping "Searched addresses" (which is left-side)
left: 'auto',
bottom: 'auto',
top: '1rem',
right: '1rem',
zIndex: '1000'
});
@ -663,7 +664,7 @@
</h2>
<sm-form oninvalid="handleInvalidSearch()">
<div id="input_wrapper">
<sm-input id="check_balance_input" class="password-field flex-1" placeholder="Address, private key, or tx hash"
<sm-input id="check_balance_input" class="password-field flex-1" placeholder="MNT Address, private key, or tx hash"
type="password" animate>
<svg class="icon" slot="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <g> <rect fill="none" height="24" width="24"></rect> </g> <g> <path d="M21,10h-8.35C11.83,7.67,9.61,6,7,6c-3.31,0-6,2.69-6,6s2.69,6,6,6c2.61,0,4.83-1.67,5.65-4H13l2,2l2-2l2,2l4-4.04L21,10z M7,15c-1.65,0-3-1.35-3-3c0-1.65,1.35-3,3-3s3,1.35,3,3C10,13.65,8.65,15,7,15z"> </path> </g> </svg>
<label slot="right" class="interact">
@ -734,13 +735,14 @@
}
const renderedContacts = []
for (const floAddress in contacts) {
const { ethAddress } = contacts[floAddress]
const { ethAddress, btcAddress } = contacts[floAddress]
renderedContacts.push(html`
<li class="contact" .dataset=${{ floAddress, ethAddress }}>
<li class="contact" .dataset=${{ floAddress, ethAddress, btcAddress }}>
${floAddress === ethAddress ? html`
`: html`
<sm-chips onchange=${e => e.target.closest('.contact').querySelector('sm-copy').value = e.target.value}>
<sm-chip value=${floAddress} selected>FLO</sm-chip>
${btcAddress ? html`<sm-chip value=${btcAddress}>BTC</sm-chip>` : ''}
<sm-chip value=${ethAddress}>MNT</sm-chip>
</sm-chips>
`}
@ -777,6 +779,19 @@
}
// The search bar is versatile: it accepts addresses, private keys, or transaction hashes.
// Reject FLO addresses (start with F)
if (/^F[a-km-zA-HJ-NP-Z1-9]{26,34}$/.test(keyToConvert)) {
notify('FLO addresses are not supported. Please use a MNT address or private key.', 'error');
return;
}
// Reject BTC addresses (legacy: 1/3, segwit: bc1)
if (/^(1|3)[a-km-zA-HJ-NP-Z1-9]{25,34}$/.test(keyToConvert) || /^bc1[a-z0-9]{39,59}$/i.test(keyToConvert)) {
notify('BTC addresses are not supported. Please use a MNT address or private key.', 'error');
return;
}
if (ethOperator.isValidAddress(keyToConvert)) {
ethAddress = keyToConvert
}
@ -787,12 +802,37 @@
// Otherwise, try to convert as private key
else {
try {
let isHex = false;
let btcAddress;
if (/^[0-9a-fA-F]{64}$/.test(keyToConvert)) {
keyToConvert = coinjs.privkey2wif(keyToConvert)
isHex = true;
}
const ethPrivateKey = coinjs.wif2privkey(keyToConvert).privkey;
ethAddress = floEthereum.ethAddressFromPrivateKey(ethPrivateKey)
if (!isHex) {
floAddress = floCrypto.getFloID(keyToConvert)
try {
btcAddress = btcOperator.bech32Address(keyToConvert)
} catch (e) { console.error(e) }
}
// Save to indexed DB
compactIDB.readData('contacts', floAddress || ethAddress).then(result => {
if (result) return
compactIDB.addData('contacts', {
ethAddress,
btcAddress
}, floAddress || ethAddress).then(() => {
renderSearchedAddressList()
}).catch((error) => {
console.error(error)
})
})
} catch (error) {
notify('Invalid input. Please enter a valid Ethereum address or private key.', 'error');
return;
@ -1962,8 +2002,24 @@
const { floID, privKey } = floCrypto.generateNewID();
const ethPrivateKey = coinjs.wif2privkey(privKey).privkey;
const ethAddress = floEthereum.ethAddressFromPrivateKey(ethPrivateKey)
// Bitcoin support
const btcBech32 = btcOperator.bech32Address(privKey);
// Convert to Bitcoin WIF format
const btcPrivKey = btcOperator.convert.wif(privKey);
renderElem(getRef('created_address_wrapper'), html`
<ul id="generated_addresses" class="grid gap-1-5">
<li class="grid gap-0-5">
<div>
<h5>Bitcoin Address</h5>
<sm-copy value="${btcBech32}"></sm-copy>
</div>
<div>
<h5>Private Key</h5>
<sm-copy value="${btcPrivKey}"></sm-copy>
</div>
</li>
<li class="grid gap-0-5">
<div>
<h5>FLO Address</h5>