Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Y333 201224/appflags hex #17

Draft
wants to merge 21 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/workflows/swap_ci_workflow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Swap functional tests

on:
workflow_dispatch:
push:
branches:
- master
- main
- develop
pull_request:

jobs:
job_functional_tests:
uses: LedgerHQ/app-exchange/.github/workflows/reusable_swap_functional_tests.yml@swap-near
with:
branch_for_near: ${{ github.ref }}
test_filter: '"NEAR or near or Near"'
branch_for_exchange: 'swap-near'
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 4 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[package]
name = "near"
version = "2.2.1"
version = "2.3.2"
authors = ["dj8yf0μl", "polyprogrammist"]
edition = "2021"

[dependencies]
ledger_device_sdk = "1.17.5"
ledger_device_sdk = "1.19.0"
include_gif = "1.2.0"
hex = { version = "0.4.3", default-features = false, features = ["serde"] }
bs58 = { version = "0.5.0", default-features = false }
Expand All @@ -22,13 +22,10 @@ lto = true

[package.metadata.ledger]
curve = ["ed25519"]
flags = "0"
flags = "0x800"
path = ["44'/397'"]
name = "NEAR"

[package.metadata.ledger.nanos]
icon = "icons/app_near_16px.gif"

[package.metadata.ledger.nanox]
icon = "icons/app_near_14px.gif"

Expand All @@ -43,4 +40,5 @@ icon = "icons/app_near_40px.gif"

[features]
default = []
debug = ["ledger_device_sdk/debug"]
speculos = ["ledger_device_sdk/speculos"]
82 changes: 82 additions & 0 deletions src/handlers/sign_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,85 @@ pub fn handler(mut stream: SingleTxStream<'_>) -> Result<Signature, AppSW> {

finalize_sign::end(stream, &path)
}

use ledger_device_sdk::libcall::swap::CreateTxParams;

pub fn handler_swap(
mut stream: SingleTxStream<'_>,
tx_params: &CreateTxParams,
) -> Result<Signature, AppSW> {
ledger_device_sdk::testing::debug_print("sign_tx.rs: handler_swap()\n");

let path = <crypto::PathBip32 as BorshDeserialize>::deserialize_reader(&mut stream)
.map_err(|_| AppSW::Bip32PathParsingFail)?;

ledger_device_sdk::testing::debug_print("sign_tx.rs: path computed\n");

let mut stream = HashingStream::new(stream)?;

ledger_device_sdk::testing::debug_print("sign_tx.rs: hashing stream instantiated\n");

let mut tx_prefix = parsing::types::transaction::prefix::Prefix::new();

tx_prefix
.deserialize_reader_in_place(&mut stream)
.map_err(|_err| AppSW::TxParsingFail)?;

let tx_public_key = match PublicKeyBe::try_from(tx_prefix.public_key) {
Ok(tx_public_key) => tx_public_key,
Err(_) => return Err(AppSW::PublicKeyMismatch),
};

let matching_private_key = {
let pk = ledger_device_sdk::ecc::Ed25519::derive_from_path_slip10(&path.0)
.public_key()
.map_err(|_| AppSW::KeyDeriveFail)?;
PublicKeyBe::from_little_endian(pk)
};

if tx_public_key != matching_private_key {
return Err(AppSW::PublicKeyMismatch);
}

match tx_prefix.number_of_actions {
1 => {
let action = crate::parsing::types::Action::deserialize_reader(&mut stream)
.map_err(|_err| AppSW::TxParsingFail)?;

match action {
crate::parsing::types::Action::Transfer => {
let transfer = crate::parsing::types::Transfer::deserialize_reader(&mut stream)
.map_err(|_err| AppSW::TxParsingFail)?;

let amount_match = near_token::NearToken::from_yoctonear(u128::from_be_bytes(
tx_params.amount,
)) == transfer.deposit;

if !amount_match {
ledger_device_sdk::testing::debug_print(
"sign_tx.rs: amounts do not not match\n",
);
return Err(AppSW::TxSignFail);
}

let dest_address_match = tx_prefix.receiver_id.as_str()
== core::str::from_utf8(
tx_params.dest_address[..tx_params.dest_address_len].as_ref(),
)
.unwrap();

if !dest_address_match {
ledger_device_sdk::testing::debug_print(
"sign_tx.rs: receiver_id does not match with dest_address\n",
);
return Err(AppSW::TxSignFail);
}

finalize_sign::end(stream, &path)
}
_ => Err(AppSW::TxSignFail),
}
}
_ => Err(AppSW::TxSignFail),
}
}
30 changes: 19 additions & 11 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,20 +238,28 @@ impl TryFrom<ApduHeader> for Instruction {
#[cfg(any(target_os = "stax", target_os = "flex"))]
use ledger_device_sdk::nbgl::init_comm;

mod swap;

#[no_mangle]
extern "C" fn sample_main() {
let mut comm = Comm::new();
extern "C" fn sample_main(arg0: u32) {
if arg0 != 0 {
swap::swap_main(arg0);
} else {
ledger_device_sdk::testing::debug_print("call app-near as a standalone\n");

let mut comm = Comm::new();

#[cfg(any(target_os = "stax", target_os = "flex"))]
init_comm(&mut comm);
#[cfg(any(target_os = "stax", target_os = "flex"))]
init_comm(&mut comm);

loop {
// Wait for either a specific button push to exit the app
// or an APDU command
if let Event::Command(ins) = ui_menu_main(&mut comm) {
match handle_apdu(&mut comm, ins) {
Ok(()) => comm.reply_ok(),
Err(sw) => comm.reply(sw),
loop {
// Wait for either a specific button push to exit the app
// or an APDU command
if let Event::Command(ins) = ui_menu_main(&mut comm) {
match handle_apdu(&mut comm, ins) {
Ok(()) => comm.reply_ok(),
Err(sw) => comm.reply(sw),
}
}
}
}
Expand Down
115 changes: 115 additions & 0 deletions src/swap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use crate::utils::crypto::{PathBip32, PublicKeyBe};
use near_token::{NearToken, TokenBuffer};

use ledger_device_sdk::{
ecc,
io::Comm,
libcall::{
self,
swap::{self, CreateTxParams},
},
testing::debug_print,
};

use crate::parsing::transaction_stream_reader::SingleTxStream;

pub fn swap_main(arg0: u32) {
debug_print("call app for swap \n");

let cmd = libcall::get_command(arg0);

match cmd {
libcall::LibCallCommand::SwapCheckAddress => {
let mut params = swap::get_check_address_params(arg0);

let mut res = 0i32;
match PathBip32::parse(&params.dpath[..params.dpath_len * 4]) {
Ok(path) => match ecc::Ed25519::derive_from_path_slip10(&path.0).public_key() {
Ok(pk) => {
let pk = PublicKeyBe::from_little_endian(pk);

let mut buf = [0u8; 64];
let address = pk.display_str_hex(&mut buf);
let ref_address =
core::str::from_utf8(&params.ref_address[..params.ref_address_len]);

if address.eq(ref_address.unwrap()) {
res = 1i32;
}
}
Err(_) => {
debug_print("Public key derivation failure\n");
}
},
Err(_) => {
debug_print("Derivation path failure\n");
}
}
swap::swap_return(swap::SwapResult::CheckAddressResult(&mut params, res));
}
libcall::LibCallCommand::SwapGetPrintableAmount => {
let mut params = swap::get_printable_amount_params(arg0);

let amount = u128::from_be_bytes(params.amount);
let near_token = NearToken::from_yoctonear(amount);
let mut near_token_buffer = TokenBuffer::new();
near_token.display_as_buffer(&mut near_token_buffer);
let s = near_token_buffer.as_str();

swap::swap_return(swap::SwapResult::PrintableAmountResult(&mut params, s));
}
libcall::LibCallCommand::SwapSignTransaction => {
let mut params = swap::sign_tx_params(arg0);

{
let mut comm = Comm::new().set_expected_cla(super::CLA);

debug_print("Wait for APDU\n");

// Wait for an APDU command
let ins: super::Instruction = comm.next_command();

debug_print("APDU received\n");

match handle_apdu(&mut comm, ins, &params) {
Ok(sig) => {
comm.append(&sig);
comm.swap_reply_ok();
swap::swap_return(swap::SwapResult::CreateTxResult(&mut params, 1));
}
Err(sw) => {
comm.swap_reply(sw);
swap::swap_return(swap::SwapResult::CreateTxResult(&mut params, 0));
}
}
}
}
}
}

fn handle_apdu(
comm: &mut Comm,
ins: super::Instruction,
tx_params: &CreateTxParams,
) -> Result<[u8; 64], crate::AppSW> {
match ins {
super::Instruction::SignTx {
is_last_chunk,
sign_mode,
} => {
debug_print("handle_swap_apdu => Sign Tx\n");
let stream = SingleTxStream::new(comm, is_last_chunk, sign_mode);
match sign_mode {
super::SignMode::Transaction => {
let signature = crate::handlers::sign_tx::handler_swap(stream, tx_params);
match signature {
Ok(sig) => Ok(sig.0),
Err(sw) => Err(sw),
}
}
_ => Err(crate::AppSW::TxSignFail),
}
}
_ => Err(crate::AppSW::InsNotSupported),
}
}
2 changes: 1 addition & 1 deletion tests/test_version_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ def test_get_version_cmd(backend):
version = client.get_version().data
assert len(version) == 3
# Assert that we have received the correct app version compared as Makefile data
assert (version[0], version[1], version[2]) == (2, 2, 1)
assert (version[0], version[1], version[2]) == (2, 3, 2)
Loading