-
Notifications
You must be signed in to change notification settings - Fork 4
EthAccount tests for initialization & upgrade #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| use eth_712_account::interface::{IAccount712AdminDispatcher, IAccount712AdminDispatcherTrait}; | ||
| use eth_712_account::test_utils::{ | ||
| TEST_ETH_ADDRESS, declare_register_interfaces_eic, deploy_eth712_account, get_invalid_signature, | ||
| get_ownership_signature, | ||
| }; | ||
| use openzeppelin::account::extensions::src9::interface::ISRC9_V2_ID; | ||
| use openzeppelin::account::interface::ISRC6_ID; | ||
| use openzeppelin::introspection::interface::{ISRC5Dispatcher, ISRC5DispatcherTrait}; | ||
| use snforge_std::{EventSpyTrait, load, spy_events}; | ||
| use starknet::EthAddress; | ||
| use starkware_utils_testing::test_utils::cheat_caller_address_once; | ||
| use testing_utils::event_helpers::get_event_by_selector; | ||
|
|
||
| // ================================ | ||
| // initialize tests | ||
| // ================================ | ||
|
|
||
| #[test] | ||
| fn test_initialize_success() { | ||
| let (account_address, _) = deploy_eth712_account(); | ||
| let account_contract = IAccount712AdminDispatcher { contract_address: account_address }; | ||
|
|
||
| // Initialize with valid signature | ||
| account_contract.initialize(TEST_ETH_ADDRESS(), get_ownership_signature()); | ||
|
|
||
| // Verify eth_address was stored correctly by reading storage directly | ||
| let stored_values = load(account_address, selector!("eth_address"), 1); | ||
| let stored_eth_address: EthAddress = (*stored_values.at(0)).try_into().unwrap(); | ||
| assert!(stored_eth_address == TEST_ETH_ADDRESS(), "eth_address not stored correctly"); | ||
|
|
||
| // Verify interfaces are registered | ||
| let src5 = ISRC5Dispatcher { contract_address: account_address }; | ||
| assert!(src5.supports_interface(ISRC9_V2_ID), "ISRC9_V2_ID not registered"); | ||
| assert!(src5.supports_interface(ISRC6_ID), "ISRC6_ID not registered"); | ||
| } | ||
|
|
||
| #[test] | ||
| #[should_panic(expected: 'ALREADY_INITIALIZED')] | ||
| fn test_initialize_already_initialized_reverts() { | ||
| let (account_address, _) = deploy_eth712_account(); | ||
| let account_contract = IAccount712AdminDispatcher { contract_address: account_address }; | ||
|
|
||
| // First initialization should succeed | ||
| account_contract.initialize(TEST_ETH_ADDRESS(), get_ownership_signature()); | ||
|
|
||
| // Second initialization should fail | ||
| account_contract.initialize(TEST_ETH_ADDRESS(), get_ownership_signature()); | ||
| } | ||
|
|
||
| #[test] | ||
| #[should_panic(expected: 'INVALID_OWNERSHIP_SIGNATURE')] | ||
| fn test_initialize_invalid_signature_reverts() { | ||
| let (account_address, _) = deploy_eth712_account(); | ||
| let account_contract = IAccount712AdminDispatcher { contract_address: account_address }; | ||
|
|
||
| // Initialize with invalid signature | ||
| account_contract.initialize(TEST_ETH_ADDRESS(), get_invalid_signature()); | ||
| } | ||
|
|
||
| // ================================ | ||
| // upgrade tests | ||
| // ================================ | ||
|
|
||
| const DUMMY_CLASS_HASH: felt252 = 'DUMMY_CLASS_HASH'; | ||
|
|
||
| #[test] | ||
| #[should_panic(expected: 'UNAUTHORIZED')] | ||
| fn test_upgrade_unauthorized_reverts() { | ||
| let (account_address, _) = deploy_eth712_account(); | ||
| let account_contract = IAccount712AdminDispatcher { contract_address: account_address }; | ||
|
|
||
| // Initialize first | ||
| account_contract.initialize(TEST_ETH_ADDRESS(), get_ownership_signature()); | ||
|
|
||
| // Try to upgrade from external caller (not self) - reverts before checking class hash | ||
| account_contract.upgrade(DUMMY_CLASS_HASH.try_into().unwrap(), Option::None); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_upgrade_from_self_succeeds() { | ||
| let (account_address, class_hash) = deploy_eth712_account(); | ||
| let account_contract = IAccount712AdminDispatcher { contract_address: account_address }; | ||
|
|
||
| // Initialize first | ||
| account_contract.initialize(TEST_ETH_ADDRESS(), get_ownership_signature()); | ||
|
|
||
| // Spoof caller as self for a single call | ||
| cheat_caller_address_once(contract_address: account_address, caller_address: account_address); | ||
|
|
||
| let mut spy = spy_events(); | ||
| account_contract.upgrade(class_hash, Option::None); | ||
|
|
||
| // Verify Upgraded event was emitted | ||
| let events = spy.get_events(); | ||
| let event_option = get_event_by_selector(events.events.span(), selector!("Upgraded")); | ||
| assert!(event_option.is_some(), "Upgraded event not found"); | ||
| let (from, event) = event_option.unwrap(); | ||
| assert!(*from == account_address, "Event from wrong address"); | ||
| assert!(event.data.len() > 0, "Event has no data"); | ||
| let class_hash_felt: felt252 = class_hash.into(); | ||
| assert!(*event.data.at(0) == class_hash_felt, "Wrong class hash in event"); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_upgrade_with_eic() { | ||
| let (account_address, class_hash) = deploy_eth712_account(); | ||
| let account_contract = IAccount712AdminDispatcher { contract_address: account_address }; | ||
|
|
||
| // Initialize first | ||
| account_contract.initialize(TEST_ETH_ADDRESS(), get_ownership_signature()); | ||
|
|
||
| // Spoof caller as self for a single call | ||
| cheat_caller_address_once(contract_address: account_address, caller_address: account_address); | ||
|
|
||
| let eic_class_hash = declare_register_interfaces_eic(); | ||
|
|
||
| // Register a custom interface via EIC | ||
| let custom_interface_id: felt252 = 0x12345678; | ||
| let eic_data: Span<felt252> = array![custom_interface_id].span(); | ||
|
|
||
| account_contract.upgrade(class_hash, Option::Some((eic_class_hash, eic_data))); | ||
|
|
||
| // Verify the custom interface was registered | ||
| let src5 = ISRC5Dispatcher { contract_address: account_address }; | ||
| assert!(src5.supports_interface(custom_interface_id), "Custom interface not registered"); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| use snforge_std::{ContractClassTrait, DeclareResultTrait}; | ||
| use starknet::secp256_trait::Signature; | ||
| use starknet::{ClassHash, ContractAddress, EthAddress, SyscallResultTrait}; | ||
|
|
||
| /// Test Ethereum address corresponding to private key: | ||
| /// 0xa6d86467b6ec9e161649b27edfd8519e75a2e1cf5f4c309c628706e6999780e8 | ||
| /// Address: 0xbF60187c5dFfA627249f1C3000A4168dbB9D7A1A | ||
| pub fn TEST_ETH_ADDRESS() -> EthAddress { | ||
| 0xbF60187c5dFfA627249f1C3000A4168dbB9D7A1A_felt252.try_into().unwrap() | ||
| } | ||
|
|
||
| /// A different Ethereum address for testing invalid cases. | ||
| pub fn WRONG_ETH_ADDRESS() -> EthAddress { | ||
| 0x1234567890123456789012345678901234567890_felt252.try_into().unwrap() | ||
| } | ||
|
|
||
| /// Returns the ownership signature for TEST_ETH_ADDRESS. | ||
| /// This signature was generated by signing the OWNERSHIP_TRANSFER_MSG_HASH | ||
| /// (0x3ce976d55131cd0bdd49f20afbded052d8e907dc6034d95cdf117a8fd7752e3c) | ||
| /// with the test private key. | ||
| /// | ||
| /// Values from: split_raw_eth_sig_to_felts output | ||
| /// '0xda47d5165a4577a024d18b8d61c5fe53 0xe994c0e202b390bddaffacf04bdea826 | ||
| /// 0x46dd0af587023ccad738aa0a82b05f98 0x2e117624d8cc474d0641c3168944eb67 0x1' | ||
| pub fn get_ownership_signature() -> Signature { | ||
| Signature { | ||
| r: u256 { | ||
| low: 0xda47d5165a4577a024d18b8d61c5fe53, high: 0xe994c0e202b390bddaffacf04bdea826, | ||
| }, | ||
| s: u256 { | ||
| low: 0x46dd0af587023ccad738aa0a82b05f98, high: 0x2e117624d8cc474d0641c3168944eb67, | ||
| }, | ||
| y_parity: true // v % 2 == 0 | ||
| } | ||
| } | ||
|
|
||
| /// Returns an invalid signature for testing. | ||
| pub fn get_invalid_signature() -> Signature { | ||
| Signature { | ||
| r: u256 { low: 0x1234567890abcdef, high: 0xfedcba0987654321 }, | ||
| s: u256 { low: 0xabcdef1234567890, high: 0x1234567890abcdef }, | ||
| y_parity: false, | ||
| } | ||
| } | ||
|
|
||
| /// Declare and deploy the StarknetEth712Account contract. | ||
| /// Returns the contract address and the class hash. | ||
| pub fn deploy_eth712_account() -> (ContractAddress, ClassHash) { | ||
| let contract_class = snforge_std::declare("StarknetEth712Account") | ||
| .unwrap_syscall() | ||
| .contract_class(); | ||
| let (contract_address, _) = contract_class.deploy(@array![]).unwrap_syscall(); | ||
| (contract_address, *contract_class.class_hash) | ||
| } | ||
|
|
||
| /// Declare the RegisterInterfacesEIC contract and return its class hash. | ||
| pub fn declare_register_interfaces_eic() -> ClassHash { | ||
| *snforge_std::declare("RegisterInterfacesEIC").unwrap_syscall().contract_class().class_hash | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.