Skip to content

Commit

Permalink
feat: initial implementation of NEP-413 support
Browse files Browse the repository at this point in the history
  • Loading branch information
akorchyn committed Dec 20, 2024
1 parent a04f161 commit d00299f
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 155 deletions.
2 changes: 2 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ pub enum SignerError {
SecretKeyIsNotAvailable,
#[error("Failed to fetch nonce: {0}")]
FetchNonceError(#[from] QueryError<RpcQueryRequest>),
#[error("IO error: {0}")]
IO(#[from] std::io::Error),

#[cfg(feature = "ledger")]
#[error(transparent)]
Expand Down
59 changes: 0 additions & 59 deletions src/signer/access_keyfile_signer.rs

This file was deleted.

39 changes: 11 additions & 28 deletions src/signer/keystore.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
use near_crypto::{PublicKey, SecretKey};
use near_primitives::{
transaction::Transaction,
types::{AccountId, Nonce},
views::AccessKeyPermissionView,
};
use near_primitives::{types::AccountId, views::AccessKeyPermissionView};
use tracing::{debug, info, instrument, trace, warn};

use crate::{
config::NetworkConfig,
errors::{KeyStoreError, SignerError},
types::{transactions::PrepopulateTransaction, CryptoHash},
};

use super::{AccountKeyPair, SignerTrait};
Expand All @@ -23,38 +18,26 @@ pub struct KeystoreSigner {

#[async_trait::async_trait]
impl SignerTrait for KeystoreSigner {
#[instrument(skip(self, tr), fields(signer_id = %tr.signer_id, receiver_id = %tr.receiver_id))]
fn tx_and_secret(
#[instrument(skip(self))]
fn secret(
&self,
tr: PrepopulateTransaction,
public_key: PublicKey,
nonce: Nonce,
block_hash: CryptoHash,
) -> Result<(Transaction, SecretKey), SignerError> {
signer_id: &AccountId,
public_key: &PublicKey,
) -> Result<SecretKey, SignerError> {
debug!(target: KEYSTORE_SIGNER_TARGET, "Searching for matching public key");
self.potential_pubkeys
.iter()
.find(|key| *key == &public_key)
.find(|key| *key == public_key)
.ok_or(SignerError::PublicKeyIsNotAvailable)?;

info!(target: KEYSTORE_SIGNER_TARGET, "Retrieving secret key");
// TODO: fix this. Well the search is a bit suboptimal, but it's not a big deal for now
let secret = Self::get_secret_key(&tr.signer_id, &public_key, "mainnet")
.or_else(|_| Self::get_secret_key(&tr.signer_id, &public_key, "testnet"))
let secret = Self::get_secret_key(signer_id, public_key, "mainnet")
.or_else(|_| Self::get_secret_key(signer_id, public_key, "testnet"))
.map_err(|_| SignerError::SecretKeyIsNotAvailable)?;

debug!(target: KEYSTORE_SIGNER_TARGET, "Creating transaction");
let mut transaction = Transaction::new_v0(
tr.signer_id.clone(),
public_key,
tr.receiver_id,
nonce,
block_hash.into(),
);
*transaction.actions_mut() = tr.actions;

info!(target: KEYSTORE_SIGNER_TARGET, "Transaction and secret key prepared successfully");
Ok((transaction, secret.private_key))
info!(target: KEYSTORE_SIGNER_TARGET, "Secret key prepared successfully");
Ok(secret.private_key)
}

#[instrument(skip(self))]
Expand Down
42 changes: 36 additions & 6 deletions src/signer/ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
types::{transactions::PrepopulateTransaction, CryptoHash},
};

use super::SignerTrait;
use super::{NEP413Payload, SignerTrait};

const LEDGER_SIGNER_TARGET: &str = "near_api::signer::ledger";

Expand Down Expand Up @@ -130,13 +130,43 @@ impl SignerTrait for LedgerSigner {
})
}

fn tx_and_secret(
#[instrument(skip(self), fields(receiver_id = %payload.recipient, message = %payload.message))]
async fn sign_message_nep413(
&self,
_tr: PrepopulateTransaction,
_signer_id: crate::AccountId,
_public_key: PublicKey,
_nonce: Nonce,
_block_hash: CryptoHash,
) -> Result<(Transaction, SecretKey), SignerError> {
payload: NEP413Payload,
) -> Result<near_crypto::Signature, SignerError> {
info!(target: LEDGER_SIGNER_TARGET, "Signing NEP413 message with Ledger");
let hd_path = self.hd_path.clone();
let payload = payload.into();

let signature = tokio::task::spawn_blocking(move || {
let signature =
near_ledger::sign_message_nep413(&payload, hd_path).map_err(LedgerError::from)?;

Ok::<_, LedgerError>(signature)
})
.await
.map_err(LedgerError::from)
.map_err(SignerError::from)?;

let signature = signature.map_err(SignerError::from)?;

debug!(target: LEDGER_SIGNER_TARGET, "Creating Signature object for NEP413");
let signature =
near_crypto::Signature::from_parts(near_crypto::KeyType::ED25519, &signature)
.map_err(LedgerError::from)
.map_err(SignerError::from)?;

Ok(signature)
}

fn secret(
&self,
_signer_id: &crate::AccountId,
_public_key: &PublicKey,
) -> Result<SecretKey, SignerError> {
warn!(target: LEDGER_SIGNER_TARGET, "Attempted to access secret key, which is not available for Ledger signer");
Err(SignerError::SecretKeyIsNotAvailable)
}
Expand Down
Loading

0 comments on commit d00299f

Please sign in to comment.