mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-11 21:49:26 +00:00
Smash out RPC, wallet
This commit is contained in:
72
Cargo.lock
generated
72
Cargo.lock
generated
@@ -4847,20 +4847,29 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "monero-rpc"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"curve25519-dalek",
|
||||||
|
"hex",
|
||||||
|
"monero-serai",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"std-shims",
|
||||||
|
"thiserror",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "monero-serai"
|
name = "monero-serai"
|
||||||
version = "0.1.4-alpha"
|
version = "0.1.4-alpha"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
|
||||||
"base58-monero",
|
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"dalek-ff-group",
|
|
||||||
"digest_auth",
|
"digest_auth",
|
||||||
"flexible-transcript",
|
|
||||||
"group",
|
|
||||||
"hex",
|
"hex",
|
||||||
"hex-literal",
|
"hex-literal",
|
||||||
"modular-frost",
|
|
||||||
"monero-borromean",
|
"monero-borromean",
|
||||||
"monero-bulletproofs",
|
"monero-bulletproofs",
|
||||||
"monero-clsag",
|
"monero-clsag",
|
||||||
@@ -4868,6 +4877,43 @@ dependencies = [
|
|||||||
"monero-io",
|
"monero-io",
|
||||||
"monero-mlsag",
|
"monero-mlsag",
|
||||||
"monero-primitives",
|
"monero-primitives",
|
||||||
|
"rand_core",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"std-shims",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "monero-simple-request-rpc"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"digest_auth",
|
||||||
|
"hex",
|
||||||
|
"monero-rpc",
|
||||||
|
"simple-request",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "monero-wallet"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"base58-monero",
|
||||||
|
"curve25519-dalek",
|
||||||
|
"dalek-ff-group",
|
||||||
|
"flexible-transcript",
|
||||||
|
"group",
|
||||||
|
"hex",
|
||||||
|
"hex-literal",
|
||||||
|
"modular-frost",
|
||||||
|
"monero-rpc",
|
||||||
|
"monero-serai",
|
||||||
|
"monero-simple-request-rpc",
|
||||||
"pbkdf2 0.12.2",
|
"pbkdf2 0.12.2",
|
||||||
"rand",
|
"rand",
|
||||||
"rand_chacha",
|
"rand_chacha",
|
||||||
@@ -4876,7 +4922,6 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha3",
|
"sha3",
|
||||||
"simple-request",
|
|
||||||
"std-shims",
|
"std-shims",
|
||||||
"subtle",
|
"subtle",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@@ -7867,7 +7912,7 @@ dependencies = [
|
|||||||
"frost-schnorrkel",
|
"frost-schnorrkel",
|
||||||
"hex",
|
"hex",
|
||||||
"modular-frost",
|
"modular-frost",
|
||||||
"monero-serai",
|
"monero-wallet",
|
||||||
"multiaddr",
|
"multiaddr",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
@@ -8025,7 +8070,8 @@ dependencies = [
|
|||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"dockertest",
|
"dockertest",
|
||||||
"hex",
|
"hex",
|
||||||
"monero-serai",
|
"monero-simple-request-rpc",
|
||||||
|
"monero-wallet",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
"serai-client",
|
"serai-client",
|
||||||
@@ -8129,7 +8175,9 @@ dependencies = [
|
|||||||
"monero-io",
|
"monero-io",
|
||||||
"monero-mlsag",
|
"monero-mlsag",
|
||||||
"monero-primitives",
|
"monero-primitives",
|
||||||
|
"monero-rpc",
|
||||||
"monero-serai",
|
"monero-serai",
|
||||||
|
"monero-wallet",
|
||||||
"multiexp",
|
"multiexp",
|
||||||
"schnorr-signatures",
|
"schnorr-signatures",
|
||||||
]
|
]
|
||||||
@@ -8230,7 +8278,8 @@ dependencies = [
|
|||||||
"k256",
|
"k256",
|
||||||
"log",
|
"log",
|
||||||
"modular-frost",
|
"modular-frost",
|
||||||
"monero-serai",
|
"monero-simple-request-rpc",
|
||||||
|
"monero-wallet",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"rand_chacha",
|
"rand_chacha",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
@@ -8276,7 +8325,8 @@ dependencies = [
|
|||||||
"ethereum-serai",
|
"ethereum-serai",
|
||||||
"hex",
|
"hex",
|
||||||
"k256",
|
"k256",
|
||||||
"monero-serai",
|
"monero-simple-request-rpc",
|
||||||
|
"monero-wallet",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
"serai-client",
|
"serai-client",
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ members = [
|
|||||||
"coins/monero/ringct/borromean",
|
"coins/monero/ringct/borromean",
|
||||||
"coins/monero/ringct/bulletproofs",
|
"coins/monero/ringct/bulletproofs",
|
||||||
"coins/monero",
|
"coins/monero",
|
||||||
|
"coins/monero/rpc",
|
||||||
|
"coins/monero/rpc/simple-request",
|
||||||
|
"coins/monero/wallet",
|
||||||
|
|
||||||
"message-queue",
|
"message-queue",
|
||||||
|
|
||||||
|
|||||||
@@ -18,32 +18,13 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
std-shims = { path = "../../common/std-shims", version = "^0.1.1", default-features = false }
|
std-shims = { path = "../../common/std-shims", version = "^0.1.1", default-features = false }
|
||||||
|
|
||||||
async-trait = { version = "0.1", default-features = false }
|
|
||||||
thiserror = { version = "1", default-features = false, optional = true }
|
thiserror = { version = "1", default-features = false, optional = true }
|
||||||
|
|
||||||
zeroize = { version = "^1.5", default-features = false, features = ["zeroize_derive"] }
|
zeroize = { version = "^1.5", default-features = false, features = ["zeroize_derive"] }
|
||||||
subtle = { version = "^2.4", default-features = false }
|
|
||||||
|
|
||||||
rand_core = { version = "0.6", default-features = false }
|
rand_core = { version = "0.6", default-features = false }
|
||||||
# Used to send transactions
|
|
||||||
rand = { version = "0.8", default-features = false }
|
|
||||||
rand_chacha = { version = "0.3", default-features = false }
|
|
||||||
# Used to select decoys
|
|
||||||
rand_distr = { version = "0.4", default-features = false }
|
|
||||||
|
|
||||||
sha3 = { version = "0.10", default-features = false }
|
|
||||||
pbkdf2 = { version = "0.12", features = ["simple"], default-features = false }
|
|
||||||
|
|
||||||
curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize"] }
|
curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize"] }
|
||||||
|
|
||||||
# Used for the hash to curve, along with the more complicated proofs
|
|
||||||
group = { version = "0.13", default-features = false }
|
|
||||||
dalek-ff-group = { path = "../../crypto/dalek-ff-group", version = "0.4", default-features = false }
|
|
||||||
|
|
||||||
# Needed for multisig
|
|
||||||
transcript = { package = "flexible-transcript", path = "../../crypto/transcript", version = "0.3", default-features = false, features = ["recommended"], optional = true }
|
|
||||||
frost = { package = "modular-frost", path = "../../crypto/frost", version = "0.8", default-features = false, features = ["ed25519"], optional = true }
|
|
||||||
|
|
||||||
monero-io = { path = "io", version = "0.1", default-features = false }
|
monero-io = { path = "io", version = "0.1", default-features = false }
|
||||||
monero-generators = { path = "generators", version = "0.4", default-features = false }
|
monero-generators = { path = "generators", version = "0.4", default-features = false }
|
||||||
monero-primitives = { path = "primitives", version = "0.1", default-features = false }
|
monero-primitives = { path = "primitives", version = "0.1", default-features = false }
|
||||||
@@ -57,22 +38,10 @@ hex = { version = "0.4", default-features = false, features = ["alloc"] }
|
|||||||
serde = { version = "1", default-features = false, features = ["derive", "alloc"] }
|
serde = { version = "1", default-features = false, features = ["derive", "alloc"] }
|
||||||
serde_json = { version = "1", default-features = false, features = ["alloc"] }
|
serde_json = { version = "1", default-features = false, features = ["alloc"] }
|
||||||
|
|
||||||
base58-monero = { version = "2", default-features = false, features = ["check"] }
|
|
||||||
|
|
||||||
# Used for the provided HTTP RPC
|
# Used for the provided HTTP RPC
|
||||||
digest_auth = { version = "0.3", default-features = false, optional = true }
|
digest_auth = { version = "0.3", default-features = false, optional = true }
|
||||||
simple-request = { path = "../../common/request", version = "0.1", default-features = false, features = ["tls"], optional = true }
|
|
||||||
tokio = { version = "1", default-features = false, optional = true }
|
tokio = { version = "1", default-features = false, optional = true }
|
||||||
|
|
||||||
[build-dependencies]
|
|
||||||
dalek-ff-group = { path = "../../crypto/dalek-ff-group", version = "0.4", default-features = false }
|
|
||||||
monero-generators = { path = "generators", version = "0.4", default-features = false }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
tokio = { version = "1", features = ["sync", "macros"] }
|
|
||||||
|
|
||||||
frost = { package = "modular-frost", path = "../../crypto/frost", features = ["tests"] }
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
std = [
|
std = [
|
||||||
"std-shims/std",
|
"std-shims/std",
|
||||||
@@ -80,17 +49,8 @@ std = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
|
|
||||||
"zeroize/std",
|
"zeroize/std",
|
||||||
"subtle/std",
|
|
||||||
|
|
||||||
"rand_core/std",
|
"rand_core/std",
|
||||||
"rand/std",
|
|
||||||
"rand_chacha/std",
|
|
||||||
"rand_distr/std",
|
|
||||||
|
|
||||||
"sha3/std",
|
|
||||||
"pbkdf2/std",
|
|
||||||
|
|
||||||
"transcript/std",
|
|
||||||
|
|
||||||
"monero-io/std",
|
"monero-io/std",
|
||||||
"monero-generators/std",
|
"monero-generators/std",
|
||||||
@@ -102,13 +62,9 @@ std = [
|
|||||||
"hex/std",
|
"hex/std",
|
||||||
"serde/std",
|
"serde/std",
|
||||||
"serde_json/std",
|
"serde_json/std",
|
||||||
|
|
||||||
"base58-monero/std",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
compile-time-generators = ["curve25519-dalek/precomputed-tables", "monero-bulletproofs/compile-time-generators"]
|
compile-time-generators = ["curve25519-dalek/precomputed-tables", "monero-bulletproofs/compile-time-generators"]
|
||||||
http-rpc = ["digest_auth", "simple-request", "tokio"]
|
multisig = ["monero-clsag/multisig", "std"]
|
||||||
multisig = ["transcript", "frost", "monero-clsag/multisig", "std"]
|
#binaries = ["tokio/rt-multi-thread", "tokio/macros", "http-rpc"]
|
||||||
binaries = ["tokio/rt-multi-thread", "tokio/macros", "http-rpc"]
|
default = ["std"]
|
||||||
|
|
||||||
default = ["std", "http-rpc"]
|
|
||||||
|
|||||||
46
coins/monero/rpc/Cargo.toml
Normal file
46
coins/monero/rpc/Cargo.toml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
[package]
|
||||||
|
name = "monero-rpc"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Trait for an RPC connection to a Monero daemon, built around monero-serai"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/serai-dex/serai/tree/develop/coins/monero/rpc"
|
||||||
|
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.79"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
std-shims = { path = "../../../common/std-shims", version = "^0.1.1", default-features = false }
|
||||||
|
|
||||||
|
async-trait = { version = "0.1", default-features = false }
|
||||||
|
thiserror = { version = "1", default-features = false, optional = true }
|
||||||
|
|
||||||
|
zeroize = { version = "^1.5", default-features = false, features = ["zeroize_derive"] }
|
||||||
|
hex = { version = "0.4", default-features = false, features = ["alloc"] }
|
||||||
|
serde = { version = "1", default-features = false, features = ["derive", "alloc"] }
|
||||||
|
serde_json = { version = "1", default-features = false, features = ["alloc"] }
|
||||||
|
|
||||||
|
curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize"] }
|
||||||
|
|
||||||
|
monero-serai = { path = "..", default-features = false }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
std = [
|
||||||
|
"std-shims/std",
|
||||||
|
|
||||||
|
"thiserror",
|
||||||
|
|
||||||
|
"zeroize/std",
|
||||||
|
"hex/std",
|
||||||
|
"serde/std",
|
||||||
|
"serde_json/std",
|
||||||
|
|
||||||
|
"monero-serai/std",
|
||||||
|
]
|
||||||
|
default = ["std"]
|
||||||
21
coins/monero/rpc/LICENSE
Normal file
21
coins/monero/rpc/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022-2024 Luke Parker
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
6
coins/monero/rpc/README.md
Normal file
6
coins/monero/rpc/README.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Monero RPC
|
||||||
|
|
||||||
|
Trait for an RPC connection to a Monero daemon, built around monero-serai.
|
||||||
|
|
||||||
|
This library is usable under no-std when the `std` feature (on by default) is
|
||||||
|
disabled.
|
||||||
26
coins/monero/rpc/simple-request/Cargo.toml
Normal file
26
coins/monero/rpc/simple-request/Cargo.toml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
[package]
|
||||||
|
name = "monero-simple-request-rpc"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "RPC connection to a Monero daemon via simple-request, built around monero-serai"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/serai-dex/serai/tree/develop/coins/monero/rpc/simple-request"
|
||||||
|
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.79"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
async-trait = { version = "0.1", default-features = false }
|
||||||
|
|
||||||
|
hex = { version = "0.4", default-features = false, features = ["alloc"] }
|
||||||
|
digest_auth = { version = "0.3", default-features = false }
|
||||||
|
simple-request = { path = "../../../../common/request", version = "0.1", default-features = false, features = ["tls"] }
|
||||||
|
tokio = { version = "1", default-features = false }
|
||||||
|
|
||||||
|
monero-rpc = { path = "..", default-features = false, features = ["std"] }
|
||||||
21
coins/monero/rpc/simple-request/LICENSE
Normal file
21
coins/monero/rpc/simple-request/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022-2024 Luke Parker
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
3
coins/monero/rpc/simple-request/README.md
Normal file
3
coins/monero/rpc/simple-request/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Monero simple-request RPC
|
||||||
|
|
||||||
|
RPC connection to a Monero daemon via simple-request, built around monero-serai.
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
#![doc = include_str!("../README.md")]
|
||||||
|
// #![deny(missing_docs)] // TODO
|
||||||
|
|
||||||
use std::{sync::Arc, io::Read, time::Duration};
|
use std::{sync::Arc, io::Read, time::Duration};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
@@ -10,7 +14,7 @@ use simple_request::{
|
|||||||
Response, Client,
|
Response, Client,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::rpc::{RpcError, RpcConnection, Rpc};
|
use monero_rpc::{RpcError, RpcConnection, Rpc};
|
||||||
|
|
||||||
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
|
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
|
||||||
|
|
||||||
@@ -33,13 +37,13 @@ enum Authentication {
|
|||||||
///
|
///
|
||||||
/// Requires tokio.
|
/// Requires tokio.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct HttpRpc {
|
pub struct SimpleRequestRpc {
|
||||||
authentication: Authentication,
|
authentication: Authentication,
|
||||||
url: String,
|
url: String,
|
||||||
request_timeout: Duration,
|
request_timeout: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpRpc {
|
impl SimpleRequestRpc {
|
||||||
fn digest_auth_challenge(
|
fn digest_auth_challenge(
|
||||||
response: &Response,
|
response: &Response,
|
||||||
) -> Result<Option<(WwwAuthenticateHeader, u64)>, RpcError> {
|
) -> Result<Option<(WwwAuthenticateHeader, u64)>, RpcError> {
|
||||||
@@ -60,7 +64,7 @@ impl HttpRpc {
|
|||||||
///
|
///
|
||||||
/// A daemon requiring authentication can be used via including the username and password in the
|
/// A daemon requiring authentication can be used via including the username and password in the
|
||||||
/// URL.
|
/// URL.
|
||||||
pub async fn new(url: String) -> Result<Rpc<HttpRpc>, RpcError> {
|
pub async fn new(url: String) -> Result<Rpc<SimpleRequestRpc>, RpcError> {
|
||||||
Self::with_custom_timeout(url, DEFAULT_TIMEOUT).await
|
Self::with_custom_timeout(url, DEFAULT_TIMEOUT).await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +75,7 @@ impl HttpRpc {
|
|||||||
pub async fn with_custom_timeout(
|
pub async fn with_custom_timeout(
|
||||||
mut url: String,
|
mut url: String,
|
||||||
request_timeout: Duration,
|
request_timeout: Duration,
|
||||||
) -> Result<Rpc<HttpRpc>, RpcError> {
|
) -> Result<Rpc<SimpleRequestRpc>, RpcError> {
|
||||||
let authentication = if url.contains('@') {
|
let authentication = if url.contains('@') {
|
||||||
// Parse out the username and password
|
// Parse out the username and password
|
||||||
let url_clone = url;
|
let url_clone = url;
|
||||||
@@ -119,11 +123,11 @@ impl HttpRpc {
|
|||||||
Authentication::Unauthenticated(Client::with_connection_pool())
|
Authentication::Unauthenticated(Client::with_connection_pool())
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Rpc(HttpRpc { authentication, url, request_timeout }))
|
Ok(Rpc::new(SimpleRequestRpc { authentication, url, request_timeout }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpRpc {
|
impl SimpleRequestRpc {
|
||||||
async fn inner_post(&self, route: &str, body: Vec<u8>) -> Result<Vec<u8>, RpcError> {
|
async fn inner_post(&self, route: &str, body: Vec<u8>) -> Result<Vec<u8>, RpcError> {
|
||||||
let request_fn = |uri| {
|
let request_fn = |uri| {
|
||||||
Request::post(uri)
|
Request::post(uri)
|
||||||
@@ -277,7 +281,7 @@ impl HttpRpc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl RpcConnection for HttpRpc {
|
impl RpcConnection for SimpleRequestRpc {
|
||||||
async fn post(&self, route: &str, body: Vec<u8>) -> Result<Vec<u8>, RpcError> {
|
async fn post(&self, route: &str, body: Vec<u8>) -> Result<Vec<u8>, RpcError> {
|
||||||
tokio::time::timeout(self.request_timeout, self.inner_post(route, body))
|
tokio::time::timeout(self.request_timeout, self.inner_post(route, body))
|
||||||
.await
|
.await
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
#![doc = include_str!("../README.md")]
|
||||||
|
// #![deny(missing_docs)] // TODO
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
@@ -7,33 +12,72 @@ use std_shims::{
|
|||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
use curve25519_dalek::edwards::EdwardsPoint;
|
use curve25519_dalek::edwards::EdwardsPoint;
|
||||||
|
|
||||||
use monero_io::decompress_point;
|
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize, de::DeserializeOwned};
|
use serde::{Serialize, Deserialize, de::DeserializeOwned};
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
|
|
||||||
use crate::{
|
use monero_serai::{
|
||||||
|
io::*,
|
||||||
Protocol,
|
Protocol,
|
||||||
serialize::*,
|
|
||||||
transaction::{Input, Timelock, Transaction},
|
transaction::{Input, Timelock, Transaction},
|
||||||
block::Block,
|
block::Block,
|
||||||
wallet::{FeePriority, Fee},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "http-rpc")]
|
|
||||||
mod http;
|
|
||||||
#[cfg(feature = "http-rpc")]
|
|
||||||
pub use http::*;
|
|
||||||
|
|
||||||
// Number of blocks the fee estimate will be valid for
|
// Number of blocks the fee estimate will be valid for
|
||||||
// https://github.com/monero-project/monero/blob/94e67bf96bbc010241f29ada6abc89f49a81759c/
|
// https://github.com/monero-project/monero/blob/94e67bf96bbc010241f29ada6abc89f49a81759c/
|
||||||
// src/wallet/wallet2.cpp#L121
|
// src/wallet/wallet2.cpp#L121
|
||||||
const GRACE_BLOCKS_FOR_FEE_ESTIMATE: u64 = 10;
|
const GRACE_BLOCKS_FOR_FEE_ESTIMATE: u64 = 10;
|
||||||
|
|
||||||
|
/// Fee struct, defined as a per-unit cost and a mask for rounding purposes.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
|
||||||
|
pub struct Fee {
|
||||||
|
pub per_weight: u64,
|
||||||
|
pub mask: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Fee {
|
||||||
|
pub fn calculate_fee_from_weight(&self, weight: usize) -> u64 {
|
||||||
|
let fee = (((self.per_weight * u64::try_from(weight).unwrap()) + self.mask - 1) / self.mask) *
|
||||||
|
self.mask;
|
||||||
|
debug_assert_eq!(weight, self.calculate_weight_from_fee(fee), "Miscalculated weight from fee");
|
||||||
|
fee
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn calculate_weight_from_fee(&self, fee: u64) -> usize {
|
||||||
|
usize::try_from(fee / self.per_weight).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fee priority, determining how quickly a transaction is included in a block.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub enum FeePriority {
|
||||||
|
Unimportant,
|
||||||
|
Normal,
|
||||||
|
Elevated,
|
||||||
|
Priority,
|
||||||
|
Custom { priority: u32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://github.com/monero-project/monero/blob/ac02af92867590ca80b2779a7bbeafa99ff94dcb/
|
||||||
|
/// src/simplewallet/simplewallet.cpp#L161
|
||||||
|
impl FeePriority {
|
||||||
|
pub(crate) fn fee_priority(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
FeePriority::Unimportant => 1,
|
||||||
|
FeePriority::Normal => 2,
|
||||||
|
FeePriority::Elevated => 3,
|
||||||
|
FeePriority::Priority => 4,
|
||||||
|
FeePriority::Custom { priority, .. } => *priority,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct EmptyResponse {}
|
pub struct EmptyResponse {}
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
@@ -132,6 +176,10 @@ pub trait RpcConnection: Clone + Debug {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Rpc<R: RpcConnection>(R);
|
pub struct Rpc<R: RpcConnection>(R);
|
||||||
impl<R: RpcConnection> Rpc<R> {
|
impl<R: RpcConnection> Rpc<R> {
|
||||||
|
pub fn new(connection: R) -> Self {
|
||||||
|
Self(connection)
|
||||||
|
}
|
||||||
|
|
||||||
/// Perform a RPC call to the specified route with the provided parameters.
|
/// Perform a RPC call to the specified route with the provided parameters.
|
||||||
///
|
///
|
||||||
/// This is NOT a JSON-RPC call. They use a route of "json_rpc" and are available via
|
/// This is NOT a JSON-RPC call. They use a route of "json_rpc" and are available via
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* TODO
|
||||||
#[cfg(feature = "binaries")]
|
#[cfg(feature = "binaries")]
|
||||||
mod binaries {
|
mod binaries {
|
||||||
pub(crate) use std::sync::Arc;
|
pub(crate) use std::sync::Arc;
|
||||||
@@ -12,14 +13,14 @@ mod binaries {
|
|||||||
ringct::{RctPrunable, bulletproofs::BatchVerifier},
|
ringct::{RctPrunable, bulletproofs::BatchVerifier},
|
||||||
transaction::{Input, Transaction},
|
transaction::{Input, Transaction},
|
||||||
block::Block,
|
block::Block,
|
||||||
rpc::{RpcError, Rpc, HttpRpc},
|
rpc::{RpcError, Rpc, SimpleRequestRpc},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) use monero_io::decompress_point;
|
pub(crate) use monero_io::decompress_point;
|
||||||
|
|
||||||
pub(crate) use tokio::task::JoinHandle;
|
pub(crate) use tokio::task::JoinHandle;
|
||||||
|
|
||||||
pub(crate) async fn check_block(rpc: Arc<Rpc<HttpRpc>>, block_i: usize) {
|
pub(crate) async fn check_block(rpc: Arc<Rpc<SimpleRequestRpc>>, block_i: usize) {
|
||||||
let hash = loop {
|
let hash = loop {
|
||||||
match rpc.get_block_hash(block_i).await {
|
match rpc.get_block_hash(block_i).await {
|
||||||
Ok(hash) => break hash,
|
Ok(hash) => break hash,
|
||||||
@@ -157,7 +158,7 @@ mod binaries {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn get_outs(
|
async fn get_outs(
|
||||||
rpc: &Rpc<HttpRpc>,
|
rpc: &Rpc<SimpleRequestRpc>,
|
||||||
amount: u64,
|
amount: u64,
|
||||||
indexes: &[u64],
|
indexes: &[u64],
|
||||||
) -> Vec<[EdwardsPoint; 2]> {
|
) -> Vec<[EdwardsPoint; 2]> {
|
||||||
@@ -268,9 +269,9 @@ async fn main() {
|
|||||||
let nodes = if specified_nodes.is_empty() { default_nodes } else { specified_nodes };
|
let nodes = if specified_nodes.is_empty() { default_nodes } else { specified_nodes };
|
||||||
|
|
||||||
let rpc = |url: String| async move {
|
let rpc = |url: String| async move {
|
||||||
HttpRpc::new(url.clone())
|
SimpleRequestRpc::new(url.clone())
|
||||||
.await
|
.await
|
||||||
.unwrap_or_else(|_| panic!("couldn't create HttpRpc connected to {url}"))
|
.unwrap_or_else(|_| panic!("couldn't create SimpleRequestRpc connected to {url}"))
|
||||||
};
|
};
|
||||||
let main_rpc = rpc(nodes[0].clone()).await;
|
let main_rpc = rpc(nodes[0].clone()).await;
|
||||||
let mut rpcs = vec![];
|
let mut rpcs = vec![];
|
||||||
@@ -315,3 +316,6 @@ async fn main() {
|
|||||||
fn main() {
|
fn main() {
|
||||||
panic!("To run binaries, please build with `--feature binaries`.");
|
panic!("To run binaries, please build with `--feature binaries`.");
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|||||||
@@ -27,14 +27,6 @@ pub mod transaction;
|
|||||||
/// Block structs.
|
/// Block structs.
|
||||||
pub mod block;
|
pub mod block;
|
||||||
|
|
||||||
/// Monero daemon RPC interface.
|
|
||||||
pub mod rpc;
|
|
||||||
/// Wallet functionality, enabling scanning and sending transactions.
|
|
||||||
pub mod wallet;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests;
|
|
||||||
|
|
||||||
pub const DEFAULT_LOCK_WINDOW: usize = 10;
|
pub const DEFAULT_LOCK_WINDOW: usize = 10;
|
||||||
pub const COINBASE_LOCK_WINDOW: usize = 60;
|
pub const COINBASE_LOCK_WINDOW: usize = 60;
|
||||||
pub const BLOCK_TIME: usize = 120;
|
pub const BLOCK_TIME: usize = 120;
|
||||||
@@ -106,7 +98,7 @@ impl Protocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn write<W: stdio::Write>(&self, w: &mut W) -> stdio::Result<()> {
|
pub fn write<W: stdio::Write>(&self, w: &mut W) -> stdio::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Protocol::v14 => w.write_all(&[0, 14]),
|
Protocol::v14 => w.write_all(&[0, 14]),
|
||||||
Protocol::v16 => w.write_all(&[0, 16]),
|
Protocol::v16 => w.write_all(&[0, 16]),
|
||||||
@@ -122,7 +114,7 @@ impl Protocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read<R: stdio::Read>(r: &mut R) -> stdio::Result<Protocol> {
|
pub fn read<R: stdio::Read>(r: &mut R) -> stdio::Result<Protocol> {
|
||||||
Ok(match read_byte(r)? {
|
Ok(match read_byte(r)? {
|
||||||
// Monero protocol
|
// Monero protocol
|
||||||
0 => match read_byte(r)? {
|
0 => match read_byte(r)? {
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ pub struct RctBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RctBase {
|
impl RctBase {
|
||||||
pub(crate) fn fee_weight(outputs: usize, fee: u64) -> usize {
|
pub fn fee_weight(outputs: usize, fee: u64) -> usize {
|
||||||
// 1 byte for the RCT signature type
|
// 1 byte for the RCT signature type
|
||||||
1 + (outputs * (8 + 32)) + varint_len(fee)
|
1 + (outputs * (8 + 32)) + varint_len(fee)
|
||||||
}
|
}
|
||||||
@@ -227,7 +227,7 @@ pub enum RctPrunable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RctPrunable {
|
impl RctPrunable {
|
||||||
pub(crate) fn fee_weight(protocol: Protocol, inputs: usize, outputs: usize) -> usize {
|
pub fn fee_weight(protocol: Protocol, inputs: usize, outputs: usize) -> usize {
|
||||||
// 1 byte for number of BPs (technically a VarInt, yet there's always just zero or one)
|
// 1 byte for number of BPs (technically a VarInt, yet there's always just zero or one)
|
||||||
1 + Bulletproof::fee_weight(protocol.bp_plus(), outputs) +
|
1 + Bulletproof::fee_weight(protocol.bp_plus(), outputs) +
|
||||||
(inputs * (Clsag::fee_weight(protocol.ring_len()) + 32))
|
(inputs * (Clsag::fee_weight(protocol.ring_len()) + 32))
|
||||||
@@ -383,7 +383,7 @@ impl RctSignatures {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn fee_weight(protocol: Protocol, inputs: usize, outputs: usize, fee: u64) -> usize {
|
pub fn fee_weight(protocol: Protocol, inputs: usize, outputs: usize, fee: u64) -> usize {
|
||||||
RctBase::fee_weight(outputs, fee) + RctPrunable::fee_weight(protocol, inputs, outputs)
|
RctBase::fee_weight(outputs, fee) + RctPrunable::fee_weight(protocol, inputs, outputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ pub enum Input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
pub(crate) fn fee_weight(offsets_weight: usize) -> usize {
|
pub fn fee_weight(offsets_weight: usize) -> usize {
|
||||||
// Uses 1 byte for the input type
|
// Uses 1 byte for the input type
|
||||||
// Uses 1 byte for the VarInt amount due to amount being 0
|
// Uses 1 byte for the VarInt amount due to amount being 0
|
||||||
1 + 1 + offsets_weight + 32
|
1 + 1 + offsets_weight + 32
|
||||||
@@ -82,7 +82,7 @@ pub struct Output {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Output {
|
impl Output {
|
||||||
pub(crate) fn fee_weight(view_tags: bool) -> usize {
|
pub fn fee_weight(view_tags: bool) -> usize {
|
||||||
// Uses 1 byte for the output type
|
// Uses 1 byte for the output type
|
||||||
// Uses 1 byte for the VarInt amount due to amount being 0
|
// Uses 1 byte for the VarInt amount due to amount being 0
|
||||||
1 + 1 + 32 + if view_tags { 1 } else { 0 }
|
1 + 1 + 32 + if view_tags { 1 } else { 0 }
|
||||||
@@ -182,7 +182,7 @@ pub struct TransactionPrefix {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TransactionPrefix {
|
impl TransactionPrefix {
|
||||||
pub(crate) fn fee_weight(
|
pub fn fee_weight(
|
||||||
decoy_weights: &[usize],
|
decoy_weights: &[usize],
|
||||||
outputs: usize,
|
outputs: usize,
|
||||||
view_tags: bool,
|
view_tags: bool,
|
||||||
@@ -254,7 +254,7 @@ pub struct Transaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Transaction {
|
impl Transaction {
|
||||||
pub(crate) fn fee_weight(
|
pub fn fee_weight(
|
||||||
protocol: Protocol,
|
protocol: Protocol,
|
||||||
decoy_weights: &[usize],
|
decoy_weights: &[usize],
|
||||||
outputs: usize,
|
outputs: usize,
|
||||||
|
|||||||
88
coins/monero/wallet/Cargo.toml
Normal file
88
coins/monero/wallet/Cargo.toml
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
[package]
|
||||||
|
name = "monero-wallet"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Wallet functionality for the Monero protocol, built around monero-serai"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/serai-dex/serai/tree/develop/coins/monero/wallet"
|
||||||
|
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.79"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
std-shims = { path = "../../../common/std-shims", version = "^0.1.1", default-features = false }
|
||||||
|
|
||||||
|
async-trait = { version = "0.1", default-features = false }
|
||||||
|
thiserror = { version = "1", default-features = false, optional = true }
|
||||||
|
|
||||||
|
zeroize = { version = "^1.5", default-features = false, features = ["zeroize_derive"] }
|
||||||
|
subtle = { version = "^2.4", default-features = false }
|
||||||
|
|
||||||
|
rand_core = { version = "0.6", default-features = false }
|
||||||
|
# Used to send transactions
|
||||||
|
rand = { version = "0.8", default-features = false }
|
||||||
|
rand_chacha = { version = "0.3", default-features = false }
|
||||||
|
# Used to select decoys
|
||||||
|
rand_distr = { version = "0.4", default-features = false }
|
||||||
|
|
||||||
|
sha3 = { version = "0.10", default-features = false }
|
||||||
|
pbkdf2 = { version = "0.12", features = ["simple"], default-features = false }
|
||||||
|
|
||||||
|
group = { version = "0.13", default-features = false }
|
||||||
|
curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize", "group"] }
|
||||||
|
|
||||||
|
# Multisig dependencies
|
||||||
|
transcript = { package = "flexible-transcript", path = "../../../crypto/transcript", version = "0.3", default-features = false, features = ["recommended"], optional = true }
|
||||||
|
dalek-ff-group = { path = "../../../crypto/dalek-ff-group", version = "0.4", default-features = false, optional = true }
|
||||||
|
frost = { package = "modular-frost", path = "../../../crypto/frost", default-features = false, features = ["ed25519"], optional = true }
|
||||||
|
|
||||||
|
hex = { version = "0.4", default-features = false, features = ["alloc"] }
|
||||||
|
base58-monero = { version = "2", default-features = false, features = ["check"] }
|
||||||
|
serde = { version = "1", default-features = false, features = ["derive", "alloc"] }
|
||||||
|
serde_json = { version = "1", default-features = false, features = ["alloc"] }
|
||||||
|
|
||||||
|
monero-serai = { path = "..", default-features = false }
|
||||||
|
monero-rpc = { path = "../rpc", default-features = false }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
hex-literal = "0.4"
|
||||||
|
|
||||||
|
frost = { package = "modular-frost", path = "../../../crypto/frost", default-features = false, features = ["ed25519", "tests"] }
|
||||||
|
|
||||||
|
tokio = { version = "1", features = ["sync", "macros"] }
|
||||||
|
|
||||||
|
monero-simple-request-rpc = { path = "../rpc/simple-request", default-features = false }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
std = [
|
||||||
|
"std-shims/std",
|
||||||
|
|
||||||
|
"thiserror",
|
||||||
|
|
||||||
|
"zeroize/std",
|
||||||
|
"subtle/std",
|
||||||
|
|
||||||
|
"rand_core/std",
|
||||||
|
"rand/std",
|
||||||
|
"rand_chacha/std",
|
||||||
|
"rand_distr/std",
|
||||||
|
|
||||||
|
"sha3/std",
|
||||||
|
"pbkdf2/std",
|
||||||
|
|
||||||
|
"hex/std",
|
||||||
|
"base58-monero/std",
|
||||||
|
"serde/std",
|
||||||
|
"serde_json/std",
|
||||||
|
|
||||||
|
"monero-serai/std",
|
||||||
|
"monero-rpc/std",
|
||||||
|
]
|
||||||
|
multisig = ["transcript", "dalek-ff-group", "frost", "monero-serai/multisig", "std"]
|
||||||
|
default = ["std"]
|
||||||
21
coins/monero/wallet/LICENSE
Normal file
21
coins/monero/wallet/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022-2024 Luke Parker
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
6
coins/monero/wallet/README.md
Normal file
6
coins/monero/wallet/README.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Monero Wallet
|
||||||
|
|
||||||
|
Wallet functionality for the Monero protocol, built around monero-serai.
|
||||||
|
|
||||||
|
This library is usable under no-std when the `std` feature (on by default) is
|
||||||
|
disabled.
|
||||||
@@ -5,7 +5,7 @@ use zeroize::Zeroize;
|
|||||||
|
|
||||||
use curve25519_dalek::edwards::EdwardsPoint;
|
use curve25519_dalek::edwards::EdwardsPoint;
|
||||||
|
|
||||||
use crate::io::decompress_point;
|
use monero_serai::io::decompress_point;
|
||||||
|
|
||||||
use base58_monero::base58::{encode_check, decode_check};
|
use base58_monero::base58::{encode_check, decode_check};
|
||||||
|
|
||||||
@@ -9,11 +9,9 @@ use rand_distr::num_traits::Float;
|
|||||||
|
|
||||||
use curve25519_dalek::edwards::EdwardsPoint;
|
use curve25519_dalek::edwards::EdwardsPoint;
|
||||||
|
|
||||||
use crate::{
|
use monero_serai::{DEFAULT_LOCK_WINDOW, COINBASE_LOCK_WINDOW, BLOCK_TIME};
|
||||||
wallet::SpendableOutput,
|
use monero_rpc::{RpcError, RpcConnection, Rpc};
|
||||||
rpc::{RpcError, RpcConnection, Rpc},
|
use crate::SpendableOutput;
|
||||||
DEFAULT_LOCK_WINDOW, COINBASE_LOCK_WINDOW, BLOCK_TIME,
|
|
||||||
};
|
|
||||||
|
|
||||||
const RECENT_WINDOW: usize = 15;
|
const RECENT_WINDOW: usize = 15;
|
||||||
const BLOCKS_PER_YEAR: usize = 365 * 24 * 60 * 60 / BLOCK_TIME;
|
const BLOCKS_PER_YEAR: usize = 365 * 24 * 60 * 60 / BLOCK_TIME;
|
||||||
@@ -274,7 +272,7 @@ async fn select_decoys<R: RngCore + CryptoRng, RPC: RpcConnection>(
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use monero_primitives::Decoys;
|
pub use monero_serai::primitives::Decoys;
|
||||||
|
|
||||||
// TODO: Remove this trait
|
// TODO: Remove this trait
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@@ -8,7 +8,7 @@ use zeroize::Zeroize;
|
|||||||
|
|
||||||
use curve25519_dalek::edwards::EdwardsPoint;
|
use curve25519_dalek::edwards::EdwardsPoint;
|
||||||
|
|
||||||
use crate::io::*;
|
use monero_serai::io::*;
|
||||||
|
|
||||||
pub const MAX_TX_EXTRA_PADDING_COUNT: usize = 255;
|
pub const MAX_TX_EXTRA_PADDING_COUNT: usize = 255;
|
||||||
pub const MAX_TX_EXTRA_NONCE_SIZE: usize = 255;
|
pub const MAX_TX_EXTRA_NONCE_SIZE: usize = 255;
|
||||||
@@ -209,7 +209,7 @@ impl Extra {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
pub(crate) fn fee_weight(
|
pub fn fee_weight(
|
||||||
outputs: usize,
|
outputs: usize,
|
||||||
additional: bool,
|
additional: bool,
|
||||||
payment_id: bool,
|
payment_id: bool,
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
#![doc = include_str!("../README.md")]
|
||||||
|
// #![deny(missing_docs)] // TODO
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
use std_shims::collections::{HashSet, HashMap};
|
use std_shims::collections::{HashSet, HashMap};
|
||||||
|
|
||||||
@@ -9,12 +14,15 @@ use curve25519_dalek::{
|
|||||||
edwards::{EdwardsPoint, CompressedEdwardsY},
|
edwards::{EdwardsPoint, CompressedEdwardsY},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use monero_serai::{
|
||||||
io::write_varint,
|
io::write_varint,
|
||||||
primitives::{Commitment, keccak256, keccak256_to_scalar},
|
primitives::{Commitment, keccak256, keccak256_to_scalar},
|
||||||
ringct::EncryptedAmount,
|
ringct::EncryptedAmount,
|
||||||
transaction::Input,
|
transaction::Input,
|
||||||
};
|
};
|
||||||
|
pub use monero_serai as monero;
|
||||||
|
|
||||||
|
pub use monero_rpc as rpc;
|
||||||
|
|
||||||
pub mod extra;
|
pub mod extra;
|
||||||
pub(crate) use extra::{PaymentId, ExtraField, Extra};
|
pub(crate) use extra::{PaymentId, ExtraField, Extra};
|
||||||
@@ -33,7 +41,7 @@ pub use scan::{ReceivedOutput, SpendableOutput, Timelocked};
|
|||||||
pub mod decoys;
|
pub mod decoys;
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
pub mod decoys {
|
pub mod decoys {
|
||||||
pub use monero_primitives::Decoys;
|
pub use monero_serai::primitives::Decoys;
|
||||||
pub trait DecoySelection {}
|
pub trait DecoySelection {}
|
||||||
}
|
}
|
||||||
pub use decoys::{DecoySelection, Decoys};
|
pub use decoys::{DecoySelection, Decoys};
|
||||||
@@ -47,6 +55,9 @@ pub(crate) use send::InternalPayment;
|
|||||||
#[cfg(feature = "multisig")]
|
#[cfg(feature = "multisig")]
|
||||||
pub use send::TransactionMachine;
|
pub use send::TransactionMachine;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
fn key_image_sort(x: &EdwardsPoint, y: &EdwardsPoint) -> core::cmp::Ordering {
|
fn key_image_sort(x: &EdwardsPoint, y: &EdwardsPoint) -> core::cmp::Ordering {
|
||||||
x.compress().to_bytes().cmp(&y.compress().to_bytes()).reverse()
|
x.compress().to_bytes().cmp(&y.compress().to_bytes()).reverse()
|
||||||
}
|
}
|
||||||
@@ -109,12 +120,19 @@ pub(crate) fn compact_amount_encryption(amount: u64, key: Scalar) -> [u8; 8] {
|
|||||||
(amount ^ u64::from_le_bytes(keccak256(amount_mask)[.. 8].try_into().unwrap())).to_le_bytes()
|
(amount ^ u64::from_le_bytes(keccak256(amount_mask)[.. 8].try_into().unwrap())).to_le_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EncryptedAmount {
|
pub trait EncryptedAmountExt {
|
||||||
/// Decrypt an EncryptedAmount into the Commitment it encrypts.
|
/// Decrypt an EncryptedAmount into the Commitment it encrypts.
|
||||||
///
|
///
|
||||||
/// The caller must verify the decrypted Commitment matches with the actual Commitment used
|
/// The caller must verify the decrypted Commitment matches with the actual Commitment used
|
||||||
/// within in the Monero protocol.
|
/// within in the Monero protocol.
|
||||||
pub fn decrypt(&self, key: Scalar) -> Commitment {
|
fn decrypt(&self, key: Scalar) -> Commitment;
|
||||||
|
}
|
||||||
|
impl EncryptedAmountExt for EncryptedAmount {
|
||||||
|
/// Decrypt an EncryptedAmount into the Commitment it encrypts.
|
||||||
|
///
|
||||||
|
/// The caller must verify the decrypted Commitment matches with the actual Commitment used
|
||||||
|
/// within in the Monero protocol.
|
||||||
|
fn decrypt(&self, key: Scalar) -> Commitment {
|
||||||
match self {
|
match self {
|
||||||
// TODO: Add a test vector for this
|
// TODO: Add a test vector for this
|
||||||
EncryptedAmount::Original { mask, amount } => {
|
EncryptedAmount::Original { mask, amount } => {
|
||||||
@@ -9,15 +9,15 @@ use zeroize::{Zeroize, ZeroizeOnDrop};
|
|||||||
|
|
||||||
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwards::EdwardsPoint};
|
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwards::EdwardsPoint};
|
||||||
|
|
||||||
use monero_io::decompress_point;
|
use monero_rpc::{RpcError, RpcConnection, Rpc};
|
||||||
|
use monero_serai::{
|
||||||
use crate::{
|
|
||||||
io::*,
|
io::*,
|
||||||
primitives::Commitment,
|
primitives::Commitment,
|
||||||
transaction::{Input, Timelock, Transaction},
|
transaction::{Input, Timelock, Transaction},
|
||||||
block::Block,
|
block::Block,
|
||||||
rpc::{RpcError, RpcConnection, Rpc},
|
};
|
||||||
wallet::{PaymentId, Extra, address::SubaddressIndex, Scanner, uniqueness, shared_key},
|
use crate::{
|
||||||
|
PaymentId, Extra, address::SubaddressIndex, Scanner, EncryptedAmountExt, uniqueness, shared_key,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An absolute output ID, defined as its transaction hash and output index.
|
/// An absolute output ID, defined as its transaction hash and output index.
|
||||||
@@ -11,7 +11,7 @@ use rand_core::{RngCore, CryptoRng};
|
|||||||
|
|
||||||
use curve25519_dalek::scalar::Scalar;
|
use curve25519_dalek::scalar::Scalar;
|
||||||
|
|
||||||
use crate::wallet::seed::SeedError;
|
use crate::seed::SeedError;
|
||||||
|
|
||||||
pub(crate) const CLASSIC_SEED_LENGTH: usize = 24;
|
pub(crate) const CLASSIC_SEED_LENGTH: usize = 24;
|
||||||
pub(crate) const CLASSIC_SEED_LENGTH_WITH_CHECKSUM: usize = 25;
|
pub(crate) const CLASSIC_SEED_LENGTH_WITH_CHECKSUM: usize = 25;
|
||||||
@@ -2,12 +2,10 @@ use std::sync::{Arc, RwLock};
|
|||||||
|
|
||||||
use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
|
use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
|
||||||
|
|
||||||
|
use monero_serai::Protocol;
|
||||||
use crate::{
|
use crate::{
|
||||||
Protocol,
|
|
||||||
wallet::{
|
|
||||||
address::MoneroAddress, Fee, SpendableOutput, Change, Decoys, SignableTransaction,
|
address::MoneroAddress, Fee, SpendableOutput, Change, Decoys, SignableTransaction,
|
||||||
TransactionError, extra::MAX_ARBITRARY_DATA_SIZE,
|
TransactionError, extra::MAX_ARBITRARY_DATA_SIZE,
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
|
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
|
||||||
@@ -17,14 +17,13 @@ use curve25519_dalek::{
|
|||||||
scalar::Scalar,
|
scalar::Scalar,
|
||||||
edwards::EdwardsPoint,
|
edwards::EdwardsPoint,
|
||||||
};
|
};
|
||||||
use dalek_ff_group as dfg;
|
|
||||||
|
|
||||||
#[cfg(feature = "multisig")]
|
#[cfg(feature = "multisig")]
|
||||||
use frost::FrostError;
|
use frost::FrostError;
|
||||||
|
|
||||||
use monero_io::varint_len;
|
use monero_rpc::RpcError;
|
||||||
|
pub use monero_rpc::{Fee, FeePriority};
|
||||||
use crate::{
|
use monero_serai::{
|
||||||
io::*,
|
io::*,
|
||||||
primitives::{Commitment, keccak256},
|
primitives::{Commitment, keccak256},
|
||||||
Protocol,
|
Protocol,
|
||||||
@@ -35,13 +34,12 @@ use crate::{
|
|||||||
RctBase, RctPrunable, RctSignatures,
|
RctBase, RctPrunable, RctSignatures,
|
||||||
},
|
},
|
||||||
transaction::{Input, Output, Timelock, TransactionPrefix, Transaction},
|
transaction::{Input, Output, Timelock, TransactionPrefix, Transaction},
|
||||||
rpc::RpcError,
|
};
|
||||||
wallet::{
|
use crate::{
|
||||||
address::{Network, AddressSpec, MoneroAddress},
|
address::{Network, AddressSpec, MoneroAddress},
|
||||||
ViewPair, SpendableOutput, Decoys, PaymentId, ExtraField, Extra, key_image_sort, uniqueness,
|
ViewPair, SpendableOutput, Decoys, PaymentId, ExtraField, Extra, key_image_sort, uniqueness,
|
||||||
shared_key, commitment_mask, compact_amount_encryption,
|
shared_key, commitment_mask, compact_amount_encryption,
|
||||||
extra::{ARBITRARY_DATA_MARKER, MAX_ARBITRARY_DATA_SIZE},
|
extra::{ARBITRARY_DATA_MARKER, MAX_ARBITRARY_DATA_SIZE},
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@@ -53,7 +51,7 @@ pub use builder::SignableTransactionBuilder;
|
|||||||
mod multisig;
|
mod multisig;
|
||||||
#[cfg(feature = "multisig")]
|
#[cfg(feature = "multisig")]
|
||||||
pub use multisig::TransactionMachine;
|
pub use multisig::TransactionMachine;
|
||||||
use crate::ringct::EncryptedAmount;
|
use monero_serai::ringct::EncryptedAmount;
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
|
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
|
||||||
@@ -264,51 +262,6 @@ fn calculate_weight_and_fee(
|
|||||||
(weight, fee)
|
(weight, fee)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fee struct, defined as a per-unit cost and a mask for rounding purposes.
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
|
|
||||||
pub struct Fee {
|
|
||||||
pub per_weight: u64,
|
|
||||||
pub mask: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Fee {
|
|
||||||
pub fn calculate_fee_from_weight(&self, weight: usize) -> u64 {
|
|
||||||
let fee = (((self.per_weight * u64::try_from(weight).unwrap()) + self.mask - 1) / self.mask) *
|
|
||||||
self.mask;
|
|
||||||
debug_assert_eq!(weight, self.calculate_weight_from_fee(fee), "Miscalculated weight from fee");
|
|
||||||
fee
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn calculate_weight_from_fee(&self, fee: u64) -> usize {
|
|
||||||
usize::try_from(fee / self.per_weight).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fee priority, determining how quickly a transaction is included in a block.
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
pub enum FeePriority {
|
|
||||||
Unimportant,
|
|
||||||
Normal,
|
|
||||||
Elevated,
|
|
||||||
Priority,
|
|
||||||
Custom { priority: u32 },
|
|
||||||
}
|
|
||||||
|
|
||||||
/// https://github.com/monero-project/monero/blob/ac02af92867590ca80b2779a7bbeafa99ff94dcb/
|
|
||||||
/// src/simplewallet/simplewallet.cpp#L161
|
|
||||||
impl FeePriority {
|
|
||||||
pub(crate) fn fee_priority(&self) -> u32 {
|
|
||||||
match self {
|
|
||||||
FeePriority::Unimportant => 1,
|
|
||||||
FeePriority::Normal => 2,
|
|
||||||
FeePriority::Elevated => 3,
|
|
||||||
FeePriority::Priority => 4,
|
|
||||||
FeePriority::Custom { priority, .. } => *priority,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Zeroize)]
|
#[derive(Clone, PartialEq, Eq, Debug, Zeroize)]
|
||||||
pub(crate) enum InternalPayment {
|
pub(crate) enum InternalPayment {
|
||||||
Payment((MoneroAddress, u64), bool),
|
Payment((MoneroAddress, u64), bool),
|
||||||
@@ -694,7 +647,7 @@ impl SignableTransaction {
|
|||||||
} else {
|
} else {
|
||||||
// If this used tx_key, randomize its R
|
// If this used tx_key, randomize its R
|
||||||
// This is so when extra is created, there's a distinct R for it to use
|
// This is so when extra is created, there's a distinct R for it to use
|
||||||
output.R = dfg::EdwardsPoint::random(&mut rng).0;
|
output.R = EdwardsPoint::random(&mut rng);
|
||||||
}
|
}
|
||||||
(output, payment_id)
|
(output, payment_id)
|
||||||
}
|
}
|
||||||
@@ -24,14 +24,14 @@ use frost::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use monero_serai::{
|
||||||
ringct::{
|
ringct::{
|
||||||
clsag::{ClsagContext, ClsagMultisigMaskSender, ClsagAddendum, ClsagMultisig},
|
clsag::{ClsagContext, ClsagMultisigMaskSender, ClsagAddendum, ClsagMultisig},
|
||||||
RctPrunable,
|
RctPrunable,
|
||||||
},
|
},
|
||||||
transaction::{Input, Transaction},
|
transaction::{Input, Transaction},
|
||||||
wallet::{TransactionError, InternalPayment, SignableTransaction, key_image_sort, uniqueness},
|
|
||||||
};
|
};
|
||||||
|
use crate::{TransactionError, InternalPayment, SignableTransaction, key_image_sort, uniqueness};
|
||||||
|
|
||||||
/// FROST signing machine to produce a signed transaction.
|
/// FROST signing machine to produce a signed transaction.
|
||||||
pub struct TransactionMachine {
|
pub struct TransactionMachine {
|
||||||
@@ -4,9 +4,9 @@ use rand_core::{RngCore, OsRng};
|
|||||||
|
|
||||||
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar};
|
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar};
|
||||||
|
|
||||||
use monero_io::decompress_point;
|
use monero_serai::io::decompress_point;
|
||||||
|
|
||||||
use crate::wallet::address::{Network, AddressType, AddressMeta, MoneroAddress};
|
use crate::address::{Network, AddressType, AddressMeta, MoneroAddress};
|
||||||
|
|
||||||
const SPEND: [u8; 32] = hex!("f8631661f6ab4e6fda310c797330d86e23a682f20d5bc8cc27b18051191f16d7");
|
const SPEND: [u8; 32] = hex!("f8631661f6ab4e6fda310c797330d86e23a682f20d5bc8cc27b18051191f16d7");
|
||||||
const VIEW: [u8; 32] = hex!("4a1535063ad1fee2dabbf909d4fd9a873e29541b401f0944754e17c9a41820ce");
|
const VIEW: [u8; 32] = hex!("4a1535063ad1fee2dabbf909d4fd9a873e29541b401f0944754e17c9a41820ce");
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
use crate::{
|
|
||||||
wallet::{ExtraField, Extra, extra::MAX_TX_EXTRA_PADDING_COUNT},
|
|
||||||
serialize::write_varint,
|
|
||||||
};
|
|
||||||
|
|
||||||
use curve25519_dalek::edwards::{EdwardsPoint, CompressedEdwardsY};
|
use curve25519_dalek::edwards::{EdwardsPoint, CompressedEdwardsY};
|
||||||
|
|
||||||
|
use monero_serai::io::write_varint;
|
||||||
|
use crate::{ExtraField, Extra, extra::MAX_TX_EXTRA_PADDING_COUNT};
|
||||||
|
|
||||||
// Borrowed tests from
|
// Borrowed tests from
|
||||||
// https://github.com/monero-project/monero/blob/ac02af92867590ca80b2779a7bbeafa99ff94dcb/
|
// https://github.com/monero-project/monero/blob/ac02af92867590ca80b2779a7bbeafa99ff94dcb/
|
||||||
// tests/unit_tests/test_tx_utils.cpp
|
// tests/unit_tests/test_tx_utils.cpp
|
||||||
@@ -4,9 +4,9 @@ use rand_core::OsRng;
|
|||||||
|
|
||||||
use curve25519_dalek::scalar::Scalar;
|
use curve25519_dalek::scalar::Scalar;
|
||||||
|
|
||||||
use monero_primitives::keccak256;
|
use monero_serai::primitives::keccak256;
|
||||||
|
|
||||||
use crate::wallet::seed::{
|
use crate::seed::{
|
||||||
Seed, SeedType, SeedError,
|
Seed, SeedType, SeedError,
|
||||||
classic::{self, trim_by_lang},
|
classic::{self, trim_by_lang},
|
||||||
polyseed,
|
polyseed,
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
use monero_serai::{
|
use monero_serai::transaction::Transaction;
|
||||||
transaction::Transaction,
|
use monero_wallet::{TransactionError, extra::MAX_ARBITRARY_DATA_SIZE};
|
||||||
wallet::{TransactionError, extra::MAX_ARBITRARY_DATA_SIZE},
|
|
||||||
};
|
|
||||||
|
|
||||||
mod runner;
|
mod runner;
|
||||||
|
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
use monero_serai::{
|
use monero_rpc::{Rpc, OutputResponse};
|
||||||
transaction::Transaction,
|
use monero_serai::{transaction::Transaction, Protocol, DEFAULT_LOCK_WINDOW};
|
||||||
wallet::SpendableOutput,
|
use monero_wallet::SpendableOutput;
|
||||||
rpc::{Rpc, OutputResponse},
|
|
||||||
Protocol, DEFAULT_LOCK_WINDOW,
|
|
||||||
};
|
|
||||||
|
|
||||||
mod runner;
|
mod runner;
|
||||||
|
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
use curve25519_dalek::constants::ED25519_BASEPOINT_POINT;
|
use curve25519_dalek::constants::ED25519_BASEPOINT_POINT;
|
||||||
|
|
||||||
use monero_serai::{
|
use monero_serai::transaction::Transaction;
|
||||||
transaction::Transaction,
|
use monero_wallet::{
|
||||||
wallet::{
|
|
||||||
Eventuality,
|
Eventuality,
|
||||||
address::{AddressType, AddressMeta, MoneroAddress},
|
address::{AddressType, AddressMeta, MoneroAddress},
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mod runner;
|
mod runner;
|
||||||
@@ -8,15 +8,13 @@ use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar};
|
|||||||
|
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use monero_serai::{
|
use monero_rpc::Rpc;
|
||||||
rpc::{HttpRpc, Rpc},
|
use monero_simple_request_rpc::SimpleRequestRpc;
|
||||||
wallet::{
|
use monero_serai::{transaction::Transaction, DEFAULT_LOCK_WINDOW};
|
||||||
|
use monero_wallet::{
|
||||||
ViewPair, Scanner,
|
ViewPair, Scanner,
|
||||||
address::{Network, AddressType, AddressSpec, AddressMeta, MoneroAddress},
|
address::{Network, AddressType, AddressSpec, AddressMeta, MoneroAddress},
|
||||||
SpendableOutput, Fee,
|
SpendableOutput, Fee,
|
||||||
},
|
|
||||||
transaction::Transaction,
|
|
||||||
DEFAULT_LOCK_WINDOW,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn random_address() -> (Scalar, ViewPair, MoneroAddress) {
|
pub fn random_address() -> (Scalar, ViewPair, MoneroAddress) {
|
||||||
@@ -36,7 +34,7 @@ pub fn random_address() -> (Scalar, ViewPair, MoneroAddress) {
|
|||||||
|
|
||||||
// TODO: Support transactions already on-chain
|
// TODO: Support transactions already on-chain
|
||||||
// TODO: Don't have a side effect of mining blocks more blocks than needed under race conditions
|
// TODO: Don't have a side effect of mining blocks more blocks than needed under race conditions
|
||||||
pub async fn mine_until_unlocked(rpc: &Rpc<HttpRpc>, addr: &str, tx_hash: [u8; 32]) {
|
pub async fn mine_until_unlocked(rpc: &Rpc<SimpleRequestRpc>, addr: &str, tx_hash: [u8; 32]) {
|
||||||
// mine until tx is in a block
|
// mine until tx is in a block
|
||||||
let mut height = rpc.get_height().await.unwrap();
|
let mut height = rpc.get_height().await.unwrap();
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
@@ -66,7 +64,7 @@ pub async fn mine_until_unlocked(rpc: &Rpc<HttpRpc>, addr: &str, tx_hash: [u8; 3
|
|||||||
|
|
||||||
// Mines 60 blocks and returns an unlocked miner TX output.
|
// Mines 60 blocks and returns an unlocked miner TX output.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub async fn get_miner_tx_output(rpc: &Rpc<HttpRpc>, view: &ViewPair) -> SpendableOutput {
|
pub async fn get_miner_tx_output(rpc: &Rpc<SimpleRequestRpc>, view: &ViewPair) -> SpendableOutput {
|
||||||
let mut scanner = Scanner::from_view(view.clone(), Some(HashSet::new()));
|
let mut scanner = Scanner::from_view(view.clone(), Some(HashSet::new()));
|
||||||
|
|
||||||
// Mine 60 blocks to unlock a miner TX
|
// Mine 60 blocks to unlock a miner TX
|
||||||
@@ -92,8 +90,9 @@ pub fn check_weight_and_fee(tx: &Transaction, fee_rate: Fee) {
|
|||||||
assert_eq!(fee, expected_fee);
|
assert_eq!(fee, expected_fee);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn rpc() -> Rpc<HttpRpc> {
|
pub async fn rpc() -> Rpc<SimpleRequestRpc> {
|
||||||
let rpc = HttpRpc::new("http://serai:seraidex@127.0.0.1:18081".to_string()).await.unwrap();
|
let rpc =
|
||||||
|
SimpleRequestRpc::new("http://serai:seraidex@127.0.0.1:18081".to_string()).await.unwrap();
|
||||||
|
|
||||||
// Only run once
|
// Only run once
|
||||||
if rpc.get_height().await.unwrap() != 1 {
|
if rpc.get_height().await.unwrap() != 1 {
|
||||||
@@ -171,12 +170,10 @@ macro_rules! test {
|
|||||||
tests::{THRESHOLD, key_gen},
|
tests::{THRESHOLD, key_gen},
|
||||||
};
|
};
|
||||||
|
|
||||||
use monero_serai::{
|
use monero_wallet::{
|
||||||
wallet::{
|
|
||||||
address::{Network, AddressSpec},
|
address::{Network, AddressSpec},
|
||||||
ViewPair, Scanner, Change, DecoySelection, Decoys, FeePriority,
|
ViewPair, Scanner, Change, DecoySelection, Decoys, FeePriority,
|
||||||
SignableTransaction, SignableTransactionBuilder,
|
SignableTransaction, SignableTransactionBuilder,
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use runner::{
|
use runner::{
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
use rand::RngCore;
|
use rand_core::RngCore;
|
||||||
|
|
||||||
use monero_serai::{
|
use monero_serai::transaction::Transaction;
|
||||||
transaction::Transaction,
|
use monero_wallet::{address::SubaddressIndex, extra::PaymentId};
|
||||||
wallet::{address::SubaddressIndex, extra::PaymentId},
|
|
||||||
};
|
|
||||||
|
|
||||||
mod runner;
|
mod runner;
|
||||||
|
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
use rand_core::OsRng;
|
use rand_core::OsRng;
|
||||||
|
|
||||||
use monero_serai::{
|
use monero_serai::{transaction::Transaction, Protocol};
|
||||||
transaction::Transaction,
|
use monero_rpc::Rpc;
|
||||||
wallet::{
|
use monero_simple_request_rpc::SimpleRequestRpc;
|
||||||
extra::Extra, address::SubaddressIndex, ReceivedOutput, SpendableOutput, DecoySelection,
|
use monero_wallet::{
|
||||||
Decoys, SignableTransactionBuilder,
|
extra::Extra, address::SubaddressIndex, ReceivedOutput, SpendableOutput, DecoySelection, Decoys,
|
||||||
},
|
SignableTransactionBuilder,
|
||||||
rpc::{Rpc, HttpRpc},
|
|
||||||
Protocol,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mod runner;
|
mod runner;
|
||||||
@@ -15,7 +13,7 @@ mod runner;
|
|||||||
// Set up inputs, select decoys, then add them to the TX builder
|
// Set up inputs, select decoys, then add them to the TX builder
|
||||||
async fn add_inputs(
|
async fn add_inputs(
|
||||||
protocol: Protocol,
|
protocol: Protocol,
|
||||||
rpc: &Rpc<HttpRpc>,
|
rpc: &Rpc<SimpleRequestRpc>,
|
||||||
outputs: Vec<ReceivedOutput>,
|
outputs: Vec<ReceivedOutput>,
|
||||||
builder: &mut SignableTransactionBuilder,
|
builder: &mut SignableTransactionBuilder,
|
||||||
) {
|
) {
|
||||||
@@ -101,7 +99,7 @@ test!(
|
|||||||
),
|
),
|
||||||
(
|
(
|
||||||
|protocol, rpc: Rpc<_>, _, _, outputs: Vec<ReceivedOutput>| async move {
|
|protocol, rpc: Rpc<_>, _, _, outputs: Vec<ReceivedOutput>| async move {
|
||||||
use monero_serai::wallet::FeePriority;
|
use monero_wallet::FeePriority;
|
||||||
|
|
||||||
let change_view = ViewPair::new(
|
let change_view = ViewPair::new(
|
||||||
&Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE,
|
&Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE,
|
||||||
@@ -290,7 +288,7 @@ test!(
|
|||||||
),
|
),
|
||||||
(
|
(
|
||||||
|protocol, rpc: Rpc<_>, _, addr, outputs: Vec<ReceivedOutput>| async move {
|
|protocol, rpc: Rpc<_>, _, addr, outputs: Vec<ReceivedOutput>| async move {
|
||||||
use monero_serai::wallet::FeePriority;
|
use monero_wallet::FeePriority;
|
||||||
|
|
||||||
let mut builder = SignableTransactionBuilder::new(
|
let mut builder = SignableTransactionBuilder::new(
|
||||||
protocol,
|
protocol,
|
||||||
@@ -5,19 +5,18 @@ use rand_core::{OsRng, RngCore};
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
use monero_serai::{
|
use monero_serai::transaction::Transaction;
|
||||||
transaction::Transaction,
|
use monero_rpc::{EmptyResponse, Rpc};
|
||||||
rpc::{EmptyResponse, HttpRpc, Rpc},
|
use monero_simple_request_rpc::SimpleRequestRpc;
|
||||||
wallet::{
|
use monero_wallet::{
|
||||||
address::{Network, AddressSpec, SubaddressIndex, MoneroAddress},
|
address::{Network, AddressSpec, SubaddressIndex, MoneroAddress},
|
||||||
extra::{MAX_TX_EXTRA_NONCE_SIZE, Extra, PaymentId},
|
extra::{MAX_TX_EXTRA_NONCE_SIZE, Extra, PaymentId},
|
||||||
Scanner,
|
Scanner,
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mod runner;
|
mod runner;
|
||||||
|
|
||||||
async fn make_integrated_address(rpc: &Rpc<HttpRpc>, payment_id: [u8; 8]) -> String {
|
async fn make_integrated_address(rpc: &Rpc<SimpleRequestRpc>, payment_id: [u8; 8]) -> String {
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct IntegratedAddressResponse {
|
struct IntegratedAddressResponse {
|
||||||
integrated_address: String,
|
integrated_address: String,
|
||||||
@@ -34,8 +33,8 @@ async fn make_integrated_address(rpc: &Rpc<HttpRpc>, payment_id: [u8; 8]) -> Str
|
|||||||
res.integrated_address
|
res.integrated_address
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn initialize_rpcs() -> (Rpc<HttpRpc>, Rpc<HttpRpc>, String) {
|
async fn initialize_rpcs() -> (Rpc<SimpleRequestRpc>, Rpc<SimpleRequestRpc>, String) {
|
||||||
let wallet_rpc = HttpRpc::new("http://127.0.0.1:18082".to_string()).await.unwrap();
|
let wallet_rpc = SimpleRequestRpc::new("http://127.0.0.1:18082".to_string()).await.unwrap();
|
||||||
let daemon_rpc = runner::rpc().await;
|
let daemon_rpc = runner::rpc().await;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@@ -174,7 +173,7 @@ test!(
|
|||||||
.add_payment(MoneroAddress::from_str(Network::Mainnet, &wallet_rpc_addr).unwrap(), 1000000);
|
.add_payment(MoneroAddress::from_str(Network::Mainnet, &wallet_rpc_addr).unwrap(), 1000000);
|
||||||
(builder.build().unwrap(), wallet_rpc)
|
(builder.build().unwrap(), wallet_rpc)
|
||||||
},
|
},
|
||||||
|_, tx: Transaction, _, data: Rpc<HttpRpc>| async move {
|
|_, tx: Transaction, _, data: Rpc<SimpleRequestRpc>| async move {
|
||||||
// confirm receipt
|
// confirm receipt
|
||||||
let _: EmptyResponse = data.json_rpc_call("refresh", None).await.unwrap();
|
let _: EmptyResponse = data.json_rpc_call("refresh", None).await.unwrap();
|
||||||
let transfer: TransfersResponse = data
|
let transfer: TransfersResponse = data
|
||||||
@@ -208,7 +207,7 @@ test!(
|
|||||||
.add_payment(MoneroAddress::from_str(Network::Mainnet, &addr.address).unwrap(), 1000000);
|
.add_payment(MoneroAddress::from_str(Network::Mainnet, &addr.address).unwrap(), 1000000);
|
||||||
(builder.build().unwrap(), (wallet_rpc, addr.account_index))
|
(builder.build().unwrap(), (wallet_rpc, addr.account_index))
|
||||||
},
|
},
|
||||||
|_, tx: Transaction, _, data: (Rpc<HttpRpc>, u32)| async move {
|
|_, tx: Transaction, _, data: (Rpc<SimpleRequestRpc>, u32)| async move {
|
||||||
// confirm receipt
|
// confirm receipt
|
||||||
let _: EmptyResponse = data.0.json_rpc_call("refresh", None).await.unwrap();
|
let _: EmptyResponse = data.0.json_rpc_call("refresh", None).await.unwrap();
|
||||||
let transfer: TransfersResponse = data
|
let transfer: TransfersResponse = data
|
||||||
@@ -260,7 +259,7 @@ test!(
|
|||||||
]);
|
]);
|
||||||
(builder.build().unwrap(), (wallet_rpc, daemon_rpc, addrs.address_index))
|
(builder.build().unwrap(), (wallet_rpc, daemon_rpc, addrs.address_index))
|
||||||
},
|
},
|
||||||
|_, tx: Transaction, _, data: (Rpc<HttpRpc>, Rpc<HttpRpc>, u32)| async move {
|
|_, tx: Transaction, _, data: (Rpc<SimpleRequestRpc>, Rpc<SimpleRequestRpc>, u32)| async move {
|
||||||
// confirm receipt
|
// confirm receipt
|
||||||
let _: EmptyResponse = data.0.json_rpc_call("refresh", None).await.unwrap();
|
let _: EmptyResponse = data.0.json_rpc_call("refresh", None).await.unwrap();
|
||||||
let transfer: TransfersResponse = data
|
let transfer: TransfersResponse = data
|
||||||
@@ -305,7 +304,7 @@ test!(
|
|||||||
builder.add_payment(MoneroAddress::from_str(Network::Mainnet, &addr).unwrap(), 1000000);
|
builder.add_payment(MoneroAddress::from_str(Network::Mainnet, &addr).unwrap(), 1000000);
|
||||||
(builder.build().unwrap(), (wallet_rpc, payment_id))
|
(builder.build().unwrap(), (wallet_rpc, payment_id))
|
||||||
},
|
},
|
||||||
|_, tx: Transaction, _, data: (Rpc<HttpRpc>, [u8; 8])| async move {
|
|_, tx: Transaction, _, data: (Rpc<SimpleRequestRpc>, [u8; 8])| async move {
|
||||||
// confirm receipt
|
// confirm receipt
|
||||||
let _: EmptyResponse = data.0.json_rpc_call("refresh", None).await.unwrap();
|
let _: EmptyResponse = data.0.json_rpc_call("refresh", None).await.unwrap();
|
||||||
let transfer: TransfersResponse = data
|
let transfer: TransfersResponse = data
|
||||||
@@ -340,7 +339,7 @@ test!(
|
|||||||
|
|
||||||
(builder.build().unwrap(), wallet_rpc)
|
(builder.build().unwrap(), wallet_rpc)
|
||||||
},
|
},
|
||||||
|_, tx: Transaction, _, data: Rpc<HttpRpc>| async move {
|
|_, tx: Transaction, _, data: Rpc<SimpleRequestRpc>| async move {
|
||||||
// confirm receipt
|
// confirm receipt
|
||||||
let _: EmptyResponse = data.json_rpc_call("refresh", None).await.unwrap();
|
let _: EmptyResponse = data.json_rpc_call("refresh", None).await.unwrap();
|
||||||
let transfer: TransfersResponse = data
|
let transfer: TransfersResponse = data
|
||||||
@@ -53,7 +53,8 @@ ethereum-serai = { path = "../coins/ethereum", default-features = false, optiona
|
|||||||
|
|
||||||
# Monero
|
# Monero
|
||||||
dalek-ff-group = { path = "../crypto/dalek-ff-group", default-features = false, features = ["std"], optional = true }
|
dalek-ff-group = { path = "../crypto/dalek-ff-group", default-features = false, features = ["std"], optional = true }
|
||||||
monero-serai = { path = "../coins/monero", default-features = false, features = ["std", "http-rpc", "multisig"], optional = true }
|
monero-simple-request-rpc = { path = "../coins/monero/rpc/simple-request", default-features = false, optional = true }
|
||||||
|
monero-wallet = { path = "../coins/monero/wallet", default-features = false, features = ["std", "multisig"], optional = true }
|
||||||
|
|
||||||
# Application
|
# Application
|
||||||
log = { version = "0.4", default-features = false, features = ["std"] }
|
log = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
@@ -87,7 +88,7 @@ bitcoin = ["dep:secp256k1", "secp256k1", "bitcoin-serai", "serai-client/bitcoin"
|
|||||||
ethereum = ["secp256k1", "ethereum-serai/tests"]
|
ethereum = ["secp256k1", "ethereum-serai/tests"]
|
||||||
|
|
||||||
ed25519 = ["dalek-ff-group", "frost/ed25519"]
|
ed25519 = ["dalek-ff-group", "frost/ed25519"]
|
||||||
monero = ["ed25519", "monero-serai", "serai-client/monero"]
|
monero = ["ed25519", "monero-simple-request-rpc", "monero-wallet", "serai-client/monero"]
|
||||||
|
|
||||||
binaries = ["env_logger", "serai-env", "message-queue"]
|
binaries = ["env_logger", "serai-env", "message-queue"]
|
||||||
parity-db = ["serai-db/parity-db"]
|
parity-db = ["serai-db/parity-db"]
|
||||||
|
|||||||
@@ -13,18 +13,14 @@ use ciphersuite::group::{ff::Field, Group};
|
|||||||
use dalek_ff_group::{Scalar, EdwardsPoint};
|
use dalek_ff_group::{Scalar, EdwardsPoint};
|
||||||
use frost::{curve::Ed25519, ThresholdKeys};
|
use frost::{curve::Ed25519, ThresholdKeys};
|
||||||
|
|
||||||
use monero_serai::{
|
use monero_simple_request_rpc::SimpleRequestRpc;
|
||||||
Protocol,
|
use monero_wallet::{
|
||||||
ringct::RctType,
|
monero::{Protocol, ringct::RctType, transaction::Transaction, block::Block},
|
||||||
transaction::Transaction,
|
rpc::{RpcError, Rpc},
|
||||||
block::Block,
|
|
||||||
rpc::{RpcError, HttpRpc, Rpc},
|
|
||||||
wallet::{
|
|
||||||
ViewPair, Scanner,
|
ViewPair, Scanner,
|
||||||
address::{Network as MoneroNetwork, SubaddressIndex, AddressSpec},
|
address::{Network as MoneroNetwork, SubaddressIndex, AddressSpec},
|
||||||
Fee, SpendableOutput, Change, DecoySelection, Decoys, TransactionError,
|
Fee, SpendableOutput, Change, DecoySelection, Decoys, TransactionError,
|
||||||
SignableTransaction as MSignableTransaction, Eventuality, TransactionMachine,
|
SignableTransaction as MSignableTransaction, Eventuality, TransactionMachine,
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
@@ -226,7 +222,7 @@ impl BlockTrait<Monero> for Block {
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Monero {
|
pub struct Monero {
|
||||||
rpc: Rpc<HttpRpc>,
|
rpc: Rpc<SimpleRequestRpc>,
|
||||||
}
|
}
|
||||||
// Shim required for testing/debugging purposes due to generic arguments also necessitating trait
|
// Shim required for testing/debugging purposes due to generic arguments also necessitating trait
|
||||||
// bounds
|
// bounds
|
||||||
@@ -249,11 +245,11 @@ fn map_rpc_err(err: RpcError) -> NetworkError {
|
|||||||
|
|
||||||
impl Monero {
|
impl Monero {
|
||||||
pub async fn new(url: String) -> Monero {
|
pub async fn new(url: String) -> Monero {
|
||||||
let mut res = HttpRpc::new(url.clone()).await;
|
let mut res = SimpleRequestRpc::new(url.clone()).await;
|
||||||
while let Err(e) = res {
|
while let Err(e) = res {
|
||||||
log::error!("couldn't connect to Monero node: {e:?}");
|
log::error!("couldn't connect to Monero node: {e:?}");
|
||||||
tokio::time::sleep(Duration::from_secs(5)).await;
|
tokio::time::sleep(Duration::from_secs(5)).await;
|
||||||
res = HttpRpc::new(url.clone()).await;
|
res = SimpleRequestRpc::new(url.clone()).await;
|
||||||
}
|
}
|
||||||
Monero { rpc: res.unwrap() }
|
Monero { rpc: res.unwrap() }
|
||||||
}
|
}
|
||||||
@@ -760,7 +756,7 @@ impl Network for Monero {
|
|||||||
async fn test_send(&self, address: Address) -> Block {
|
async fn test_send(&self, address: Address) -> Block {
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
use rand_core::OsRng;
|
use rand_core::OsRng;
|
||||||
use monero_serai::wallet::FeePriority;
|
use monero_wallet::FeePriority;
|
||||||
|
|
||||||
let new_block = self.get_latest_block_number().await.unwrap() + 1;
|
let new_block = self.get_latest_block_number().await.unwrap() + 1;
|
||||||
for _ in 0 .. 80 {
|
for _ in 0 .. 80 {
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ simple-request = { path = "../../common/request", version = "0.1", optional = tr
|
|||||||
bitcoin = { version = "0.32", optional = true }
|
bitcoin = { version = "0.32", optional = true }
|
||||||
|
|
||||||
ciphersuite = { path = "../../crypto/ciphersuite", version = "0.4", optional = true }
|
ciphersuite = { path = "../../crypto/ciphersuite", version = "0.4", optional = true }
|
||||||
monero-serai = { path = "../../coins/monero", version = "0.1.4-alpha", optional = true }
|
monero-wallet = { path = "../../coins/monero/wallet", version = "0.1.0", default-features = false, features = ["std"], optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rand_core = "0.6"
|
rand_core = "0.6"
|
||||||
@@ -62,7 +62,7 @@ borsh = ["serai-abi/borsh"]
|
|||||||
|
|
||||||
networks = []
|
networks = []
|
||||||
bitcoin = ["networks", "dep:bitcoin"]
|
bitcoin = ["networks", "dep:bitcoin"]
|
||||||
monero = ["networks", "ciphersuite/ed25519", "monero-serai"]
|
monero = ["networks", "ciphersuite/ed25519", "monero-wallet"]
|
||||||
|
|
||||||
# Assumes the default usage is to use Serai as a DEX, which doesn't actually
|
# Assumes the default usage is to use Serai as a DEX, which doesn't actually
|
||||||
# require connecting to a Serai node
|
# require connecting to a Serai node
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use scale::{Encode, Decode};
|
|||||||
|
|
||||||
use ciphersuite::{Ciphersuite, Ed25519};
|
use ciphersuite::{Ciphersuite, Ed25519};
|
||||||
|
|
||||||
use monero_serai::wallet::address::{AddressError, Network, AddressType, AddressMeta, MoneroAddress};
|
use monero_wallet::address::{AddressError, Network, AddressType, AddressMeta, MoneroAddress};
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct Address(MoneroAddress);
|
pub struct Address(MoneroAddress);
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ rand_core = { version = "0.6", default-features = false }
|
|||||||
curve25519-dalek = { version = "4", features = ["rand_core"] }
|
curve25519-dalek = { version = "4", features = ["rand_core"] }
|
||||||
|
|
||||||
bitcoin-serai = { path = "../../coins/bitcoin" }
|
bitcoin-serai = { path = "../../coins/bitcoin" }
|
||||||
monero-serai = { path = "../../coins/monero" }
|
monero-simple-request-rpc = { path = "../../coins/monero/rpc/simple-request" }
|
||||||
|
monero-wallet = { path = "../../coins/monero/wallet" }
|
||||||
|
|
||||||
scale = { package = "parity-scale-codec", version = "3" }
|
scale = { package = "parity-scale-codec", version = "3" }
|
||||||
serde = "1"
|
serde = "1"
|
||||||
|
|||||||
@@ -53,8 +53,8 @@ impl Handles {
|
|||||||
pub async fn monero(
|
pub async fn monero(
|
||||||
&self,
|
&self,
|
||||||
ops: &DockerOperations,
|
ops: &DockerOperations,
|
||||||
) -> monero_serai::rpc::Rpc<monero_serai::rpc::HttpRpc> {
|
) -> monero_wallet::rpc::Rpc<monero_simple_request_rpc::SimpleRequestRpc> {
|
||||||
use monero_serai::rpc::HttpRpc;
|
use monero_simple_request_rpc::SimpleRequestRpc;
|
||||||
|
|
||||||
let rpc = ops.handle(&self.monero.0).host_port(self.monero.1).unwrap();
|
let rpc = ops.handle(&self.monero.0).host_port(self.monero.1).unwrap();
|
||||||
let rpc = format!("http://{RPC_USER}:{RPC_PASS}@{}:{}", rpc.0, rpc.1);
|
let rpc = format!("http://{RPC_USER}:{RPC_PASS}@{}:{}", rpc.0, rpc.1);
|
||||||
@@ -62,7 +62,7 @@ impl Handles {
|
|||||||
// If the RPC server has yet to start, sleep for up to 60s until it does
|
// If the RPC server has yet to start, sleep for up to 60s until it does
|
||||||
for _ in 0 .. 60 {
|
for _ in 0 .. 60 {
|
||||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||||
let Ok(client) = HttpRpc::new(rpc.clone()).await else { continue };
|
let Ok(client) = SimpleRequestRpc::new(rpc.clone()).await else { continue };
|
||||||
if client.get_height().await.is_err() {
|
if client.get_height().await.is_err() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ async fn mint_and_burn_test() {
|
|||||||
// Mine a Monero block
|
// Mine a Monero block
|
||||||
let monero_blocks = {
|
let monero_blocks = {
|
||||||
use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar};
|
use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar};
|
||||||
use monero_serai::wallet::{
|
use monero_wallet::{
|
||||||
ViewPair,
|
ViewPair,
|
||||||
address::{Network, AddressSpec},
|
address::{Network, AddressSpec},
|
||||||
};
|
};
|
||||||
@@ -345,14 +345,10 @@ async fn mint_and_burn_test() {
|
|||||||
// Send in XMR
|
// Send in XMR
|
||||||
{
|
{
|
||||||
use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar};
|
use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar};
|
||||||
use monero_serai::{
|
use monero_wallet::{
|
||||||
Protocol,
|
monero::{io::decompress_point, Protocol, transaction::Timelock},
|
||||||
transaction::Timelock,
|
|
||||||
wallet::{
|
|
||||||
ViewPair, Scanner, DecoySelection, Decoys, Change, FeePriority, SignableTransaction,
|
ViewPair, Scanner, DecoySelection, Decoys, Change, FeePriority, SignableTransaction,
|
||||||
address::{Network, AddressType, AddressMeta, MoneroAddress},
|
address::{Network, AddressType, AddressMeta, MoneroAddress},
|
||||||
},
|
|
||||||
io::decompress_point,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Grab the first output on the chain
|
// Grab the first output on the chain
|
||||||
@@ -473,7 +469,7 @@ async fn mint_and_burn_test() {
|
|||||||
let spend = ED25519_BASEPOINT_TABLE * &Scalar::random(&mut OsRng);
|
let spend = ED25519_BASEPOINT_TABLE * &Scalar::random(&mut OsRng);
|
||||||
let view = Scalar::random(&mut OsRng);
|
let view = Scalar::random(&mut OsRng);
|
||||||
|
|
||||||
use monero_serai::wallet::address::{Network, AddressType, AddressMeta, MoneroAddress};
|
use monero_wallet::address::{Network, AddressType, AddressMeta, MoneroAddress};
|
||||||
let addr = MoneroAddress::new(
|
let addr = MoneroAddress::new(
|
||||||
AddressMeta::new(Network::Mainnet, AddressType::Standard),
|
AddressMeta::new(Network::Mainnet, AddressType::Standard),
|
||||||
spend,
|
spend,
|
||||||
@@ -578,7 +574,7 @@ async fn mint_and_burn_test() {
|
|||||||
|
|
||||||
// Verify the received Monero TX
|
// Verify the received Monero TX
|
||||||
{
|
{
|
||||||
use monero_serai::wallet::{ViewPair, Scanner};
|
use monero_wallet::{ViewPair, Scanner};
|
||||||
let rpc = handles[0].monero(&ops).await;
|
let rpc = handles[0].monero(&ops).await;
|
||||||
let mut scanner = Scanner::from_view(
|
let mut scanner = Scanner::from_view(
|
||||||
ViewPair::new(monero_spend, Zeroizing::new(monero_view)),
|
ViewPair::new(monero_spend, Zeroizing::new(monero_view)),
|
||||||
|
|||||||
@@ -42,3 +42,5 @@ monero-mlsag = { path = "../../coins/monero/ringct/mlsag", default-features = fa
|
|||||||
monero-clsag = { path = "../../coins/monero/ringct/clsag", default-features = false }
|
monero-clsag = { path = "../../coins/monero/ringct/clsag", default-features = false }
|
||||||
monero-bulletproofs = { path = "../../coins/monero/ringct/bulletproofs", default-features = false }
|
monero-bulletproofs = { path = "../../coins/monero/ringct/bulletproofs", default-features = false }
|
||||||
monero-serai = { path = "../../coins/monero", default-features = false }
|
monero-serai = { path = "../../coins/monero", default-features = false }
|
||||||
|
monero-rpc = { path = "../../coins/monero/rpc", default-features = false }
|
||||||
|
monero-wallet = { path = "../../coins/monero/wallet", default-features = false }
|
||||||
|
|||||||
@@ -27,3 +27,4 @@ pub use monero_mlsag;
|
|||||||
pub use monero_clsag;
|
pub use monero_clsag;
|
||||||
pub use monero_bulletproofs;
|
pub use monero_bulletproofs;
|
||||||
pub use monero_serai;
|
pub use monero_serai;
|
||||||
|
pub use monero_rpc;
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ bitcoin-serai = { path = "../../coins/bitcoin" }
|
|||||||
k256 = "0.13"
|
k256 = "0.13"
|
||||||
ethereum-serai = { path = "../../coins/ethereum" }
|
ethereum-serai = { path = "../../coins/ethereum" }
|
||||||
|
|
||||||
monero-serai = { path = "../../coins/monero" }
|
monero-simple-request-rpc = { path = "../../coins/monero/rpc/simple-request" }
|
||||||
|
monero-wallet = { path = "../../coins/monero/wallet" }
|
||||||
|
|
||||||
messages = { package = "serai-processor-messages", path = "../../processor/messages" }
|
messages = { package = "serai-processor-messages", path = "../../processor/messages" }
|
||||||
|
|
||||||
|
|||||||
@@ -274,11 +274,11 @@ impl Coordinator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
NetworkId::Monero => {
|
NetworkId::Monero => {
|
||||||
use monero_serai::rpc::HttpRpc;
|
use monero_simple_request_rpc::SimpleRequestRpc;
|
||||||
|
|
||||||
// Monero's won't, so call get_height
|
// Monero's won't, so call get_height
|
||||||
if handle
|
if handle
|
||||||
.block_on(HttpRpc::new(rpc_url.clone()))
|
.block_on(SimpleRequestRpc::new(rpc_url.clone()))
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|rpc| handle.block_on(rpc.get_height()).ok())
|
.and_then(|rpc| handle.block_on(rpc.get_height()).ok())
|
||||||
.is_some()
|
.is_some()
|
||||||
@@ -403,15 +403,13 @@ impl Coordinator {
|
|||||||
}
|
}
|
||||||
NetworkId::Monero => {
|
NetworkId::Monero => {
|
||||||
use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar};
|
use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar};
|
||||||
use monero_serai::{
|
use monero_simple_request_rpc::SimpleRequestRpc;
|
||||||
wallet::{
|
use monero_wallet::{
|
||||||
ViewPair,
|
ViewPair,
|
||||||
address::{Network, AddressSpec},
|
address::{Network, AddressSpec},
|
||||||
},
|
|
||||||
rpc::HttpRpc,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let rpc = HttpRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC");
|
let rpc = SimpleRequestRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC");
|
||||||
let _: EmptyResponse = rpc
|
let _: EmptyResponse = rpc
|
||||||
.json_rpc_call(
|
.json_rpc_call(
|
||||||
"generateblocks",
|
"generateblocks",
|
||||||
@@ -517,13 +515,16 @@ impl Coordinator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
NetworkId::Monero => {
|
NetworkId::Monero => {
|
||||||
use monero_serai::rpc::HttpRpc;
|
use monero_simple_request_rpc::SimpleRequestRpc;
|
||||||
|
|
||||||
let rpc = HttpRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC");
|
let rpc = SimpleRequestRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC");
|
||||||
let to = rpc.get_height().await.unwrap();
|
let to = rpc.get_height().await.unwrap();
|
||||||
for coordinator in others {
|
for coordinator in others {
|
||||||
let other_rpc =
|
let other_rpc = SimpleRequestRpc::new(network_rpc(
|
||||||
HttpRpc::new(network_rpc(coordinator.network, ops, &coordinator.network_handle))
|
coordinator.network,
|
||||||
|
ops,
|
||||||
|
&coordinator.network_handle,
|
||||||
|
))
|
||||||
.await
|
.await
|
||||||
.expect("couldn't connect to the Monero RPC");
|
.expect("couldn't connect to the Monero RPC");
|
||||||
|
|
||||||
@@ -574,10 +575,12 @@ impl Coordinator {
|
|||||||
let _ = provider.send_raw_transaction(tx).await.unwrap();
|
let _ = provider.send_raw_transaction(tx).await.unwrap();
|
||||||
}
|
}
|
||||||
NetworkId::Monero => {
|
NetworkId::Monero => {
|
||||||
use monero_serai::{transaction::Transaction, rpc::HttpRpc};
|
use monero_simple_request_rpc::SimpleRequestRpc;
|
||||||
|
use monero_wallet::monero::transaction::Transaction;
|
||||||
|
|
||||||
let rpc =
|
let rpc = SimpleRequestRpc::new(rpc_url)
|
||||||
HttpRpc::new(rpc_url).await.expect("couldn't connect to the coordinator's Monero RPC");
|
.await
|
||||||
|
.expect("couldn't connect to the coordinator's Monero RPC");
|
||||||
rpc.publish_transaction(&Transaction::read(&mut &*tx).unwrap()).await.unwrap();
|
rpc.publish_transaction(&Transaction::read(&mut &*tx).unwrap()).await.unwrap();
|
||||||
}
|
}
|
||||||
NetworkId::Serai => panic!("processor tests broadcasting block to Serai"),
|
NetworkId::Serai => panic!("processor tests broadcasting block to Serai"),
|
||||||
@@ -672,10 +675,11 @@ impl Coordinator {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
NetworkId::Monero => {
|
NetworkId::Monero => {
|
||||||
use monero_serai::rpc::HttpRpc;
|
use monero_simple_request_rpc::SimpleRequestRpc;
|
||||||
|
|
||||||
let rpc =
|
let rpc = SimpleRequestRpc::new(rpc_url)
|
||||||
HttpRpc::new(rpc_url).await.expect("couldn't connect to the coordinator's Monero RPC");
|
.await
|
||||||
|
.expect("couldn't connect to the coordinator's Monero RPC");
|
||||||
let mut hash = [0; 32];
|
let mut hash = [0; 32];
|
||||||
hash.copy_from_slice(tx);
|
hash.copy_from_slice(tx);
|
||||||
if let Ok(tx) = rpc.get_transaction(hash).await {
|
if let Ok(tx) = rpc.get_transaction(hash).await {
|
||||||
|
|||||||
@@ -103,8 +103,8 @@ pub enum Wallet {
|
|||||||
Monero {
|
Monero {
|
||||||
handle: String,
|
handle: String,
|
||||||
spend_key: Zeroizing<curve25519_dalek::scalar::Scalar>,
|
spend_key: Zeroizing<curve25519_dalek::scalar::Scalar>,
|
||||||
view_pair: monero_serai::wallet::ViewPair,
|
view_pair: monero_wallet::ViewPair,
|
||||||
inputs: Vec<monero_serai::wallet::ReceivedOutput>,
|
inputs: Vec<monero_wallet::ReceivedOutput>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,12 +189,10 @@ impl Wallet {
|
|||||||
|
|
||||||
NetworkId::Monero => {
|
NetworkId::Monero => {
|
||||||
use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar};
|
use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar};
|
||||||
use monero_serai::{
|
use monero_simple_request_rpc::SimpleRequestRpc;
|
||||||
wallet::{
|
use monero_wallet::{
|
||||||
ViewPair, Scanner,
|
ViewPair, Scanner,
|
||||||
address::{Network, AddressSpec},
|
address::{Network, AddressSpec},
|
||||||
},
|
|
||||||
rpc::HttpRpc,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut bytes = [0; 64];
|
let mut bytes = [0; 64];
|
||||||
@@ -206,7 +204,7 @@ impl Wallet {
|
|||||||
let view_pair =
|
let view_pair =
|
||||||
ViewPair::new(ED25519_BASEPOINT_POINT * spend_key, Zeroizing::new(view_key));
|
ViewPair::new(ED25519_BASEPOINT_POINT * spend_key, Zeroizing::new(view_key));
|
||||||
|
|
||||||
let rpc = HttpRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC");
|
let rpc = SimpleRequestRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC");
|
||||||
|
|
||||||
let height = rpc.get_height().await.unwrap();
|
let height = rpc.get_height().await.unwrap();
|
||||||
// Mines 200 blocks so sufficient decoys exist, as only 60 is needed for maturity
|
// Mines 200 blocks so sufficient decoys exist, as only 60 is needed for maturity
|
||||||
@@ -436,20 +434,17 @@ impl Wallet {
|
|||||||
|
|
||||||
Wallet::Monero { handle, ref spend_key, ref view_pair, ref mut inputs } => {
|
Wallet::Monero { handle, ref spend_key, ref view_pair, ref mut inputs } => {
|
||||||
use curve25519_dalek::constants::ED25519_BASEPOINT_POINT;
|
use curve25519_dalek::constants::ED25519_BASEPOINT_POINT;
|
||||||
use monero_serai::{
|
use monero_simple_request_rpc::SimpleRequestRpc;
|
||||||
Protocol,
|
use monero_wallet::{
|
||||||
wallet::{
|
monero::{Protocol, io::decompress_point},
|
||||||
address::{Network, AddressType, AddressMeta, Address},
|
address::{Network, AddressType, AddressMeta, Address},
|
||||||
SpendableOutput, DecoySelection, Decoys, Change, FeePriority, Scanner,
|
SpendableOutput, DecoySelection, Decoys, Change, FeePriority, Scanner,
|
||||||
SignableTransaction,
|
SignableTransaction,
|
||||||
},
|
|
||||||
rpc::HttpRpc,
|
|
||||||
io::decompress_point,
|
|
||||||
};
|
};
|
||||||
use processor::{additional_key, networks::Monero};
|
use processor::{additional_key, networks::Monero};
|
||||||
|
|
||||||
let rpc_url = network_rpc(NetworkId::Monero, ops, handle);
|
let rpc_url = network_rpc(NetworkId::Monero, ops, handle);
|
||||||
let rpc = HttpRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC");
|
let rpc = SimpleRequestRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC");
|
||||||
|
|
||||||
// Prepare inputs
|
// Prepare inputs
|
||||||
let outputs = std::mem::take(inputs);
|
let outputs = std::mem::take(inputs);
|
||||||
@@ -532,7 +527,7 @@ impl Wallet {
|
|||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
Wallet::Monero { view_pair, .. } => {
|
Wallet::Monero { view_pair, .. } => {
|
||||||
use monero_serai::wallet::address::{Network, AddressSpec};
|
use monero_wallet::address::{Network, AddressSpec};
|
||||||
ExternalAddress::new(
|
ExternalAddress::new(
|
||||||
networks::monero::Address::new(
|
networks::monero::Address::new(
|
||||||
view_pair.address(Network::Mainnet, AddressSpec::Standard),
|
view_pair.address(Network::Mainnet, AddressSpec::Standard),
|
||||||
|
|||||||
Reference in New Issue
Block a user