Added script-path address creation

This commit is contained in:
sairaj mote 2023-11-03 01:53:31 +05:30
parent 13fd4bb6e3
commit aea2979bee
4 changed files with 223 additions and 114 deletions

View File

@ -1051,15 +1051,41 @@ body.loaded .nav-item__indicator {
border: solid thin rgba(var(--text-color), 0.3);
}
#creation_menu {
display: grid;
grid-area: 0.5rem;
grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
}
.primary-action {
padding: 0.6rem 0.8rem 0.6rem 0.6rem;
gap: 0.5rem;
display: grid;
grid-template-columns: auto 1fr;
align-items: flex-start;
padding: max(1rem, 1.5vw);
gap: 0.5rem 1rem;
white-space: normal;
font-size: 0.9rem;
border-radius: 0.5rem;
background-color: transparent;
border: thin solid rgba(var(--accent-color-rgb), 0.2);
text-align: start;
width: 100%;
height: 100%;
}
.primary-action .icon {
height: 1.5rem;
width: 1.5rem;
margin-bottom: 1rem;
grid-row: 1/3;
}
.primary-action h4 {
grid-column: 2;
font-size: 1rem;
}
.primary-action p {
grid-column: 2;
font-weight: 400;
color: rgba(var(--text-color), 0.8);
margin-bottom: auto;
}
#flo_id_warning {
@ -1293,16 +1319,22 @@ body.loaded .nav-item__indicator {
#main_card:not(.nav-hidden) {
grid-template-columns: auto 1fr;
grid-template-rows: auto 1fr;
grid-template-areas: "nav header" "nav .";
grid-template-areas: "header header" "nav .";
}
#main_header {
grid-area: header;
border-bottom: solid thin rgba(var(--text-color), 0.2);
padding: 0.8rem 1rem;
}
#main_header .app-brand {
gap: 0.5rem;
}
#main_navbar {
grid-area: nav;
border-top: none;
flex-direction: column;
background-color: rgba(37, 110, 255, 0.03);
background-color: transparent;
border-right: solid thin rgba(var(--text-color), 0.2);
}
#main_navbar ul {
flex-direction: column;
@ -1313,6 +1345,7 @@ body.loaded .nav-item__indicator {
flex-direction: row;
justify-content: flex-start;
padding: 0.8rem 1rem 0.8rem 0.5rem;
min-width: 10rem;
}
.nav-item__indicator {
width: 0.25rem;
@ -1321,9 +1354,6 @@ body.loaded .nav-item__indicator {
border-radius: 0 1rem 1rem 0;
bottom: auto;
}
body[data-theme=dark] #main_navbar {
background-color: rgba(0, 0, 0, 0.2);
}
#transactions_list {
gap: 0.5rem;
}
@ -1335,7 +1365,7 @@ body.loaded .nav-item__indicator {
#increase_fee_popup {
--width: 30rem;
}
#generate_address_popup,
#generate_key_path_address_popup,
#convert_to_taproot_popup {
--width: min(36rem, 100%);
}
@ -1359,6 +1389,9 @@ body.loaded .nav-item__indicator {
grid-template-columns: 1fr 1fr;
align-items: flex-start;
}
#generate_script_path_address_popup {
--width: 36rem;
}
}
@media only screen and (min-width: 1280px) {
.page {

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -983,16 +983,40 @@ body.loaded .nav-item {
border-radius: 0.5rem;
border: solid thin rgba(var(--text-color), 0.3);
}
#creation_menu {
display: grid;
grid-area: 0.5rem;
grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
}
.primary-action {
padding: 0.6rem 0.8rem 0.6rem 0.6rem;
gap: 0.5rem;
display: grid;
grid-template-columns: auto 1fr;
align-items: flex-start;
padding: max(1rem, 1.5vw);
gap: 0.5rem 1rem;
white-space: normal;
font-size: 0.9rem;
border-radius: 0.5rem;
background-color: transparent;
border: thin solid rgba(var(--accent-color-rgb), 0.2);
text-align: start;
width: 100%;
height: 100%;
.icon {
height: 1.5rem;
width: 1.5rem;
margin-bottom: 1rem;
grid-row: 1/3;
}
h4 {
grid-column: 2;
font-size: 1rem;
}
p {
grid-column: 2;
font-weight: 400;
color: rgba(var(--text-color), 0.8);
margin-bottom: auto;
}
}
#flo_id_warning {
padding-bottom: 1.5rem;
@ -1196,7 +1220,7 @@ body.loaded .nav-item {
&:not(.nav-hidden) {
grid-template-columns: auto 1fr;
grid-template-rows: auto 1fr;
grid-template-areas: "nav header" "nav .";
grid-template-areas: "header header" "nav .";
}
position: relative;
overflow: hidden;
@ -1205,12 +1229,18 @@ body.loaded .nav-item {
}
#main_header {
grid-area: header;
border-bottom: solid thin rgba(var(--text-color), 0.2);
padding: 0.8rem 1rem;
.app-brand {
gap: 0.5rem;
}
}
#main_navbar {
grid-area: nav;
border-top: none;
flex-direction: column;
background-color: rgba(37 110 255/ 0.03);
background-color: transparent;
border-right: solid thin rgba(var(--text-color), 0.2);
ul {
flex-direction: column;
gap: 0.5rem;
@ -1221,6 +1251,7 @@ body.loaded .nav-item {
flex-direction: row;
justify-content: flex-start;
padding: 0.8rem 1rem 0.8rem 0.5rem;
min-width: 10rem;
&__indicator {
width: 0.25rem;
height: 50%;
@ -1229,11 +1260,6 @@ body.loaded .nav-item {
bottom: auto;
}
}
body[data-theme="dark"] {
#main_navbar {
background-color: rgba(0 0 0/ 0.2);
}
}
#transactions_list {
gap: 0.5rem;
}
@ -1245,7 +1271,7 @@ body.loaded .nav-item {
#increase_fee_popup {
--width: 30rem;
}
#generate_address_popup,
#generate_key_path_address_popup,
#convert_to_taproot_popup {
--width: min(36rem, 100%);
}
@ -1270,6 +1296,9 @@ body.loaded .nav-item {
grid-template-columns: 1fr 1fr;
align-items: flex-start;
}
#generate_script_path_address_popup {
--width: 36rem;
}
}
@media only screen and (min-width: 1280px) {
.page {

View File

@ -94,10 +94,23 @@
</span>
</a>
</li>
<li>
<a href="#/create" class="nav-item interactive">
<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="M13 7h-2v4H7v2h4v4h2v-4h4v-2h-4V7zm-1-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z" />
</svg>
<span class="nav-item__title">
Create
</span>
</a>
</li>
</ul>
</nav>
</main>
<sm-popup id="generate_address_popup">
<sm-popup id="generate_key_path_address_popup">
<header slot="header" class="popup__header">
<div class="flex align-center">
<button class="popup__header__close" onclick="closePopup()">
@ -123,6 +136,21 @@
<div id="generated_btc_addr" class="generated-id-card"></div>
</div>
</sm-popup>
<sm-popup id="generate_script_path_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 id="generate_script_path_address_popup__content"></div>
</sm-popup>
<sm-popup id="convert_to_taproot_popup">
<header slot="header" class="popup__header">
<div class="flex align-center">
@ -251,19 +279,86 @@
document.addEventListener('popupopened', e => {
switch (e.target.id) {
case 'generate_address_popup':
case 'generate_key_path_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>
`);
<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;
}
case 'generate_script_path_address_popup': {
const { wif, tr: { address } } = getTaprootAddress()
const privateKey = coinjs.wif2privkey(wif).privkey
console.log(wif, address)
const scriptInputs = [1];
const renderScriptInput = (index) => html`
<div class="flex gap-0-5">
<sm-input class="member-script-input flex-1" placeholder=${`Member script #${index + 1} (Hex)`} pattern="^[0-9A-Fa-f]+$" error-text="Only hexadecimal values are allowed" animate required></sm-input>
${index ? html`
<button class="button button--danger" onclick=${() => removeScriptInput(index)} title="Remove">
<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="M16 9v10H8V9h8m-1.5-6h-5l-1 1H5v2h14V4h-3.5l-1-1zM18 7H6v12c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7z"/></svg>
</button>
`: ''}
</div>
`
function addMemberScriptInput() {
scriptInputs.push(scriptInputs.length + 1)
renderScriptInputList()
}
function removeScriptInput(index) {
scriptInputs.splice(index, 1)
renderScriptInputList()
}
function generateScriptPathAddress() {
const schnorrPublicKey = secp256k1_schnorr.getPublicKey(hex.decode(privateKey));
const taprootTree = [...document.querySelectorAll('.member-script-input')].map(input => {
return {
script: input.value.trim(),
leafVersion: 0xc0,
}
})
const { address } = taproot.p2tr(
schnorrPublicKey,
taprootTree,
undefined,
true
);
renderElem(getRef('generate_script_path_address_popup__content'), html`
<div class="grid gap-1">
<h4>Generated Taproot script-path address</h4>
<sm-copy value="${address}"></sm-copy>
</div>
`);
}
function renderScriptInputList() {
renderElem(getRef('generate_script_path_address_popup__content'), html`
<sm-form>
<div class="grid gap-1">
<h4>Add member scripts</h4>
<div id="member_input_container" class="grid gap-0-5">
${scriptInputs.map((no, index) => renderScriptInput(index))}
</div>
</div>
<div class="flex gap-0-5">
<button class="button button--colored margin-right-auto" onclick=${addMemberScriptInput}>
Add member
</button>
<button id="create_script_path_address_button" class="button button--primary flex-1" onclick=${generateScriptPathAddress} type="submit" disabled>Create</button>
</div>
</sm-form>
`);
getRef('create_script_path_address_button').scrollIntoView({ behavior: 'smooth' })
}
renderScriptInputList()
break;
}
}
})
document.addEventListener('popupclosed', e => {
@ -1170,6 +1265,9 @@
const { page } = state
if (!page)
page = 'search'
if (page !== 'send') {
taprootScriptTxDetails = {}
}
const previousTarget = getRef('main_navbar').querySelector('.nav-item--active')
if (previousTarget) {
previousTarget.classList.remove('nav-item--active')
@ -1201,20 +1299,6 @@
<svg slot="icon" 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> <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path> </svg>
</button>
</sm-form>
<menu class="flex gap-0-5">
<li>
<button class="button button--colored primary-action" onclick="openPopup('generate_address_popup')">
<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="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z" /> </svg>
Create new address
</button>
</li>
<li>
<button class="button button--colored primary-action" onclick="openPopup('convert_to_taproot_popup')">
<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="M6.99 11L3 15l3.99 4v-3H14v-2H6.99v-3zM21 9l-3.99-4v3H10v2h7.01v3L21 9z" /> </svg>
Retrieve Taproot address
</button>
</li>
</menu>
<div id="address_details" class="hidden flex flex-direction-column gap-1">
<div id="address_balance_card" class="grid gap-1 hidden">
<div class="flex">
@ -1357,6 +1441,7 @@
break;
}
} else {
taprootScriptTxDetails = {}
form = html`
<sm-form id="send_tx_form" onvalid=${() => calculateSuggestedFee('key-path')} oninvalid=${handleInvalidForm} ?skip-submit=${feeType() === 'suggested'}>
<fieldset class="flex flex-direction-column gap-0-5">
@ -2068,6 +2153,33 @@
buttonLoader(document.getElementById('increase_fee'), false)
}
}
router.addRoute('create', state => {
renderElem(getRef('page_container'), html`
<menu id="creation_menu" class="flex gap-0-5">
<li>
<button class="button button--colored primary-action" onclick="openPopup('generate_key_path_address_popup')">
<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="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z" /> </svg>
<h4> Create key-path address </h4>
<p> Generates a Taproot address and private key pair </p>
</button>
</li>
<li>
<button class="button button--colored primary-action" onclick="openPopup('generate_script_path_address_popup')">
<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="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z" /> </svg>
<h4> Create script-path address </h4>
<p> Generates a Taproot address with given member scripts </p>
</button>
</li>
<li>
<button class="button button--colored primary-action" onclick="openPopup('convert_to_taproot_popup')">
<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="M6.99 11L3 15l3.99 4v-3H14v-2H6.99v-3zM21 9l-3.99-4v3H10v2h7.01v3L21 9z" /> </svg>
<h4>Retrieve Taproot address</h4>
<p>Get Taproot address corresponding to given BTC private key</p>
</button>
</li>
</menu>
`)
})
</script>
<script type="text/javascript">
const DUST_AMT = 546,
@ -2322,73 +2434,8 @@
})
}
</script>
<script>
keyPairFromSecret = (hexSecretKey) => {
const secretKey = hex.decode(hexSecretKey);
const schnorrPublicKey = secp256k1_schnorr.getPublicKey(secretKey);
return {
schnorrPublicKey,
secretKey,
};
};
// generate new private key
internalKeyPair = keyPairFromSecret(
'1229101a0fcf2104e8808dab35661134aa5903867d44deb73ce1c7e4eb925be8'
);
preimage = hashmini.sha256(
hex.decode('107661134f21fc7c02223d50ab9eb3600bc3ffc3712423a1e47bb1f9a9dbf55f')
);
aliceKeyPair = keyPairFromSecret(
'2bd806c97f0e00af1a1fc3328fa763a9269723c8db8fac4f93af71db186d6e90'
);
bobKeyPair = keyPairFromSecret(
'81b637d8fcd2c6da6359e6963113a1170de795e4b725b84d1e0b4cfd9ec58ce9'
);
scriptAlice = new Uint8Array([
0x02,
144,
0x00,
btc.OP.CHECKSEQUENCEVERIFY,
btc.OP.DROP,
0x20,
...aliceKeyPair.schnorrPublicKey,
0xac,
]);
scriptBob = new Uint8Array([
btc.OP.SHA256,
0x20,
...preimage,
btc.OP.EQUALVERIFY,
0x20,
...bobKeyPair.schnorrPublicKey,
0xac,
]);
taprootTree = btc.taprootListToTree([
{
script: scriptAlice,
leafVersion: 0xc0,
},
{
script: scriptBob,
leafVersion: 0xc0,
},
]);
taprootCommitment = btc.p2tr(
internalKeyPair.schnorrPublicKey,
taprootTree,
undefined,
true
);
</script>
<!-- 029000b275209997a497d964fc1a62885b05a51166a65a90df00492c8d7cf61d6accf54803beac -->
<!-- a8206c60f404f8167a38fc70eaf8aa17ac351023bef86bcb9d1086a19afe95bd533388204edfcf9dfe6c0b5c83d1ab3f78d1b39a46ebac6798e08e19761f5ed89ec83c10ac -->
</body>
</html>