ic_web3_rs/types/
signed.rs

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
use crate::types::{AccessList, Address, Bytes, CallRequest, H256, U256, U64};
use serde::{Deserialize, Serialize};

/// Struct representing signed data returned from `Accounts::sign` method.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct SignedData {
    /// The original message that was signed.
    pub message: Vec<u8>,
    /// The keccak256 hash of the signed data.
    #[serde(rename = "messageHash")]
    pub message_hash: H256,
    /// V value in 'Electrum' notation.
    pub v: u8,
    /// R value.
    pub r: H256,
    /// S value.
    pub s: H256,
    /// The signature bytes.
    pub signature: Bytes,
}

/// Transaction data for signing.
///
/// The `Accounts::sign_transaction` method will fill optional fields with sane
/// defaults when they are omitted. Specifically the signing account's current
/// transaction count will be used for the `nonce`, the estimated recommended
/// gas price will be used for `gas_price`, and the current network ID will be
/// used for the `chain_id`.
///
/// It is worth noting that the chain ID is not equivalent to the network ID.
/// They happen to be the same much of the time but it is recommended to set
/// this for signing transactions.
///
/// `TransactionParameters` implements `Default` and uses `100_000` as the
/// default `gas` to use for the transaction. This is more than enough for
/// simple transactions sending ETH between accounts but may not be enough when
/// interacting with complex contracts. It is recommended when interacting
/// with contracts to use `Eth::estimate_gas` to estimate the required gas for
/// the transaction.
#[derive(Clone, Debug, PartialEq)]
pub struct TransactionParameters {
    /// Transaction nonce (None for account transaction count)
    pub nonce: Option<U256>,
    /// To address
    pub to: Option<Address>,
    /// Supplied gas
    pub gas: U256,
    /// Gas price (None for estimated gas price)
    pub gas_price: Option<U256>,
    /// Transferred value
    pub value: U256,
    /// Data
    pub data: Bytes,
    /// The chain ID (None for network ID)
    pub chain_id: Option<u64>,
    /// Transaction type, Some(1) for AccessList transaction, None for Legacy
    pub transaction_type: Option<U64>,
    /// Access list
    pub access_list: Option<AccessList>,
    /// Max fee per gas
    pub max_fee_per_gas: Option<U256>,
    /// miner bribe
    pub max_priority_fee_per_gas: Option<U256>,
}

/// The default fas for transactions.
///
/// Unfortunately there is no way to construct `U256`s with const functions for
/// constants so we just build it from it's `u64` words. Note that there is a
/// unit test to verify that it is constructed correctly and holds the expected
/// value of 100_000.
const TRANSACTION_DEFAULT_GAS: U256 = U256([100_000, 0, 0, 0]);

impl Default for TransactionParameters {
    fn default() -> Self {
        TransactionParameters {
            nonce: None,
            to: None,
            gas: TRANSACTION_DEFAULT_GAS,
            gas_price: None,
            value: U256::zero(),
            data: Bytes::default(),
            chain_id: None,
            transaction_type: None,
            access_list: None,
            max_fee_per_gas: None,
            max_priority_fee_per_gas: None,
        }
    }
}

impl From<CallRequest> for TransactionParameters {
    fn from(call: CallRequest) -> Self {
        TransactionParameters {
            nonce: None,
            to: call.to,
            gas: call.gas.unwrap_or(TRANSACTION_DEFAULT_GAS),
            gas_price: call.gas_price,
            value: call.value.unwrap_or_default(),
            data: call.data.unwrap_or_default(),
            chain_id: None,
            transaction_type: call.transaction_type,
            access_list: call.access_list,
            max_fee_per_gas: call.max_fee_per_gas,
            max_priority_fee_per_gas: call.max_priority_fee_per_gas,
        }
    }
}

impl From<TransactionParameters> for CallRequest {
    fn from(val: TransactionParameters) -> Self {
        CallRequest {
            from: None,
            to: val.to,
            gas: Some(val.gas),
            gas_price: val.gas_price,
            value: Some(val.value),
            data: Some(val.data),
            transaction_type: val.transaction_type,
            access_list: val.access_list,
            max_fee_per_gas: val.max_fee_per_gas,
            max_priority_fee_per_gas: val.max_priority_fee_per_gas,
        }
    }
}

/// Data for offline signed transaction
#[derive(Clone, Debug, PartialEq)]
pub struct SignedTransaction {
    /// The given message hash
    pub message_hash: H256,
    /// V value with chain replay protection.
    pub v: u64,
    /// R value.
    pub r: H256,
    /// S value.
    pub s: H256,
    /// The raw signed transaction ready to be sent with `send_raw_transaction`
    pub raw_transaction: Bytes,
    /// The transaction hash for the RLP encoded transaction.
    pub transaction_hash: H256,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn verify_transaction_default_gas() {
        assert_eq!(TRANSACTION_DEFAULT_GAS, U256::from(100_000));
    }
}