Skip to content

Commit

Permalink
feat: add eip-7702 auth list types
Browse files Browse the repository at this point in the history
  • Loading branch information
onbjerg committed Jun 20, 2024
1 parent 1ee31cf commit 98a8dd7
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 2 deletions.
1 change: 1 addition & 0 deletions crates/eips/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ Contains constants, helpers, and basic data structures for consensus EIPs.
- [EIP-7002](https://eips.ethereum.org/EIPS/eip-7002)
- [EIP-7251](https://eips.ethereum.org/EIPS/eip-7251)
- [EIP-7685](https://eips.ethereum.org/EIPS/eip-7685)
- [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702)
112 changes: 112 additions & 0 deletions crates/eips/src/eip7702/auth_list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
use core::ops::Deref;

use alloy_primitives::{keccak256, Address, ChainId, Signature, SignatureError, B256};
use alloy_rlp::{BufMut, Decodable, Encodable, Header, RlpEncodable};

use super::constants::MAGIC;

/// An EIP-7702 authorization list.
pub type AuthorizationList = Vec<Authorization>;

/// An EIP-7702 authorization.
#[derive(Debug, Clone, RlpEncodable)]
pub struct Authorization {
chain_id: ChainId,
address: Address,
nonce: OptionalNonce,
signature: Signature,
}

impl Authorization {
/// Get the `chain_id` for the authorization.
///
/// # Note
///
/// Implementers should check that this matches the current `chain_id` *or* is 0.
pub fn chain_id(&self) -> ChainId {
self.chain_id
}

/// Get the `address` for the authorization.
pub fn address(&self) -> &Address {
&self.address
}

/// Get the `nonce` for the authorization.
///
/// # Note
///
/// If this is `Some`, implementers should check that the nonce of the authority (see [`Self::recover_authority`]) is equal to this nonce.
pub fn nonce(&self) -> Option<u64> {
*self.nonce
}

/// Get the `signature` for the authorization.
pub fn signature(&self) -> &Signature {
&self.signature
}

/// Computes the authority prehash used to recover the authority from an authorization list item.
///
/// The authority prehash is `keccak(MAGIC || rlp([chain_id, [nonce], address]))`
#[inline]
fn authority_prehash(&self) -> B256 {
#[derive(RlpEncodable)]
struct Auth {
chain_id: ChainId,
nonce: OptionalNonce,
address: Address,
}

let mut buf = Vec::new();
buf.put_u8(MAGIC);

Auth { chain_id: self.chain_id, nonce: self.nonce, address: self.address }.encode(&mut buf);

keccak256(buf)
}

/// Recover the authority for the authorization.
///
/// # Note
///
/// Implementers should check that the authority has no code.
pub fn recover_authority(&self) -> Result<Address, SignatureError> {
self.signature.recover_address_from_prehash(&self.authority_prehash())
}
}

/// An internal wrapper around an `Option<u64>` for optional nonces.
///
/// In EIP-7702 the nonce is encoded as a list of either 0 or 1 items, where 0 items means that no nonce was specified (i.e. `None`). If there is 1 item, this is the same as `Some`.
///
/// The wrapper type is used for RLP encoding and decoding.
#[derive(Debug, Copy, Clone)]
struct OptionalNonce(Option<u64>);

impl Encodable for OptionalNonce {
fn encode(&self, out: &mut dyn BufMut) {
match self.0 {
Some(nonce) => {
Header { list: true, payload_length: nonce.length() }.encode(out);
nonce.encode(out);
}
None => Header { list: true, payload_length: 0 }.encode(out),
}
}
}

impl Decodable for OptionalNonce {
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
let list: Vec<u64> = Vec::decode(buf)?;
Ok(Self(list.first().copied()))
}
}

impl Deref for OptionalNonce {
type Target = Option<u64>;

fn deref(&self) -> &Self::Target {
&self.0
}
}
18 changes: 18 additions & 0 deletions crates/eips/src/eip7702/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//! [EIP-7702] constants.
//!
//! [EIP-7702]: https://eips.ethereum.org/EIPS/eip-7702
/// Identifier for EIP7702's set code transaction.
///
/// See also [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702).
pub const EIP7702_TX_TYPE_ID: u8 = 4;

/// Magic number used to calculate an EIP7702 authority.
///
/// See also [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702).
pub const MAGIC: u8 = 0x05;

/// An additional gas cost per EIP7702 authorization list item.
///
/// See also [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702).
pub const PER_AUTH_BASE_COST: u64 = 2500;
8 changes: 8 additions & 0 deletions crates/eips/src/eip7702/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//! [EIP-7702] constants, helpers, and types.
//!
//! [EIP-7702]: https://eips.ethereum.org/EIPS/eip-7702
mod auth_list;
pub use auth_list::*;

pub mod constants;
6 changes: 4 additions & 2 deletions crates/eips/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ pub mod eip2935;

pub mod eip4788;

pub mod eip4895;

pub mod eip4844;
pub use eip4844::{calc_blob_gasprice, calc_excess_blob_gas};

pub mod eip4895;

pub mod eip6110;
pub mod merge;

Expand All @@ -39,3 +39,5 @@ pub mod eip7002;
pub mod eip7251;

pub mod eip7685;

pub mod eip7702;

0 comments on commit 98a8dd7

Please sign in to comment.