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
use super::msg::Msg;
use crate::{Signature, VerifyingKey};
use cosmos_sdk_proto::cosmos::tx::v1beta1::{
mode_info, AuthInfo, Fee, ModeInfo, SignDoc, SignerInfo, TxBody, TxRaw,
};
use ecdsa::signature::Signer;
use eyre::Result;
use tendermint::{block, chain};
pub struct Builder {
chain_id: chain::Id,
account_number: u64,
}
impl Builder {
pub fn new(chain_id: impl Into<chain::Id>, account_number: u64) -> Self {
Self {
chain_id: chain_id.into(),
account_number,
}
}
pub fn chain_id(&self) -> &chain::Id {
&self.chain_id
}
pub fn account_number(&self) -> u64 {
self.account_number
}
pub fn sign_tx<S>(
&self,
signer: &S,
sequence: u64,
messages: &[Msg],
fee: Fee,
memo: impl Into<String>,
timeout_height: block::Height,
) -> Result<Vec<u8>>
where
S: Signer<Signature>,
VerifyingKey: for<'a> From<&'a S>,
{
let body = TxBody {
messages: messages.iter().map(|msg| msg.0.clone()).collect(),
memo: memo.into(),
timeout_height: timeout_height.into(),
extension_options: Default::default(),
non_critical_extension_options: Default::default(),
};
let mut body_buf = Vec::new();
prost::Message::encode(&body, &mut body_buf).unwrap();
let pk = VerifyingKey::from(signer);
let mut pk_buf = Vec::new();
prost::Message::encode(&pk.to_bytes().to_vec(), &mut pk_buf).unwrap();
let pk_any = prost_types::Any {
type_url: "/cosmos.crypto.secp256k1.PubKey".to_string(),
value: Vec::from(&pk.to_bytes()[..]),
};
let single = mode_info::Single { mode: 1 };
let mode = Some(ModeInfo {
sum: Some(mode_info::Sum::Single(single)),
});
let signer_info = SignerInfo {
public_key: Some(pk_any),
mode_info: mode,
sequence,
};
let auth_info = AuthInfo {
signer_infos: vec![signer_info],
fee: Some(fee),
};
let mut auth_buf = Vec::new();
prost::Message::encode(&auth_info, &mut auth_buf)?;
let sign_doc = SignDoc {
body_bytes: body_buf.clone(),
auth_info_bytes: auth_buf.clone(),
chain_id: self.chain_id.to_string(),
account_number: self.account_number,
};
let mut signdoc_buf = Vec::new();
prost::Message::encode(&sign_doc, &mut signdoc_buf)?;
let signed = signer.sign(&signdoc_buf);
let tx_raw = TxRaw {
body_bytes: body_buf,
auth_info_bytes: auth_buf,
signatures: vec![signed.as_ref().to_vec()],
};
let mut txraw_buf = Vec::new();
prost::Message::encode(&tx_raw, &mut txraw_buf)?;
Ok(txraw_buf)
}
}