reweb3 0.2.4

Client-side protocol(Web3) for ethereum and other EVM-based chains rewritten in rust
Documentation
use serde::{Deserialize, Serialize};

use super::AccessList;

use crate::primitives::{Address, Bytes, U256};

#[cfg(feature = "rlp")]
use crate::{
    errors::Result,
    primitives::{Eip1559Signature, H256},
    rlp::RlpEncoder,
};

#[cfg(feature = "rlp")]
use crate::primitives::keccak256;

/// Represents ethereum transaction type defined in eip1559.
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Eip1559TransactionRequest {
    pub chain_id: U256,

    /// Transaction nonce
    pub nonce: U256,
    /// Gas price
    pub max_priority_fee_per_gas: U256,

    pub max_fee_per_gas: U256,
    /// Supplied gas
    pub gas: U256,
    /// Recipient address (None for contract creation)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub to: Option<Address>,
    /// Transferred value
    pub value: Option<U256>,
    /// The compiled code of a contract OR the first 4 bytes of the hash of the
    /// invoked method signature and encoded parameters. For details see Ethereum Contract ABI
    #[serde(skip_serializing_if = "Option::is_none")]
    pub data: Option<Bytes>,

    pub access_list: AccessList,
}

#[cfg(feature = "rlp")]
#[cfg_attr(docsrs, doc(cfg(feature = "rlp")))]
impl Eip1559TransactionRequest {
    /// Generate legacy transaction sign hash.
    pub fn sign_hash(&self) -> Result<H256> {
        Ok(keccak256(self.rlp()?.0).into())
    }

    pub fn rlp(&self) -> Result<Bytes> {
        let mut s = RlpEncoder::default();
        (
            &self.chain_id,
            &self.nonce,
            &self.max_priority_fee_per_gas,
            &self.max_fee_per_gas,
            &self.gas,
            &self.to,
            &self.value,
            &self.data,
            &self.access_list,
        )
            .serialize(&mut s)?;

        let mut buff = vec![0x02u8];

        let mut append = s.finalize()?.into();

        buff.append(&mut append);

        Ok(buff.into())
    }

    /// Returns signed tx rlp encoding stream.
    pub fn rlp_signed(&self, signature: Eip1559Signature) -> Result<Bytes> {
        let mut s = RlpEncoder::default();

        (
            &self.chain_id,
            &self.nonce,
            &self.max_priority_fee_per_gas,
            &self.max_fee_per_gas,
            &self.gas,
            &self.to,
            &self.value,
            &self.data,
            &self.access_list,
            signature.v,
            signature.r,
            signature.s,
        )
            .serialize(&mut s)?;

        let mut buff = vec![0x02u8];

        let mut append = s.finalize()?.into();

        buff.append(&mut append);

        Ok(buff.into())
    }
}

#[cfg(feature = "rlp")]
#[cfg(test)]
mod tests {

    use serde_json::json;

    use super::*;

    #[test]
    fn test_rlp() {
        let tx = json!({
          "maxPriorityFeePerGas": "0x0",
          "maxFeePerGas": "0x0",
          "gas": "0x0",
          "nonce": "0x0",
          "to": null,
          "value": "0x0",
          "chainId": "0x1",
          "type": "0x02",
          "data": "0x00",
          "accessList": [
            {
              "address": "0x0000000000000000000000000000000000000000",
              "storageKeys": [
                "0x0000000000000000000000000000000000000000000000000000000000000000"
              ]
            },
            {
              "address": "0x0000000000000000000000000000000000000000",
              "storageKeys": [
                "0x0000000000000000000000000000000000000000000000000000000000000000"
              ]
            }
          ]
        });

        let tx: Eip1559TransactionRequest = serde_json::from_value(tx).unwrap();

        assert_eq!(
            tx.rlp().unwrap().to_string(),
            "0x02f87a0180808080808000f870f7940000000000000000000000000000000000000000e1a00000000000000000000000000000000000000000000000000000000000000000f7940000000000000000000000000000000000000000e1a00000000000000000000000000000000000000000000000000000000000000000"
        );

        let sig: Eip1559Signature = "0x007a53fb20b46d9cc2600d8dc3168a698d41c0dec029d46db4ba88ffe359bbe4092536bd58c593edcda36c5f2e35ed4db158b0cab202b6b2648403117e483a9b30".parse().unwrap();

        assert_eq!(
            tx.rlp_signed(sig).unwrap().to_string(),
            "0x02f8bd0180808080808000f870f7940000000000000000000000000000000000000000e1a00000000000000000000000000000000000000000000000000000000000000000f7940000000000000000000000000000000000000000e1a0000000000000000000000000000000000000000000000000000000000000000080a07a53fb20b46d9cc2600d8dc3168a698d41c0dec029d46db4ba88ffe359bbe409a02536bd58c593edcda36c5f2e35ed4db158b0cab202b6b2648403117e483a9b30"
        );
    }
}