Skip to content

Commit

Permalink
tests: add bitcoin
Browse files Browse the repository at this point in the history
  • Loading branch information
sgliner-ledger committed Nov 15, 2023
1 parent 8608b97 commit d67a5d6
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 1 deletion.
40 changes: 39 additions & 1 deletion test/python/apps/bitcoin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,44 @@
import sys
from enum import IntEnum
from pathlib import Path
from ragger.utils import create_currency_config
from ragger.bip import BtcDerivationPathFormat, bitcoin_pack_derivation_path
from ragger.backend.interface import BackendInterface, RAPDU
from ragger.backend import RaisePolicy

sys.path.append(f"{Path(__file__).parent.resolve()}/bitcoin_client")
from txmaker import createPsbt
from ledger_bitcoin import Client, WalletPolicy, MultisigWallet, AddressType, PartialSignature, segwit_addr
from ledger_bitcoin import Client, Chain, createClient
from ledger_bitcoin.bip380.descriptors import Descriptor

BTC_CONF = create_currency_config("BTC", "Bitcoin")

BTC_PACKED_DERIVATION_PATH = bitcoin_pack_derivation_path(BtcDerivationPathFormat.BECH32, "m/44'/0'/0'/0/0")
BTC_PACKED_DERIVATION_PATH = bitcoin_pack_derivation_path(BtcDerivationPathFormat.BECH32, "m/84'/0'/0'/0/0")

CHAIN = Chain.MAIN

class BitcoinErrors(IntEnum):
SW_SWAP_CHECKING_FAIL = 0x6b00

class BitcoinClient:
def __init__(self, backend: BackendInterface):
if not isinstance(backend, BackendInterface):
raise TypeError("backend must be an instance of BackendInterface")
self._backend = backend
self._backend.raise_policy = RaisePolicy.RAISE_CUSTOM
self._backend.whitelisted_status = [0x9000, 0xE000]
self.client = createClient(backend, chain=CHAIN, debug=True)

def send_simple_sign_tx(self, in_wallet: WalletPolicy, fees: int, destination: WalletPolicy, send_amount: int) -> RAPDU:
in_amounts = [send_amount + fees]
out_amounts = [send_amount]
psbt = createPsbt(in_wallet, in_amounts, out_amounts, [False], [destination])
self.client.sign_psbt(psbt, in_wallet, None)

def get_address_from_wallet(wallet: WalletPolicy):
desc = Descriptor.from_str(wallet.get_descriptor(False))
desc.derive(0)
spk = desc.script_pubkey
hrp = "bc" if CHAIN == Chain.MAIN else "tb"
return segwit_addr.encode(hrp, 0, spk[2:])
2 changes: 2 additions & 0 deletions test/python/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ stellar_sdk
base58
xrpl-py
scalecodec
bip32
embit
73 changes: 73 additions & 0 deletions test/python/test_bitcoin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import pytest

from .apps.exchange_test_runner import ExchangeTestRunner, ALL_TESTS_EXCEPT_MEMO
from .apps.bitcoin import BitcoinClient, BitcoinErrors
from ledger_bitcoin import WalletPolicy

in_wallet = WalletPolicy(
"",
"wpkh(@0/**)",
[
"[f5acc2fd/84'/0'/0']xpub6DUYn4moKgHkK2d7bXX3mHTPb6XQwRVFRMdZ6ZwLS5u3nonGVpJiFeZiQkHutwdFqxKP75jex8gvVm7ed4euYeDtMnoiF1Cz1z4CeBJYWin"
],
)

out_wallet = WalletPolicy(
"",
"wpkh(@0/**)",
[
"xpub6CatWdiZiodmYVtWLtEQsAg1H9ooS1bmsJUBwQ83FE1Fyk386FWcyicJgEZv3quZSJKA5dh5Lo2PbubMGxCfZtRthV6ST2qquL9w3HSzcUn"
],
)

out_wallet_2 = WalletPolicy(
"",
"wpkh(@0/**)",
[
"xpub6D7atwj3ewAGT347tUzTNzfTGos1rCFVX4v8gViXiM2R1QHvox1LhEf6NtCeNsCwpppFUoQuS6mHUwfTveA5tEEwn2LqZHfVBEz5qvYmYhf"
],
)

# ExchangeTestRunner implementation for Bitcoin
class BitcoinTests(ExchangeTestRunner):

currency_ticker = "BTC"
valid_destination_1 = BitcoinClient.get_address_from_wallet(out_wallet)
valid_destination_memo_1 = ""
valid_destination_2 = BitcoinClient.get_address_from_wallet(out_wallet_2)
valid_destination_memo_2 = "0"
valid_refund = BitcoinClient.get_address_from_wallet(in_wallet)
valid_refund_memo = ""
valid_send_amount_1 = 20900000
valid_send_amount_2 = 446739662
valid_fees_1 = 100000
valid_fees_2 = 10078
fake_refund = "abcdabcd"
fake_refund_memo = ""
fake_payout = "abcdabcd"
fake_payout_memo = ""
signature_refusal_error_code = BitcoinErrors.SW_SWAP_CHECKING_FAIL

def perform_final_tx(self, destination, send_amount, fees, memo):
if destination == BitcoinClient.get_address_from_wallet(out_wallet):
BitcoinClient(self.backend).send_simple_sign_tx(in_wallet=in_wallet,
fees=fees,
destination=out_wallet,
send_amount=send_amount)

elif destination == BitcoinClient.get_address_from_wallet(out_wallet_2):
BitcoinClient(self.backend).send_simple_sign_tx(in_wallet=in_wallet,
fees=fees,
destination=out_wallet_2,
send_amount=send_amount)

# TODO : assert signature validity


# Use a class to reuse the same Speculos instance
class TestsBitcoin:

@pytest.mark.parametrize('test_to_run', ALL_TESTS_EXCEPT_MEMO)
def test_bitcoin(self, backend, exchange_navigation_helper, test_to_run):
BitcoinTests(backend, exchange_navigation_helper).run_test(test_to_run)

0 comments on commit d67a5d6

Please sign in to comment.