|
|
|
@ -3,6 +3,7 @@ from typing import TYPE_CHECKING
|
|
|
|
|
from trezor import utils
|
|
|
|
|
from trezor.crypto import base58
|
|
|
|
|
from trezor.crypto.base58 import blake256d_32
|
|
|
|
|
from trezor.enums import DecredStakingSpendType
|
|
|
|
|
from trezor.wire import DataError
|
|
|
|
|
|
|
|
|
|
from . import scripts
|
|
|
|
@ -11,7 +12,22 @@ from .scripts import ( # noqa: F401
|
|
|
|
|
write_output_script_multisig,
|
|
|
|
|
write_output_script_p2pkh,
|
|
|
|
|
)
|
|
|
|
|
from .writers import write_compact_size
|
|
|
|
|
from .writers import (
|
|
|
|
|
write_bytes_fixed,
|
|
|
|
|
write_compact_size,
|
|
|
|
|
write_op_push,
|
|
|
|
|
write_bytes_fixed,
|
|
|
|
|
write_uint64_le,
|
|
|
|
|
op_push_length,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# These are decred specific opcodes related to staking.
|
|
|
|
|
OP_SSTX = 0xBA
|
|
|
|
|
OP_SSGEN = 0xBB
|
|
|
|
|
OP_SSRTX = 0xBC
|
|
|
|
|
OP_SSTXCHANGE = 0xBD
|
|
|
|
|
|
|
|
|
|
STAKE_TREE = 1
|
|
|
|
|
|
|
|
|
|
if TYPE_CHECKING:
|
|
|
|
|
from trezor.enums import InputScriptType
|
|
|
|
@ -62,7 +78,6 @@ def _write_input_script_multisig_prefixed(
|
|
|
|
|
coin: CoinInfo,
|
|
|
|
|
) -> None:
|
|
|
|
|
from .multisig import multisig_get_pubkeys
|
|
|
|
|
from .writers import op_push_length, write_op_push
|
|
|
|
|
|
|
|
|
|
signatures = multisig.signatures # other signatures
|
|
|
|
|
if len(signatures[signature_index]) > 0:
|
|
|
|
@ -98,7 +113,7 @@ def output_script_sstxsubmissionpkh(addr: str) -> bytearray:
|
|
|
|
|
raise DataError("Invalid address")
|
|
|
|
|
|
|
|
|
|
w = utils.empty_bytearray(26)
|
|
|
|
|
w.append(0xBA) # OP_SSTX
|
|
|
|
|
w.append(OP_SSTX)
|
|
|
|
|
scripts.write_output_script_p2pkh(w, raw_address[2:])
|
|
|
|
|
return w
|
|
|
|
|
|
|
|
|
@ -111,7 +126,7 @@ def output_script_sstxchange(addr: str) -> bytearray:
|
|
|
|
|
raise DataError("Invalid address")
|
|
|
|
|
|
|
|
|
|
w = utils.empty_bytearray(26)
|
|
|
|
|
w.append(0xBD) # OP_SSTXCHANGE
|
|
|
|
|
w.append(OP_SSTXCHANGE)
|
|
|
|
|
scripts.write_output_script_p2pkh(w, raw_address[2:])
|
|
|
|
|
return w
|
|
|
|
|
|
|
|
|
@ -120,7 +135,7 @@ def output_script_sstxchange(addr: str) -> bytearray:
|
|
|
|
|
def write_output_script_ssrtx_prefixed(w: Writer, pkh: bytes) -> None:
|
|
|
|
|
utils.ensure(len(pkh) == 20)
|
|
|
|
|
write_compact_size(w, 26)
|
|
|
|
|
w.append(0xBC) # OP_SSRTX
|
|
|
|
|
w.append(OP_SSRTX)
|
|
|
|
|
scripts.write_output_script_p2pkh(w, pkh)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -128,16 +143,65 @@ def write_output_script_ssrtx_prefixed(w: Writer, pkh: bytes) -> None:
|
|
|
|
|
def write_output_script_ssgen_prefixed(w: Writer, pkh: bytes) -> None:
|
|
|
|
|
utils.ensure(len(pkh) == 20)
|
|
|
|
|
write_compact_size(w, 26)
|
|
|
|
|
w.append(0xBB) # OP_SSGEN
|
|
|
|
|
w.append(OP_SSGEN)
|
|
|
|
|
scripts.write_output_script_p2pkh(w, pkh)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Stake commitment OPRETURN.
|
|
|
|
|
def sstxcommitment_pkh(pkh: bytes, amount: int) -> bytes:
|
|
|
|
|
from apps.common.writers import write_bytes_fixed, write_uint64_le
|
|
|
|
|
|
|
|
|
|
w = utils.empty_bytearray(30)
|
|
|
|
|
write_bytes_fixed(w, pkh, 20)
|
|
|
|
|
write_uint64_le(w, amount)
|
|
|
|
|
write_bytes_fixed(w, b"\x00\x58", 2) # standard fee limits
|
|
|
|
|
return w
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def output_script_p2pkh(pubkeyhash: bytes) -> bytearray:
|
|
|
|
|
s = utils.empty_bytearray(25)
|
|
|
|
|
scripts.write_output_script_p2pkh(s, pubkeyhash)
|
|
|
|
|
return s
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def output_script_p2sh(scripthash: bytes) -> bytearray:
|
|
|
|
|
# A9 14 <scripthash> 87
|
|
|
|
|
utils.ensure(len(scripthash) == 20)
|
|
|
|
|
s = bytearray(23)
|
|
|
|
|
s[0] = 0xA9 # OP_HASH_160
|
|
|
|
|
s[1] = 0x14 # pushing 20 bytes
|
|
|
|
|
s[2:22] = scripthash
|
|
|
|
|
s[22] = 0x87 # OP_EQUAL
|
|
|
|
|
return s
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def output_derive_script(tree: int, stakeType: int, addr: str, coin: CoinInfo) -> bytes:
|
|
|
|
|
from trezor.crypto import base58
|
|
|
|
|
from apps.common import address_type
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
raw_address = base58.decode_check(addr, blake256d_32)
|
|
|
|
|
except ValueError:
|
|
|
|
|
raise DataError("Invalid address")
|
|
|
|
|
|
|
|
|
|
if tree == STAKE_TREE:
|
|
|
|
|
if stakeType == DecredStakingSpendType.SSGen:
|
|
|
|
|
script = utils.empty_bytearray(26)
|
|
|
|
|
script.append(OP_SSGEN)
|
|
|
|
|
scripts.write_output_script_p2pkh(script, raw_address[2:])
|
|
|
|
|
return script
|
|
|
|
|
elif stakeType == DecredStakingSpendType.SSRTX:
|
|
|
|
|
script = utils.empty_bytearray(26)
|
|
|
|
|
script.append(OP_SSRTX)
|
|
|
|
|
scripts.write_output_script_p2pkh(script, raw_address[2:])
|
|
|
|
|
return script
|
|
|
|
|
|
|
|
|
|
elif address_type.check(coin.address_type, raw_address):
|
|
|
|
|
# p2pkh
|
|
|
|
|
pubkeyhash = address_type.strip(coin.address_type, raw_address)
|
|
|
|
|
script = output_script_p2pkh(pubkeyhash)
|
|
|
|
|
return script
|
|
|
|
|
elif address_type.check(coin.address_type_p2sh, raw_address):
|
|
|
|
|
scripthash = address_type.strip(coin.address_type_p2sh, raw_address)
|
|
|
|
|
script = output_script_p2sh(scripthash)
|
|
|
|
|
return script
|
|
|
|
|
|
|
|
|
|
raise DataError("Invalid address type")
|
|
|
|
|