ic_web3_rs/types/
signed.rs

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