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

Merged
merged 30 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
7563664
Add swap CI workflow
yogh333 Oct 16, 2024
55ee04f
check_address: first implementation
yogh333 Oct 22, 2024
0940392
check_address and get_printable_amount OK
yogh333 Dec 5, 2024
f4cd890
Handle swap module from SDK
yogh333 Dec 5, 2024
dd16dc4
Signing Tx: get params from exchange app and returns always OK
yogh333 Dec 10, 2024
fdc6f9e
Swap complete
yogh333 Dec 12, 2024
aaa9988
Add debug feature
yogh333 Dec 12, 2024
b38613d
Add swap module
yogh333 Dec 13, 2024
adff200
remove comments
yogh333 Dec 13, 2024
2dc1aa7
Remove traces
yogh333 Dec 13, 2024
bbec714
Delete verbose traces
yogh333 Dec 13, 2024
94b8da9
Use last published Rust SDK
yogh333 Dec 16, 2024
a24605f
Remove Rust SDK sys crate dependency
yogh333 Dec 16, 2024
e0055a0
Fix Clippy errors
yogh333 Dec 16, 2024
e681371
Bump version
yogh333 Dec 17, 2024
3239626
Fix test
yogh333 Dec 17, 2024
d80821d
Update app name to NEAR and set proper appflags (see ledger-secure-sd…
yogh333 Dec 19, 2024
24c7794
Keep package name to near, app name is defined in metadata.ledger
yogh333 Dec 19, 2024
5e91134
Update get version test
yogh333 Dec 19, 2024
6f893f1
Swap: Check address is in hex (32 bytes) and not in base58
yogh333 Dec 20, 2024
9d43b57
set appflags in hexa
yogh333 Dec 20, 2024
0e08ef8
Bump SDK version
yogh333 Jan 6, 2025
71f3cb2
Fix Clippy issues
yogh333 Jan 6, 2025
45bed9d
Process GetPubKey instruction in swap mode
yogh333 Jan 7, 2025
17571c8
Bump version
yogh333 Jan 7, 2025
3c9bf0a
Update version in version test
yogh333 Jan 8, 2025
1487624
Update after PR review
yogh333 Jan 14, 2025
1357cd9
Fix get_version test
yogh333 Jan 14, 2025
0d29b66
return constant fees when swapping (sending) Near (0.450 Tgas)
yogh333 Jan 14, 2025
1771c38
Bump Rust SDK version
yogh333 Jan 16, 2025
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'
12 changes: 6 additions & 6 deletions Cargo.lock

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

13 changes: 7 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.3"
authors = ["dj8yf0μl", "polyprogrammist"]
edition = "2021"

[dependencies]
ledger_device_sdk = "1.17.5"
ledger_device_sdk = "1.19.1"
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,8 @@ icon = "icons/app_near_40px.gif"

[features]
default = []
debug = ["ledger_device_sdk/debug"]
speculos = ["ledger_device_sdk/speculos"]

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(target_os, values("stax", "flex", "nanos", "nanox", "nanosplus"))'] }
3 changes: 0 additions & 3 deletions src/app_ui/fields_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ pub struct FieldsWriter<'a, const N: usize> {
#[cfg(feature = "speculos")]
use ledger_device_sdk::testing;

#[derive(Debug)]
pub struct FieldsOverflow;

impl<'a, const N: usize> FieldsWriter<'a, N> {
pub fn new() -> Self {
let max_fields = [(); N].map(|_| Field {
Expand Down
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(
yogh333 marked this conversation as resolved.
Show resolved Hide resolved
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 = {
yogh333 marked this conversation as resolved.
Show resolved Hide resolved
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 {
yogh333 marked this conversation as resolved.
Show resolved Hide resolved
return Err(AppSW::PublicKeyMismatch);
}

match tx_prefix.number_of_actions {
1 => {
yogh333 marked this conversation as resolved.
Show resolved Hide resolved
let action = crate::parsing::types::Action::deserialize_reader(&mut stream)
.map_err(|_err| AppSW::TxParsingFail)?;

match action {
crate::parsing::types::Action::Transfer => {
yogh333 marked this conversation as resolved.
Show resolved Hide resolved
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);
}

yogh333 marked this conversation as resolved.
Show resolved Hide resolved
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
4 changes: 2 additions & 2 deletions src/parsing/transaction_stream_reader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl<R: io::Read> io::Read for HashingStream<R> {
}
}

impl<'a> SingleTxStream<'a> {
impl SingleTxStream<'_> {
pub fn peek_u8(&mut self) -> io::Result<Option<u8>> {
let data = self
.comm
Expand Down Expand Up @@ -132,7 +132,7 @@ impl<'a> SingleTxStream<'a> {
}
}

impl<'a> io::Read for SingleTxStream<'a> {
impl io::Read for SingleTxStream<'_> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let data = self
.comm
Expand Down
120 changes: 120 additions & 0 deletions src/swap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
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 => {
yogh333 marked this conversation as resolved.
Show resolved Hide resolved
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 => {
yogh333 marked this conversation as resolved.
Show resolved Hide resolved
let mut params = swap::get_printable_amount_params(arg0);
yogh333 marked this conversation as resolved.
Show resolved Hide resolved

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);
yogh333 marked this conversation as resolved.
Show resolved Hide resolved

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

debug_print("Wait for APDU\n");

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

debug_print("APDU received\n");

handle_apdu(&mut comm, ins, &mut params);
}
}
}
}
}

fn handle_apdu(comm: &mut Comm, ins: super::Instruction, tx_params: &mut CreateTxParams) {
yogh333 marked this conversation as resolved.
Show resolved Hide resolved
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) => {
comm.append(&sig.0);
comm.swap_reply_ok();
swap::swap_return(swap::SwapResult::CreateTxResult(tx_params, 1));
}
Err(sw) => {
comm.swap_reply(sw);
swap::swap_return(swap::SwapResult::CreateTxResult(tx_params, 0));
}
}
}
_ => {
comm.swap_reply(crate::AppSW::TxSignFail);
swap::swap_return(swap::SwapResult::CreateTxResult(tx_params, 0));
}
}
}
super::Instruction::GetPubkey { display } => match display {
true => comm.swap_reply(crate::AppSW::InsNotSupported),
false => match crate::handlers::get_public_key::handler(comm, display) {
Ok(()) => comm.swap_reply_ok(),
Err(sw) => comm.swap_reply(sw),
},
},
_ => comm.swap_reply(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, 3)
yogh333 marked this conversation as resolved.
Show resolved Hide resolved
Loading