Added address creation and conversion
This commit is contained in:
parent
0cdd912f6f
commit
6214a64a08
43
css/main.css
43
css/main.css
@ -769,6 +769,44 @@ main {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
#flo_id_warning {
|
||||
padding-bottom: 1.5rem;
|
||||
border-bottom: thin solid rgba(var(--text-color), 0.3);
|
||||
}
|
||||
#flo_id_warning .icon {
|
||||
height: 4rem;
|
||||
width: 4rem;
|
||||
padding: 1rem;
|
||||
background-color: #ffc107;
|
||||
border-radius: 3rem;
|
||||
fill: rgba(0, 0, 0, 0.8);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.generated-id-card {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
}
|
||||
.generated-id-card h5 {
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
#convert_to_taproot_popup::part(popup) {
|
||||
view-transition-name: popup;
|
||||
}
|
||||
#convert_to_taproot_popup::part(popup-header) {
|
||||
view-transition-name: popup-header;
|
||||
}
|
||||
#convert_to_taproot_popup::part(popup-body) {
|
||||
view-transition-name: popup-body;
|
||||
}
|
||||
|
||||
::view-transition-old(popup),
|
||||
::view-transition-new(popup) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#transaction_result {
|
||||
display: grid;
|
||||
gap: 1.5rem;
|
||||
@ -861,8 +899,9 @@ main {
|
||||
.popup__header {
|
||||
padding: 1rem 1.5rem 0 1.5rem;
|
||||
}
|
||||
#page_header {
|
||||
padding: 1.5rem 0;
|
||||
#generate_address_popup,
|
||||
#convert_to_taproot_popup {
|
||||
--width: 28rem;
|
||||
}
|
||||
main sm-form::part(form) {
|
||||
gap: 0.5rem;
|
||||
|
||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -716,6 +716,42 @@ main {
|
||||
gap: 1.5rem;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
#flo_id_warning {
|
||||
padding-bottom: 1.5rem;
|
||||
border-bottom: thin solid rgba(var(--text-color), 0.3);
|
||||
.icon {
|
||||
height: 4rem;
|
||||
width: 4rem;
|
||||
padding: 1rem;
|
||||
background-color: #ffc107;
|
||||
border-radius: 3rem;
|
||||
fill: rgba(0, 0, 0, 0.8);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
}
|
||||
.generated-id-card {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
h5 {
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
}
|
||||
#convert_to_taproot_popup {
|
||||
&::part(popup) {
|
||||
view-transition-name: popup;
|
||||
}
|
||||
&::part(popup-header) {
|
||||
view-transition-name: popup-header;
|
||||
}
|
||||
&::part(popup-body) {
|
||||
view-transition-name: popup-body;
|
||||
}
|
||||
}
|
||||
::view-transition-old(popup),
|
||||
::view-transition-new(popup) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
#transaction_result {
|
||||
display: grid;
|
||||
gap: 1.5rem;
|
||||
@ -786,8 +822,9 @@ main {
|
||||
.popup__header {
|
||||
padding: 1rem 1.5rem 0 1.5rem;
|
||||
}
|
||||
#page_header {
|
||||
padding: 1.5rem 0;
|
||||
#generate_address_popup,
|
||||
#convert_to_taproot_popup {
|
||||
--width: 28rem;
|
||||
}
|
||||
main {
|
||||
sm-form {
|
||||
|
||||
153
index.html
153
index.html
@ -29,10 +29,10 @@
|
||||
</header>
|
||||
<menu>
|
||||
<li>
|
||||
<button class="button button--colored" onclick="generateNewAddress()">
|
||||
<button class="button button--colored" onclick="openPopup('generate_address_popup')">
|
||||
Create new address
|
||||
</button>
|
||||
<button class="button button--colored" onclick="convertToTaproot()">
|
||||
<button class="button button--colored" onclick="openPopup('convert_to_taproot_popup')">
|
||||
Convert to Taproot address
|
||||
</button>
|
||||
</li>
|
||||
@ -104,6 +104,83 @@
|
||||
</div>
|
||||
</sm-form>
|
||||
</main>
|
||||
<sm-popup id="generate_address_popup">
|
||||
<header slot="header" class="popup__header">
|
||||
<div class="flex align-center">
|
||||
<button class="popup__header__close" onclick="closePopup()">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
||||
fill="#000000">
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
<path
|
||||
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<div class="grid gap-2">
|
||||
<div id="flo_id_warning" class="grid justify-center gap-0-5">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
||||
fill="#000000">
|
||||
<path d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" />
|
||||
</svg>
|
||||
<h3>Keep your keys safe!</h3>
|
||||
<strong>Don't share with anyone. The private key cannot be recovered if lost.</strong>
|
||||
</div>
|
||||
<div id="generated_btc_addr" class="generated-id-card"></div>
|
||||
</div>
|
||||
</sm-popup>
|
||||
<sm-popup id="convert_to_taproot_popup">
|
||||
<header slot="header" class="popup__header">
|
||||
<div class="flex align-center">
|
||||
<button class="popup__header__close" onclick="closePopup()">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
||||
fill="#000000">
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
<path
|
||||
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<section class="grid gap-1-5">
|
||||
<div class="grid gap-0-5">
|
||||
<h4>Convert to Taproot</h4>
|
||||
<p>Get Taproot address from your bitcoin private key</p>
|
||||
</div>
|
||||
<sm-form id="convert_to_taproot_form">
|
||||
<div class="grid gap-0-5">
|
||||
<sm-input id="convert_to_taproot_input" type="password" placeholder="Private key"
|
||||
class="password-field" data-private-key required autofocus>
|
||||
<label slot="right" class="interact">
|
||||
<input type="checkbox" class="hidden" autocomplete="off" readonly
|
||||
onchange="togglePrivateKeyVisibility(this)">
|
||||
<svg class="icon invisible" xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||
viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||
<title>Hide password</title>
|
||||
<path d="M0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0zm0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z" />
|
||||
</svg>
|
||||
<svg class="icon visible" xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||
viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||
<title>Show password</title>
|
||||
<path d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z" />
|
||||
</svg>
|
||||
</label>
|
||||
</sm-input>
|
||||
<button class="button button--primary cta" type="submit"
|
||||
onclick="convertToTaproot()">Convert</button>
|
||||
</div>
|
||||
</sm-form>
|
||||
<div id="converted_address_wrapper" class="hidden grid gap-0-5">
|
||||
<h5>Converted Taproot address</h5>
|
||||
<sm-copy id="converted_address"></sm-copy>
|
||||
</div>
|
||||
</section>
|
||||
</sm-popup>
|
||||
<script src="https://unpkg.com/uhtml@3.0.1/es.js"></script>
|
||||
<script src="scripts/components.min.js" type="text/javascript"></script>
|
||||
<script src="scripts/btcwallet_scripts_lib.js" type="text/javascript"></script>
|
||||
@ -150,16 +227,26 @@
|
||||
|
||||
document.addEventListener('popupopened', e => {
|
||||
switch (e.target.id) {
|
||||
case 'generate_address_popup':
|
||||
const { wif, tr: { address } } = getTaprootAddress()
|
||||
renderElem(getRef('generated_btc_addr'), html`
|
||||
<div>
|
||||
<h5>BTC Address</h5>
|
||||
<sm-copy value="${address}"></sm-copy>
|
||||
</div>
|
||||
<div>
|
||||
<h5>Private Key</h5>
|
||||
<sm-copy value="${wif}"></sm-copy>
|
||||
</div>
|
||||
`);
|
||||
break;
|
||||
}
|
||||
})
|
||||
document.addEventListener('popupclosed', e => {
|
||||
zIndex--
|
||||
switch (e.target.id) {
|
||||
case 'retrieve_btc_addr_popup':
|
||||
getRef('recovered_btc_addr_wrapper').classList.add('hidden')
|
||||
break;
|
||||
case 'increase_fee_popup':
|
||||
renderElem(getRef('increase_fee_popup_content'), html``)
|
||||
case 'convert_to_taproot_popup':
|
||||
getRef('converted_address_wrapper').classList.add('hidden')
|
||||
break;
|
||||
}
|
||||
})
|
||||
@ -409,8 +496,28 @@
|
||||
target.type = target.type === 'password' ? 'text' : 'password';
|
||||
target.focusIn()
|
||||
}
|
||||
function generateNewAddress() {
|
||||
|
||||
getRef('convert_to_taproot_form').addEventListener('invalid', () => {
|
||||
if (!document.startViewTransition) {
|
||||
getRef('converted_address_wrapper').classList.add('hidden')
|
||||
return
|
||||
}
|
||||
document.startViewTransition(() => {
|
||||
getRef('converted_address_wrapper').classList.add('hidden')
|
||||
})
|
||||
})
|
||||
function convertToTaproot() {
|
||||
function convert() {
|
||||
let wif = getRef('convert_to_taproot_input').value.trim();
|
||||
getRef('converted_address_wrapper').classList.remove('hidden');
|
||||
const { tr: { address } } = getTaprootAddress(wif);
|
||||
getRef('converted_address').value = address;
|
||||
}
|
||||
if (!document.startViewTransition) {
|
||||
return convert()
|
||||
}
|
||||
document.startViewTransition(() => {
|
||||
convert()
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
@ -441,8 +548,8 @@
|
||||
|
||||
const util = {};
|
||||
|
||||
util.Sat_to_BTC = value => parseFloat((value / SATOSHI_IN_BTC).toFixed(8));
|
||||
util.BTC_to_Sat = value => parseInt(value * SATOSHI_IN_BTC);
|
||||
util.Sat_to_BTC = value => BigInt(parseFloat((value / SATOSHI_IN_BTC).toFixed(8)));
|
||||
util.BTC_to_Sat = value => BigInt(parseInt(value * SATOSHI_IN_BTC));
|
||||
|
||||
function get_fee_rate() {
|
||||
return new Promise((resolve, reject) => {
|
||||
@ -489,10 +596,10 @@
|
||||
const { privkey } = coinjs.wif2privkey(wif)
|
||||
const privKey_arrayform = hex.decode(privkey)
|
||||
const pubS = secp256k1_schnorr.getPublicKey(privKey_arrayform);
|
||||
const taproot = btc.p2tr(pubS);
|
||||
const tr = btc.p2tr(pubS);
|
||||
return {
|
||||
taproot,
|
||||
privKey: wif
|
||||
tr,
|
||||
wif
|
||||
}
|
||||
}
|
||||
|
||||
@ -536,15 +643,15 @@
|
||||
}
|
||||
async function createTx(senderPrivateKey, receiver, amount, fee) {
|
||||
try {
|
||||
const { taproot: { address, script } } = getTaprootAddress(senderPrivateKey)
|
||||
const amountInSat = BigInt(util.BTC_to_Sat(amount))
|
||||
const { tr: { address, script } } = getTaprootAddress(senderPrivateKey)
|
||||
const amountInSat = util.BTC_to_Sat(amount)
|
||||
const opts = {};
|
||||
const tx = new btc.Transaction(opts);
|
||||
const tx = new taproot.Transaction(opts);
|
||||
|
||||
await addUTXOs(tx, taproot, [address], util.BTC_to_Sat(amount))
|
||||
await addUTXOs(tx, tr, [address], util.BTC_to_Sat(amount))
|
||||
|
||||
tx.addOutputAddress(receiver, amountInSat);
|
||||
|
||||
tx.addOutputAddress(address, tx.inputAmount - amountInSat - util.BTC_to_Sat(fee));
|
||||
tx.sign(privKey_arrayform, undefined, new Uint8Array(32));
|
||||
|
||||
tx.finalize()
|
||||
@ -554,7 +661,7 @@
|
||||
}
|
||||
}
|
||||
const testTaproot = 'bc1p05whkacavgmh77pgsr7v5k4tyg28x3pqyjanfnjkzzdngqur4yks39w8zk'
|
||||
function addUTXOs(tx, taproot, senders = [testTaproot], required_amount, fee_rate, rec_args = {}) {
|
||||
function addUTXOs(tx, tr, senders = [testTaproot], required_amount, fee_rate, rec_args = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
required_amount = parseFloat(required_amount.toFixed(8));
|
||||
if (typeof rec_args.n === "undefined") {
|
||||
@ -580,8 +687,8 @@
|
||||
continue;
|
||||
const { tx_hash, tx_index, value } = utxos[i];
|
||||
// tx.addinput(utxos[i].tx_hash_big_endian, utxos[i].tx_output_n, script, 0xfffffffd /*sequence*/); //0xfffffffd for Replace-by-fee
|
||||
const input = { txid: tx_hash, index: tx_index, script: taproot.script, amount: value }
|
||||
tx.addInput({ ...input, ...taproot, witnessUtxo: { script: input.script, amount: input.amount }, });
|
||||
const input = { txid: tx_hash, index: tx_index, script: tr.script, amount: value }
|
||||
tx.addInput({ ...input, ...tr, witnessUtxo: { script: input.script, amount: input.amount }, });
|
||||
|
||||
//update track values
|
||||
rec_args.input_size += size_per_input; // Adjust input size calculation
|
||||
@ -591,7 +698,7 @@
|
||||
required_amount += size_per_input * fee_rate;
|
||||
}
|
||||
rec_args.n += 1;
|
||||
addUTXOs(tx, taproot, senders, required_amount, fee_rate, rec_args)
|
||||
addUTXOs(tx, tr, senders, required_amount, fee_rate, rec_args)
|
||||
.then(result => resolve(result))
|
||||
.catch(error => reject(error))
|
||||
}).catch(error => reject(error))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user