|
| 1 | +//! RPC types that are supported by Beaverbuild |
| 2 | +use alloy_primitives::{hex::FromHex, Address, BlockNumber, Bytes, TxHash}; |
| 3 | +use alloy_rpc_types_mev::EthSendBundle; |
| 4 | +use serde::Serialize; |
| 5 | +use serde_with::{serde_as, skip_serializing_none}; |
| 6 | + |
| 7 | +/// Bundle as recognised by Beaverbuild |
| 8 | +/// |
| 9 | +/// Consult <https://beaverbuild.org/docs.html>. Note that the deprecated `replacementUuid` field |
| 10 | +/// has been omitted. |
| 11 | +#[serde_as] |
| 12 | +#[skip_serializing_none] |
| 13 | +#[derive(Clone, Debug, Default, Serialize)] |
| 14 | +pub struct BeaverBundle { |
| 15 | + #[serde(flatten)] |
| 16 | + pub bundle: EthSendBundle, |
| 17 | + #[serde(skip_serializing_if = "Vec::is_empty")] |
| 18 | + /// A list of transaction hashes contained in the bundle, that can be allowed to be removed from your bundle if it's deemed useful (but not revert) |
| 19 | + pub dropping_transaction_hashes: Vec<TxHash>, |
| 20 | + /// An integer between 1-99. How much of the total priority fee + coinbase payment you want to be refunded for. This will negatively impact your prioritization because this refund is gonna eat into your bundle payment. Example: if a bundle pays 0.2 ETH of priority fee plus 1 ETH to coinbase, a refundPercent set to 50 will result in a transaction being appended after the bundle, paying 0.59 ETH back to the EOA. This is assuming the payout tx will cost beaver 0.01 ETH in fees, which are deduced from the 0.6 ETH payout. |
| 21 | + pub refund_percent: Option<u64>, |
| 22 | + /// You can specify an address that the funds from `refundPercent` will be sent to. If not specified, they will be sent to the `from` address of the first transaction |
| 23 | + pub refund_recipient: Option<Address>, |
| 24 | + #[serde(skip_serializing_if = "Vec::is_empty")] |
| 25 | + /// The hashes of transactions in the bundle that the refund will be based on. If it's empty, we'll use the last transaction |
| 26 | + pub refund_transaction_hashes: Vec<TxHash>, |
| 27 | +} |
| 28 | + |
| 29 | +pub fn bundle_from_rlp_hex( |
| 30 | + txs: Vec<String>, |
| 31 | + block_number: BlockNumber, |
| 32 | +) -> eyre::Result<EthSendBundle> { |
| 33 | + Ok(EthSendBundle { |
| 34 | + txs: txs |
| 35 | + .iter() |
| 36 | + .map(Bytes::from_hex) |
| 37 | + .collect::<Result<Vec<Bytes>, _>>()?, |
| 38 | + block_number, |
| 39 | + ..EthSendBundle::default() |
| 40 | + }) |
| 41 | +} |
| 42 | + |
| 43 | +#[cfg(test)] |
| 44 | +mod test { |
| 45 | + use super::*; |
| 46 | + |
| 47 | + #[test] |
| 48 | + fn test_beaver_bundle_serialisation() { |
| 49 | + assert!(serde_json::to_string(&BeaverBundle::default()).is_ok()); |
| 50 | + assert_eq!( |
| 51 | + serde_json::to_string(&BeaverBundle::default()).unwrap(), |
| 52 | + "{\"txs\":[],\"blockNumber\":\"0x0\"}".to_string() |
| 53 | + ); |
| 54 | + |
| 55 | + assert!(serde_json::to_string(&BeaverBundle { |
| 56 | + bundle: EthSendBundle { |
| 57 | + txs: vec![], |
| 58 | + block_number: 21862873, |
| 59 | + ..Default::default() |
| 60 | + }, |
| 61 | + ..Default::default() |
| 62 | + }) |
| 63 | + .is_ok()); |
| 64 | + assert_eq!( |
| 65 | + serde_json::to_string(&BeaverBundle { |
| 66 | + bundle: EthSendBundle { |
| 67 | + txs: vec![], |
| 68 | + block_number: 21862873, |
| 69 | + ..Default::default() |
| 70 | + }, |
| 71 | + ..Default::default() |
| 72 | + }) |
| 73 | + .unwrap(), |
| 74 | + "{\"txs\":[],\"blockNumber\":\"0x14d99d9\"}".to_string() |
| 75 | + ); |
| 76 | + assert!( |
| 77 | + serde_json::to_string(& |
| 78 | + bundle_from_rlp_hex(vec!["0x02f8b20181948449bdee618501dcd6500083016b93942dabcea55a12d73191aece59f508b191fb68adac80b844095ea7b300000000000000000000000054e44dbb92dba848ace27f44c0cb4268981ef1cc00000000000000000000000000000000000000000000000052616e065f6915ebc080a0c497b6e53d7cb78e68c37f6186c8bb9e1b8a55c3e22462163495979b25c2caafa052769811779f438b73159c4cc6a05a889da8c1a16e432c2e37e3415c9a0b9887".to_string()], 21862873).unwrap() |
| 79 | + ) |
| 80 | + .is_ok()); |
| 81 | + assert_eq!( |
| 82 | + serde_json::to_string(& |
| 83 | + bundle_from_rlp_hex(vec!["0x02f8b20181948449bdee618501dcd6500083016b93942dabcea55a12d73191aece59f508b191fb68adac80b844095ea7b300000000000000000000000054e44dbb92dba848ace27f44c0cb4268981ef1cc00000000000000000000000000000000000000000000000052616e065f6915ebc080a0c497b6e53d7cb78e68c37f6186c8bb9e1b8a55c3e22462163495979b25c2caafa052769811779f438b73159c4cc6a05a889da8c1a16e432c2e37e3415c9a0b9887".to_string()], 21862873).unwrap() |
| 84 | + ) |
| 85 | + .unwrap(), |
| 86 | + "{\"txs\":[\"0x02f8b20181948449bdee618501dcd6500083016b93942dabcea55a12d73191aece59f508b191fb68adac80b844095ea7b300000000000000000000000054e44dbb92dba848ace27f44c0cb4268981ef1cc00000000000000000000000000000000000000000000000052616e065f6915ebc080a0c497b6e53d7cb78e68c37f6186c8bb9e1b8a55c3e22462163495979b25c2caafa052769811779f438b73159c4cc6a05a889da8c1a16e432c2e37e3415c9a0b9887\"],\"blockNumber\":\"0x14d99d9\"}".to_string() |
| 87 | + ); |
| 88 | + } |
| 89 | +} |
0 commit comments