Skip to content

Commit

Permalink
Merge pull request LedgerHQ#229 from LedgerHQ/cev/B2CA-1838_implement…
Browse files Browse the repository at this point in the history
…-swap

Initial cardano tests implementation
  • Loading branch information
cedelavergne-ledger authored Dec 12, 2024
2 parents acd7e44 + 03921f0 commit 50e2c39
Show file tree
Hide file tree
Showing 385 changed files with 268 additions and 19 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/reusable_swap_functional_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,15 @@ on:
default: 'LedgerHQ/app-ton-new'
type: string

branch_for_cardano:
required: false
default: 'develop'
type: string
repo_for_cardano:
required: false
default: 'LedgerHQ/app-cardano'
type: string

test_filter:
required: false
default: '""'
Expand Down Expand Up @@ -165,6 +174,9 @@ jobs:
- name: ton
repo: ${{ inputs.repo_for_ton }}
branch: ${{ inputs.branch_for_ton }}
- name: cardano
repo: ${{ inputs.repo_for_cardano }}
branch: ${{ inputs.branch_for_cardano }}

uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_build.yml@v1
with:
Expand Down
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ include $(BOLOS_SDK)/Makefile.defines
APPNAME = "Exchange"

# Application version
APPVERSION_M = 3
APPVERSION_N = 4
APPVERSION_P = 1
APPVERSION_M = 4
APPVERSION_N = 0
APPVERSION_P = 0
APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)"

# Application source files
Expand Down
2 changes: 1 addition & 1 deletion ledger_app.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[app]
build_directory = "./"
sdk = "C"
devices = ["nanos", "nanox", "nanos+", "stax", "flex"]
devices = ["nanox", "nanos+", "stax", "flex"]

[use_cases]
use_test_keys = "TEST_PUBLIC_KEY=1"
Expand Down
10 changes: 5 additions & 5 deletions src/proto/protocol.options
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
ledger_swap.NewTransactionResponse.payin_address max_size:63;
ledger_swap.NewTransactionResponse.payin_address max_size:150;
ledger_swap.NewTransactionResponse.payin_extra_id max_size:20;
ledger_swap.NewTransactionResponse.payin_extra_data max_size:33;
ledger_swap.NewTransactionResponse.refund_address max_size:63;
ledger_swap.NewTransactionResponse.refund_address max_size:150;
ledger_swap.NewTransactionResponse.refund_extra_id max_size:20;
ledger_swap.NewTransactionResponse.payout_address max_size:63;
ledger_swap.NewTransactionResponse.payout_address max_size:150;
ledger_swap.NewTransactionResponse.payout_extra_id max_size:20;
ledger_swap.NewTransactionResponse.currency_from max_size:10;
ledger_swap.NewTransactionResponse.currency_to max_size:10;
Expand All @@ -15,15 +15,15 @@ ledger_swap.NewTransactionResponse.device_transaction_id_ng max_size:32;
ledger_swap.NewSellResponse.trader_email max_size:50;
ledger_swap.NewSellResponse.in_currency max_size:10;
ledger_swap.NewSellResponse.in_amount max_size:16;
ledger_swap.NewSellResponse.in_address max_size:63;
ledger_swap.NewSellResponse.in_address max_size:150;
ledger_swap.NewSellResponse.out_currency max_size:10;
ledger_swap.NewSellResponse.device_transaction_id max_size:32;

ledger_swap.NewFundResponse.user_id max_size:50;
ledger_swap.NewFundResponse.account_name max_size:50;
ledger_swap.NewFundResponse.in_currency max_size:10;
ledger_swap.NewFundResponse.in_amount max_size:16;
ledger_swap.NewFundResponse.in_address max_size:63;
ledger_swap.NewFundResponse.in_address max_size:150;
ledger_swap.NewFundResponse.device_transaction_id max_size:32;

ledger_swap.UDecimal.coefficient max_size:16;
2 changes: 1 addition & 1 deletion src/proto/protocol.pb.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.3.9 at Mon Jun 24 15:05:18 2024. */
/* Generated by nanopb-0.3.9 at Mon Nov 18 08:50:16 2024. */

#include "protocol.pb.h"

Expand Down
18 changes: 9 additions & 9 deletions src/proto/protocol.pb.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.3.9 at Mon Jun 24 15:05:18 2024. */
/* Generated by nanopb-0.3.9 at Mon Nov 18 08:50:16 2024. */

#ifndef PB_LEDGER_SWAP_PROTOCOL_PB_H_INCLUDED
#define PB_LEDGER_SWAP_PROTOCOL_PB_H_INCLUDED
Expand All @@ -22,7 +22,7 @@ typedef struct _ledger_swap_NewFundResponse {
char account_name[50];
char in_currency[10];
ledger_swap_NewFundResponse_in_amount_t in_amount;
char in_address[63];
char in_address[150];
ledger_swap_NewFundResponse_device_transaction_id_t device_transaction_id;
/* @@protoc_insertion_point(struct:ledger_swap_NewFundResponse) */
} ledger_swap_NewFundResponse;
Expand All @@ -32,11 +32,11 @@ typedef PB_BYTES_ARRAY_T(16) ledger_swap_NewTransactionResponse_amount_to_provid
typedef PB_BYTES_ARRAY_T(16) ledger_swap_NewTransactionResponse_amount_to_wallet_t;
typedef PB_BYTES_ARRAY_T(32) ledger_swap_NewTransactionResponse_device_transaction_id_ng_t;
typedef struct _ledger_swap_NewTransactionResponse {
char payin_address[63];
char payin_address[150];
char payin_extra_id[20];
char refund_address[63];
char refund_address[150];
char refund_extra_id[20];
char payout_address[63];
char payout_address[150];
char payout_extra_id[20];
char currency_from[10];
char currency_to[10];
Expand All @@ -61,7 +61,7 @@ typedef struct _ledger_swap_NewSellResponse {
char trader_email[50];
char in_currency[10];
ledger_swap_NewSellResponse_in_amount_t in_amount;
char in_address[63];
char in_address[150];
char out_currency[10];
ledger_swap_UDecimal out_amount;
ledger_swap_NewSellResponse_device_transaction_id_t device_transaction_id;
Expand Down Expand Up @@ -117,10 +117,10 @@ extern const pb_field_t ledger_swap_NewSellResponse_fields[8];
extern const pb_field_t ledger_swap_NewFundResponse_fields[7];

/* Maximum encoded size of messages (where known) */
#define ledger_swap_NewTransactionResponse_size 403
#define ledger_swap_NewTransactionResponse_size 667
#define ledger_swap_UDecimal_size 24
#define ledger_swap_NewSellResponse_size 219
#define ledger_swap_NewFundResponse_size 233
#define ledger_swap_NewSellResponse_size 307
#define ledger_swap_NewFundResponse_size 321

/* Message IDs (where set with "msgid" option) */
#ifdef PB_MSGID
Expand Down
3 changes: 3 additions & 0 deletions test/python/apps/cal.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from .ton import TON_PACKED_DERIVATION_PATH, TON_CONF
from .tron import TRX_PACKED_DERIVATION_PATH, TRX_CONF
from .tron import TRX_USDT_CONF, TRX_USDC_CONF, TRX_TUSD_CONF, TRX_USDD_CONF
from .cardano import ADA_BYRON_PACKED_DERIVATION_PATH, ADA_SHELLEY_PACKED_DERIVATION_PATH, ADA_CONF

@dataclass
class CurrencyConfiguration:
Expand Down Expand Up @@ -54,6 +55,8 @@ def get_conf_for_ticker(self, overload_signer: Optional[SigningAuthority]=None)
USDC_CURRENCY_CONFIGURATION = CurrencyConfiguration(ticker="USDC", conf=TRX_USDC_CONF, packed_derivation_path=TRX_PACKED_DERIVATION_PATH)
TUSD_CURRENCY_CONFIGURATION = CurrencyConfiguration(ticker="TUSD", conf=TRX_TUSD_CONF, packed_derivation_path=TRX_PACKED_DERIVATION_PATH)
USDD_CURRENCY_CONFIGURATION = CurrencyConfiguration(ticker="USDD", conf=TRX_USDD_CONF, packed_derivation_path=TRX_PACKED_DERIVATION_PATH)
ADA_BYRON_CURRENCY_CONFIGURATION = CurrencyConfiguration(ticker="ADA", conf=ADA_CONF, packed_derivation_path=ADA_BYRON_PACKED_DERIVATION_PATH)
ADA_SHELLEY_CURRENCY_CONFIGURATION = CurrencyConfiguration(ticker="ADA", conf=ADA_CONF, packed_derivation_path=ADA_SHELLEY_PACKED_DERIVATION_PATH)


# Helper that can be called from outside if we want to generate errors easily
Expand Down
141 changes: 141 additions & 0 deletions test/python/apps/cardano.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
from enum import IntEnum

from hashlib import sha512
from ecdsa.curves import Ed25519
from ecdsa.keys import VerifyingKey

from ragger.backend.interface import BackendInterface
from ragger.bip import pack_derivation_path, calculate_public_key_and_chaincode, CurveChoice
from ragger.utils import create_currency_config


ADA_CONF = create_currency_config("ADA", "Cardano ADA")

ADA_BYRON_DERIVATION_PATH = "m/44'/1815'/0'/0/0"
ADA_SHELLEY_DERIVATION_PATH = "m/1852'/1815'/0'/0/0"
ADA_BYRON_PACKED_DERIVATION_PATH = pack_derivation_path(ADA_BYRON_DERIVATION_PATH)
ADA_SHELLEY_PACKED_DERIVATION_PATH = pack_derivation_path(ADA_SHELLEY_DERIVATION_PATH)


class Errors(IntEnum):
SW_SWAP_CHECKING_FAIL = 0x6001
SW_SUCCESS = 0x9000


class CardanoClient:

def __init__(self, backend: BackendInterface):
self._backend = backend


def _check_signature_validity(self, path: str, signature: bytes, data: bytes) -> None:
"""Check the signature validity
Args:
path (str): The derivation path
signature (bytes): The received signature
data (bytes): The signed data
"""

ref_pk, _ = calculate_public_key_and_chaincode(CurveChoice.Ed25519Kholaw, path)
pk: VerifyingKey = VerifyingKey.from_string(bytes.fromhex(ref_pk[2:]), curve=Ed25519)
assert pk.verify(signature, data, sha512)


# def perform_byron_sign_tx(self, path: str, destination: str, send_amount: int, send_fees: int) -> None:
# """Send a Sign TX command to the Cardano app.
# Based on Byron, address type THIRD_PARTY

# Args:
# path (str): Derivation path
# destination (str): Destination address
# send_amount (int): Amount to send
# send_fees (int): Fees to pay

# Returns:
# Tuple[bytes, bytes]: Data Hash and the Signature
# """

# dest_len = len(destination) // 2
# output_len = 2 + 4 + dest_len + len(send_amount) // 2 + 6
# signTx = {
# # Based on ragger testsByron: Sign tx with third-party Byron mainnet output
# "signTxInit": "d72101003c0000000000000000012d964a090201010101010101010103000000010000000100000000000000000000000000000000000000000000000000000001",
# "signTxInputs": "d7210200241af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc00000000",
# "signTxOutputBasic": f"d7210330{output_len:02x}0001{dest_len:08x}{destination}{send_amount}000000000101",
# "signTxOutputConfirm": "d721033300",
# "signTxFees": f"d721040008{send_fees}",
# "signTxTtl": "d721050008000000000000000a",
# "signTxConfirm": "d7210a0000",
# "signTxWitness": f"d7210f0015{pack_derivation_path(path).hex()}",
# }

# data: str = ""
# signature: str = ""
# for step, value in signTx.items():
# response = self._backend.exchange_raw(bytes.fromhex(value))
# assert response.status == Errors.SW_SUCCESS
# if step == "signTxConfirm":
# # Retrieve the data hash
# data = response.data
# elif step == "signTxWitness":
# # Retrieve the signature
# signature = response.data

# self._check_signature_validity(path, signature, data)


def perform_shelley_sign_tx(self, destination: str, send_amount: int, send_fees: int) -> None:
"""Send a Sign TX command to the Cardano app.
Based on Shelley, address type DEVICE_OWNED
Args:
destination (str): Destination address
send_amount (int): Amount to send
send_fees (int): Fees to pay
Returns:
Tuple[bytes, bytes]: Data Hash and the Signature
"""

if destination is None:
raise ValueError(f"Invalid destination address: {destination}")

witness_path1 = "m/1852'/1815'/2'/1/0"
witness_path2 = "m/1852'/1815'/2'/2/0"
dest_len = len(destination) // 2
output_len = 6 + dest_len + len(send_amount) // 2 + 6
signTx = {
# Based on LL example output
"getVersion": "d700000000",
"deriveAddress": "d71101002d0001058000073c8000071780000002000000000000000222058000073c80000717800000020000000200000000",
"signTxInit": "d72101003c0000000000000000012d964a090201010101010101010103000000010000000200000000000000010000000000000000000000000000000000000002",
"signTxInputs": "d7210200247c50edd7d2b7891dc3c33fade1ea557ac748bf177af7088e622f1454b6f71d0d00000000",
# Send To address (destination)
"signTxOutputBasic1": f"d7210330{output_len:02x}0101{dest_len:08x}{destination}{send_amount}000000000101",
"signTxOutputConfirm1": "d721033300",
# Send From address
"signTxOutputBasic2": "d72103303d01020001058000073c8000071780000002000000010000000122058000073c800007178000000200000002000000000000000000476009000000000101",
"signTxOutputConfirm2": "d721033300",
"signTxFees": f"d721040008{send_fees}",
"signTxTtl": "d72105000800000000085f492b",
"SignTxWithdrawals": "d72107001e0000000000004f1b00058000073c80000717800000020000000200000000",
"signTxConfirm": "d7210a0000",
"signTxWitness1": f"d7210f0015{pack_derivation_path(witness_path1).hex()}",
"signTxWitness2": f"d7210f0015{pack_derivation_path(witness_path2).hex()}",
}

data = bytes()
for step, value in signTx.items():
response = self._backend.exchange_raw(bytes.fromhex(value))
assert response.status == Errors.SW_SUCCESS
if step == "signTxConfirm":
# Retrieve the data hash
data = response.data
elif step.startswith("signTxWitness"):
# Retrieve the signature
signature = response.data
# Verify the signature for the selected path
witness_path = witness_path1 if step == "signTxWitness1" else witness_path2
self._check_signature_validity(witness_path, signature, data)

1 change: 1 addition & 0 deletions test/python/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"DOT": "Polkadot",
"tron": "Tron",
"ton": "TON",
"cardano": "Cardano ADA",
}

configuration.OPTIONAL.SIDELOADED_APPS_DIR = "test/python/lib_binaries/"
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 50e2c39

Please sign in to comment.