77//!
88//! This module uses the starknet crate's account abstraction for transaction handling.
99
10- use std:: sync:: Arc ;
1110use std:: time:: { Duration , Instant } ;
1211
1312use anyhow:: { anyhow, Context , Result } ;
1413use ark_ff:: PrimeField ;
15- use katana_contracts:: vrf:: CartridgeVrfAccount ;
14+ use katana_contracts:: vrf:: { CartridgeVrfAccount , CartridgeVrfConsumer } ;
1615use katana_genesis:: constant:: DEFAULT_STRK_FEE_TOKEN_ADDRESS ;
1716use katana_primitives:: chain:: ChainId ;
1817use katana_primitives:: class:: ClassHash ;
1918use katana_primitives:: utils:: get_contract_address;
2019use katana_primitives:: { ContractAddress , Felt } ;
2120use katana_rpc_types:: RpcSierraContractClass ;
2221use stark_vrf:: { generate_public_key, ScalarField } ;
23- use starknet:: accounts:: { Account , ExecutionEncoding , SingleOwnerAccount } ;
22+ use starknet:: accounts:: { Account , ConnectedAccount , ExecutionEncoding , SingleOwnerAccount } ;
2423use starknet:: contract:: ContractFactory ;
2524use starknet:: core:: types:: { BlockId , BlockTag , Call , FlattenedSierraClass , StarknetError } ;
2625use starknet:: macros:: selector;
@@ -75,9 +74,9 @@ pub struct VrfBootstrapResult {
7574
7675/// Derived VRF account information.
7776#[ derive( Debug , Clone ) ]
78- pub struct VrfDerivedAccounts {
79- pub vrf_account_private_key : Felt ,
80- pub vrf_account_address : ContractAddress ,
77+ pub struct VrfAccountCredentials {
78+ pub private_key : Felt ,
79+ pub account_address : ContractAddress ,
8180 pub vrf_public_key_x : Felt ,
8281 pub vrf_public_key_y : Felt ,
8382 pub secret_key : u64 ,
@@ -91,7 +90,7 @@ pub struct VrfDerivedAccounts {
9190///
9291/// This computes the deterministic VRF account address and VRF key pair
9392/// from a fixed VRF private key.
94- pub fn get_vrf_account ( ) -> Result < VrfDerivedAccounts > {
93+ pub fn get_vrf_account ( ) -> Result < VrfAccountCredentials > {
9594 let secret_key = VRF_HARDCODED_SECRET_KEY ;
9695 let vrf_account_private_key = Felt :: from ( secret_key) ;
9796 let public_key = generate_public_key ( scalar_from_felt ( secret_key. into ( ) ) ) ;
@@ -108,13 +107,13 @@ pub fn get_vrf_account() -> Result<VrfDerivedAccounts> {
108107 Felt :: from ( VRF_ACCOUNT_SALT ) ,
109108 vrf_account_class_hash,
110109 & [ account_public_key] ,
111- Felt :: ZERO ,
110+ ContractAddress :: ZERO ,
112111 )
113112 . into ( ) ;
114113
115- Ok ( VrfDerivedAccounts {
116- vrf_account_private_key,
117- vrf_account_address,
114+ Ok ( VrfAccountCredentials {
115+ private_key : vrf_account_private_key,
116+ account_address : vrf_account_address,
118117 vrf_public_key_x,
119118 vrf_public_key_y,
120119 secret_key,
@@ -126,18 +125,10 @@ pub async fn bootstrap_vrf(
126125 bootstrapper_account_address : ContractAddress ,
127126 bootstrapper_account_private_key : Felt ,
128127) -> Result < VrfBootstrapResult > {
129- let provider = Arc :: new ( JsonRpcClient :: new ( HttpTransport :: new ( rpc_url. clone ( ) ) ) ) ;
128+ let provider = JsonRpcClient :: new ( HttpTransport :: new ( rpc_url. clone ( ) ) ) ;
130129
131130 // Get chain ID from the node
132- let chain_id_felt = provider. chain_id ( ) . await . context ( "failed to get chain ID from node" ) ?;
133- let chain_id = ChainId :: Id ( chain_id_felt) ;
134-
135- let derived = get_vrf_account ( ) ?;
136- let vrf_account_address = derived. vrf_account_address ;
137- let account_public_key =
138- SigningKey :: from_secret_scalar ( derived. vrf_account_private_key ) . verifying_key ( ) . scalar ( ) ;
139-
140- let vrf_account_class_hash = CartridgeVrfAccount :: HASH ;
131+ let chain_id = provider. chain_id ( ) . await . context ( "failed to get chain ID from node" ) ?;
141132
142133 // Create the source account for transactions
143134 let signer =
@@ -146,38 +137,61 @@ pub async fn bootstrap_vrf(
146137 provider. clone ( ) ,
147138 signer,
148139 bootstrapper_account_address. into ( ) ,
149- chain_id_felt ,
140+ chain_id ,
150141 ExecutionEncoding :: New ,
151142 ) ;
152143
153- if !is_declared ( & provider, vrf_account_class_hash) . await ? {
144+ let vrf_acc_cred = bootstrap_vrf_account ( & account) . await ?;
145+ let vrf_consumer_addr = bootstrap_vrf_consumer ( & account, vrf_acc_cred. account_address ) . await ?;
146+
147+ Ok ( VrfBootstrapResult {
148+ chain_id : chain_id. into ( ) ,
149+ secret_key : vrf_acc_cred. secret_key ,
150+ vrf_consumer_address : vrf_consumer_addr,
151+ vrf_account_address : vrf_acc_cred. account_address ,
152+ vrf_account_private_key : vrf_acc_cred. private_key ,
153+ } )
154+ }
155+
156+ async fn bootstrap_vrf_account (
157+ bootstrapper_account : & SingleOwnerAccount < JsonRpcClient < HttpTransport > , LocalWallet > ,
158+ ) -> Result < VrfAccountCredentials > {
159+ let provider = bootstrapper_account. provider ( ) ;
160+
161+ let vrf_acc_cred = get_vrf_account ( ) ?;
162+ let vrf_account_address = vrf_acc_cred. account_address ;
163+
164+ if !is_declared ( provider, CartridgeVrfAccount :: HASH ) . await ? {
154165 let class = CartridgeVrfAccount :: CLASS . clone ( ) ;
155166 let compiled_hash = CartridgeVrfAccount :: CASM_HASH ;
156167
157168 let rpc_class = RpcSierraContractClass :: from ( class. to_sierra ( ) . unwrap ( ) ) ;
158169 let rpc_class = FlattenedSierraClass :: try_from ( rpc_class) . unwrap ( ) ;
159170
160- let result = account
171+ let result = bootstrapper_account
161172 . declare_v3 ( rpc_class. into ( ) , compiled_hash)
162173 . send ( )
163174 . await
164175 . expect ( "fail to declare class" ) ;
165176
166- assert_eq ! ( result. class_hash, vrf_account_class_hash , "Class hash mismatch" ) ;
167- wait_for_class ( & provider, vrf_account_class_hash , BOOTSTRAP_TIMEOUT ) . await ?;
177+ assert_eq ! ( result. class_hash, CartridgeVrfAccount :: HASH , "Class hash mismatch" ) ;
178+ wait_for_class ( provider, CartridgeVrfAccount :: HASH , BOOTSTRAP_TIMEOUT ) . await ?;
168179 }
169180
170181 // Deploy VRF account if not already deployed
171- if !is_deployed ( & provider, vrf_account_address) . await ? {
182+ if !is_deployed ( provider, vrf_account_address) . await ? {
183+ let account_public_key =
184+ SigningKey :: from_secret_scalar ( vrf_acc_cred. private_key ) . verifying_key ( ) . scalar ( ) ;
185+
172186 #[ allow( deprecated) ]
173- let factory = ContractFactory :: new ( vrf_account_class_hash , & account ) ;
187+ let factory = ContractFactory :: new ( CartridgeVrfAccount :: HASH , & bootstrapper_account ) ;
174188 factory
175189 . deploy_v3 ( vec ! [ account_public_key] , Felt :: from ( VRF_ACCOUNT_SALT ) , false )
176190 . send ( )
177191 . await
178192 . map_err ( |e| anyhow ! ( "failed to deploy VRF account: {e}" ) ) ?;
179193
180- wait_for_contract ( & provider, vrf_account_address, BOOTSTRAP_TIMEOUT ) . await ?;
194+ wait_for_contract ( provider, vrf_account_address, BOOTSTRAP_TIMEOUT ) . await ?;
181195 }
182196
183197 // Fund VRF account
@@ -189,32 +203,29 @@ pub async fn bootstrap_vrf(
189203 calldata : vec ! [ vrf_account_address. into( ) , amount, Felt :: ZERO ] ,
190204 } ;
191205
192- let result = account
206+ let result = bootstrapper_account
193207 . execute_v3 ( vec ! [ transfer_call] )
194208 . send ( )
195209 . await
196210 . map_err ( |e| anyhow ! ( "failed to fund VRF account: {e}" ) ) ?;
197211
198- wait_for_tx ( & provider, result. transaction_hash , BOOTSTRAP_TIMEOUT ) . await ?;
212+ wait_for_tx ( provider, result. transaction_hash , BOOTSTRAP_TIMEOUT ) . await ?;
199213 }
200214
201215 // Set VRF public key on the deployed account
202216 // Create account for the VRF account to call set_vrf_public_key on itself
203- let vrf_signer =
204- LocalWallet :: from ( SigningKey :: from_secret_scalar ( derived. vrf_account_private_key ) ) ;
205- let mut vrf_account = SingleOwnerAccount :: new (
206- provider. clone ( ) ,
207- vrf_signer,
217+ let vrf_account = SingleOwnerAccount :: new (
218+ provider,
219+ LocalWallet :: from ( SigningKey :: from_secret_scalar ( vrf_acc_cred. private_key ) ) ,
208220 vrf_account_address. into ( ) ,
209- chain_id_felt ,
221+ bootstrapper_account . chain_id ( ) ,
210222 ExecutionEncoding :: New ,
211223 ) ;
212- vrf_account. set_block_id ( BlockId :: Tag ( BlockTag :: PreConfirmed ) ) ;
213224
214225 let set_vrf_key_call = Call {
215226 to : vrf_account_address. into ( ) ,
216227 selector : selector ! ( "set_vrf_public_key" ) ,
217- calldata : vec ! [ derived . vrf_public_key_x, derived . vrf_public_key_y] ,
228+ calldata : vec ! [ vrf_acc_cred . vrf_public_key_x, vrf_acc_cred . vrf_public_key_y] ,
218229 } ;
219230
220231 let result = vrf_account
@@ -223,39 +234,56 @@ pub async fn bootstrap_vrf(
223234 . await
224235 . map_err ( |e| anyhow ! ( "failed to set VRF public key: {e}" ) ) ?;
225236
226- wait_for_tx ( & provider, result. transaction_hash , BOOTSTRAP_TIMEOUT ) . await ?;
237+ wait_for_tx ( provider, result. transaction_hash , BOOTSTRAP_TIMEOUT ) . await ?;
238+
239+ Ok ( vrf_acc_cred)
240+ }
241+
242+ async fn bootstrap_vrf_consumer (
243+ bootstrapper_account : & SingleOwnerAccount < JsonRpcClient < HttpTransport > , LocalWallet > ,
244+ vrf_account : ContractAddress ,
245+ ) -> Result < ContractAddress > {
246+ let provider = bootstrapper_account. provider ( ) ;
227247
228- // Deploy VRF consumer
229- let vrf_consumer_class_hash = katana_contracts:: vrf:: CartridgeVrfConsumer :: HASH ;
230248 // When using UDC with unique=0 (non-unique deployment), the deployer_address
231249 // used in address computation is 0, not the actual deployer or UDC address.
232250 let vrf_consumer_address = get_contract_address (
233251 Felt :: from ( VRF_CONSUMER_SALT ) ,
234- vrf_consumer_class_hash,
235- & [ vrf_account_address. into ( ) ] ,
236- Felt :: ZERO ,
237- )
238- . into ( ) ;
252+ CartridgeVrfConsumer :: HASH ,
253+ & [ vrf_account. into ( ) ] ,
254+ ContractAddress :: ZERO ,
255+ ) ;
256+
257+ if !is_declared ( provider, CartridgeVrfConsumer :: HASH ) . await ? {
258+ let class = CartridgeVrfConsumer :: CLASS . clone ( ) ;
259+ let compiled_hash = CartridgeVrfConsumer :: CASM_HASH ;
260+
261+ let rpc_class = RpcSierraContractClass :: from ( class. to_sierra ( ) . unwrap ( ) ) ;
262+ let rpc_class = FlattenedSierraClass :: try_from ( rpc_class) . unwrap ( ) ;
263+
264+ let result = bootstrapper_account
265+ . declare_v3 ( rpc_class. into ( ) , compiled_hash)
266+ . send ( )
267+ . await
268+ . expect ( "fail to declare class" ) ;
239269
240- if !is_deployed ( & provider, vrf_consumer_address) . await ? {
270+ assert_eq ! ( result. class_hash, CartridgeVrfConsumer :: HASH , "Class hash mismatch" ) ;
271+ wait_for_class ( provider, CartridgeVrfConsumer :: HASH , BOOTSTRAP_TIMEOUT ) . await ?;
272+ }
273+
274+ if !is_deployed ( provider, vrf_consumer_address. into ( ) ) . await ? {
241275 #[ allow( deprecated) ]
242- let factory = ContractFactory :: new ( vrf_consumer_class_hash , & account ) ;
276+ let factory = ContractFactory :: new ( CartridgeVrfConsumer :: HASH , & bootstrapper_account ) ;
243277 factory
244- . deploy_v3 ( vec ! [ vrf_account_address . into( ) ] , Felt :: from ( VRF_CONSUMER_SALT ) , false )
278+ . deploy_v3 ( vec ! [ vrf_account . into( ) ] , Felt :: from ( VRF_CONSUMER_SALT ) , false )
245279 . send ( )
246280 . await
247281 . map_err ( |e| anyhow ! ( "failed to deploy VRF consumer: {e}" ) ) ?;
248282
249- wait_for_contract ( & provider, vrf_consumer_address, BOOTSTRAP_TIMEOUT ) . await ?;
283+ wait_for_contract ( provider, vrf_consumer_address. into ( ) , BOOTSTRAP_TIMEOUT ) . await ?;
250284 }
251285
252- Ok ( VrfBootstrapResult {
253- secret_key : derived. secret_key ,
254- vrf_consumer_address,
255- chain_id,
256- vrf_account_address,
257- vrf_account_private_key : derived. vrf_account_private_key ,
258- } )
286+ Ok ( vrf_consumer_address. into ( ) )
259287}
260288
261289// ============================================================================
@@ -358,15 +386,15 @@ mod tests {
358386 fn derive_vrf_accounts_uses_hardcoded_secret_key ( ) {
359387 let derived = get_vrf_account ( ) . expect ( "must derive" ) ;
360388 assert_eq ! ( derived. secret_key, VRF_HARDCODED_SECRET_KEY ) ;
361- assert_eq ! ( derived. vrf_account_private_key , VRF_HARDCODED_SECRET_KEY . into( ) ) ;
389+ assert_eq ! ( derived. private_key , VRF_HARDCODED_SECRET_KEY . into( ) ) ;
362390 }
363391
364392 #[ test]
365393 fn derive_vrf_accounts_is_deterministic ( ) {
366394 let first = get_vrf_account ( ) . expect ( "first derivation" ) ;
367395 let second = get_vrf_account ( ) . expect ( "second derivation" ) ;
368396
369- assert_eq ! ( first. vrf_account_address , second. vrf_account_address ) ;
397+ assert_eq ! ( first. account_address , second. account_address ) ;
370398 assert_eq ! ( first. vrf_public_key_x, second. vrf_public_key_x) ;
371399 assert_eq ! ( first. vrf_public_key_y, second. vrf_public_key_y) ;
372400 }
0 commit comments