Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/embit/script.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ def address(self, network=NETWORKS["main"]):
ver = ver % 0x50
return bech32.encode(network["bech32"], ver, data[2:])

if script_type == "p2a":
# PayToAnchor (OP_1 <2:0x4e73>) hard-codes version 1
ver = 1
return bech32.encode(network["bech32"], ver, data[2:])

# we should never get here
raise ValueError("Unsupported script type")

Expand All @@ -57,6 +62,9 @@ def script_type(self):
# OP_1 <x-only-pubkey>
if len(data) == 34 and data[:2] == b"\x51\x20":
return "p2tr"
# OP_1 <2:0x4e73> (PayToAnchor is always hard-coded to this value)
if data == b"\x51\x02\x4e\x73":
return "p2a"
# unknown type
return None

Expand Down Expand Up @@ -151,6 +159,12 @@ def p2tr(pubkey, script_tree=None):
return Script(b"\x51\x20" + output_pubkey.xonly())


def p2a():
"""Return Pay-To-Anchor Script"""
# PayToAnchor is hard-coded by definition to: OP_1 <2:0x4e73>
return Script(b"\x51\x02\x4e\x73")


def p2pkh_from_p2wpkh(script):
"""Convert p2wpkh to p2pkh script"""
return Script(b"\x76\xa9" + script.serialize()[2:] + b"\x88\xac")
Expand Down Expand Up @@ -185,6 +199,9 @@ def address_to_scriptpubkey(addr):
# fail - then it's bech32 address
hrp = addr.split("1")[0]
ver, data = bech32.decode(hrp, addr)
if ver == 1 and data == [int.from_bytes(b"\x4e"), int.from_bytes(b"\x73")]:
# PayToAnchor address (OP_1 <0x4e73>)
return p2a()
if ver not in [0, 1] or len(data) not in [20, 32]:
raise EmbitError("Invalid bech32 address")
if ver == 1 and len(data) != 32:
Expand Down
8 changes: 6 additions & 2 deletions tests/tests/test_script.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from unittest import TestCase
from embit.script import Script, p2wpkh, p2sh, p2pkh, p2tr
from embit.script import Script, p2wpkh, p2sh, p2pkh, p2tr, p2a
from embit.ec import PrivateKey
from embit.hashes import hash160
from embit.networks import NETWORKS


class ScriptTest(TestCase):
Expand All @@ -12,9 +13,12 @@ def test_from_addr(self):
p2pkh(pk),
p2sh(p2wpkh(pk)),
p2tr(pk),
p2a(),
]
for sc in scripts:
self.assertEqual(sc, Script.from_address(sc.address()))
for network in NETWORKS.values():
# Addresses will differ by network (e.g. bc1q vs bcrt1q) so test them all
self.assertEqual(sc, Script.from_address(sc.address(network)))

def test_push(self):
pk = PrivateKey(b"\x11" * 32)
Expand Down