1+ use crate :: l2:: bindings:: SurgeInbox ;
12use alloy:: {
23 consensus:: SidecarBuilder ,
34 eips:: eip4844:: BlobTransactionSidecar ,
@@ -8,11 +9,14 @@ use alloy::{
89 } ,
910 providers:: { DynProvider , Provider } ,
1011 rpc:: types:: TransactionRequest ,
12+ signers:: Signer ,
13+ sol_types:: SolValue ,
1114} ;
1215use alloy_json_rpc:: RpcError ;
1316use anyhow:: Error ;
1417use common:: l1:: { fees_per_gas:: FeesPerGas , tools, transaction_error:: TransactionError } ;
1518use common:: shared:: l2_block_v2:: L2BlockV2 ;
19+ use taiko_bindings:: anchor:: ICheckpointStore :: Checkpoint ;
1620use taiko_bindings:: inbox:: { IInbox :: ProposeInput , Inbox , LibBlobs :: BlobReference } ;
1721use taiko_protocol:: shasta:: {
1822 BlobCoder ,
@@ -23,13 +27,19 @@ use tracing::warn;
2327pub struct ProposalTxBuilder {
2428 provider : DynProvider ,
2529 extra_gas_percentage : u64 ,
30+ checkpoint_signer : alloy:: signers:: local:: PrivateKeySigner ,
2631}
2732
2833impl ProposalTxBuilder {
29- pub fn new ( provider : DynProvider , extra_gas_percentage : u64 ) -> Self {
34+ pub fn new (
35+ provider : DynProvider ,
36+ extra_gas_percentage : u64 ,
37+ checkpoint_signer : alloy:: signers:: local:: PrivateKeySigner ,
38+ ) -> Self {
3039 Self {
3140 provider,
3241 extra_gas_percentage,
42+ checkpoint_signer,
3343 }
3444 }
3545
@@ -40,9 +50,10 @@ impl ProposalTxBuilder {
4050 from : Address ,
4151 to : Address ,
4252 num_forced_inclusion : u8 ,
53+ checkpoint : Checkpoint ,
4354 ) -> Result < TransactionRequest , Error > {
4455 let tx_blob = self
45- . build_propose_blob ( l2_blocks, from, to, num_forced_inclusion)
56+ . build_propose_blob ( l2_blocks, from, to, num_forced_inclusion, checkpoint )
4657 . await ?;
4758 let tx_blob_gas = match self . provider . estimate_gas ( tx_blob. clone ( ) ) . await {
4859 Ok ( gas) => gas,
@@ -87,6 +98,7 @@ impl ProposalTxBuilder {
8798 from : Address ,
8899 to : Address ,
89100 num_forced_inclusion : u8 ,
101+ checkpoint : Checkpoint ,
90102 ) -> Result < TransactionRequest , Error > {
91103 let mut block_manifests = <Vec < BlockManifest > >:: with_capacity ( l2_blocks. len ( ) ) ;
92104 for l2_block in & l2_blocks {
@@ -131,15 +143,36 @@ impl ProposalTxBuilder {
131143 let inbox = Inbox :: new ( to, self . provider . clone ( ) ) ;
132144 let encoded_proposal_input = inbox. encodeProposeInput ( input) . call ( ) . await ?;
133145
146+ // Surge: using `proposeWithProof(..)` in Surge Inbox
147+ let proof_data = self . build_proof_data ( & checkpoint) . await ?;
134148 let tx = TransactionRequest :: default ( )
135149 . with_from ( from)
136150 . with_to ( to)
137151 . with_blob_sidecar ( sidecar)
138- . with_call ( & Inbox :: proposeCall {
152+ . with_call ( & SurgeInbox :: proposeWithProofCall {
139153 _lookahead : Bytes :: new ( ) ,
140154 _data : encoded_proposal_input,
155+ _proof : proof_data,
141156 } ) ;
142157
143158 Ok ( tx)
144159 }
160+
161+ // Surge: builds the 161-byte proof data
162+ // [0..96: ABI-encoded checkpoint][96..161: signed checkpoint digest]
163+ async fn build_proof_data ( & self , checkpoint : & Checkpoint ) -> Result < Bytes , Error > {
164+ let checkpoint_encoded = checkpoint. abi_encode ( ) ;
165+ let checkpoint_digest = alloy:: primitives:: keccak256 ( & checkpoint_encoded) ;
166+ let signature = self . checkpoint_signer . sign_hash ( & checkpoint_digest) . await ?;
167+
168+ let mut signature_bytes = [ 0_u8 ; 65 ] ;
169+ signature_bytes[ ..32 ] . copy_from_slice ( signature. r ( ) . to_be_bytes :: < 32 > ( ) . as_slice ( ) ) ;
170+ signature_bytes[ 32 ..64 ] . copy_from_slice ( signature. s ( ) . to_be_bytes :: < 32 > ( ) . as_slice ( ) ) ;
171+ signature_bytes[ 64 ] = ( signature. v ( ) as u8 ) + 27 ;
172+
173+ let mut proof_data = Vec :: with_capacity ( 161 ) ;
174+ proof_data. extend_from_slice ( & checkpoint_encoded) ;
175+ proof_data. extend_from_slice ( & signature_bytes) ;
176+ Ok ( Bytes :: from ( proof_data) )
177+ }
145178}
0 commit comments