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}