mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-04-20 17:19:01 +00:00
feat(tests): Support non-bitcoinlike coins in make_payment_request.
This commit is contained in:
parent
17e9515ee2
commit
faf09b48d0
@ -85,7 +85,6 @@ Q(apps.bitcoin.sign_tx.helpers)
|
||||
Q(apps.bitcoin.sign_tx.layout)
|
||||
Q(apps.bitcoin.sign_tx.matchcheck)
|
||||
Q(apps.bitcoin.sign_tx.omni)
|
||||
Q(apps.bitcoin.sign_tx.payment_request)
|
||||
Q(apps.bitcoin.sign_tx.progress)
|
||||
Q(apps.bitcoin.sign_tx.sig_hasher)
|
||||
Q(apps.bitcoin.sign_tx.tx_info)
|
||||
@ -107,6 +106,7 @@ Q(apps.common.keychain)
|
||||
Q(apps.common.passphrase)
|
||||
Q(apps.common.paths)
|
||||
Q(apps.common.payment_request)
|
||||
Q(payment_request)
|
||||
Q(apps.common.readers)
|
||||
Q(apps.common.request_pin)
|
||||
Q(apps.common.safety_checks)
|
||||
|
@ -27,7 +27,7 @@ from trezorlib.tools import parse_path
|
||||
|
||||
from .. import common
|
||||
from .. import translations as TR
|
||||
from ..device_tests.bitcoin.payment_req import make_coinjoin_request
|
||||
from ..device_tests.bitcoin.coinjoin_req import make_coinjoin_request
|
||||
from ..tx_cache import TxCache
|
||||
from . import recovery
|
||||
from .common import go_next, unlock_gesture
|
||||
|
26
tests/device_tests/bitcoin/coinjoin_req.py
Normal file
26
tests/device_tests/bitcoin/coinjoin_req.py
Normal file
@ -0,0 +1,26 @@
|
||||
from trezorlib import messages
|
||||
|
||||
|
||||
def make_coinjoin_request(
|
||||
coordinator_name,
|
||||
inputs,
|
||||
input_script_pubkeys,
|
||||
outputs,
|
||||
output_script_pubkeys,
|
||||
no_fee_indices,
|
||||
fee_rate=500_000, # 0.5 %
|
||||
no_fee_threshold=1_000_000,
|
||||
min_registrable_amount=5_000,
|
||||
):
|
||||
# Process inputs.
|
||||
for i, txi in enumerate(inputs):
|
||||
# Set no_fee flag in coinjoin_flags.
|
||||
txi.coinjoin_flags |= (i in no_fee_indices) << 1
|
||||
|
||||
return messages.CoinJoinRequest(
|
||||
fee_rate=fee_rate,
|
||||
no_fee_threshold=no_fee_threshold,
|
||||
min_registrable_amount=min_registrable_amount,
|
||||
mask_public_key=b"",
|
||||
signature=b"",
|
||||
)
|
@ -25,7 +25,7 @@ from trezorlib.tools import parse_path
|
||||
|
||||
from ...common import is_core
|
||||
from ...tx_cache import TxCache
|
||||
from .payment_req import make_coinjoin_request
|
||||
from .coinjoin_req import make_coinjoin_request
|
||||
from .signtx import (
|
||||
assert_tx_matches,
|
||||
request_finished,
|
||||
|
@ -24,7 +24,7 @@ from trezorlib.exceptions import TrezorFailure
|
||||
from trezorlib.tools import parse_path
|
||||
|
||||
from ...input_flows import InputFlowPaymentRequestDetails
|
||||
from .payment_req import CoinPurchaseMemo, RefundMemo, TextMemo, make_payment_request
|
||||
from ..payment_req import CoinPurchaseMemo, RefundMemo, TextMemo, make_payment_request
|
||||
from .signtx import forge_prevtx
|
||||
|
||||
# address at seed "all all all..." path m/84h/1h/0h/0/0
|
||||
@ -146,13 +146,24 @@ def test_payment_request(client: Client, payment_request_params):
|
||||
for i, params in enumerate(payment_request_params):
|
||||
request_outputs = []
|
||||
for txo_index in params.txo_indices:
|
||||
outputs[txo_index].payment_req_index = i
|
||||
request_outputs.append(outputs[txo_index])
|
||||
output = outputs[txo_index]
|
||||
output.payment_req_index = i
|
||||
request_outputs.append((output.amount, output.address))
|
||||
nonce = misc.get_nonce(client) if params.get_nonce else None
|
||||
for memo in params.memos:
|
||||
if isinstance(memo, RefundMemo):
|
||||
memo.address_resp = btc.get_authenticated_address(
|
||||
client, "Testnet", memo.address_n
|
||||
)
|
||||
elif isinstance(memo, CoinPurchaseMemo):
|
||||
memo.address_resp = btc.get_authenticated_address(
|
||||
client, memo.coin_name, memo.address_n
|
||||
)
|
||||
payment_reqs.append(
|
||||
make_payment_request(
|
||||
client,
|
||||
recipient_name="trezor.io",
|
||||
slip44=1,
|
||||
outputs=request_outputs,
|
||||
change_addresses=["tb1qkvwu9g3k2pdxewfqr7syz89r3gj557l3uuf9r9"],
|
||||
memos=params.memos,
|
||||
@ -194,7 +205,8 @@ def test_payment_request_details(client: Client):
|
||||
make_payment_request(
|
||||
client,
|
||||
recipient_name="trezor.io",
|
||||
outputs=outputs[:2],
|
||||
slip44=1,
|
||||
outputs=[(txo.amount, txo.address) for txo in outputs[:2]],
|
||||
memos=[TextMemo("Invoice #87654321.")],
|
||||
nonce=nonce,
|
||||
)
|
||||
@ -224,7 +236,8 @@ def test_payment_req_wrong_amount(client: Client):
|
||||
payment_req = make_payment_request(
|
||||
client,
|
||||
recipient_name="trezor.io",
|
||||
outputs=outputs[:2],
|
||||
slip44=1,
|
||||
outputs=[(txo.amount, txo.address) for txo in outputs[:2]],
|
||||
nonce=misc.get_nonce(client),
|
||||
)
|
||||
|
||||
@ -245,13 +258,15 @@ def test_payment_req_wrong_amount(client: Client):
|
||||
def test_payment_req_wrong_mac_refund(client: Client):
|
||||
# Test wrong MAC in payment request memo.
|
||||
memo = RefundMemo(parse_path("m/44h/1h/0h/1/0"))
|
||||
memo.address_resp = btc.get_authenticated_address(client, "Testnet", memo.address_n)
|
||||
outputs[0].payment_req_index = 0
|
||||
outputs[1].payment_req_index = 0
|
||||
outputs[2].payment_req_index = None
|
||||
payment_req = make_payment_request(
|
||||
client,
|
||||
recipient_name="trezor.io",
|
||||
outputs=outputs[:2],
|
||||
slip44=1,
|
||||
outputs=[(txo.amount, txo.address) for txo in outputs[:2]],
|
||||
memos=[memo],
|
||||
nonce=misc.get_nonce(client),
|
||||
)
|
||||
@ -282,13 +297,17 @@ def test_payment_req_wrong_mac_purchase(client: Client):
|
||||
slip44=5,
|
||||
address_n=parse_path("m/44h/5h/0h/1/0"),
|
||||
)
|
||||
memo.address_resp = btc.get_authenticated_address(
|
||||
client, memo.coin_name, memo.address_n
|
||||
)
|
||||
outputs[0].payment_req_index = 0
|
||||
outputs[1].payment_req_index = 0
|
||||
outputs[2].payment_req_index = None
|
||||
payment_req = make_payment_request(
|
||||
client,
|
||||
recipient_name="trezor.io",
|
||||
outputs=outputs[:2],
|
||||
slip44=1,
|
||||
outputs=[(txo.amount, txo.address) for txo in outputs[:2]],
|
||||
memos=[memo],
|
||||
nonce=misc.get_nonce(client),
|
||||
)
|
||||
@ -317,7 +336,8 @@ def test_payment_req_wrong_output(client: Client):
|
||||
payment_req = make_payment_request(
|
||||
client,
|
||||
recipient_name="trezor.io",
|
||||
outputs=outputs[:2],
|
||||
slip44=1,
|
||||
outputs=[(txo.amount, txo.address) for txo in outputs[:2]],
|
||||
nonce=misc.get_nonce(client),
|
||||
)
|
||||
|
||||
|
@ -1,19 +1,32 @@
|
||||
from collections import namedtuple
|
||||
from dataclasses import dataclass
|
||||
from hashlib import sha256
|
||||
|
||||
from ecdsa import SECP256k1, SigningKey
|
||||
|
||||
from trezorlib import btc, messages
|
||||
from trezorlib import messages
|
||||
|
||||
from ...common import compact_size
|
||||
from ..common import compact_size
|
||||
|
||||
SLIP44 = 1 # Testnet
|
||||
|
||||
TextMemo = namedtuple("TextMemo", "text")
|
||||
RefundMemo = namedtuple("RefundMemo", "address_n")
|
||||
CoinPurchaseMemo = namedtuple(
|
||||
"CoinPurchaseMemo", "amount, coin_name, slip44, address_n"
|
||||
)
|
||||
@dataclass
|
||||
class TextMemo:
|
||||
text: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class RefundMemo:
|
||||
address_n: list[int]
|
||||
address_resp: messages.Address | messages.EthereumAddress | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class CoinPurchaseMemo:
|
||||
amount: int
|
||||
coin_name: str
|
||||
slip44: int
|
||||
address_n: list[int]
|
||||
address_resp: messages.Address | messages.EthereumAddress | None = None
|
||||
|
||||
|
||||
payment_req_signer = SigningKey.from_string(
|
||||
b"?S\ti\x8b\xc5o{,\xab\x03\x194\xea\xa8[_:\xeb\xdf\xce\xef\xe50\xf17D\x98`\xb9dj",
|
||||
@ -27,7 +40,13 @@ def hash_bytes_prefixed(hasher, data):
|
||||
|
||||
|
||||
def make_payment_request(
|
||||
client, recipient_name, outputs, change_addresses=None, memos=None, nonce=None
|
||||
client,
|
||||
recipient_name,
|
||||
slip44,
|
||||
outputs,
|
||||
change_addresses=None,
|
||||
memos=None,
|
||||
nonce=None,
|
||||
):
|
||||
h_pr = sha256(b"SL\x00\x24")
|
||||
|
||||
@ -51,25 +70,19 @@ def make_payment_request(
|
||||
h_pr.update(memo_type.to_bytes(4, "little"))
|
||||
hash_bytes_prefixed(h_pr, memo.text.encode())
|
||||
elif isinstance(memo, RefundMemo):
|
||||
address_resp = btc.get_authenticated_address(
|
||||
client, "Testnet", memo.address_n
|
||||
)
|
||||
msg_memo = messages.RefundMemo(
|
||||
address=address_resp.address, mac=address_resp.mac
|
||||
address=memo.address_resp.address, mac=memo.address_resp.mac
|
||||
)
|
||||
msg_memos.append(messages.PaymentRequestMemo(refund_memo=msg_memo))
|
||||
memo_type = 2
|
||||
h_pr.update(memo_type.to_bytes(4, "little"))
|
||||
hash_bytes_prefixed(h_pr, address_resp.address.encode())
|
||||
hash_bytes_prefixed(h_pr, memo.address_resp.address.encode())
|
||||
elif isinstance(memo, CoinPurchaseMemo):
|
||||
address_resp = btc.get_authenticated_address(
|
||||
client, memo.coin_name, memo.address_n
|
||||
)
|
||||
msg_memo = messages.CoinPurchaseMemo(
|
||||
coin_type=memo.slip44,
|
||||
amount=memo.amount,
|
||||
address=address_resp.address,
|
||||
mac=address_resp.mac,
|
||||
address=memo.address_resp.address,
|
||||
mac=memo.address_resp.mac,
|
||||
)
|
||||
msg_memos.append(messages.PaymentRequestMemo(coin_purchase_memo=msg_memo))
|
||||
|
||||
@ -77,17 +90,18 @@ def make_payment_request(
|
||||
h_pr.update(memo_type.to_bytes(4, "little"))
|
||||
h_pr.update(memo.slip44.to_bytes(4, "little"))
|
||||
hash_bytes_prefixed(h_pr, memo.amount.encode())
|
||||
hash_bytes_prefixed(h_pr, address_resp.address.encode())
|
||||
hash_bytes_prefixed(h_pr, memo.address_resp.address.encode())
|
||||
else:
|
||||
raise ValueError
|
||||
|
||||
h_pr.update(SLIP44.to_bytes(4, "little"))
|
||||
h_pr.update(slip44.to_bytes(4, "little"))
|
||||
|
||||
change_address = iter(change_addresses or [])
|
||||
h_outputs = sha256()
|
||||
for txo in outputs:
|
||||
h_outputs.update(txo.amount.to_bytes(8, "little"))
|
||||
address = txo.address or next(change_address)
|
||||
for amount, address in outputs:
|
||||
h_outputs.update(amount.to_bytes(8, "little"))
|
||||
if not address:
|
||||
address = next(change_address)
|
||||
h_outputs.update(len(address).to_bytes(1, "little"))
|
||||
h_outputs.update(address.encode())
|
||||
|
||||
@ -95,33 +109,8 @@ def make_payment_request(
|
||||
|
||||
return messages.PaymentRequest(
|
||||
recipient_name=recipient_name,
|
||||
amount=sum(txo.amount for txo in outputs if txo.address),
|
||||
amount=sum(amount for amount, address in outputs if address),
|
||||
memos=msg_memos,
|
||||
nonce=nonce,
|
||||
signature=payment_req_signer.sign_digest_deterministic(h_pr.digest()),
|
||||
)
|
||||
|
||||
|
||||
def make_coinjoin_request(
|
||||
coordinator_name,
|
||||
inputs,
|
||||
input_script_pubkeys,
|
||||
outputs,
|
||||
output_script_pubkeys,
|
||||
no_fee_indices,
|
||||
fee_rate=500_000, # 0.5 %
|
||||
no_fee_threshold=1_000_000,
|
||||
min_registrable_amount=5_000,
|
||||
):
|
||||
# Process inputs.
|
||||
for i, txi in enumerate(inputs):
|
||||
# Set no_fee flag in coinjoin_flags.
|
||||
txi.coinjoin_flags |= (i in no_fee_indices) << 1
|
||||
|
||||
return messages.CoinJoinRequest(
|
||||
fee_rate=fee_rate,
|
||||
no_fee_threshold=no_fee_threshold,
|
||||
min_registrable_amount=min_registrable_amount,
|
||||
mask_public_key=b"",
|
||||
signature=b"",
|
||||
)
|
Loading…
Reference in New Issue
Block a user