2020-10-13 18:32:25 -04:00
|
|
|
use crate::serde::monero_private_key;
|
2020-09-28 02:18:50 -04:00
|
|
|
use anyhow::Result;
|
|
|
|
use async_trait::async_trait;
|
2020-10-07 20:07:37 -04:00
|
|
|
use rand::{CryptoRng, RngCore};
|
2020-10-13 18:32:25 -04:00
|
|
|
use serde::{Deserialize, Serialize};
|
2020-10-21 19:57:42 -04:00
|
|
|
use std::ops::{Add, Sub};
|
2020-09-28 02:18:50 -04:00
|
|
|
|
2020-11-06 14:57:35 -05:00
|
|
|
pub use curve25519_dalek::scalar::Scalar;
|
|
|
|
pub use monero::*;
|
|
|
|
|
2020-10-14 22:10:31 -04:00
|
|
|
pub const MIN_CONFIRMATIONS: u32 = 10;
|
|
|
|
|
2020-09-28 02:18:50 -04:00
|
|
|
pub fn random_private_key<R: RngCore + CryptoRng>(rng: &mut R) -> PrivateKey {
|
|
|
|
let scalar = Scalar::random(rng);
|
|
|
|
|
|
|
|
PrivateKey::from_scalar(scalar)
|
|
|
|
}
|
|
|
|
|
2020-11-08 19:07:06 -05:00
|
|
|
pub fn private_key_from_secp256k1_scalar(scalar: crate::bitcoin::Scalar) -> PrivateKey {
|
|
|
|
let mut bytes = scalar.to_bytes();
|
|
|
|
|
|
|
|
// we must reverse the bytes because a secp256k1 scalar is big endian, whereas a
|
|
|
|
// ed25519 scalar is little endian
|
|
|
|
bytes.reverse();
|
|
|
|
|
|
|
|
PrivateKey::from_scalar(Scalar::from_bytes_mod_order(bytes))
|
|
|
|
}
|
|
|
|
|
2020-10-13 18:32:25 -04:00
|
|
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)]
|
|
|
|
pub struct PrivateViewKey(#[serde(with = "monero_private_key")] PrivateKey);
|
2020-09-28 02:18:50 -04:00
|
|
|
|
|
|
|
impl PrivateViewKey {
|
|
|
|
pub fn new_random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
|
|
|
|
let scalar = Scalar::random(rng);
|
|
|
|
let private_key = PrivateKey::from_scalar(scalar);
|
|
|
|
|
|
|
|
Self(private_key)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn public(&self) -> PublicViewKey {
|
|
|
|
PublicViewKey(PublicKey::from_private_key(&self.0))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Add for PrivateViewKey {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn add(self, rhs: Self) -> Self::Output {
|
|
|
|
Self(self.0 + rhs.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<PrivateViewKey> for PrivateKey {
|
|
|
|
fn from(from: PrivateViewKey) -> Self {
|
|
|
|
from.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<PublicViewKey> for PublicKey {
|
|
|
|
fn from(from: PublicViewKey) -> Self {
|
|
|
|
from.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
pub struct PublicViewKey(PublicKey);
|
|
|
|
|
2020-10-21 23:33:16 -04:00
|
|
|
#[derive(Debug, Copy, Clone, Deserialize, Serialize, PartialEq, PartialOrd)]
|
2020-09-28 02:18:50 -04:00
|
|
|
pub struct Amount(u64);
|
|
|
|
|
|
|
|
impl Amount {
|
|
|
|
/// Create an [Amount] with piconero precision and the given number of
|
|
|
|
/// piconeros.
|
|
|
|
///
|
|
|
|
/// A piconero (a.k.a atomic unit) is equal to 1e-12 XMR.
|
|
|
|
pub fn from_piconero(amount: u64) -> Self {
|
|
|
|
Amount(amount)
|
|
|
|
}
|
2020-09-29 01:36:50 -04:00
|
|
|
pub fn as_piconero(&self) -> u64 {
|
|
|
|
self.0
|
|
|
|
}
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|
|
|
|
|
2020-10-21 19:57:42 -04:00
|
|
|
impl Add for Amount {
|
|
|
|
type Output = Amount;
|
|
|
|
|
|
|
|
fn add(self, rhs: Self) -> Self::Output {
|
|
|
|
Self(self.0 + rhs.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Sub for Amount {
|
|
|
|
type Output = Amount;
|
|
|
|
|
|
|
|
fn sub(self, rhs: Self) -> Self::Output {
|
|
|
|
Self(self.0 - rhs.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-28 02:18:50 -04:00
|
|
|
impl From<Amount> for u64 {
|
|
|
|
fn from(from: Amount) -> u64 {
|
|
|
|
from.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-13 18:32:25 -04:00
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
2020-09-28 02:18:50 -04:00
|
|
|
pub struct TransferProof {
|
|
|
|
tx_hash: TxHash,
|
2020-10-13 18:32:25 -04:00
|
|
|
#[serde(with = "monero_private_key")]
|
2020-09-28 02:18:50 -04:00
|
|
|
tx_key: PrivateKey,
|
|
|
|
}
|
|
|
|
|
2020-09-29 01:36:50 -04:00
|
|
|
impl TransferProof {
|
|
|
|
pub fn new(tx_hash: TxHash, tx_key: PrivateKey) -> Self {
|
|
|
|
Self { tx_hash, tx_key }
|
|
|
|
}
|
|
|
|
pub fn tx_hash(&self) -> TxHash {
|
|
|
|
self.tx_hash.clone()
|
|
|
|
}
|
|
|
|
pub fn tx_key(&self) -> PrivateKey {
|
|
|
|
self.tx_key
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: add constructor/ change String to fixed length byte array
|
2020-10-13 18:32:25 -04:00
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
2020-09-29 01:36:50 -04:00
|
|
|
pub struct TxHash(pub String);
|
2020-09-28 02:18:50 -04:00
|
|
|
|
|
|
|
impl From<TxHash> for String {
|
|
|
|
fn from(from: TxHash) -> Self {
|
|
|
|
from.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_trait]
|
|
|
|
pub trait Transfer {
|
|
|
|
async fn transfer(
|
|
|
|
&self,
|
|
|
|
public_spend_key: PublicKey,
|
|
|
|
public_view_key: PublicViewKey,
|
|
|
|
amount: Amount,
|
2020-10-14 22:10:31 -04:00
|
|
|
) -> anyhow::Result<(TransferProof, Amount)>;
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[async_trait]
|
2020-10-14 22:10:31 -04:00
|
|
|
pub trait WatchForTransfer {
|
|
|
|
async fn watch_for_transfer(
|
2020-09-28 02:18:50 -04:00
|
|
|
&self,
|
|
|
|
public_spend_key: PublicKey,
|
|
|
|
public_view_key: PublicViewKey,
|
|
|
|
transfer_proof: TransferProof,
|
|
|
|
amount: Amount,
|
2020-10-14 22:10:31 -04:00
|
|
|
expected_confirmations: u32,
|
|
|
|
) -> Result<(), InsufficientFunds>;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, thiserror::Error)]
|
|
|
|
#[error("transaction does not pay enough: expected {expected:?}, got {actual:?}")]
|
|
|
|
pub struct InsufficientFunds {
|
|
|
|
pub expected: Amount,
|
|
|
|
pub actual: Amount,
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[async_trait]
|
2020-10-07 20:27:54 -04:00
|
|
|
pub trait CreateWalletForOutput {
|
|
|
|
async fn create_and_load_wallet_for_output(
|
2020-09-28 02:18:50 -04:00
|
|
|
&self,
|
|
|
|
private_spend_key: PrivateKey,
|
|
|
|
private_view_key: PrivateViewKey,
|
2020-10-14 22:10:31 -04:00
|
|
|
) -> anyhow::Result<()>;
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|