Skip to content

Commit

Permalink
Add p2tr.
Browse files Browse the repository at this point in the history
  • Loading branch information
richardkiss committed Dec 13, 2021
1 parent 824a668 commit 68ec7eb
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 1 deletion.
7 changes: 7 additions & 0 deletions pycoin/networks/AddressAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ def for_script_info(self, script_info):
if type == "p2sh":
return self.for_p2sh(script_info["hash160"])

if type == "p2tr":
return self.for_p2tr(script_info["synthetic_key"])

if type == "nulldata":
return "(nulldata %s)" % b2h(script_info["data"])

Expand All @@ -67,6 +70,10 @@ def for_p2sh_wit(self, hash256):
assert len(hash256) == 32
return bech32m.encode(bech32_hrp, 0, iterbytes(hash256))

if bech32_hrp:
def for_p2tr(self, synthetic_key):
return bech32m.encode(bech32_hrp, 1, iterbytes(synthetic_key))

# p2s and p2s_wit helpers

if pay_to_script_prefix:
Expand Down
13 changes: 13 additions & 0 deletions pycoin/networks/ContractAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ def for_p2s(self, underlying_script):
def for_p2s_wit(self, underlying_script):
return self.for_p2sh_wit(hashlib.sha256(underlying_script).digest())

def for_p2tr(self, synthetic_key):
return self.for_info(dict(type="p2tr", synthetic_key=synthetic_key))

def match(self, template_disassembly, script):
template = self._script_tools.compile(template_disassembly)
r = collections.defaultdict(list)
Expand All @@ -76,6 +79,10 @@ def match(self, template_disassembly, script):
r["SEGWIT_LIST"].append(data1)
elif data2 == b'DATA':
r["DATA_LIST"].append(data1)
elif data2 == b'SYNTHETIC_KEY':
if l1 != 32:
break
r["SYNTHETIC_KEY"].append(data1)
elif (opcode1, data1) != (opcode2, data2):
break
return None
Expand All @@ -86,6 +93,7 @@ def match(self, template_disassembly, script):
p2pkh_wit=lambda info: "OP_0 %s" % b2h(info.get("hash160")),
p2sh=lambda info: "OP_HASH160 %s OP_EQUAL" % b2h(info.get("hash160")),
p2sh_wit=lambda info: "OP_0 %s" % b2h(info.get("hash256")),
p2tr=lambda info: "PUSH_81 %s" % b2h(info.get("synthetic_key")),
multisig=lambda info: "%d %s %d OP_CHECKMULTISIG" % (
info.get("m"), " ".join(b2h(sk) for sk in info.get("sec_keys")), len(info.get("sec_keys"))),
)
Expand Down Expand Up @@ -127,6 +135,11 @@ def info_for_script(self, script):
if d:
return dict(type="p2pk", sec=d["PUBKEY_LIST"][0])

d = self.match("OP_1 'SYNTHETIC_KEY'", script)
if d:
if len(d["SYNTHETIC_KEY"][0]) == 32:
return dict(type="p2tr", synthetic_key=d["SYNTHETIC_KEY"][0])

if self._script_tools.compile("OP_RETURN") == script[:1]:
return dict(type="nulldata", data=script[1:])

Expand Down
12 changes: 11 additions & 1 deletion pycoin/networks/ParseAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,13 @@ def p2sh_segwit(self, s):
"""
return self._bech32m(s, 0, 32, "for_p2sh_wit")

def p2tr(self, s):
"""
Parse a pay-to-taproot segwit address.
Return a :class:`Contract <pycoin.networks.Contract.Contract>` or None.
"""
return self._bech32m(s, 1, 32, "for_p2tr")

# payable (+ all address types)
def script(self, s):
"""
Expand Down Expand Up @@ -352,7 +359,10 @@ def address(self, s):
Return a :class:`Contract <pycoin.networks.Contract.Contract>`, or None.
"""
s = parseable_str(s)
return self.p2pkh(s) or self.p2sh(s) or self.p2pkh_segwit(s) or self.p2sh_segwit(s)
return (
self.p2pkh(s) or self.p2sh(s) or self.p2pkh_segwit(s) or self.p2sh_segwit(s)
or self.p2tr(s)
)

def payable(self, s):
"""
Expand Down

0 comments on commit 68ec7eb

Please sign in to comment.