1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
use alloc::borrow::Cow;
use alloc::vec::Vec;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use crate::models::{XRPLModelException, XRPLModelResult};
use crate::{
constants::CryptoAlgorithm,
models::{requests::RequestMethod, Model},
};
use super::{CommonFields, Request};
/// The channel_authorize method creates a signature that can be
/// used to redeem a specific amount of XRP from a payment channel.
///
/// Warning: Do not send secret keys to untrusted servers or
/// through unsecured network connections. (This includes the
/// secret, seed, seed_hex, or passphrase fields of this request.)
/// You should only use this method on a secure, encrypted network
/// connection to a server you run or fully trust with your funds.
/// Otherwise, eavesdroppers could use your secret key to sign
/// claims and take all the money from this payment channel and
/// anything else using the same key pair.
///
/// See Set Up Secure Signing:
/// `<https://xrpl.org/set-up-secure-signing.html>`
///
/// See Channel Authorize:
/// `<https://xrpl.org/channel_authorize.html>`
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct ChannelAuthorize<'a> {
/// The common fields shared by all requests.
#[serde(flatten)]
pub common_fields: CommonFields<'a>,
/// The unique ID of the payment channel to use.
pub channel_id: Cow<'a, str>,
/// Cumulative amount of XRP, in drops, to authorize.
/// If the destination has already received a lesser amount
/// of XRP from this channel, the signature created by this
/// method can be redeemed for the difference.
pub amount: Cow<'a, str>,
/// The secret key to use to sign the claim. This must be
/// the same key pair as the public key specified in the
/// channel. Cannot be used with seed, seed_hex, or passphrase.
pub secret: Option<Cow<'a, str>>,
/// The secret seed to use to sign the claim. This must be
/// the same key pair as the public key specified in the channel.
/// Must be in the XRP Ledger's base58 format. If provided,
/// you must also specify the key_type. Cannot be used with
/// secret, seed_hex, or passphrase.
pub seed: Option<Cow<'a, str>>,
/// The secret seed to use to sign the claim. This must be the
/// same key pair as the public key specified in the channel.
/// Must be in hexadecimal format. If provided, you must also
/// specify the key_type. Cannot be used with secret, seed,
/// or passphrase.
pub seed_hex: Option<Cow<'a, str>>,
/// A string passphrase to use to sign the claim. This must be
/// the same key pair as the public key specified in the channel.
/// The key derived from this passphrase must match the public
/// key specified in the channel. If provided, you must also
/// specify the key_type. Cannot be used with secret, seed,
/// or seed_hex.
pub passphrase: Option<Cow<'a, str>>,
/// The signing algorithm of the cryptographic key pair provided.
/// Valid types are secp256k1 or ed25519. The default is secp256k1.
pub key_type: Option<CryptoAlgorithm>,
}
impl<'a> Model for ChannelAuthorize<'a> {
fn get_errors(&self) -> XRPLModelResult<()> {
self._get_field_error()
}
}
impl<'a> Request<'a> for ChannelAuthorize<'a> {
fn get_common_fields(&self) -> &CommonFields<'a> {
&self.common_fields
}
fn get_common_fields_mut(&mut self) -> &mut CommonFields<'a> {
&mut self.common_fields
}
}
impl<'a> ChannelAuthorizeError for ChannelAuthorize<'a> {
fn _get_field_error(&self) -> XRPLModelResult<()> {
let mut signing_methods = Vec::new();
for method in [
self.secret.clone(),
self.seed.clone(),
self.seed_hex.clone(),
self.passphrase.clone(),
] {
if method.is_some() {
signing_methods.push(method)
}
}
if signing_methods.len() != 1 {
Err(XRPLModelException::ExpectedOneOf(&[
"secret",
"seed",
"seed_hex",
"passphrase",
]))
} else {
Ok(())
}
}
}
impl<'a> ChannelAuthorize<'a> {
pub fn new(
id: Option<Cow<'a, str>>,
channel_id: Cow<'a, str>,
amount: Cow<'a, str>,
secret: Option<Cow<'a, str>>,
seed: Option<Cow<'a, str>>,
seed_hex: Option<Cow<'a, str>>,
passphrase: Option<Cow<'a, str>>,
key_type: Option<CryptoAlgorithm>,
) -> Self {
Self {
common_fields: CommonFields {
command: RequestMethod::ChannelAuthorize,
id,
},
channel_id,
amount,
secret,
seed,
seed_hex,
passphrase,
key_type,
}
}
}
pub trait ChannelAuthorizeError {
fn _get_field_error(&self) -> XRPLModelResult<()>;
}
#[cfg(test)]
mod test_channel_authorize_errors {
use crate::{constants::CryptoAlgorithm, models::Model};
use alloc::string::ToString;
use super::*;
#[test]
fn test_fields_error() {
let channel_authorize = ChannelAuthorize::new(
None,
"5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3".into(),
"1000000".into(),
None,
Some("".into()),
Some("".into()),
None,
Some(CryptoAlgorithm::SECP256K1),
);
assert_eq!(
channel_authorize
.validate()
.unwrap_err()
.to_string()
.as_str(),
"Expected one of: secret, seed, seed_hex, passphrase"
);
}
#[test]
fn test_serde() {
let req = ChannelAuthorize::new(
None,
"5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3".into(),
"1000000".into(),
None,
Some("".into()),
None,
None,
Some(CryptoAlgorithm::SECP256K1),
);
let serialized = serde_json::to_string(&req).unwrap();
let deserialized: ChannelAuthorize = serde_json::from_str(&serialized).unwrap();
assert_eq!(req, deserialized);
}
}