mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Acknowledge Substrate's ordering and move to a multi-key wallet setup
This commit is contained in:
@@ -1,24 +1,30 @@
|
||||
use async_trait::async_trait;
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
use curve25519_dalek::scalar::Scalar;
|
||||
use curve25519_dalek::{scalar::Scalar, edwards::CompressedEdwardsY};
|
||||
|
||||
use dalek_ff_group as dfg;
|
||||
use frost::MultisigKeys;
|
||||
|
||||
use monero::util::address::Address;
|
||||
use monero_serai::{frost::Ed25519, rpc::Rpc, wallet::{SpendableOutput, SignableTransaction}};
|
||||
use monero_serai::{
|
||||
frost::Ed25519,
|
||||
transaction::Transaction,
|
||||
rpc::Rpc,
|
||||
wallet::{SpendableOutput, SignableTransaction}
|
||||
};
|
||||
|
||||
use crate::{Output as OutputTrait, CoinError, Coin, view_key};
|
||||
|
||||
pub struct Output(SpendableOutput);
|
||||
impl OutputTrait for Output {
|
||||
// If Monero ever does support more than 255 outputs at once, which it could, this u8 could be a
|
||||
// u16 which serializes as little endian, dropping the last byte if empty, without conflict
|
||||
type Id = ([u8; 32], u8);
|
||||
// While we could use (tx, o), using the key ensures we won't be susceptible to the burning bug.
|
||||
// While the Monero library offers a variant which allows senders to ensure their TXs have unique
|
||||
// output keys, Serai can still be targeted using the classic burning bug
|
||||
type Id = CompressedEdwardsY;
|
||||
|
||||
fn id(&self) -> Self::Id {
|
||||
(self.0.tx, self.0.o.try_into().unwrap())
|
||||
self.0.key.compress()
|
||||
}
|
||||
|
||||
fn amount(&self) -> u64 {
|
||||
@@ -59,34 +65,32 @@ impl Coin for Monero {
|
||||
type Curve = Ed25519;
|
||||
|
||||
type Output = Output;
|
||||
type Block = Vec<Transaction>;
|
||||
type SignableTransaction = SignableTransaction;
|
||||
|
||||
type Address = Address;
|
||||
|
||||
fn id() -> &'static [u8] { b"Monero" }
|
||||
async fn confirmations() -> usize { 10 }
|
||||
fn confirmations() -> usize { 10 }
|
||||
// Testnet TX bb4d188a4c571f2f0de70dca9d475abc19078c10ffa8def26dd4f63ce1bcfd79 uses 146 inputs
|
||||
// while using less than 100kb of space, albeit with just 2 outputs (though outputs share a BP)
|
||||
// The TX size limit is half the contextual median block weight, where said weight is >= 300,000
|
||||
// This means any TX which fits into 150kb will be accepted by Monero
|
||||
// 128, even with 16 outputs, should fit into 100kb. Further efficiency by 192 may be viable
|
||||
// TODO: Get hard numbers and tune
|
||||
async fn max_inputs() -> usize { 128 }
|
||||
async fn max_outputs() -> usize { 16 }
|
||||
fn max_inputs() -> usize { 128 }
|
||||
fn max_outputs() -> usize { 16 }
|
||||
|
||||
async fn get_height(&self) -> Result<usize, CoinError> {
|
||||
self.rpc.get_height().await.map_err(|_| CoinError::ConnectionError)
|
||||
}
|
||||
|
||||
async fn get_outputs_in_block(
|
||||
&self,
|
||||
height: usize,
|
||||
key: dfg::EdwardsPoint
|
||||
) -> Result<Vec<Self::Output>, CoinError> {
|
||||
Ok(
|
||||
self.rpc.get_block_transactions_possible(height).await.map_err(|_| CoinError::ConnectionError)?
|
||||
.iter().flat_map(|tx| tx.scan(self.view, key.0)).map(Output::from).collect()
|
||||
)
|
||||
async fn get_block(&self, height: usize) -> Result<Self::Block, CoinError> {
|
||||
self.rpc.get_block_transactions_possible(height).await.map_err(|_| CoinError::ConnectionError)
|
||||
}
|
||||
|
||||
async fn get_outputs(&self, block: &Self::Block, key: dfg::EdwardsPoint) -> Vec<Self::Output> {
|
||||
block.iter().flat_map(|tx| tx.scan(self.view, key.0)).map(Output::from).collect()
|
||||
}
|
||||
|
||||
async fn prepare_send<R: RngCore + CryptoRng>(
|
||||
|
||||
Reference in New Issue
Block a user