Project structure
thnbr/
├── LICENSE # MIT License permission outline
├── README.md # Project setup and test setup walkthrough
├── index.html # Hypertext template where application is embedded
├── package.json # Project definitions and dependencies
├── src/
│ ├── App.vue # Vue single-page application base view
│ ├── assets/ # Collection of stylesheets and vector assets
│ │ └── ... # TODO: expand descriptions
│ │
│ ├── components/ # Collection of Vue frontend components
│ │ └── ... # TODO: expand descriptions
│ │
│ ├── main.ts # Vue single-page application entrypoint
│ ├── stores/ # Collection of Vue composable stores
│ │ └── ... # TODO: expand descriptions
│ │
│ ├── style.css # Vue single-page application cascade styling sheet
│ ├── views/ # Collection of Vue frontend pages
│ │ └── ... # TODO: expand descriptions
│ │
│ └── workers/ # Collection of web workers
│ └── interpreter.ts # Pyodide interpreter with required shims
│
├── static/ # Static assets
│ ├── coi-serviceworker.min.js # Cross-origin isolation through a service worker
│ ├── chrome.svg # Vector asset of Chrome web browser logo
│ ├── favicon.ico # Small graphic image for the browser's address bar
│ ├── firefox.svg # Vector asset of Firefox logo used by README.md
│ ├── pymatt-0.0.1-py3-none-any.whl # Wheel file for `pymatt` python package
│ ├── pyodide.asm.js # The JS half of the main "binary"
│ ├── pyodide.asm.wasm # The WebAssembly half of the main "binary"
│ ├── pyodide.js # Legacy support for browsers unable to use es6 module
│ ├── pyodide.mjs # Small JS loader shim which exports `loadPyodide`
│ ├── pyodide-lock.json # Lockfile for Python packages
│ ├── python_stdlib.zip # Python standard libraries for Pyodide
│ ├── thnbr.svg # Project logo
│ ├── thnbr-banner.svg # Project banner
│ └── thnbr-social.svg # Project social link preview
│
├── tailwind.config.js # Styling plugins and rules for TailwindCSS
└── vite.config.ts # Bundler configuration and static asset bypass
Notable exemptions: dotfiles, lockfile and component library generated files
- node - Run JavaScript Everywhere
- pnpm - Fast, disk space efficient package manager
- Web browser of choice (Chrome or Firefox)
Install the project dependencies with the following command:
pnpm installSample output of successful dependency installation
$ pnpm install
> Lockfile is up to date, resolution step is skipped
> Packages: +263
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> Downloading @biomejs/cli-darwin-x64@2.2.2: 14.67 MB/14.67 MB, done
> Progress: resolved 263, reused 260, downloaded 3, added 263, done
>
> dependencies:
> + @codemirror/commands 6.8.1
> + @codemirror/lang-python 6.2.1
> + @codemirror/language 6.11.1
> + @codemirror/state 6.5.2
> + @codemirror/view 6.37.2
> + @lezer/common 1.2.3
> + @lezer/highlight 1.2.1
> + @noble/hashes 1.8.0
> + @tanstack/vue-table 8.21.3
> + class-variance-authority 0.7.1
> + clsx 2.1.1
> + jdenticon 3.3.0
> + lucide-vue-next 0.541.0
> + pinia 2.3.1
> + pyodide 0.27.7
> + reka-ui 2.4.1
> + tailwind-merge 3.3.1
> + tailwindcss-animate 1.0.7
> + vue 3.5.17
> + vue-router 4.5.1
> + vue-sonner 2.0.0
>
> devDependencies:
> + @biomejs/biome 2.2.2
> + @tailwindcss/typography 0.5.16
> + @vitejs/plugin-vue 4.6.2
> + @vueuse/core 11.3.0
> + autoprefixer 10.4.21
> + tailwindcss 3.4.17
> + typescript 5.8.3
> + unplugin-auto-import 0.18.6
> + vite 5.4.19
> + vite-plugin-top-level-await 1.5.0
> + vite-svg-loader 5.1.0
> + vue-tsc 2.2.10
>
> Done in 11sBefore the current repository can be built with pnpm run build command, you must first
download the required shadcn/vue components first. We currently
use two of the many components listed under shadcn/vue components which are:
Using the following commands:
pnpm dlx shadcn-vue@latest add buttonand
pnpm dlx shadcn-vue@latest add dropdown-menuSample outputs of running the component download commands successfully
$ pnpm dlx shadcn-vue@latest add button
> ✔ Checking registry.
> ✔ Installing dependencies.
> ✔ Created 2 files:
> - src/components/ui/button/Button.vue 6:43:58 PM
> - src/components/ui/button/index.ts
$ pnpm dlx shadcn-vue@latest add dropdown-menu
> ✔ Checking registry.
> ✔ Installing dependencies.
> ✔ Created 15 files:
> - src/components/ui/dropdown-menu/DropdownMenu.vue 6:45:07 PM
> - src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue 6:45:08 PM
> - src/components/ui/dropdown-menu/DropdownMenuContent.vue 6:45:08 PM
> - src/components/ui/dropdown-menu/DropdownMenuGroup.vue 6:45:08 PM
> - src/components/ui/dropdown-menu/DropdownMenuItem.vue 6:45:08 PM
> - src/components/ui/dropdown-menu/DropdownMenuLabel.vue 6:45:08 PM
> - src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue 6:45:08 PM
> - src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue 6:45:08 PM
> - src/components/ui/dropdown-menu/DropdownMenuSeparator.vue 6:45:08 PM
> - src/components/ui/dropdown-menu/DropdownMenuShortcut.vue 6:45:08 PM
> - src/components/ui/dropdown-menu/DropdownMenuSub.vue 6:45:08 PM
> - src/components/ui/dropdown-menu/DropdownMenuSubContent.vue 6:45:08 PM
> - src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue 6:45:08 PM
> - src/components/ui/dropdown-menu/DropdownMenuTrigger.vue 6:45:08 PM
> - src/components/ui/dropdown-menu/index.tsThe online interpreter has been patched with few moderations in order to ease development.
Override hashlib.pbkdf2_hmac
This normally is an operation where hashlib binds to OpenSSL in user's environment
and not supported in pyodide environment, but interpreter overrides this with a pure
python implementation at runtime to make possible some of buidl method calls.
# NOTE: shim pbkdf2_hmac without openssl
# https://pyodide.org/en/stable/usage/wasm-constraints.html#modules-with-limited-functionality
import hashlib
import hmac
def pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None):
hash_func = getattr(hashlib, hash_name)
hlen = hash_func().digest_size
if dklen is None:
dklen = hlen
blocks = -(-dklen // hlen) # ceil division
def F(block_index):
U = hmac.new(password, salt + block_index.to_bytes(4, "big"), hash_func).digest()
result = bytearray(U)
for _ in range(iterations - 1):
U = hmac.new(password, U, hash_func).digest()
result = bytearray(x ^ y for x, y in zip(result, U))
return result
dk = b''.join(F(i + 1) for i in range(blocks))
return dk[:dklen]
hashlib.pbkdf2_hmac = pbkdf2_hmacShim OP_CODES into global built-ins
This gives access to developer to immediately use OP_CODES such as OP_0, OP_ADD,
OP_EQUAL, and etc. without imports
# NOTE: shim opcodes from buidl.op.OP_CODE_NAMES
from buidl.op import OP_CODE_NAMES
OP_CODES: dict[str, int] = {value: key for key, value in OP_CODE_NAMES.items()}
globals().update(OP_CODES)from binascii import unhexlify
from buidl.ecc import S256Point
from buidl.taproot import TapLeaf, TapBranch, TapScript
# buidl doesn't have constants/variables defined for op codes hence why
# we use use their integer values
script_a = TapScript([OP_1, OP_ADD, OP_2, OP_EQUAL])
script_b = TapScript([OP_2, OP_ADD, OP_4, OP_EQUAL])
script_c = TapScript([OP_1, OP_ADD, OP_5, OP_EQUAL])
leaf_a = TapLeaf(script_a)
leaf_b = TapLeaf(script_b)
leaf_c = TapLeaf(script_c)
# we need to construct a tree of branches ourselves
branch_bc = TapBranch(leaf_b, leaf_c)
branch_abc = TapBranch(leaf_a, branch_bc)
internal_pubkey = S256Point.parse_xonly(unhexlify("50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0"))
addr = internal_pubkey.p2tr_address(branch_abc.hash(), network="regtest")
print("Send 0.01 BTC to the following address: {}".format(addr))
# prints: Send 0.01 BTC to the following address: bcrt1py7e8e0q7pdkxwyp2tjn65k4kd5kgch0aqe03jzjczn96xat6nwjswsu892from binascii import unhexlify
from buidl.ecc import PrivateKey, S256Point
from buidl.script import Script
from buidl.helper import decode_base58, sha256, hash160
# secret and preimage
preimage_secret = b"super secret code"
preimage = sha256(preimage_secret)
# create private keys from WIF
sender_wif = "cUZLbjpNRAAuu5sV8e8ocwMqAYDtdxY2EXCPyjvyeGATzCnCCaMK"
sender_decoded = decode_base58(sender_wif)
seckey_sender = PrivateKey(int.from_bytes(sender_decoded[1:], "big"))
pubkey_sender = seckey_sender.point.sec()
recipient_wif = "cVhjB76GwuZiva15i88Hwbgc1ZZB6KFMUAjAgiauD1mpugQDVGTc"
recipient_decoded = decode_base58(recipient_wif)
seckey_recipient = PrivateKey(int.from_bytes(recipient_decoded[1:], "big"))
pubkey_recipient = seckey_recipient.point.sec()
# construct redeem script
redeem_script = Script([
OP_IF,
OP_SHA256,
preimage,
OP_EQUALVERIFY,
OP_DUP,
OP_HASH160,
hash160(pubkey_recipient),
OP_ELSE,
10,
OP_CHECKSEQUENCEVERIFY,
OP_DROP,
OP_DUP,
OP_HASH160,
hash160(pubkey_sender),
OP_ENDIF,
OP_EQUALVERIFY,
OP_CHECKSIG,
])
# redeem script hash for P2WSH
redeem_script_hash = sha256(redeem_script.serialize())
# P2WSH scriptPubKey: OP_0 <redeem_script_hash>
script_pubkey = Script([OP_0, redeem_script_hash])
internal_pubkey = S256Point.parse_xonly(unhexlify("50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0"))
address = internal_pubkey.p2tr_address(script_pubkey.serialize(), network="regtest")- วง - Wong typeface by uvSOV - Worawut Thanawatanawanich
- VitePress Python Editor by @zqianem
- YT: Build in-browser 3D experiences with WebGL and PyScript by Łukasz Langa at Pycon US 2024
This project is licensed under the terms of the MIT license.