mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: add transaction request
This commit is contained in:
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -1143,11 +1143,25 @@ dependencies = [
|
||||
"ethers-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reth-rpc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"reth-primitives",
|
||||
"reth-rpc-api",
|
||||
"reth-rpc-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reth-rpc-api"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"jsonrpsee",
|
||||
"reth-primitives",
|
||||
"reth-rpc-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
@ -1157,6 +1171,8 @@ dependencies = [
|
||||
name = "reth-rpc-types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"fastrlp",
|
||||
"reth-primitives",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
|
||||
@ -12,6 +12,9 @@ Reth RPC types
|
||||
# reth
|
||||
reth-primitives = { path = "../primitives" }
|
||||
|
||||
# eth
|
||||
fastrlp = { version = "0.1" }
|
||||
|
||||
# misc
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
@ -1 +1,7 @@
|
||||
//! Ethereum related types
|
||||
//! Ethereum related types
|
||||
|
||||
pub use reth_primitives::{BlockId, BlockNumber};
|
||||
|
||||
mod transaction;
|
||||
|
||||
pub use transaction::*;
|
||||
5
crates/rpc-types/src/eth/transaction/mod.rs
Normal file
5
crates/rpc-types/src/eth/transaction/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
mod request;
|
||||
mod typed;
|
||||
|
||||
pub use request::TransactionRequest;
|
||||
pub use typed::*;
|
||||
115
crates/rpc-types/src/eth/transaction/request.rs
Normal file
115
crates/rpc-types/src/eth/transaction/request.rs
Normal file
@ -0,0 +1,115 @@
|
||||
use crate::eth::transaction::typed::{
|
||||
EIP1559TransactionRequest, EIP2930TransactionRequest, LegacyTransactionRequest,
|
||||
TransactionKind, TypedTransactionRequest,
|
||||
};
|
||||
|
||||
use reth_primitives::{
|
||||
transaction::eip2930::AccessListItem, Address, Bytes, U256,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Represents _all_ transaction requests received from RPC
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TransactionRequest {
|
||||
/// from address
|
||||
pub from: Option<Address>,
|
||||
/// to address
|
||||
pub to: Option<Address>,
|
||||
/// legacy, gas Price
|
||||
#[serde(default)]
|
||||
pub gas_price: Option<U256>,
|
||||
/// max base fee per gas sender is willing to pay
|
||||
#[serde(default)]
|
||||
pub max_fee_per_gas: Option<U256>,
|
||||
/// miner tip
|
||||
#[serde(default)]
|
||||
pub max_priority_fee_per_gas: Option<U256>,
|
||||
/// gas
|
||||
pub gas: Option<U256>,
|
||||
/// value of th tx in wei
|
||||
pub value: Option<U256>,
|
||||
/// Any additional data sent
|
||||
pub data: Option<Bytes>,
|
||||
/// Transaction nonce
|
||||
pub nonce: Option<U256>,
|
||||
/// warm storage access pre-payment
|
||||
#[serde(default)]
|
||||
pub access_list: Option<Vec<AccessListItem>>,
|
||||
/// EIP-2718 type
|
||||
#[serde(rename = "type")]
|
||||
pub transaction_type: Option<U256>,
|
||||
}
|
||||
|
||||
// == impl TransactionRequest ==
|
||||
|
||||
impl TransactionRequest {
|
||||
/// Converts the request into a [TypedTransactionRequest]
|
||||
pub fn into_typed_request(self) -> Option<TypedTransactionRequest> {
|
||||
let TransactionRequest {
|
||||
to,
|
||||
gas_price,
|
||||
max_fee_per_gas,
|
||||
max_priority_fee_per_gas,
|
||||
gas,
|
||||
value,
|
||||
data,
|
||||
nonce,
|
||||
mut access_list,
|
||||
..
|
||||
} = self;
|
||||
match (gas_price, max_fee_per_gas, access_list.take()) {
|
||||
// legacy transaction
|
||||
(Some(_), None, None) => {
|
||||
Some(TypedTransactionRequest::Legacy(LegacyTransactionRequest {
|
||||
nonce: nonce.unwrap_or(U256::zero()),
|
||||
gas_price: gas_price.unwrap_or_default(),
|
||||
gas_limit: gas.unwrap_or_default(),
|
||||
value: value.unwrap_or(U256::zero()),
|
||||
input: data.unwrap_or_default(),
|
||||
kind: match to {
|
||||
Some(to) => TransactionKind::Call(to),
|
||||
None => TransactionKind::Create,
|
||||
},
|
||||
chain_id: None,
|
||||
}))
|
||||
}
|
||||
// EIP2930
|
||||
(_, None, Some(access_list)) => {
|
||||
Some(TypedTransactionRequest::EIP2930(EIP2930TransactionRequest {
|
||||
nonce: nonce.unwrap_or(U256::zero()),
|
||||
gas_price: gas_price.unwrap_or_default(),
|
||||
gas_limit: gas.unwrap_or_default(),
|
||||
value: value.unwrap_or(U256::zero()),
|
||||
input: data.unwrap_or_default(),
|
||||
kind: match to {
|
||||
Some(to) => TransactionKind::Call(to),
|
||||
None => TransactionKind::Create,
|
||||
},
|
||||
chain_id: 0,
|
||||
access_list,
|
||||
}))
|
||||
}
|
||||
// EIP1559
|
||||
(None, Some(_), access_list) | (None, None, access_list @ None) => {
|
||||
// Empty fields fall back to the canonical transaction schema.
|
||||
Some(TypedTransactionRequest::EIP1559(EIP1559TransactionRequest {
|
||||
nonce: nonce.unwrap_or(U256::zero()),
|
||||
max_fee_per_gas: max_fee_per_gas.unwrap_or_default(),
|
||||
max_priority_fee_per_gas: max_priority_fee_per_gas.unwrap_or(U256::zero()),
|
||||
gas_limit: gas.unwrap_or_default(),
|
||||
value: value.unwrap_or(U256::zero()),
|
||||
input: data.unwrap_or_default(),
|
||||
kind: match to {
|
||||
Some(to) => TransactionKind::Call(to),
|
||||
None => TransactionKind::Create,
|
||||
},
|
||||
chain_id: 0,
|
||||
access_list: access_list.unwrap_or_default(),
|
||||
}))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
111
crates/rpc-types/src/eth/transaction/typed.rs
Normal file
111
crates/rpc-types/src/eth/transaction/typed.rs
Normal file
@ -0,0 +1,111 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use fastrlp::{RlpDecodable, RlpEncodable};
|
||||
use reth_primitives::{transaction::eip2930::AccessListItem, Address, Bytes, U256};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Container type for various Ethereum transaction requests
|
||||
///
|
||||
/// Its variants correspond to specific allowed transactions:
|
||||
/// 1. Legacy (pre-EIP2718) [`LegacyTransactionRequest`]
|
||||
/// 2. EIP2930 (state access lists) [`EIP2930TransactionRequest`]
|
||||
/// 3. EIP1559 [`EIP1559TransactionRequest`]
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum TypedTransactionRequest {
|
||||
Legacy(LegacyTransactionRequest),
|
||||
EIP2930(EIP2930TransactionRequest),
|
||||
EIP1559(EIP1559TransactionRequest),
|
||||
}
|
||||
|
||||
/// Represents a legacy transaction request
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct LegacyTransactionRequest {
|
||||
pub nonce: U256,
|
||||
pub gas_price: U256,
|
||||
pub gas_limit: U256,
|
||||
pub kind: TransactionKind,
|
||||
pub value: U256,
|
||||
pub input: Bytes,
|
||||
pub chain_id: Option<u64>,
|
||||
}
|
||||
|
||||
/// Represents an EIP-2930 transaction request
|
||||
#[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)]
|
||||
pub struct EIP2930TransactionRequest {
|
||||
pub chain_id: u64,
|
||||
pub nonce: U256,
|
||||
pub gas_price: U256,
|
||||
pub gas_limit: U256,
|
||||
pub kind: TransactionKind,
|
||||
pub value: U256,
|
||||
pub input: Bytes,
|
||||
pub access_list: Vec<AccessListItem>,
|
||||
}
|
||||
|
||||
/// Represents an EIP-1559 transaction request
|
||||
#[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)]
|
||||
pub struct EIP1559TransactionRequest {
|
||||
pub chain_id: u64,
|
||||
pub nonce: U256,
|
||||
pub max_priority_fee_per_gas: U256,
|
||||
pub max_fee_per_gas: U256,
|
||||
pub gas_limit: U256,
|
||||
pub kind: TransactionKind,
|
||||
pub value: U256,
|
||||
pub input: Bytes,
|
||||
pub access_list: Vec<AccessListItem>,
|
||||
}
|
||||
|
||||
/// Represents the `to` field of a transaction request
|
||||
///
|
||||
/// This determines what kind of transaction this is
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum TransactionKind {
|
||||
/// Transaction will call this address or transfer funds to this address
|
||||
Call(Address),
|
||||
/// No `to` field set, this transaction will create a contract
|
||||
Create,
|
||||
}
|
||||
|
||||
// == impl TransactionKind ==
|
||||
|
||||
impl TransactionKind {
|
||||
/// If this transaction is a call this returns the address of the callee
|
||||
pub fn as_call(&self) -> Option<&Address> {
|
||||
match self {
|
||||
TransactionKind::Call(to) => Some(to),
|
||||
TransactionKind::Create => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fastrlp::Encodable for TransactionKind {
|
||||
fn length(&self) -> usize {
|
||||
match self {
|
||||
TransactionKind::Call(to) => to.length(),
|
||||
TransactionKind::Create => ([]).length(),
|
||||
}
|
||||
}
|
||||
fn encode(&self, out: &mut dyn fastrlp::BufMut) {
|
||||
match self {
|
||||
TransactionKind::Call(to) => to.encode(out),
|
||||
TransactionKind::Create => ([]).encode(out),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fastrlp::Decodable for TransactionKind {
|
||||
fn decode(buf: &mut &[u8]) -> Result<Self, fastrlp::DecodeError> {
|
||||
if let Some(&first) = buf.first() {
|
||||
if first == 0x80 {
|
||||
*buf = &buf[1..];
|
||||
Ok(TransactionKind::Create)
|
||||
} else {
|
||||
let addr = <Address as fastrlp::Decodable>::decode(buf)?;
|
||||
Ok(TransactionKind::Call(addr))
|
||||
}
|
||||
} else {
|
||||
Err(fastrlp::DecodeError::InputTooShort)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,4 +9,6 @@
|
||||
//!
|
||||
//! Provides all relevant types for the various RPC endpoints, grouped by namespace.
|
||||
|
||||
mod eth;
|
||||
mod eth;
|
||||
|
||||
pub use eth::*;
|
||||
Reference in New Issue
Block a user