pink_web3/types/signed.rs
1use crate::prelude::*;
2use crate::types::{AccessList, Address, Bytes, CallRequest, H256, U256, U64};
3use serde::{Deserialize, Serialize};
4
5/// Struct representing signed data returned from `Accounts::sign` method.
6#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
7pub struct SignedData {
8 /// The original message that was signed.
9 pub message: Vec<u8>,
10 /// The keccak256 hash of the signed data.
11 #[serde(rename = "messageHash")]
12 pub message_hash: H256,
13 /// V value in 'Electrum' notation.
14 pub v: u8,
15 /// R value.
16 pub r: H256,
17 /// S value.
18 pub s: H256,
19 /// The signature bytes.
20 pub signature: Bytes,
21}
22
23/// Transaction data for signing.
24///
25/// The `Accounts::sign_transaction` method will fill optional fields with sane
26/// defaults when they are omitted. Specifically the signing account's current
27/// transaction count will be used for the `nonce`, the estimated recommended
28/// gas price will be used for `gas_price`, and the current network ID will be
29/// used for the `chain_id`.
30///
31/// It is worth noting that the chain ID is not equivalent to the network ID.
32/// They happen to be the same much of the time but it is recommended to set
33/// this for signing transactions.
34///
35/// `TransactionParameters` implements `Default` and uses `100_000` as the
36/// default `gas` to use for the transaction. This is more than enough for
37/// simple transactions sending ETH between accounts but may not be enough when
38/// interacting with complex contracts. It is recommended when interacting
39/// with contracts to use `Eth::estimate_gas` to estimate the required gas for
40/// the transaction.
41#[derive(Clone, Debug, PartialEq)]
42pub struct TransactionParameters {
43 /// Transaction nonce (None for account transaction count)
44 pub nonce: Option<U256>,
45 /// To address
46 pub to: Option<Address>,
47 /// Supplied gas
48 pub gas: U256,
49 /// Gas price (None for estimated gas price)
50 pub gas_price: Option<U256>,
51 /// Transferred value
52 pub value: U256,
53 /// Data
54 pub data: Bytes,
55 /// The chain ID (None for network ID)
56 pub chain_id: Option<u64>,
57 /// Transaction type, Some(1) for AccessList transaction, None for Legacy
58 pub transaction_type: Option<U64>,
59 /// Access list
60 pub access_list: Option<AccessList>,
61 /// Max fee per gas
62 pub max_fee_per_gas: Option<U256>,
63 /// miner bribe
64 pub max_priority_fee_per_gas: Option<U256>,
65}
66
67/// The default fas for transactions.
68///
69/// Unfortunately there is no way to construct `U256`s with const functions for
70/// constants so we just build it from it's `u64` words. Note that there is a
71/// unit test to verify that it is constructed correctly and holds the expected
72/// value of 100_000.
73const TRANSACTION_DEFAULT_GAS: U256 = U256([100_000, 0, 0, 0]);
74
75impl Default for TransactionParameters {
76 fn default() -> Self {
77 TransactionParameters {
78 nonce: None,
79 to: None,
80 gas: TRANSACTION_DEFAULT_GAS,
81 gas_price: None,
82 value: U256::zero(),
83 data: Bytes::default(),
84 chain_id: None,
85 transaction_type: None,
86 access_list: None,
87 max_fee_per_gas: None,
88 max_priority_fee_per_gas: None,
89 }
90 }
91}
92
93impl From<CallRequest> for TransactionParameters {
94 fn from(call: CallRequest) -> Self {
95 TransactionParameters {
96 nonce: None,
97 to: call.to,
98 gas: call.gas.unwrap_or(TRANSACTION_DEFAULT_GAS),
99 gas_price: call.gas_price,
100 value: call.value.unwrap_or_default(),
101 data: call.data.unwrap_or_default(),
102 chain_id: None,
103 transaction_type: call.transaction_type,
104 access_list: call.access_list,
105 max_fee_per_gas: call.max_fee_per_gas,
106 max_priority_fee_per_gas: call.max_priority_fee_per_gas,
107 }
108 }
109}
110
111impl From<TransactionParameters> for CallRequest {
112 fn from(val: TransactionParameters) -> Self {
113 CallRequest {
114 from: None,
115 to: val.to,
116 gas: Some(val.gas),
117 gas_price: val.gas_price,
118 value: Some(val.value),
119 data: Some(val.data),
120 transaction_type: val.transaction_type,
121 access_list: val.access_list,
122 max_fee_per_gas: val.max_fee_per_gas,
123 max_priority_fee_per_gas: val.max_priority_fee_per_gas,
124 }
125 }
126}
127
128/// Data for offline signed transaction
129#[derive(Clone, Debug, PartialEq)]
130pub struct SignedTransaction {
131 /// The given message hash
132 pub message_hash: H256,
133 /// V value with chain replay protection.
134 pub v: u64,
135 /// R value.
136 pub r: H256,
137 /// S value.
138 pub s: H256,
139 /// The raw signed transaction ready to be sent with `send_raw_transaction`
140 pub raw_transaction: Bytes,
141 /// The transaction hash for the RLP encoded transaction.
142 pub transaction_hash: H256,
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148
149 #[test]
150 fn verify_transaction_default_gas() {
151 assert_eq!(TRANSACTION_DEFAULT_GAS, U256::from(100_000));
152 }
153}