From ba4f528cea3d695e37d5e068cb534ab86d465b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Fri, 26 Jan 2024 02:09:48 -0300 Subject: [PATCH 1/5] Release v0.8.1 (#868) * bump version and update changelog * fix docs links * update class hashes to cairo 2.4.1 --- CHANGELOG.md | 4 +++- README.md | 8 ++++---- Scarb.lock | 2 +- Scarb.toml | 2 +- docs/antora.yml | 2 +- docs/modules/ROOT/pages/access.adoc | 2 +- docs/modules/ROOT/pages/api/access.adoc | 6 +++--- docs/modules/ROOT/pages/api/account.adoc | 10 +++++----- docs/modules/ROOT/pages/api/erc20.adoc | 8 ++++---- docs/modules/ROOT/pages/api/erc721.adoc | 2 +- docs/modules/ROOT/pages/api/introspection.adoc | 4 ++-- docs/modules/ROOT/pages/api/security.adoc | 6 +++--- docs/modules/ROOT/pages/api/upgrades.adoc | 4 ++-- docs/modules/ROOT/pages/index.adoc | 2 +- docs/modules/ROOT/pages/upgrades.adoc | 2 +- docs/modules/ROOT/pages/utilities.adoc | 4 ++-- docs/modules/ROOT/pages/utils/_class_hashes.adoc | 6 +++--- src/access/accesscontrol/accesscontrol.cairo | 2 +- src/access/accesscontrol/dual_accesscontrol.cairo | 2 +- src/access/accesscontrol/interface.cairo | 2 +- src/access/ownable/dual_ownable.cairo | 2 +- src/access/ownable/interface.cairo | 2 +- src/access/ownable/ownable.cairo | 2 +- src/account/account.cairo | 2 +- src/account/dual_account.cairo | 2 +- src/account/interface.cairo | 2 +- src/introspection/dual_src5.cairo | 2 +- src/introspection/interface.cairo | 2 +- src/introspection/src5.cairo | 2 +- src/presets/account.cairo | 2 +- src/presets/erc20.cairo | 2 +- src/presets/erc721.cairo | 2 +- src/security/initializable.cairo | 2 +- src/security/pausable.cairo | 2 +- src/security/reentrancyguard.cairo | 2 +- src/token/erc20/dual20.cairo | 2 +- src/token/erc20/erc20.cairo | 4 ++-- src/token/erc20/interface.cairo | 2 +- src/token/erc721/dual721.cairo | 2 +- src/token/erc721/dual721_receiver.cairo | 2 +- src/token/erc721/erc721.cairo | 2 +- src/token/erc721/erc721_receiver.cairo | 2 +- src/token/erc721/interface.cairo | 2 +- src/upgrades/interface.cairo | 2 +- src/upgrades/upgradeable.cairo | 2 +- src/utils.cairo | 2 +- src/utils/selectors.cairo | 2 +- src/utils/serde.cairo | 2 +- src/utils/unwrap_and_cast.cairo | 2 +- 49 files changed, 71 insertions(+), 69 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6786a852d..34f9309ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## Unreleased + +## 0.8.1 (2024-01-23) ### Added diff --git a/README.md b/README.md index 864574b42..288c124b9 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Edit `scarb.toml` and add: ```toml [dependencies] -openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.8.0" } +openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.8.1" } ``` Build the project to download it: @@ -106,7 +106,7 @@ mod MyToken { ### Unsupported -[`DualCase` dispatchers](https://docs.openzeppelin.com/contracts-cairo/0.8.0/interfaces#dualcase_dispatchers) rely on Sierra's ability to catch a revert to resume execution. Currently, Starknet live chains (testnets and mainnet) don't implement that behavior. Starknet's testing framework does support it. +[`DualCase` dispatchers](https://docs.openzeppelin.com/contracts-cairo/0.8.1/interfaces#dualcase_dispatchers) rely on Sierra's ability to catch a revert to resume execution. Currently, Starknet live chains (testnets and mainnet) don't implement that behavior. Starknet's testing framework does support it. ## Learn @@ -156,8 +156,8 @@ git clone git@github.com:OpenZeppelin/cairo-contracts.git $ cd cairo-contracts $ scarb build -Compiling lib(openzeppelin) openzeppelin v0.8.0 (~/cairo-contracts/Scarb.toml) -Compiling starknet-contract(openzeppelin) openzeppelin v0.8.0 (~/cairo-contracts/Scarb.toml) +Compiling lib(openzeppelin) openzeppelin v0.8.1 (~/cairo-contracts/Scarb.toml) +Compiling starknet-contract(openzeppelin) openzeppelin v0.8.1 (~/cairo-contracts/Scarb.toml) Finished release target(s) in 16 seconds ``` diff --git a/Scarb.lock b/Scarb.lock index e023bf036..b2c02f8ff 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -3,4 +3,4 @@ version = 1 [[package]] name = "openzeppelin" -version = "0.8.0" +version = "0.8.1" diff --git a/Scarb.toml b/Scarb.toml index 2d266f8f0..b6e404463 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -1,6 +1,6 @@ [package] name = "openzeppelin" -version = "0.8.0" +version = "0.8.1" cairo-version = "2.4.1" authors = ["OpenZeppelin Community "] description = "OpenZeppelin Contracts written in Cairo for StarkNet, a decentralized ZK Rollup" diff --git a/docs/antora.yml b/docs/antora.yml index c85c95834..1de7814ca 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -1,6 +1,6 @@ name: contracts-cairo title: Contracts for Cairo -version: 0.8.0 +version: 0.8.1 nav: - modules/ROOT/nav.adoc asciidoc: diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index d8d6f66f9..39aebf551 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -1,4 +1,4 @@ -:ownable-cairo: link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/access/ownable/ownable.cairo[Ownable] +:ownable-cairo: link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/access/ownable/ownable.cairo[Ownable] :sn_keccak: https://docs.starknet.io/documentation/architecture_and_concepts/Cryptography/hash-functions/#starknet_keccak[sn_keccak] = Access diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 28855ddce..03a331f72 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -18,7 +18,7 @@ assigned each to multiple accounts. [.contract] [[OwnableComponent]] -=== `++OwnableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/access/ownable/ownable.cairo[{github-icon},role=heading-link] +=== `++OwnableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/access/ownable/ownable.cairo[{github-icon},role=heading-link] ```javascript use openzeppelin::access::ownable::OwnableComponent; @@ -144,7 +144,7 @@ Emitted when the ownership is transferred. [.contract] [[IAccessControl]] -=== `++IAccessControl++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/access/accesscontrol/interface.cairo[{github-icon},role=heading-link] +=== `++IAccessControl++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/access/accesscontrol/interface.cairo[{github-icon},role=heading-link] :grant_role: xref:#IAccessControl-grant_role[grant_role] :revoke_role: xref:#IAccessControl-revoke_role[revoke_role] @@ -277,7 +277,7 @@ Emitted when `account` is revoked `role`. [.contract] [[AccessControlComponent]] -=== `++AccessControlComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/access/accesscontrol/accesscontrol.cairo[{github-icon},role=heading-link] +=== `++AccessControlComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/access/accesscontrol/accesscontrol.cairo[{github-icon},role=heading-link] :assert_only_role: xref:#AccessControlComponent-assert_only_role :grant_role: xref:#AccessControlComponent-grant_role[grant_role] diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 86d63f69c..1438ef696 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -10,7 +10,7 @@ Reference of interfaces, presets, and utilities related to account contracts. [.contract] [[ISRC6]] -=== `++ISRC6++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/account/interface.cairo[{github-icon},role=heading-link] +=== `++ISRC6++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/account/interface.cairo[{github-icon},role=heading-link] ```javascript use openzeppelin::account::interface::ISRC6; @@ -63,7 +63,7 @@ Returns the short string `'VALID'` if valid, otherwise it reverts. [.contract] [[AccountComponent]] -=== `++AccountComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/account/account.cairo#L27[{github-icon},role=heading-link] +=== `++AccountComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/account/account.cairo#L27[{github-icon},role=heading-link] :OwnerAdded: xref:AccountComponent-OwnerAdded[OwnerAdded] :OwnerRemoved: xref:AccountComponent-OwnerRemoved[OwnerRemoved] @@ -155,7 +155,7 @@ See xref:ISRC6-is_valid_signature[ISRC6::is_valid_signature]. [[AccountComponent-__validate_declare__]] ==== `[.contract-item-name]#++__validate_declare__++#++(self: @ContractState, class_hash: felt252) → felt252++` [.item-kind]#external# -Validates a https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/Blocks/transactions/#declare-transaction[`Declare` transaction]. +Validates a https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/transactions/#declare-transaction[`Declare` transaction]. Returns the short string `'VALID'` if valid, otherwise it reverts. @@ -163,7 +163,7 @@ Returns the short string `'VALID'` if valid, otherwise it reverts. [[AccountComponent-__validate_deploy__]] ==== `[.contract-item-name]#++__validate_deploy__++#++(self: @ContractState, class_hash: felt252, contract_address_salt: felt252, public_key: felt252) → felt252++` [.item-kind]#external# -Validates a https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/Blocks/transactions/#deploy_account_transaction[`DeployAccount` transaction]. +Validates a https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/transactions/#deploy_account_transaction[`DeployAccount` transaction]. See xref:/guides/deployment.adoc[Counterfactual Deployments]. Returns the short string `'VALID'` if valid, otherwise it reverts. @@ -264,7 +264,7 @@ Emitted when a `public_key` is removed. [.contract] [[Account]] -=== `++Account++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/presets/account.cairo[{github-icon},role=heading-link] +=== `++Account++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/presets/account.cairo[{github-icon},role=heading-link] ```javascript use openzeppelin::presets::Account; diff --git a/docs/modules/ROOT/pages/api/erc20.adoc b/docs/modules/ROOT/pages/api/erc20.adoc index ffa1ea671..007dcc717 100644 --- a/docs/modules/ROOT/pages/api/erc20.adoc +++ b/docs/modules/ROOT/pages/api/erc20.adoc @@ -14,7 +14,7 @@ TIP: For an overview of ERC20, read our {erc20-guide}. [.contract] [[IERC20]] -=== `++IERC20++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/token/erc20/interface.cairo[{github-icon},role=heading-link] +=== `++IERC20++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/token/erc20/interface.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```javascript @@ -112,7 +112,7 @@ Emitted when the allowance of a `spender` for an `owner` is set. [.contract] [[IERC20Metadata]] -=== `++IERC20Metadata++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/token/erc20/interface.cairo#L19[{github-icon},role=heading-link] +=== `++IERC20Metadata++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/token/erc20/interface.cairo#L19[{github-icon},role=heading-link] [.hljs-theme-dark] ```javascript @@ -160,7 +160,7 @@ NOTE: This information is only used for _display_ purposes: it in no way affects [.contract] [[ERC20Component]] -=== `++ERC20Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/token/erc20/erc20.cairo[{github-icon},role=heading-link] +=== `++ERC20Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/token/erc20/erc20.cairo[{github-icon},role=heading-link] [.hljs-theme-dark] ```javascript @@ -476,7 +476,7 @@ See <>. [.contract] [[ERC20]] -=== `++ERC20++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/presets/erc20.cairo[{github-icon},role=heading-link] +=== `++ERC20++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/presets/erc20.cairo[{github-icon},role=heading-link] ```javascript use openzeppelin::presets::ERC20; diff --git a/docs/modules/ROOT/pages/api/erc721.adoc b/docs/modules/ROOT/pages/api/erc721.adoc index 02aec447c..e7c154f83 100644 --- a/docs/modules/ROOT/pages/api/erc721.adoc +++ b/docs/modules/ROOT/pages/api/erc721.adoc @@ -602,7 +602,7 @@ Whenever an IERC721 `token_id` token is transferred to this non-account contract [.contract] [[ERC721]] -=== `++ERC721++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/presets/erc721.cairo[{github-icon},role=heading-link] +=== `++ERC721++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/presets/erc721.cairo[{github-icon},role=heading-link] ```javascript use openzeppelin::presets::ERC721; diff --git a/docs/modules/ROOT/pages/api/introspection.adoc b/docs/modules/ROOT/pages/api/introspection.adoc index d5af87f67..85ae501dc 100644 --- a/docs/modules/ROOT/pages/api/introspection.adoc +++ b/docs/modules/ROOT/pages/api/introspection.adoc @@ -10,7 +10,7 @@ Reference of interfaces and utilities related to https://en.wikipedia.org/wiki/T [.contract] [[ISRC5]] -=== `++ISRC5++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/introspection/interface.cairo#L7[{github-icon},role=heading-link] +=== `++ISRC5++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/introspection/interface.cairo#L7[{github-icon},role=heading-link] ```javascript use openzeppelin::introspection::interface::ISRC5; @@ -44,7 +44,7 @@ on how to compute this ID. [.contract] [[SRC5Component]] -=== `++SRC5Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/introspection/src5.cairo[{github-icon},role=heading-link] +=== `++SRC5Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/introspection/src5.cairo[{github-icon},role=heading-link] ```javascript use openzeppelin::introspection::src5::SRC5Component; diff --git a/docs/modules/ROOT/pages/api/security.adoc b/docs/modules/ROOT/pages/api/security.adoc index 9d08bcbea..a3bcce36c 100644 --- a/docs/modules/ROOT/pages/api/security.adoc +++ b/docs/modules/ROOT/pages/api/security.adoc @@ -8,7 +8,7 @@ Reference of components, interfaces and utilities found in the library's `securi [.contract] [[InitializableComponent]] -=== `++InitializableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/security/initializable.cairo[{github-icon},role=heading-link] +=== `++InitializableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/security/initializable.cairo[{github-icon},role=heading-link] ```javascript use openzeppelin::security::InitializableComponent; @@ -58,7 +58,7 @@ Requirements: [.contract] [[PausableComponent]] -=== `++PausableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/security/pausable.cairo[{github-icon},role=heading-link] +=== `++PausableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/security/pausable.cairo[{github-icon},role=heading-link] :Paused: xref:PausableComponent-Paused[Paused] :Unpaused: xref:PausableComponent-Unpaused[Unpaused] @@ -163,7 +163,7 @@ Emitted when the contract is unpaused by `account`. [.contract] [[ReentrancyGuardComponent]] -=== `++ReentrancyGuardComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/security/reentrancyguard.cairo[{github-icon},role=heading-link] +=== `++ReentrancyGuardComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/security/reentrancyguard.cairo[{github-icon},role=heading-link] ```javascript use openzeppelin::security::ReentrancyGuardComponent; diff --git a/docs/modules/ROOT/pages/api/upgrades.adoc b/docs/modules/ROOT/pages/api/upgrades.adoc index 96291b737..fba6b85ae 100644 --- a/docs/modules/ROOT/pages/api/upgrades.adoc +++ b/docs/modules/ROOT/pages/api/upgrades.adoc @@ -9,7 +9,7 @@ Reference of interfaces and utilities related to upgradeability. [.contract] [[IUpgradeable]] -=== `++IUpgradeable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/upgrades/interface.cairo#L3[{github-icon},role=heading-link] +=== `++IUpgradeable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/upgrades/interface.cairo#L3[{github-icon},role=heading-link] :Upgraded: xref:UpgradeableComponent-Upgraded[Upgraded] @@ -38,7 +38,7 @@ NOTE: This function is usually protected by an xref:access.adoc[Access Control] [.contract] [[UpgradeableComponent]] -=== `++UpgradeableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/upgrades/upgradeable.cairo[{github-icon},role=heading-link] +=== `++UpgradeableComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/upgrades/upgradeable.cairo[{github-icon},role=heading-link] ```javascript use openzeppelin::upgrades::upgradeable::UpgradeableComponent; diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index cf85d08b5..d34b0f6c2 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -57,7 +57,7 @@ Install the library by declaring it as a dependency in the project's `Scarb.toml [,text] ---- [dependencies] -openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.8.0" } +openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.8.1" } ---- WARNING: Make sure the tag matches the target release. diff --git a/docs/modules/ROOT/pages/upgrades.adoc b/docs/modules/ROOT/pages/upgrades.adoc index 7ab9e63dc..adfef7ccb 100644 --- a/docs/modules/ROOT/pages/upgrades.adoc +++ b/docs/modules/ROOT/pages/upgrades.adoc @@ -1,7 +1,7 @@ :contract_classes: https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/contract-classes/[Contract Classes] :class_hash: https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/class-hash/[class hash] :replace_class_syscall: https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/system-calls-cairo1/#replace_class[replace_class] -:upgradeable: https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0/src/upgrades/upgradeable.cairo[Upgradeable] +:upgradeable: https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/upgrades/upgradeable.cairo[Upgradeable] :ownable: xref:access.adoc#ownership_and_ownable[Ownable] :i_upgradeable: xref:api/upgrades.adoc#IUpgradeable[IUpgradeable] :library_calls: https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/system-calls-cairo1/#library_call[library calls] diff --git a/docs/modules/ROOT/pages/utilities.adoc b/docs/modules/ROOT/pages/utilities.adoc index 429e4b7da..a962ae92c 100644 --- a/docs/modules/ROOT/pages/utilities.adoc +++ b/docs/modules/ROOT/pages/utilities.adoc @@ -113,7 +113,7 @@ See xref:#serde[`openzeppelin::utils::serde`]. use openzeppelin::utils::selectors; ``` -:selectors: https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0-beta.0/src/utils/selectors.cairo[selectors.cairo] +:selectors: https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1-beta.0/src/utils/selectors.cairo[selectors.cairo] Module containing constants matching multiple selectors used through the library. To see the full list of selectors, see {selectors}. @@ -284,7 +284,7 @@ See xref:#constants[`openzeppelin::tests::utils::constants`]. use openzeppelin::tests::utils::constants; ``` -:constants: https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.0-beta.0/src/tests/utils/constants.cairo[constants.cairo] +:constants: https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1-beta.0/src/tests/utils/constants.cairo[constants.cairo] Module containing constants that are repeatedly used among tests. To see the full list, see {constants}. diff --git a/docs/modules/ROOT/pages/utils/_class_hashes.adoc b/docs/modules/ROOT/pages/utils/_class_hashes.adoc index 81c6225bc..837394e40 100644 --- a/docs/modules/ROOT/pages/utils/_class_hashes.adoc +++ b/docs/modules/ROOT/pages/utils/_class_hashes.adoc @@ -2,9 +2,9 @@ :class-hash-cairo-version: https://crates.io/crates/cairo-lang-compiler/2.3.1[cairo 2.3.1] // Class Hashes -:account-class-hash: 0x016c6081eb34ad1e0c5513234ed0c025b3c7f305902d291bad534cd6474c85bc -:erc20-class-hash: 0x01d7085cee580ba542cdb5709bda80ebfe8bdede664261a3e6af92994d9a1de7 -:erc721-class-hash: 0x04376782cbcd20a05f8e742e96150757383dab737ab3e791b8505ad856756907 +:account-class-hash: 0x061dac032f228abef9c6626f995015233097ae253a7f72d68552db02f2971b8f +:erc20-class-hash: 0x046ded64ae2dead6448e247234bab192a9c483644395b66f2155f2614e5804b0 +:erc721-class-hash: 0x05e5a302b02eca41819fe263420eb8dc96bfb9770a90f55847c4c1337b551635 // Presets page :presets-page: xref:presets.adoc[Compiled class hash] diff --git a/src/access/accesscontrol/accesscontrol.cairo b/src/access/accesscontrol/accesscontrol.cairo index e4a2b0d6c..758b38ecb 100644 --- a/src/access/accesscontrol/accesscontrol.cairo +++ b/src/access/accesscontrol/accesscontrol.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (access/accesscontrol/accesscontrol.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (access/accesscontrol/accesscontrol.cairo) /// # AccessControl Component /// diff --git a/src/access/accesscontrol/dual_accesscontrol.cairo b/src/access/accesscontrol/dual_accesscontrol.cairo index 7ac28dbc0..fc445c30c 100644 --- a/src/access/accesscontrol/dual_accesscontrol.cairo +++ b/src/access/accesscontrol/dual_accesscontrol.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (access/accesscontrol/dual_accesscontrol.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (access/accesscontrol/dual_accesscontrol.cairo) use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; diff --git a/src/access/accesscontrol/interface.cairo b/src/access/accesscontrol/interface.cairo index a949bfc0d..9a9891029 100644 --- a/src/access/accesscontrol/interface.cairo +++ b/src/access/accesscontrol/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (access/accesscontrol/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (access/accesscontrol/interface.cairo) use starknet::ContractAddress; diff --git a/src/access/ownable/dual_ownable.cairo b/src/access/ownable/dual_ownable.cairo index 7a75ab18c..e6241e3c3 100644 --- a/src/access/ownable/dual_ownable.cairo +++ b/src/access/ownable/dual_ownable.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (access/ownable/dual_ownable.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (access/ownable/dual_ownable.cairo) use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; diff --git a/src/access/ownable/interface.cairo b/src/access/ownable/interface.cairo index e350eed8a..34227016c 100644 --- a/src/access/ownable/interface.cairo +++ b/src/access/ownable/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (access/ownable/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (access/ownable/interface.cairo) use starknet::ContractAddress; diff --git a/src/access/ownable/ownable.cairo b/src/access/ownable/ownable.cairo index 9f7ad5dd6..de071e61d 100644 --- a/src/access/ownable/ownable.cairo +++ b/src/access/ownable/ownable.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (access/ownable/ownable.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (access/ownable/ownable.cairo) /// # Ownable Component /// diff --git a/src/account/account.cairo b/src/account/account.cairo index e580424f4..9af836668 100644 --- a/src/account/account.cairo +++ b/src/account/account.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (account/account.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (account/account.cairo) /// # Account Component /// diff --git a/src/account/dual_account.cairo b/src/account/dual_account.cairo index 6576dce52..2a86a0841 100644 --- a/src/account/dual_account.cairo +++ b/src/account/dual_account.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (account/dual_account.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (account/dual_account.cairo) use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; diff --git a/src/account/interface.cairo b/src/account/interface.cairo index 3dbc596ba..9b7063cd1 100644 --- a/src/account/interface.cairo +++ b/src/account/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (account/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (account/interface.cairo) use starknet::ContractAddress; use starknet::account::Call; diff --git a/src/introspection/dual_src5.cairo b/src/introspection/dual_src5.cairo index 2c6e31897..311d558cd 100644 --- a/src/introspection/dual_src5.cairo +++ b/src/introspection/dual_src5.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (introspection/dual_src5.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (introspection/dual_src5.cairo) use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; diff --git a/src/introspection/interface.cairo b/src/introspection/interface.cairo index ccfb0b62e..87247de3d 100644 --- a/src/introspection/interface.cairo +++ b/src/introspection/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (introspection/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (introspection/interface.cairo) const ISRC5_ID: felt252 = 0x3f918d17e5ee77373b56385708f855659a07f75997f365cf87748628532a055; diff --git a/src/introspection/src5.cairo b/src/introspection/src5.cairo index 1b5b1f79f..ef4c3a91d 100644 --- a/src/introspection/src5.cairo +++ b/src/introspection/src5.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (introspection/src5.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (introspection/src5.cairo) /// # SRC5 Component /// diff --git a/src/presets/account.cairo b/src/presets/account.cairo index cd68a92c8..94fea4d97 100644 --- a/src/presets/account.cairo +++ b/src/presets/account.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (presets/account.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (presets/account.cairo) /// # Account Preset /// diff --git a/src/presets/erc20.cairo b/src/presets/erc20.cairo index bb7be6b5e..21d809184 100644 --- a/src/presets/erc20.cairo +++ b/src/presets/erc20.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (presets/erc20.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (presets/erc20.cairo) /// # ERC20 Preset /// diff --git a/src/presets/erc721.cairo b/src/presets/erc721.cairo index 938c65c67..74e816605 100644 --- a/src/presets/erc721.cairo +++ b/src/presets/erc721.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (presets/erc721.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (presets/erc721.cairo) /// # ERC721 Preset /// diff --git a/src/security/initializable.cairo b/src/security/initializable.cairo index 1aa9310f6..7529c53c1 100644 --- a/src/security/initializable.cairo +++ b/src/security/initializable.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (security/initializable.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (security/initializable.cairo) /// # Initializable Component /// diff --git a/src/security/pausable.cairo b/src/security/pausable.cairo index c6442509d..63d053b76 100644 --- a/src/security/pausable.cairo +++ b/src/security/pausable.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (security/pausable.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (security/pausable.cairo) /// # Pausable Component /// diff --git a/src/security/reentrancyguard.cairo b/src/security/reentrancyguard.cairo index e5f908d14..10407b13a 100644 --- a/src/security/reentrancyguard.cairo +++ b/src/security/reentrancyguard.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (security/reentrancyguard.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (security/reentrancyguard.cairo) /// # ReentrancyGuard Component /// diff --git a/src/token/erc20/dual20.cairo b/src/token/erc20/dual20.cairo index 56c84c00e..7cb5a2e1b 100644 --- a/src/token/erc20/dual20.cairo +++ b/src/token/erc20/dual20.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (token/erc20/dual20.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (token/erc20/dual20.cairo) use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; diff --git a/src/token/erc20/erc20.cairo b/src/token/erc20/erc20.cairo index 2198b130f..f17cf2fa2 100644 --- a/src/token/erc20/erc20.cairo +++ b/src/token/erc20/erc20.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (token/erc20/erc20.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (token/erc20/erc20.cairo) /// # ERC20 Component /// @@ -7,7 +7,7 @@ /// non-standard implementations that can be used to create an ERC20 contract. This /// component is agnostic regarding how tokens are created, which means that developers /// must create their own token distribution mechanism. -/// See [the documentation](https://docs.openzeppelin.com/contracts-cairo/0.8.0/guides/erc20-supply) +/// See [the documentation](https://docs.openzeppelin.com/contracts-cairo/0.8.1/guides/erc20-supply) /// for examples. #[starknet::component] mod ERC20Component { diff --git a/src/token/erc20/interface.cairo b/src/token/erc20/interface.cairo index 0ff74267f..0e3f2419b 100644 --- a/src/token/erc20/interface.cairo +++ b/src/token/erc20/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (token/erc20/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (token/erc20/interface.cairo) use starknet::ContractAddress; diff --git a/src/token/erc721/dual721.cairo b/src/token/erc721/dual721.cairo index 88686e6c7..6064962d0 100644 --- a/src/token/erc721/dual721.cairo +++ b/src/token/erc721/dual721.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (token/erc721/dual721.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (token/erc721/dual721.cairo) use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; diff --git a/src/token/erc721/dual721_receiver.cairo b/src/token/erc721/dual721_receiver.cairo index d2ef8fdf8..699619249 100644 --- a/src/token/erc721/dual721_receiver.cairo +++ b/src/token/erc721/dual721_receiver.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (token/erc721/dual721_receiver.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (token/erc721/dual721_receiver.cairo) use openzeppelin::utils::UnwrapAndCast; use openzeppelin::utils::selectors; diff --git a/src/token/erc721/erc721.cairo b/src/token/erc721/erc721.cairo index e47e8f468..a04a6b8dd 100644 --- a/src/token/erc721/erc721.cairo +++ b/src/token/erc721/erc721.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (token/erc721/erc721.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (token/erc721/erc721.cairo) /// # ERC721 Component /// diff --git a/src/token/erc721/erc721_receiver.cairo b/src/token/erc721/erc721_receiver.cairo index bca1de52e..9f628b4c1 100644 --- a/src/token/erc721/erc721_receiver.cairo +++ b/src/token/erc721/erc721_receiver.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (token/erc721/erc721_receiver.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (token/erc721/erc721_receiver.cairo) /// # ERC721Receiver Component /// diff --git a/src/token/erc721/interface.cairo b/src/token/erc721/interface.cairo index b6ee20fa9..e9ab356be 100644 --- a/src/token/erc721/interface.cairo +++ b/src/token/erc721/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (token/erc721/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (token/erc721/interface.cairo) use starknet::ContractAddress; diff --git a/src/upgrades/interface.cairo b/src/upgrades/interface.cairo index 2cc5daff3..a22583bd8 100644 --- a/src/upgrades/interface.cairo +++ b/src/upgrades/interface.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (upgrades/interface.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (upgrades/interface.cairo) use starknet::ClassHash; diff --git a/src/upgrades/upgradeable.cairo b/src/upgrades/upgradeable.cairo index 075a295bf..0cf923a1d 100644 --- a/src/upgrades/upgradeable.cairo +++ b/src/upgrades/upgradeable.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (upgrades/upgradeable.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (upgrades/upgradeable.cairo) /// # Upgradeable Component /// diff --git a/src/utils.cairo b/src/utils.cairo index 6dda24868..6d558f18a 100644 --- a/src/utils.cairo +++ b/src/utils.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (utils.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (utils.cairo) mod selectors; mod serde; diff --git a/src/utils/selectors.cairo b/src/utils/selectors.cairo index 197524c16..2fdba894e 100644 --- a/src/utils/selectors.cairo +++ b/src/utils/selectors.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (utils/selectors.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (utils/selectors.cairo) // // AccessControl diff --git a/src/utils/serde.cairo b/src/utils/serde.cairo index 907fd4ee3..b1f3ca538 100644 --- a/src/utils/serde.cairo +++ b/src/utils/serde.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (utils/serde.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (utils/serde.cairo) trait SerializedAppend { fn append_serde(ref self: Array, value: T); diff --git a/src/utils/unwrap_and_cast.cairo b/src/utils/unwrap_and_cast.cairo index 73e856ef0..12d52638e 100644 --- a/src/utils/unwrap_and_cast.cairo +++ b/src/utils/unwrap_and_cast.cairo @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts for Cairo v0.8.0 (utils/unwrap_and_cast.cairo) +// OpenZeppelin Contracts for Cairo v0.8.1 (utils/unwrap_and_cast.cairo) use starknet::SyscallResult; use starknet::SyscallResultTrait; From 3baa10226ee2ac679beb5926ab4c299ef667e249 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 29 Jan 2024 12:18:18 +0100 Subject: [PATCH 2/5] Improve tests (#864) * feat: mocks improved * feat: add missing mocks * refactor: remove available gas * feat: refactor access assertions * refactor: account assertions * refactor: src5 test assertions * refactor: presets and security tests assertions * refactor: more tests * refactor: token assertions * Update src/tests/token/test_erc20.cairo Co-authored-by: Andrew Fleming * Update src/tests/token/test_erc20.cairo Co-authored-by: Andrew Fleming * feat: apply review updates * Update src/tests/access/test_dual_accesscontrol.cairo Co-authored-by: Andrew Fleming * feat: apply review updates * fix: markdown linter --------- Co-authored-by: Andrew Fleming --- .github/workflows/test.yml | 2 +- CHANGELOG.md | 5 + Scarb.lock | 2 +- Scarb.toml | 9 +- src/tests/access/test_accesscontrol.cairo | 133 ++++----- .../access/test_dual_accesscontrol.cairo | 100 +++---- src/tests/access/test_dual_ownable.cairo | 48 +-- src/tests/access/test_ownable.cairo | 47 +-- src/tests/account/test_account.cairo | 151 ++++------ src/tests/account/test_dual_account.cairo | 60 ++-- src/tests/introspection/test_dual_src5.cairo | 15 +- src/tests/introspection/test_src5.cairo | 19 +- src/tests/mocks.cairo | 7 +- src/tests/mocks/accesscontrol_mocks.cairo | 39 ++- src/tests/mocks/account_mocks.cairo | 33 ++- src/tests/mocks/erc20_mocks.cairo | 25 +- src/tests/mocks/erc721_mocks.cairo | 72 ++--- src/tests/mocks/erc721_receiver_mocks.cairo | 34 +-- ...e_mock.cairo => initializable_mocks.cairo} | 0 src/tests/mocks/ownable_mocks.cairo | 12 +- ...usable_mock.cairo => pausable_mocks.cairo} | 0 .../mocks/reentrancy_attacker_mock.cairo | 23 -- ...ancy_mock.cairo => reentrancy_mocks.cairo} | 32 +- src/tests/mocks/src5_mocks.cairo | 4 +- src/tests/presets/test_account.cairo | 104 +++---- src/tests/presets/test_erc20.cairo | 140 ++++----- src/tests/presets/test_erc721.cairo | 154 ++++------ src/tests/security/test_initializable.cairo | 8 +- src/tests/security/test_pausable.cairo | 28 +- src/tests/security/test_reentrancyguard.cairo | 33 ++- src/tests/token/test_dual20.cairo | 97 +++--- src/tests/token/test_dual721.cairo | 163 ++++------ src/tests/token/test_dual721_receiver.cairo | 27 +- src/tests/token/test_erc20.cairo | 174 +++++------ src/tests/token/test_erc721.cairo | 279 +++++++----------- src/tests/token/test_erc721_receiver.cairo | 32 +- src/tests/upgrades/test_upgradeable.cairo | 13 +- src/tests/utils.cairo | 9 +- src/tests/utils/debug.cairo | 16 + 39 files changed, 930 insertions(+), 1219 deletions(-) rename src/tests/mocks/{initializable_mock.cairo => initializable_mocks.cairo} (100%) rename src/tests/mocks/{pausable_mock.cairo => pausable_mocks.cairo} (100%) delete mode 100644 src/tests/mocks/reentrancy_attacker_mock.cairo rename src/tests/mocks/{reentrancy_mock.cairo => reentrancy_mocks.cairo} (79%) create mode 100644 src/tests/utils/debug.cairo diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ef1f11d2b..7088dfb42 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@v3 - uses: software-mansion/setup-scarb@v1 with: - scarb-version: "2.4.1" + scarb-version: "2.4.4" - name: Markdown lint uses: DavidAnson/markdownlint-cli2-action@5b7c9f74fec47e6b15667b2cc23c63dff11e449e # v9 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index 34f9309ef..44796a95b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ + # Changelog All notable changes to this project will be documented in this file. @@ -7,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Changed + +- Bump scarb to v2.4.4 (#864) + ## 0.8.1 (2024-01-23) ### Added diff --git a/Scarb.lock b/Scarb.lock index b2c02f8ff..e023bf036 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -3,4 +3,4 @@ version = 1 [[package]] name = "openzeppelin" -version = "0.8.1" +version = "0.8.0" diff --git a/Scarb.toml b/Scarb.toml index b6e404463..2b9288378 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -1,7 +1,8 @@ [package] name = "openzeppelin" -version = "0.8.1" -cairo-version = "2.4.1" +version = "0.8.0" +edition = "2023_01" +cairo-version = "2.4.4" authors = ["OpenZeppelin Community "] description = "OpenZeppelin Contracts written in Cairo for StarkNet, a decentralized ZK Rollup" documentation = "https://docs.openzeppelin.com/contracts-cairo" @@ -11,14 +12,14 @@ license-file = "LICENSE" keywords = ["openzeppelin", "starknet", "cairo", "contracts", "security", "standards"] [dependencies] -starknet = "2.4.1" +starknet = "2.4.4" [lib] [[target.starknet-contract]] allowed-libfuncs-list.name = "experimental" sierra = true -casm = false +casm = true [tool.fmt] sort-module-level-items = true diff --git a/src/tests/access/test_accesscontrol.cairo b/src/tests/access/test_accesscontrol.cairo index 018ae499b..ac97f0d52 100644 --- a/src/tests/access/test_accesscontrol.cairo +++ b/src/tests/access/test_accesscontrol.cairo @@ -11,6 +11,7 @@ use openzeppelin::tests::mocks::accesscontrol_mocks::DualCaseAccessControlMock; use openzeppelin::tests::utils::constants::{ ADMIN, AUTHORIZED, OTHER, OTHER_ADMIN, ROLE, OTHER_ROLE, ZERO }; +use openzeppelin::tests::utils::debug::DebugContractAddress; use openzeppelin::tests::utils; use starknet::ContractAddress; use starknet::testing; @@ -42,11 +43,11 @@ fn setup() -> ComponentState { // #[test] -#[available_gas(2000000)] fn test_initializer() { let mut state = COMPONENT_STATE(); state.initializer(); - assert(CONTRACT_STATE().supports_interface(IACCESSCONTROL_ID), 'Should support own interface'); + let supports_iaccesscontrol = CONTRACT_STATE().supports_interface(IACCESSCONTROL_ID); + assert!(supports_iaccesscontrol); } // @@ -54,21 +55,19 @@ fn test_initializer() { // #[test] -#[available_gas(2000000)] fn test_has_role() { let mut state = setup(); - assert(!state.has_role(ROLE, AUTHORIZED()), 'should not have role'); + assert!(!state.has_role(ROLE, AUTHORIZED())); state._grant_role(ROLE, AUTHORIZED()); - assert(state.has_role(ROLE, AUTHORIZED()), 'should have role'); + assert!(state.has_role(ROLE, AUTHORIZED())); } #[test] -#[available_gas(2000000)] fn test_hasRole() { let mut state = setup(); - assert(!state.hasRole(ROLE, AUTHORIZED()), 'should not have role'); + assert!(!state.hasRole(ROLE, AUTHORIZED())); state._grant_role(ROLE, AUTHORIZED()); - assert(state.hasRole(ROLE, AUTHORIZED()), 'should have role'); + assert!(state.hasRole(ROLE, AUTHORIZED())); } // @@ -76,7 +75,6 @@ fn test_hasRole() { // #[test] -#[available_gas(2000000)] fn test_assert_only_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); @@ -87,7 +85,6 @@ fn test_assert_only_role() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is missing role',))] fn test_assert_only_role_unauthorized() { let state = setup(); @@ -96,7 +93,6 @@ fn test_assert_only_role_unauthorized() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is missing role',))] fn test_assert_only_role_unauthorized_when_authorized_for_another_role() { let mut state = setup(); @@ -111,51 +107,50 @@ fn test_assert_only_role_unauthorized_when_authorized_for_another_role() { // #[test] -#[available_gas(2000000)] fn test_grant_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); state.grant_role(ROLE, AUTHORIZED()); assert_event_role_granted(ROLE, AUTHORIZED(), ADMIN()); - assert(state.has_role(ROLE, AUTHORIZED()), 'Role should be granted'); + + let has_role = state.has_role(ROLE, AUTHORIZED()); + assert!(has_role); } #[test] -#[available_gas(2000000)] fn test_grantRole() { let mut state = setup(); testing::set_caller_address(ADMIN()); state.grantRole(ROLE, AUTHORIZED()); assert_event_role_granted(ROLE, AUTHORIZED(), ADMIN()); - assert(state.hasRole(ROLE, AUTHORIZED()), 'Role should be granted'); + + let has_role = state.hasRole(ROLE, AUTHORIZED()); + assert!(has_role); } #[test] -#[available_gas(2000000)] fn test_grant_role_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); state.grant_role(ROLE, AUTHORIZED()); state.grant_role(ROLE, AUTHORIZED()); - assert(state.has_role(ROLE, AUTHORIZED()), 'Role should still be granted'); + assert!(state.has_role(ROLE, AUTHORIZED())); } #[test] -#[available_gas(2000000)] fn test_grantRole_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); state.grantRole(ROLE, AUTHORIZED()); state.grantRole(ROLE, AUTHORIZED()); - assert(state.hasRole(ROLE, AUTHORIZED()), 'Role should still be granted'); + assert!(state.hasRole(ROLE, AUTHORIZED())); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is missing role',))] fn test_grant_role_unauthorized() { let mut state = setup(); @@ -164,7 +159,6 @@ fn test_grant_role_unauthorized() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is missing role',))] fn test_grantRole_unauthorized() { let mut state = setup(); @@ -177,7 +171,6 @@ fn test_grantRole_unauthorized() { // #[test] -#[available_gas(2000000)] fn test_revoke_role_for_role_not_granted() { let mut state = setup(); testing::set_caller_address(ADMIN()); @@ -185,7 +178,6 @@ fn test_revoke_role_for_role_not_granted() { } #[test] -#[available_gas(2000000)] fn test_revokeRole_for_role_not_granted() { let mut state = setup(); testing::set_caller_address(ADMIN()); @@ -193,7 +185,6 @@ fn test_revokeRole_for_role_not_granted() { } #[test] -#[available_gas(2000000)] fn test_revoke_role_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); @@ -204,11 +195,12 @@ fn test_revoke_role_for_granted_role() { state.revoke_role(ROLE, AUTHORIZED()); assert_event_role_revoked(ROLE, AUTHORIZED(), ADMIN()); - assert(!state.has_role(ROLE, AUTHORIZED()), 'Role should be revoked'); + + let has_not_role = !state.has_role(ROLE, AUTHORIZED()); + assert!(has_not_role); } #[test] -#[available_gas(2000000)] fn test_revokeRole_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); @@ -219,11 +211,12 @@ fn test_revokeRole_for_granted_role() { state.revokeRole(ROLE, AUTHORIZED()); assert_event_role_revoked(ROLE, AUTHORIZED(), ADMIN()); - assert(!state.hasRole(ROLE, AUTHORIZED()), 'Role should be revoked'); + + let has_not_role = !state.hasRole(ROLE, AUTHORIZED()); + assert!(has_not_role); } #[test] -#[available_gas(2000000)] fn test_revoke_role_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); @@ -231,11 +224,12 @@ fn test_revoke_role_multiple_times_for_granted_role() { state.grant_role(ROLE, AUTHORIZED()); state.revoke_role(ROLE, AUTHORIZED()); state.revoke_role(ROLE, AUTHORIZED()); - assert(!state.has_role(ROLE, AUTHORIZED()), 'Role should still be revoked'); + + let has_not_role = !state.has_role(ROLE, AUTHORIZED()); + assert!(has_not_role); } #[test] -#[available_gas(2000000)] fn test_revokeRole_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); @@ -243,11 +237,12 @@ fn test_revokeRole_multiple_times_for_granted_role() { state.grantRole(ROLE, AUTHORIZED()); state.revokeRole(ROLE, AUTHORIZED()); state.revokeRole(ROLE, AUTHORIZED()); - assert(!state.hasRole(ROLE, AUTHORIZED()), 'Role should still be revoked'); + + let has_not_role = !state.hasRole(ROLE, AUTHORIZED()); + assert!(has_not_role); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is missing role',))] fn test_revoke_role_unauthorized() { let mut state = setup(); @@ -256,7 +251,6 @@ fn test_revoke_role_unauthorized() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is missing role',))] fn test_revokeRole_unauthorized() { let mut state = setup(); @@ -269,7 +263,6 @@ fn test_revokeRole_unauthorized() { // #[test] -#[available_gas(2000000)] fn test_renounce_role_for_role_not_granted() { let mut state = setup(); testing::set_caller_address(AUTHORIZED()); @@ -277,7 +270,6 @@ fn test_renounce_role_for_role_not_granted() { } #[test] -#[available_gas(2000000)] fn test_renounceRole_for_role_not_granted() { let mut state = setup(); testing::set_caller_address(AUTHORIZED()); @@ -285,7 +277,6 @@ fn test_renounceRole_for_role_not_granted() { } #[test] -#[available_gas(2000000)] fn test_renounce_role_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); @@ -297,11 +288,12 @@ fn test_renounce_role_for_granted_role() { state.renounce_role(ROLE, AUTHORIZED()); assert_event_role_revoked(ROLE, AUTHORIZED(), AUTHORIZED()); - assert(!state.has_role(ROLE, AUTHORIZED()), 'Role should be renounced'); + + let has_not_role = !state.has_role(ROLE, AUTHORIZED()); + assert!(has_not_role); } #[test] -#[available_gas(2000000)] fn test_renounceRole_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); @@ -313,11 +305,12 @@ fn test_renounceRole_for_granted_role() { state.renounceRole(ROLE, AUTHORIZED()); assert_event_role_revoked(ROLE, AUTHORIZED(), AUTHORIZED()); - assert(!state.hasRole(ROLE, AUTHORIZED()), 'Role should be renounced'); + + let has_not_role = !state.hasRole(ROLE, AUTHORIZED()); + assert!(has_not_role); } #[test] -#[available_gas(2000000)] fn test_renounce_role_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); @@ -326,11 +319,12 @@ fn test_renounce_role_multiple_times_for_granted_role() { testing::set_caller_address(AUTHORIZED()); state.renounce_role(ROLE, AUTHORIZED()); state.renounce_role(ROLE, AUTHORIZED()); - assert(!state.has_role(ROLE, AUTHORIZED()), 'Role should still be renounced'); + + let has_not_role = !state.has_role(ROLE, AUTHORIZED()); + assert!(has_not_role); } #[test] -#[available_gas(2000000)] fn test_renounceRole_multiple_times_for_granted_role() { let mut state = setup(); testing::set_caller_address(ADMIN()); @@ -339,11 +333,12 @@ fn test_renounceRole_multiple_times_for_granted_role() { testing::set_caller_address(AUTHORIZED()); state.renounceRole(ROLE, AUTHORIZED()); state.renounceRole(ROLE, AUTHORIZED()); - assert(!state.hasRole(ROLE, AUTHORIZED()), 'Role should still be renounced'); + + let has_not_role = !state.hasRole(ROLE, AUTHORIZED()); + assert!(has_not_role); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Can only renounce role for self',))] fn test_renounce_role_unauthorized() { let mut state = setup(); @@ -355,7 +350,6 @@ fn test_renounce_role_unauthorized() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Can only renounce role for self',))] fn test_renounceRole_unauthorized() { let mut state = setup(); @@ -371,18 +365,18 @@ fn test_renounceRole_unauthorized() { // #[test] -#[available_gas(2000000)] fn test__set_role_admin() { let mut state = setup(); - assert(state.get_role_admin(ROLE) == DEFAULT_ADMIN_ROLE, 'ROLE admin default should be 0'); + assert_eq!(state.get_role_admin(ROLE), DEFAULT_ADMIN_ROLE); state._set_role_admin(ROLE, OTHER_ROLE); assert_event_role_admin_changed(ROLE, DEFAULT_ADMIN_ROLE, OTHER_ROLE); - assert(state.get_role_admin(ROLE) == OTHER_ROLE, 'ROLE admin should be OTHER_ROLE'); + + let current_admin_role = state.get_role_admin(ROLE); + assert_eq!(current_admin_role, OTHER_ROLE); } #[test] -#[available_gas(2000000)] fn test_new_admin_can_grant_roles() { let mut state = setup(); state._set_role_admin(ROLE, OTHER_ROLE); @@ -392,11 +386,12 @@ fn test_new_admin_can_grant_roles() { testing::set_caller_address(OTHER_ADMIN()); state.grant_role(ROLE, AUTHORIZED()); - assert(state.has_role(ROLE, AUTHORIZED()), 'AUTHORIZED should have ROLE'); + + let has_role = state.has_role(ROLE, AUTHORIZED()); + assert!(has_role); } #[test] -#[available_gas(2000000)] fn test_new_admin_can_revoke_roles() { let mut state = setup(); state._set_role_admin(ROLE, OTHER_ROLE); @@ -407,11 +402,12 @@ fn test_new_admin_can_revoke_roles() { testing::set_caller_address(OTHER_ADMIN()); state.grant_role(ROLE, AUTHORIZED()); state.revoke_role(ROLE, AUTHORIZED()); - assert(!state.has_role(ROLE, AUTHORIZED()), 'AUTHORIZED should not have ROLE'); + + let has_not_role = !state.has_role(ROLE, AUTHORIZED()); + assert!(has_not_role); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is missing role',))] fn test_previous_admin_cannot_grant_roles() { let mut state = setup(); @@ -421,7 +417,6 @@ fn test_previous_admin_cannot_grant_roles() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is missing role',))] fn test_previous_admin_cannot_revoke_roles() { let mut state = setup(); @@ -435,20 +430,18 @@ fn test_previous_admin_cannot_revoke_roles() { // #[test] -#[available_gas(2000000)] fn test_other_role_admin_is_the_default_admin_role() { let state = setup(); - assert(state.get_role_admin(OTHER_ROLE) == DEFAULT_ADMIN_ROLE, 'Should be DEFAULT_ADMIN_ROLE'); + + let current_admin_role = state.get_role_admin(OTHER_ROLE); + assert_eq!(current_admin_role, DEFAULT_ADMIN_ROLE); } #[test] -#[available_gas(2000000)] fn test_default_admin_role_is_its_own_admin() { let state = setup(); - assert( - state.get_role_admin(DEFAULT_ADMIN_ROLE) == DEFAULT_ADMIN_ROLE, - 'Should be DEFAULT_ADMIN_ROLE' - ); + let current_admin_role = state.get_role_admin(DEFAULT_ADMIN_ROLE); + assert_eq!(current_admin_role, DEFAULT_ADMIN_ROLE); } // @@ -457,17 +450,17 @@ fn test_default_admin_role_is_its_own_admin() { fn assert_event_role_revoked(role: felt252, account: ContractAddress, sender: ContractAddress) { let event = utils::pop_log::(ZERO()).unwrap(); - assert(event.role == role, 'Invalid `role`'); - assert(event.account == account, 'Invalid `account`'); - assert(event.sender == sender, 'Invalid `sender`'); + assert_eq!(event.role, role); + assert_eq!(event.account, account); + assert_eq!(event.sender, sender); utils::assert_no_events_left(ZERO()); } fn assert_event_role_granted(role: felt252, account: ContractAddress, sender: ContractAddress) { let event = utils::pop_log::(ZERO()).unwrap(); - assert(event.role == role, 'Invalid `role`'); - assert(event.account == account, 'Invalid `account`'); - assert(event.sender == sender, 'Invalid `sender`'); + assert_eq!(event.role, role); + assert_eq!(event.account, account); + assert_eq!(event.sender, sender); utils::assert_no_events_left(ZERO()); } @@ -475,8 +468,8 @@ fn assert_event_role_admin_changed( role: felt252, previous_admin_role: felt252, new_admin_role: felt252 ) { let event = utils::pop_log::(ZERO()).unwrap(); - assert(event.role == role, 'Invalid `role`'); - assert(event.previous_admin_role == previous_admin_role, 'Invalid `previous_admin_role`'); - assert(event.new_admin_role == new_admin_role, 'Invalid `new_admin_role`'); + assert_eq!(event.role, role); + assert_eq!(event.previous_admin_role, previous_admin_role); + assert_eq!(event.new_admin_role, new_admin_role); utils::assert_no_events_left(ZERO()); } diff --git a/src/tests/access/test_dual_accesscontrol.cairo b/src/tests/access/test_dual_accesscontrol.cairo index 5c61e4d36..aaafe9f71 100644 --- a/src/tests/access/test_dual_accesscontrol.cairo +++ b/src/tests/access/test_dual_accesscontrol.cairo @@ -61,14 +61,13 @@ fn setup_accesscontrol_panic() -> (DualCaseAccessControl, DualCaseAccessControl) // #[test] -#[available_gas(2000000)] fn test_dual_supports_interface() { let (dispatcher, _) = setup_snake(); - assert(dispatcher.supports_interface(IACCESSCONTROL_ID), 'Should support own interface'); + let supports_iaccesscontrol = dispatcher.supports_interface(IACCESSCONTROL_ID); + assert!(supports_iaccesscontrol); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_supports_interface() { let dispatcher = setup_non_accesscontrol(); @@ -76,22 +75,20 @@ fn test_dual_no_supports_interface() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_supports_interface_exists_and_panics() { let (dispatcher, _) = setup_accesscontrol_panic(); dispatcher.supports_interface(IACCESSCONTROL_ID); } #[test] -#[available_gas(2000000)] fn test_dual_has_role() { let (dispatcher, _) = setup_snake(); - assert(dispatcher.has_role(DEFAULT_ADMIN_ROLE, ADMIN()), 'Should have role'); + let has_role = dispatcher.has_role(DEFAULT_ADMIN_ROLE, ADMIN()); + assert!(has_role); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_has_role() { let dispatcher = setup_non_accesscontrol(); @@ -99,22 +96,21 @@ fn test_dual_no_has_role() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_has_role_exists_and_panics() { let (dispatcher, _) = setup_accesscontrol_panic(); dispatcher.has_role(DEFAULT_ADMIN_ROLE, ADMIN()); } #[test] -#[available_gas(2000000)] fn test_dual_get_role_admin() { let (dispatcher, _) = setup_snake(); - assert(dispatcher.get_role_admin(ROLE) == DEFAULT_ADMIN_ROLE, 'Should get admin'); + + let current_admin_role = dispatcher.get_role_admin(ROLE); + assert_eq!(current_admin_role, DEFAULT_ADMIN_ROLE); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_get_role_admin() { let dispatcher = setup_non_accesscontrol(); @@ -122,24 +118,23 @@ fn test_dual_no_get_role_admin() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_get_role_admin_exists_and_panics() { let (dispatcher, _) = setup_accesscontrol_panic(); dispatcher.get_role_admin(ROLE); } #[test] -#[available_gas(2000000)] fn test_dual_grant_role() { let (dispatcher, target) = setup_snake(); set_contract_address(ADMIN()); dispatcher.grant_role(ROLE, AUTHORIZED()); - assert(target.has_role(ROLE, AUTHORIZED()), 'Should grant role'); + + let has_role = target.has_role(ROLE, AUTHORIZED()); + assert!(has_role); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_grant_role() { let dispatcher = setup_non_accesscontrol(); @@ -147,24 +142,23 @@ fn test_dual_no_grant_role() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_grant_role_exists_and_panics() { let (dispatcher, _) = setup_accesscontrol_panic(); dispatcher.grant_role(ROLE, AUTHORIZED()); } #[test] -#[available_gas(2000000)] fn test_dual_revoke_role() { let (dispatcher, target) = setup_snake(); set_contract_address(ADMIN()); dispatcher.revoke_role(ROLE, AUTHORIZED()); - assert(!target.has_role(ROLE, AUTHORIZED()), 'Should revoke role'); + + let has_not_role = !target.has_role(ROLE, AUTHORIZED()); + assert!(has_not_role); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_revoke_role() { let dispatcher = setup_non_accesscontrol(); @@ -172,24 +166,23 @@ fn test_dual_no_revoke_role() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_revoke_role_exists_and_panics() { let (dispatcher, _) = setup_accesscontrol_panic(); dispatcher.revoke_role(ROLE, AUTHORIZED()); } #[test] -#[available_gas(2000000)] fn test_dual_renounce_role() { let (dispatcher, target) = setup_snake(); set_contract_address(ADMIN()); dispatcher.renounce_role(DEFAULT_ADMIN_ROLE, ADMIN()); - assert(!target.has_role(DEFAULT_ADMIN_ROLE, ADMIN()), 'Should renounce role'); + + let has_not_role = !target.has_role(DEFAULT_ADMIN_ROLE, ADMIN()); + assert!(has_not_role); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_renounce_role() { let dispatcher = setup_non_accesscontrol(); @@ -197,8 +190,7 @@ fn test_dual_no_renounce_role() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_renounce_role_exists_and_panics() { let (dispatcher, _) = setup_accesscontrol_panic(); dispatcher.renounce_role(DEFAULT_ADMIN_ROLE, ADMIN()); @@ -209,97 +201,97 @@ fn test_dual_renounce_role_exists_and_panics() { // #[test] -#[available_gas(2000000)] fn test_dual_supportsInterface() { let (dispatcher, _) = setup_camel(); - assert(dispatcher.supports_interface(IACCESSCONTROL_ID), 'Should support own interface'); + + let supports_iaccesscontrol = dispatcher.supports_interface(IACCESSCONTROL_ID); + assert!(supports_iaccesscontrol); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_supportsInterface_exists_and_panics() { let (_, dispatcher) = setup_accesscontrol_panic(); dispatcher.supports_interface(IACCESSCONTROL_ID); } #[test] -#[available_gas(2000000)] fn test_dual_hasRole() { let (dispatcher, _) = setup_camel(); - assert(dispatcher.has_role(DEFAULT_ADMIN_ROLE, ADMIN()), 'Should have role'); + + let has_role = dispatcher.has_role(DEFAULT_ADMIN_ROLE, ADMIN()); + assert!(has_role); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_hasRole_exists_and_panics() { let (_, dispatcher) = setup_accesscontrol_panic(); dispatcher.has_role(DEFAULT_ADMIN_ROLE, ADMIN()); } #[test] -#[available_gas(2000000)] fn test_dual_getRoleAdmin() { let (dispatcher, _) = setup_camel(); - assert(dispatcher.get_role_admin(ROLE) == DEFAULT_ADMIN_ROLE, 'Should get admin'); + + let current_admin_role = dispatcher.get_role_admin(ROLE); + assert_eq!(current_admin_role, DEFAULT_ADMIN_ROLE); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_getRoleAdmin_exists_and_panics() { let (_, dispatcher) = setup_accesscontrol_panic(); dispatcher.get_role_admin(ROLE); } #[test] -#[available_gas(2000000)] fn test_dual_grantRole() { let (dispatcher, target) = setup_camel(); set_contract_address(ADMIN()); dispatcher.grant_role(ROLE, AUTHORIZED()); - assert(target.hasRole(ROLE, AUTHORIZED()), 'Should grant role'); + + let has_role = target.hasRole(ROLE, AUTHORIZED()); + assert!(has_role); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_grantRole_exists_and_panics() { let (_, dispatcher) = setup_accesscontrol_panic(); dispatcher.grant_role(ROLE, AUTHORIZED()); } #[test] -#[available_gas(2000000)] fn test_dual_revokeRole() { let (dispatcher, target) = setup_camel(); set_contract_address(ADMIN()); dispatcher.grant_role(ROLE, AUTHORIZED()); dispatcher.revoke_role(ROLE, AUTHORIZED()); - assert(!target.hasRole(ROLE, AUTHORIZED()), 'Should revoke role'); + + let has_not_role = !target.hasRole(ROLE, AUTHORIZED()); + assert!(has_not_role); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_revokeRole_exists_and_panics() { let (_, dispatcher) = setup_accesscontrol_panic(); dispatcher.revoke_role(ROLE, AUTHORIZED()); } #[test] -#[available_gas(2000000)] fn test_dual_renounceRole() { let (dispatcher, target) = setup_camel(); set_contract_address(ADMIN()); dispatcher.renounce_role(DEFAULT_ADMIN_ROLE, ADMIN()); - assert(!target.hasRole(DEFAULT_ADMIN_ROLE, ADMIN()), 'Should renounce role'); + + let has_not_role = !target.hasRole(DEFAULT_ADMIN_ROLE, ADMIN()); + assert!(has_not_role); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_renounceRole_exists_and_panics() { let (_, dispatcher) = setup_accesscontrol_panic(); dispatcher.renounce_role(DEFAULT_ADMIN_ROLE, ADMIN()); diff --git a/src/tests/access/test_dual_ownable.cairo b/src/tests/access/test_dual_ownable.cairo index 16588be16..5e13b0057 100644 --- a/src/tests/access/test_dual_ownable.cairo +++ b/src/tests/access/test_dual_ownable.cairo @@ -8,6 +8,7 @@ use openzeppelin::tests::mocks::ownable_mocks::{ CamelOwnableMock, CamelOwnablePanicMock, SnakeOwnableMock, SnakeOwnablePanicMock }; use openzeppelin::tests::utils::constants::{OWNER, NEW_OWNER}; +use openzeppelin::tests::utils::debug::DebugContractAddress; use openzeppelin::tests::utils; use openzeppelin::utils::serde::SerializedAppend; use starknet::testing::set_contract_address; @@ -53,16 +54,18 @@ fn setup_ownable_panic() -> (DualCaseOwnable, DualCaseOwnable) { // #[test] -#[available_gas(2000000)] fn test_dual_owner() { let (snake_dispatcher, _) = setup_snake(); let (camel_dispatcher, _) = setup_camel(); - assert(snake_dispatcher.owner() == OWNER(), 'Should return OWNER'); - assert(camel_dispatcher.owner() == OWNER(), 'Should return OWNER'); + + let snake_owner = snake_dispatcher.owner(); + assert_eq!(snake_owner, OWNER()); + + let camel_owner = camel_dispatcher.owner(); + assert_eq!(camel_owner, OWNER()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_owner() { let dispatcher = setup_non_ownable(); @@ -70,8 +73,7 @@ fn test_dual_no_owner() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_owner_exists_and_panics() { let (dispatcher, _) = setup_ownable_panic(); dispatcher.owner(); @@ -82,16 +84,16 @@ fn test_dual_owner_exists_and_panics() { // #[test] -#[available_gas(2000000)] fn test_dual_transfer_ownership() { let (dispatcher, target) = setup_snake(); set_contract_address(OWNER()); dispatcher.transfer_ownership(NEW_OWNER()); - assert(target.owner() == NEW_OWNER(), 'Should be new owner'); + + let current_owner = target.owner(); + assert_eq!(current_owner, NEW_OWNER()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_transfer_ownership() { let dispatcher = setup_non_ownable(); @@ -99,24 +101,23 @@ fn test_dual_no_transfer_ownership() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_transfer_ownership_exists_and_panics() { let (dispatcher, _) = setup_ownable_panic(); dispatcher.transfer_ownership(NEW_OWNER()); } #[test] -#[available_gas(2000000)] fn test_dual_renounce_ownership() { let (dispatcher, target) = setup_snake(); set_contract_address(OWNER()); dispatcher.renounce_ownership(); - assert(target.owner().is_zero(), 'Should be zero'); + + let current_owner = target.owner(); + assert!(current_owner.is_zero()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_renounce_ownership() { let dispatcher = setup_non_ownable(); @@ -124,8 +125,7 @@ fn test_dual_no_renounce_ownership() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_renounce_ownership_exists_and_panics() { let (dispatcher, _) = setup_ownable_panic(); dispatcher.renounce_ownership(); @@ -136,34 +136,34 @@ fn test_dual_renounce_ownership_exists_and_panics() { // #[test] -#[available_gas(2000000)] fn test_dual_transferOwnership() { let (dispatcher, _) = setup_camel(); set_contract_address(OWNER()); dispatcher.transfer_ownership(NEW_OWNER()); - assert(dispatcher.owner() == NEW_OWNER(), 'Should be new owner'); + + let current_owner = dispatcher.owner(); + assert_eq!(current_owner, NEW_OWNER()); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_transferOwnership_exists_and_panics() { let (_, dispatcher) = setup_ownable_panic(); dispatcher.transfer_ownership(NEW_OWNER()); } #[test] -#[available_gas(2000000)] fn test_dual_renounceOwnership() { let (dispatcher, _) = setup_camel(); set_contract_address(OWNER()); dispatcher.renounce_ownership(); - assert(dispatcher.owner().is_zero(), 'Should be zero'); + + let current_owner = dispatcher.owner(); + assert!(current_owner.is_zero()); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_renounceOwnership_exists_and_panics() { let (_, dispatcher) = setup_ownable_panic(); dispatcher.renounce_ownership(); diff --git a/src/tests/access/test_ownable.cairo b/src/tests/access/test_ownable.cairo index 29dca9fe7..c7d47e063 100644 --- a/src/tests/access/test_ownable.cairo +++ b/src/tests/access/test_ownable.cairo @@ -4,6 +4,7 @@ use openzeppelin::access::ownable::OwnableComponent; use openzeppelin::access::ownable::interface::{IOwnable, IOwnableCamelOnly}; use openzeppelin::tests::mocks::ownable_mocks::DualCaseOwnableMock; use openzeppelin::tests::utils::constants::{ZERO, OTHER, OWNER}; +use openzeppelin::tests::utils::debug::DebugContractAddress; use openzeppelin::tests::utils; use starknet::ContractAddress; use starknet::storage::StorageMemberAccessTrait; @@ -31,15 +32,18 @@ fn setup() -> ComponentState { // #[test] -#[available_gas(2000000)] fn test_initializer_owner() { let mut state = COMPONENT_STATE(); - assert(state.Ownable_owner.read().is_zero(), 'Should be zero'); + + let current_owner = state.Ownable_owner.read(); + assert!(current_owner.is_zero()); + state.initializer(OWNER()); assert_event_ownership_transferred(ZERO(), OWNER()); - assert(state.Ownable_owner.read() == OWNER(), 'Owner should be set'); + let new_owner = state.Ownable_owner.read(); + assert_eq!(new_owner, OWNER()); } // @@ -47,7 +51,6 @@ fn test_initializer_owner() { // #[test] -#[available_gas(2000000)] fn test_assert_only_owner() { let state = setup(); testing::set_caller_address(OWNER()); @@ -55,7 +58,6 @@ fn test_assert_only_owner() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is not the owner',))] fn test_assert_only_owner_when_not_owner() { let state = setup(); @@ -64,7 +66,6 @@ fn test_assert_only_owner_when_not_owner() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is the zero address',))] fn test_assert_only_owner_when_caller_zero() { let state = setup(); @@ -76,14 +77,14 @@ fn test_assert_only_owner_when_caller_zero() { // #[test] -#[available_gas(2000000)] fn test__transfer_ownership() { let mut state = setup(); state._transfer_ownership(OTHER()); assert_event_ownership_transferred(OWNER(), OTHER()); - assert(state.Ownable_owner.read() == OTHER(), 'Owner should be OTHER'); + let current_owner = state.Ownable_owner.read(); + assert_eq!(current_owner, OTHER()); } // @@ -91,19 +92,16 @@ fn test__transfer_ownership() { // #[test] -#[available_gas(2000000)] fn test_transfer_ownership() { let mut state = setup(); testing::set_caller_address(OWNER()); state.transfer_ownership(OTHER()); assert_event_ownership_transferred(OWNER(), OTHER()); - - assert(state.owner() == OTHER(), 'Should transfer ownership'); + assert_eq!(state.owner(), OTHER()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('New owner is the zero address',))] fn test_transfer_ownership_to_zero() { let mut state = setup(); @@ -112,7 +110,6 @@ fn test_transfer_ownership_to_zero() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is the zero address',))] fn test_transfer_ownership_from_zero() { let mut state = setup(); @@ -120,7 +117,6 @@ fn test_transfer_ownership_from_zero() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is not the owner',))] fn test_transfer_ownership_from_nonowner() { let mut state = setup(); @@ -129,19 +125,16 @@ fn test_transfer_ownership_from_nonowner() { } #[test] -#[available_gas(2000000)] fn test_transferOwnership() { let mut state = setup(); testing::set_caller_address(OWNER()); state.transferOwnership(OTHER()); assert_event_ownership_transferred(OWNER(), OTHER()); - - assert(state.owner() == OTHER(), 'Should transfer ownership'); + assert_eq!(state.owner(), OTHER()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('New owner is the zero address',))] fn test_transferOwnership_to_zero() { let mut state = setup(); @@ -150,7 +143,6 @@ fn test_transferOwnership_to_zero() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is the zero address',))] fn test_transferOwnership_from_zero() { let mut state = setup(); @@ -158,7 +150,6 @@ fn test_transferOwnership_from_zero() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is not the owner',))] fn test_transferOwnership_from_nonowner() { let mut state = setup(); @@ -171,19 +162,16 @@ fn test_transferOwnership_from_nonowner() { // #[test] -#[available_gas(2000000)] fn test_renounce_ownership() { let mut state = setup(); testing::set_caller_address(OWNER()); state.renounce_ownership(); assert_event_ownership_transferred(OWNER(), ZERO()); - - assert(state.owner() == ZERO(), 'Should renounce ownership'); + assert!(state.owner().is_zero()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is the zero address',))] fn test_renounce_ownership_from_zero_address() { let mut state = setup(); @@ -191,7 +179,6 @@ fn test_renounce_ownership_from_zero_address() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is not the owner',))] fn test_renounce_ownership_from_nonowner() { let mut state = setup(); @@ -200,19 +187,16 @@ fn test_renounce_ownership_from_nonowner() { } #[test] -#[available_gas(2000000)] fn test_renounceOwnership() { let mut state = setup(); testing::set_caller_address(OWNER()); state.renounceOwnership(); assert_event_ownership_transferred(OWNER(), ZERO()); - - assert(state.owner() == ZERO(), 'Should renounce ownership'); + assert!(state.owner().is_zero()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is the zero address',))] fn test_renounceOwnership_from_zero_address() { let mut state = setup(); @@ -220,7 +204,6 @@ fn test_renounceOwnership_from_zero_address() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Caller is not the owner',))] fn test_renounceOwnership_from_nonowner() { let mut state = setup(); @@ -234,7 +217,7 @@ fn test_renounceOwnership_from_nonowner() { fn assert_event_ownership_transferred(previous_owner: ContractAddress, new_owner: ContractAddress) { let event = utils::pop_log::(ZERO()).unwrap(); - assert(event.previous_owner == previous_owner, 'Invalid `previous_owner`'); - assert(event.new_owner == new_owner, 'Invalid `new_owner`'); + assert_eq!(event.previous_owner, previous_owner); + assert_eq!(event.new_owner, new_owner); utils::assert_no_events_left(ZERO()); } diff --git a/src/tests/account/test_account.cairo b/src/tests/account/test_account.cairo index 681a6c5bc..309c777a8 100644 --- a/src/tests/account/test_account.cairo +++ b/src/tests/account/test_account.cairo @@ -107,7 +107,6 @@ fn deploy_erc20(recipient: ContractAddress, initial_supply: u256) -> IERC20Dispa // #[test] -#[available_gas(2000000)] fn test_is_valid_signature() { let mut state = COMPONENT_STATE(); let data = SIGNED_TX_DATA(); @@ -119,14 +118,13 @@ fn test_is_valid_signature() { state.set_public_key(data.public_key); let is_valid = state.is_valid_signature(hash, good_signature); - assert(is_valid == starknet::VALIDATED, 'Should accept valid signature'); + assert_eq!(is_valid, starknet::VALIDATED); let is_valid = state.is_valid_signature(hash, bad_signature); - assert(is_valid == 0, 'Should reject invalid signature'); + assert!(is_valid.is_zero(), "Should reject invalid signature"); } #[test] -#[available_gas(2000000)] fn test_isValidSignature() { let mut state = COMPONENT_STATE(); let data = SIGNED_TX_DATA(); @@ -138,10 +136,10 @@ fn test_isValidSignature() { state.set_public_key(data.public_key); let is_valid = state.isValidSignature(hash, good_signature); - assert(is_valid == starknet::VALIDATED, 'Should accept valid signature'); + assert_eq!(is_valid, starknet::VALIDATED); let is_valid = state.isValidSignature(hash, bad_signature); - assert(is_valid == 0, 'Should reject invalid signature'); + assert!(is_valid.is_zero(), "Should reject invalid signature"); } // @@ -149,21 +147,17 @@ fn test_isValidSignature() { // #[test] -#[available_gas(2000000)] fn test_validate_deploy() { let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); // `__validate_deploy__` does not directly use the passed arguments. Their // values are already integrated in the tx hash. The passed arguments in this // testing context are decoupled from the signature and have no effect on the test. - assert( - account.__validate_deploy__(CLASS_HASH(), SALT, PUBKEY) == starknet::VALIDATED, - 'Should validate correctly' - ); + let is_valid = account.__validate_deploy__(CLASS_HASH(), SALT, PUBKEY); + assert_eq!(is_valid, starknet::VALIDATED); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_deploy_invalid_signature_data() { let mut data = SIGNED_TX_DATA(); @@ -174,7 +168,6 @@ fn test_validate_deploy_invalid_signature_data() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_deploy_invalid_signature_length() { let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); @@ -187,7 +180,6 @@ fn test_validate_deploy_invalid_signature_length() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_deploy_empty_signature() { let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); @@ -198,21 +190,17 @@ fn test_validate_deploy_empty_signature() { } #[test] -#[available_gas(2000000)] fn test_validate_declare() { let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); // `__validate_declare__` does not directly use the class_hash argument. Its // value is already integrated in the tx hash. The class_hash argument in this // testing context is decoupled from the signature and has no effect on the test. - assert( - account.__validate_declare__(CLASS_HASH()) == starknet::VALIDATED, - 'Should validate correctly' - ); + let is_valid = account.__validate_declare__(CLASS_HASH()); + assert_eq!(is_valid, starknet::VALIDATED); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_declare_invalid_signature_data() { let mut data = SIGNED_TX_DATA(); @@ -223,7 +211,6 @@ fn test_validate_declare_invalid_signature_data() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_declare_invalid_signature_length() { let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); @@ -236,7 +223,6 @@ fn test_validate_declare_invalid_signature_length() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_declare_empty_signature() { let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); @@ -273,17 +259,16 @@ fn test_execute_with_version(version: Option) { let ret = account.__execute__(calls); // Assert that the transfer was successful - assert(erc20.balance_of(account.contract_address) == 800, 'Should have remainder'); - assert(erc20.balance_of(recipient) == amount, 'Should have transferred'); + assert_eq!(erc20.balance_of(account.contract_address), 800, "Should have remainder"); + assert_eq!(erc20.balance_of(recipient), amount, "Should have transferred"); // Test return value let mut call_serialized_retval = *ret.at(0); let call_retval = Serde::::deserialize(ref call_serialized_retval); - assert(call_retval.unwrap(), 'Should have succeeded'); + assert!(call_retval.unwrap()); } #[test] -#[available_gas(2000000)] fn test_execute() { test_execute_with_version(Option::None(())); } @@ -294,7 +279,6 @@ fn test_execute_future_version() { } #[test] -#[available_gas(2000000)] fn test_execute_query_version() { test_execute_with_version(Option::Some(QUERY_VERSION)); } @@ -306,29 +290,26 @@ fn test_execute_invalid_query_version() { } #[test] -#[available_gas(2000000)] fn test_execute_future_query_version() { test_execute_with_version(Option::Some(QUERY_VERSION + 1)); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid tx version', 'ENTRYPOINT_FAILED'))] fn test_execute_invalid_version() { test_execute_with_version(Option::Some(MIN_TRANSACTION_VERSION - 1)); } #[test] -#[available_gas(2000000)] fn test_validate() { let calls = array![]; let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); - assert(account.__validate__(calls) == starknet::VALIDATED, 'Should validate correctly'); + let is_valid = account.__validate__(calls); + assert_eq!(is_valid, starknet::VALIDATED); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_invalid() { let calls = array![]; @@ -340,7 +321,6 @@ fn test_validate_invalid() { } #[test] -#[available_gas(20000000)] fn test_multicall() { let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); let erc20 = deploy_erc20(account.contract_address, 1000); @@ -372,33 +352,31 @@ fn test_multicall() { let ret = account.__execute__(calls); // Assert that the transfers were successful - assert(erc20.balance_of(account.contract_address) == 200, 'Should have remainder'); - assert(erc20.balance_of(recipient1) == 300, 'Should have transferred'); - assert(erc20.balance_of(recipient2) == 500, 'Should have transferred'); + assert_eq!(erc20.balance_of(account.contract_address), 200, "Should have remainder"); + assert_eq!(erc20.balance_of(recipient1), 300, "Should have transferred from call1"); + assert_eq!(erc20.balance_of(recipient2), 500, "Should have transferred from call2"); - // Test return value + // Test return values let mut call1_serialized_retval = *ret.at(0); let mut call2_serialized_retval = *ret.at(1); + let call1_retval = Serde::::deserialize(ref call1_serialized_retval); + assert!(call1_retval.unwrap()); + let call2_retval = Serde::::deserialize(ref call2_serialized_retval); - assert(call1_retval.unwrap(), 'Should have succeeded'); - assert(call2_retval.unwrap(), 'Should have succeeded'); + assert!(call2_retval.unwrap()); } #[test] -#[available_gas(2000000)] fn test_multicall_zero_calls() { let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); let mut calls = array![]; - let ret = account.__execute__(calls); - - // Test return value - assert(ret.len() == 0, 'Should have an empty response'); + let response = account.__execute__(calls); + assert!(response.is_empty()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid caller',))] fn test_account_called_from_contract() { let state = setup(); @@ -416,7 +394,6 @@ fn test_account_called_from_contract() { // #[test] -#[available_gas(2000000)] fn test_public_key_setter_and_getter() { let mut state = COMPONENT_STATE(); testing::set_contract_address(ACCOUNT_ADDRESS()); @@ -424,24 +401,19 @@ fn test_public_key_setter_and_getter() { // Check default let public_key = state.get_public_key(); - assert(public_key == 0, 'Should be zero'); + assert!(public_key.is_zero()); // Set key state.set_public_key(NEW_PUBKEY); - let event = utils::pop_log::(ACCOUNT_ADDRESS()).unwrap(); - assert(event.removed_owner_guid == 0, 'Invalid old owner key'); - - let event = utils::pop_log::(ACCOUNT_ADDRESS()).unwrap(); - assert(event.new_owner_guid == NEW_PUBKEY, 'Invalid new owner key'); - utils::assert_no_events_left(ACCOUNT_ADDRESS()); + assert_event_owner_removed(ACCOUNT_ADDRESS(), 0); + assert_only_event_owner_added(ACCOUNT_ADDRESS(), NEW_PUBKEY); let public_key = state.get_public_key(); - assert(public_key == NEW_PUBKEY, 'Should update key'); + assert_eq!(public_key, NEW_PUBKEY); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: unauthorized',))] fn test_public_key_setter_different_account() { let mut state = COMPONENT_STATE(); @@ -457,7 +429,6 @@ fn test_public_key_setter_different_account() { // #[test] -#[available_gas(2000000)] fn test_public_key_setter_and_getter_camel() { let mut state = COMPONENT_STATE(); testing::set_contract_address(ACCOUNT_ADDRESS()); @@ -465,24 +436,19 @@ fn test_public_key_setter_and_getter_camel() { // Check default let public_key = state.getPublicKey(); - assert(public_key == 0, 'Should be zero'); + assert!(public_key.is_zero()); // Set key state.setPublicKey(NEW_PUBKEY); - let event = utils::pop_log::(ACCOUNT_ADDRESS()).unwrap(); - assert(event.removed_owner_guid == 0, 'Invalid old owner key'); - - let event = utils::pop_log::(ACCOUNT_ADDRESS()).unwrap(); - assert(event.new_owner_guid == NEW_PUBKEY, 'Invalid new owner key'); - utils::assert_no_events_left(ACCOUNT_ADDRESS()); + assert_event_owner_removed(ACCOUNT_ADDRESS(), 0); + assert_only_event_owner_added(ACCOUNT_ADDRESS(), NEW_PUBKEY); let public_key = state.getPublicKey(); - assert(public_key == NEW_PUBKEY, 'Should update key'); + assert_eq!(public_key, NEW_PUBKEY); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: unauthorized',))] fn test_public_key_setter_different_account_camel() { let mut state = COMPONENT_STATE(); @@ -498,27 +464,24 @@ fn test_public_key_setter_different_account_camel() { // #[test] -#[available_gas(2000000)] fn test_initializer() { let mut state = COMPONENT_STATE(); let mock_state = CONTRACT_STATE(); state.initializer(PUBKEY); - let event = utils::pop_log::(ZERO()).unwrap(); - assert(event.new_owner_guid == PUBKEY, 'Invalid owner key'); - utils::assert_no_events_left(ZERO()); + assert_only_event_owner_added(ZERO(), PUBKEY); - assert(state.get_public_key() == PUBKEY, 'Should return PUBKEY'); + let public_key = state.get_public_key(); + assert_eq!(public_key, PUBKEY); - let supports_default_interface = mock_state.supports_interface(ISRC5_ID); - assert(supports_default_interface, 'Should support base interface'); + let supports_isrc5 = mock_state.supports_interface(ISRC5_ID); + assert!(supports_isrc5); - let supports_account_interface = mock_state.supports_interface(ISRC6_ID); - assert(supports_account_interface, 'Should support account id'); + let supports_isrc6 = mock_state.supports_interface(ISRC6_ID); + assert!(supports_isrc6); } #[test] -#[available_gas(2000000)] fn test_assert_only_self_true() { let mut state = COMPONENT_STATE(); @@ -528,7 +491,6 @@ fn test_assert_only_self_true() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: unauthorized',))] fn test_assert_only_self_false() { let mut state = COMPONENT_STATE(); @@ -540,7 +502,6 @@ fn test_assert_only_self_false() { } #[test] -#[available_gas(2000000)] fn test__is_valid_signature() { let mut state = COMPONENT_STATE(); let data = SIGNED_TX_DATA(); @@ -553,25 +514,41 @@ fn test__is_valid_signature() { state.set_public_key(data.public_key); let is_valid = state._is_valid_signature(hash, good_signature.span()); - assert(is_valid, 'Should accept valid signature'); + assert!(is_valid); - let is_valid = state._is_valid_signature(hash, bad_signature.span()); - assert(!is_valid, 'Should reject invalid signature'); + let is_not_valid = !state._is_valid_signature(hash, bad_signature.span()); + assert!(is_not_valid); - let is_valid = state._is_valid_signature(hash, invalid_length_signature.span()); - assert(!is_valid, 'Should reject invalid length'); + let is_not_valid = !state._is_valid_signature(hash, invalid_length_signature.span()); + assert!(is_not_valid); } #[test] -#[available_gas(2000000)] fn test__set_public_key() { let mut state = COMPONENT_STATE(); state._set_public_key(PUBKEY); - let event = utils::pop_log::(ZERO()).unwrap(); - assert(event.new_owner_guid == PUBKEY, 'Invalid owner key'); - utils::assert_no_events_left(ZERO()); + assert_only_event_owner_added(ZERO(), PUBKEY); let public_key = state.get_public_key(); - assert(public_key == PUBKEY, 'Should update key'); + assert_eq!(public_key, PUBKEY); +} + +// +// Helpers +// + +fn assert_event_owner_removed(contract: ContractAddress, removed_owner_guid: felt252) { + let event = utils::pop_log::(contract).unwrap(); + assert_eq!(event.removed_owner_guid, removed_owner_guid); +} + +fn assert_event_owner_added(contract: ContractAddress, new_owner_guid: felt252) { + let event = utils::pop_log::(contract).unwrap(); + assert_eq!(event.new_owner_guid, new_owner_guid); +} + +fn assert_only_event_owner_added(contract: ContractAddress, new_owner_guid: felt252) { + assert_event_owner_added(contract, new_owner_guid); + utils::assert_no_events_left(contract); } diff --git a/src/tests/account/test_dual_account.cairo b/src/tests/account/test_dual_account.cairo index ef7ee88c5..08e711c24 100644 --- a/src/tests/account/test_dual_account.cairo +++ b/src/tests/account/test_dual_account.cairo @@ -52,18 +52,18 @@ fn setup_account_panic() -> (DualCaseAccount, DualCaseAccount) { // #[test] -#[available_gas(2000000)] fn test_dual_set_public_key() { let (snake_dispatcher, target) = setup_snake(); testing::set_contract_address(snake_dispatcher.contract_address); snake_dispatcher.set_public_key(NEW_PUBKEY); - assert(target.get_public_key() == NEW_PUBKEY, 'Should return NEW_PUBKEY'); + + let public_key = target.get_public_key(); + assert_eq!(public_key, NEW_PUBKEY); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_set_public_key() { let dispatcher = setup_non_account(); @@ -71,22 +71,20 @@ fn test_dual_no_set_public_key() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_set_public_key_exists_and_panics() { let (dispatcher, _) = setup_account_panic(); dispatcher.set_public_key(NEW_PUBKEY); } #[test] -#[available_gas(2000000)] fn test_dual_get_public_key() { let (snake_dispatcher, _) = setup_snake(); - assert(snake_dispatcher.get_public_key() == PUBKEY, 'Should return PUBKEY'); + let public_key = snake_dispatcher.get_public_key(); + assert_eq!(public_key, PUBKEY); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_get_public_key() { let dispatcher = setup_non_account(); @@ -94,15 +92,13 @@ fn test_dual_no_get_public_key() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_get_public_key_exists_and_panics() { let (dispatcher, _) = setup_account_panic(); dispatcher.get_public_key(); } #[test] -#[available_gas(2000000)] fn test_dual_is_valid_signature() { let (snake_dispatcher, target) = setup_snake(); @@ -114,11 +110,10 @@ fn test_dual_is_valid_signature() { target.set_public_key(data.public_key); let is_valid = snake_dispatcher.is_valid_signature(hash, signature); - assert(is_valid == 'VALID', 'Should accept valid signature'); + assert_eq!(is_valid, starknet::VALIDATED); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_is_valid_signature() { let hash = 0x0; @@ -129,8 +124,7 @@ fn test_dual_no_is_valid_signature() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_is_valid_signature_exists_and_panics() { let hash = 0x0; let signature = array![]; @@ -140,14 +134,13 @@ fn test_dual_is_valid_signature_exists_and_panics() { } #[test] -#[available_gas(2000000)] fn test_dual_supports_interface() { let (snake_dispatcher, target) = setup_snake(); - assert(snake_dispatcher.supports_interface(ISRC5_ID), 'Should implement ISRC5'); + let supports_isrc5 = snake_dispatcher.supports_interface(ISRC5_ID); + assert!(supports_isrc5); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_supports_interface() { let dispatcher = setup_non_account(); @@ -155,8 +148,7 @@ fn test_dual_no_supports_interface() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_supports_interface_exists_and_panics() { let (dispatcher, _) = setup_account_panic(); dispatcher.supports_interface(ISRC5_ID); @@ -167,41 +159,39 @@ fn test_dual_supports_interface_exists_and_panics() { // #[test] -#[available_gas(2000000)] fn test_dual_setPublicKey() { let (camel_dispatcher, target) = setup_camel(); testing::set_contract_address(camel_dispatcher.contract_address); camel_dispatcher.set_public_key(NEW_PUBKEY); - assert(target.getPublicKey() == NEW_PUBKEY, 'Should return NEW_PUBKEY'); + + let public_key = target.getPublicKey(); + assert_eq!(public_key, NEW_PUBKEY); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_setPublicKey_exists_and_panics() { let (_, dispatcher) = setup_account_panic(); dispatcher.set_public_key(NEW_PUBKEY); } #[test] -#[available_gas(2000000)] fn test_dual_getPublicKey() { let (camel_dispatcher, _) = setup_camel(); - assert(camel_dispatcher.get_public_key() == PUBKEY, 'Should return PUBKEY'); + let public_key = camel_dispatcher.get_public_key(); + assert_eq!(public_key, PUBKEY); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_getPublicKey_exists_and_panics() { let (_, dispatcher) = setup_account_panic(); dispatcher.get_public_key(); } #[test] -#[available_gas(2000000)] fn test_dual_isValidSignature() { let (camel_dispatcher, target) = setup_camel(); @@ -213,12 +203,11 @@ fn test_dual_isValidSignature() { target.setPublicKey(data.public_key); let is_valid = camel_dispatcher.is_valid_signature(hash, signature); - assert(is_valid == 'VALID', 'Should accept valid signature'); + assert_eq!(is_valid, starknet::VALIDATED); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_isValidSignature_exists_and_panics() { let hash = 0x0; let signature = array![]; @@ -228,15 +217,14 @@ fn test_dual_isValidSignature_exists_and_panics() { } #[test] -#[available_gas(2000000)] fn test_dual_supportsInterface() { let (camel_dispatcher, _) = setup_camel(); - assert(camel_dispatcher.supports_interface(ISRC5_ID), 'Should implement ISRC5'); + let supports_isrc5 = camel_dispatcher.supports_interface(ISRC5_ID); + assert!(supports_isrc5); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_supportsInterface_exists_and_panics() { let (_, dispatcher) = setup_account_panic(); dispatcher.supports_interface(ISRC5_ID); diff --git a/src/tests/introspection/test_dual_src5.cairo b/src/tests/introspection/test_dual_src5.cairo index 80c13e56a..2240bd617 100644 --- a/src/tests/introspection/test_dual_src5.cairo +++ b/src/tests/introspection/test_dual_src5.cairo @@ -44,14 +44,13 @@ fn setup_src5_panic() -> (DualCaseSRC5, DualCaseSRC5) { // #[test] -#[available_gas(2000000)] fn test_dual_supports_interface() { let dispatcher = setup_snake(); - assert(dispatcher.supports_interface(ISRC5_ID), 'Should support base interface'); + let supports_isrc5 = dispatcher.supports_interface(ISRC5_ID); + assert!(supports_isrc5); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_supports_interface() { let dispatcher = setup_non_src5(); @@ -59,8 +58,7 @@ fn test_dual_no_supports_interface() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_supports_interface_exists_and_panics() { let (dispatcher, _) = setup_src5_panic(); dispatcher.supports_interface(ISRC5_ID); @@ -71,15 +69,14 @@ fn test_dual_supports_interface_exists_and_panics() { // #[test] -#[available_gas(2000000)] fn test_dual_supportsInterface() { let dispatcher = setup_camel(); - assert(dispatcher.supports_interface(ISRC5_ID), 'Should support base interface'); + let supports_isrc5 = dispatcher.supports_interface(ISRC5_ID); + assert!(supports_isrc5); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_supportsInterface_exists_and_panics() { let (_, dispatcher) = setup_src5_panic(); dispatcher.supports_interface(ISRC5_ID); diff --git a/src/tests/introspection/test_src5.cairo b/src/tests/introspection/test_src5.cairo index f58f8a977..d7726b7ff 100644 --- a/src/tests/introspection/test_src5.cairo +++ b/src/tests/introspection/test_src5.cairo @@ -12,42 +12,37 @@ fn COMPONENT_STATE() -> ComponentState { } #[test] -#[available_gas(2000000)] fn test_default_behavior() { let state = COMPONENT_STATE(); - let supports_default_interface = state.supports_interface(ISRC5_ID); - assert(supports_default_interface, 'Should support base interface'); + let supports_isrc5 = state.supports_interface(ISRC5_ID); + assert!(supports_isrc5); } #[test] -#[available_gas(2000000)] fn test_not_registered_interface() { let state = COMPONENT_STATE(); - let supports_unregistered_interface = state.supports_interface(OTHER_ID); - assert(!supports_unregistered_interface, 'Should not support unregistered'); + let does_not_support_unregistered_interface = !state.supports_interface(OTHER_ID); + assert!(does_not_support_unregistered_interface); } #[test] -#[available_gas(2000000)] fn test_register_interface() { let mut state = COMPONENT_STATE(); state.register_interface(OTHER_ID); let supports_new_interface = state.supports_interface(OTHER_ID); - assert(supports_new_interface, 'Should support new interface'); + assert!(supports_new_interface); } #[test] -#[available_gas(2000000)] fn test_deregister_interface() { let mut state = COMPONENT_STATE(); state.register_interface(OTHER_ID); state.deregister_interface(OTHER_ID); - let supports_old_interface = state.supports_interface(OTHER_ID); - assert(!supports_old_interface, 'Should not support interface'); + let does_not_support_old_interface = !state.supports_interface(OTHER_ID); + assert!(does_not_support_old_interface); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('SRC5: invalid id',))] fn test_deregister_default_interface() { let mut state = COMPONENT_STATE(); diff --git a/src/tests/mocks.cairo b/src/tests/mocks.cairo index 4bc03de22..7eeb6c8c8 100644 --- a/src/tests/mocks.cairo +++ b/src/tests/mocks.cairo @@ -3,11 +3,10 @@ mod account_mocks; mod erc20_mocks; mod erc721_mocks; mod erc721_receiver_mocks; -mod initializable_mock; +mod initializable_mocks; mod non_implementing_mock; mod ownable_mocks; -mod pausable_mock; -mod reentrancy_attacker_mock; -mod reentrancy_mock; +mod pausable_mocks; +mod reentrancy_mocks; mod src5_mocks; mod upgrades_mocks; diff --git a/src/tests/mocks/accesscontrol_mocks.cairo b/src/tests/mocks/accesscontrol_mocks.cairo index b037f2dfd..a2f4290d0 100644 --- a/src/tests/mocks/accesscontrol_mocks.cairo +++ b/src/tests/mocks/accesscontrol_mocks.cairo @@ -8,16 +8,19 @@ mod DualCaseAccessControlMock { component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent); component!(path: SRC5Component, storage: src5, event: SRC5Event); + // AccessControl #[abi(embed_v0)] impl AccessControlImpl = AccessControlComponent::AccessControlImpl; #[abi(embed_v0)] impl AccessControlCamelImpl = AccessControlComponent::AccessControlCamelImpl; + impl AccessControlInternalImpl = AccessControlComponent::InternalImpl; + + // SRC5 #[abi(embed_v0)] impl SRC5Impl = SRC5Component::SRC5Impl; - impl AccessControlInternalImpl = AccessControlComponent::InternalImpl; #[storage] struct Storage { @@ -53,12 +56,15 @@ mod SnakeAccessControlMock { component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent); component!(path: SRC5Component, storage: src5, event: SRC5Event); + // AccessControl #[abi(embed_v0)] impl AccessControlImpl = AccessControlComponent::AccessControlImpl; + impl AccessControlInternalImpl = AccessControlComponent::InternalImpl; + + // SCR5 #[abi(embed_v0)] impl SRC5Impl = SRC5Component::SRC5Impl; - impl AccessControlInternalImpl = AccessControlComponent::InternalImpl; #[storage] struct Storage { @@ -94,13 +100,16 @@ mod CamelAccessControlMock { component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent); component!(path: SRC5Component, storage: src5, event: SRC5Event); + // AccessControl #[abi(embed_v0)] impl AccessControlCamelImpl = AccessControlComponent::AccessControlCamelImpl; + impl AccessControlInternalImpl = AccessControlComponent::InternalImpl; + + // SCR5 #[abi(embed_v0)] impl SRC5Impl = SRC5Component::SRC5Impl; - impl AccessControlInternalImpl = AccessControlComponent::InternalImpl; #[storage] struct Storage { @@ -141,34 +150,34 @@ mod SnakeAccessControlPanicMock { #[external(v0)] fn has_role(self: @ContractState, role: felt252, account: ContractAddress) -> bool { - panic_with_felt252('Some error'); + panic!("Some error"); false } #[external(v0)] fn get_role_admin(self: @ContractState, role: felt252) -> felt252 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } #[external(v0)] fn grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); + panic!("Some error"); } #[external(v0)] fn revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); + panic!("Some error"); } #[external(v0)] fn renounce_role(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); + panic!("Some error"); } #[external(v0)] fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - panic_with_felt252('Some error'); + panic!("Some error"); false } } @@ -182,34 +191,34 @@ mod CamelAccessControlPanicMock { #[external(v0)] fn hasRole(self: @ContractState, role: felt252, account: ContractAddress) -> bool { - panic_with_felt252('Some error'); + panic!("Some error"); false } #[external(v0)] fn getRoleAdmin(self: @ContractState, role: felt252) -> felt252 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } #[external(v0)] fn grantRole(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); + panic!("Some error"); } #[external(v0)] fn revokeRole(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); + panic!("Some error"); } #[external(v0)] fn renounceRole(ref self: ContractState, role: felt252, account: ContractAddress) { - panic_with_felt252('Some error'); + panic!("Some error"); } #[external(v0)] fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - panic_with_felt252('Some error'); + panic!("Some error"); false } } diff --git a/src/tests/mocks/account_mocks.cairo b/src/tests/mocks/account_mocks.cairo index 926d4c686..03df45d92 100644 --- a/src/tests/mocks/account_mocks.cairo +++ b/src/tests/mocks/account_mocks.cairo @@ -6,6 +6,7 @@ mod DualCaseAccountMock { component!(path: AccountComponent, storage: account, event: AccountEvent); component!(path: SRC5Component, storage: src5, event: SRC5Event); + // Account #[abi(embed_v0)] impl SRC6Impl = AccountComponent::SRC6Impl; #[abi(embed_v0)] @@ -14,9 +15,11 @@ mod DualCaseAccountMock { impl DeclarerImpl = AccountComponent::DeclarerImpl; #[abi(embed_v0)] impl DeployableImpl = AccountComponent::DeployableImpl; + impl AccountInternalImpl = AccountComponent::InternalImpl; + + // SCR5 #[abi(embed_v0)] impl SRC5Impl = SRC5Component::SRC5Impl; - impl AccountInternalImpl = AccountComponent::InternalImpl; #[storage] @@ -50,13 +53,16 @@ mod SnakeAccountMock { component!(path: AccountComponent, storage: account, event: AccountEvent); component!(path: SRC5Component, storage: src5, event: SRC5Event); + // Account #[abi(embed_v0)] impl SRC6Impl = AccountComponent::SRC6Impl; #[abi(embed_v0)] impl PublicKeyImpl = AccountComponent::PublicKeyImpl; + impl AccountInternalImpl = AccountComponent::InternalImpl; + + // SCR5 #[abi(embed_v0)] impl SRC5Impl = SRC5Component::SRC5Impl; - impl AccountInternalImpl = AccountComponent::InternalImpl; #[storage] @@ -91,15 +97,18 @@ mod CamelAccountMock { component!(path: AccountComponent, storage: account, event: AccountEvent); component!(path: SRC5Component, storage: src5, event: SRC5Event); + // Account #[abi(embed_v0)] impl SRC6CamelOnlyImpl = AccountComponent::SRC6CamelOnlyImpl; #[abi(embed_v0)] impl PublicKeyCamelImpl = AccountComponent::PublicKeyCamelImpl; - #[abi(embed_v0)] - impl SRC5Impl = SRC5Component::SRC5Impl; impl SRC6Impl = AccountComponent::SRC6Impl; impl AccountInternalImpl = AccountComponent::InternalImpl; + // SCR5 + #[abi(embed_v0)] + impl SRC5Impl = SRC5Component::SRC5Impl; + #[storage] struct Storage { @@ -149,12 +158,12 @@ mod SnakeAccountPanicMock { #[external(v0)] fn set_public_key(ref self: ContractState, new_public_key: felt252) { - panic_with_felt252('Some error'); + panic!("Some error"); } #[external(v0)] fn get_public_key(self: @ContractState) -> felt252 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } @@ -162,13 +171,13 @@ mod SnakeAccountPanicMock { fn is_valid_signature( self: @ContractState, hash: felt252, signature: Array ) -> felt252 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } #[external(v0)] fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - panic_with_felt252('Some error'); + panic!("Some error"); false } } @@ -180,24 +189,24 @@ mod CamelAccountPanicMock { #[external(v0)] fn setPublicKey(ref self: ContractState, newPublicKey: felt252) { - panic_with_felt252('Some error'); + panic!("Some error"); } #[external(v0)] fn getPublicKey(self: @ContractState) -> felt252 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } #[external(v0)] fn isValidSignature(self: @ContractState, hash: felt252, signature: Array) -> felt252 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } #[external(v0)] fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - panic_with_felt252('Some error'); + panic!("Some error"); false } } diff --git a/src/tests/mocks/erc20_mocks.cairo b/src/tests/mocks/erc20_mocks.cairo index dbe4466d7..4e28bb889 100644 --- a/src/tests/mocks/erc20_mocks.cairo +++ b/src/tests/mocks/erc20_mocks.cairo @@ -99,6 +99,7 @@ mod CamelERC20Mock { #[abi(embed_v0)] impl SafeAllowanceCamelImpl = ERC20Component::SafeAllowanceCamelImpl; + // `ERC20Impl` is not embedded because it would defeat the purpose of the // mock. The `ERC20Impl` case-agnostic methods are manually exposed. impl ERC20Impl = ERC20Component::ERC20Impl; @@ -160,49 +161,49 @@ mod SnakeERC20Panic { #[external(v0)] fn name(self: @ContractState) -> felt252 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } #[external(v0)] fn symbol(self: @ContractState) -> felt252 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } #[external(v0)] fn decimals(self: @ContractState) -> u8 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } #[external(v0)] fn allowance(self: @ContractState, owner: ContractAddress, spender: ContractAddress) -> u256 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } #[external(v0)] fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool { - panic_with_felt252('Some error'); + panic!("Some error"); false } #[external(v0)] fn approve(ref self: ContractState, to: ContractAddress, token_id: u256) -> bool { - panic_with_felt252('Some error'); + panic!("Some error"); false } #[external(v0)] fn total_supply(self: @ContractState) -> u256 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } #[external(v0)] fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } @@ -210,7 +211,7 @@ mod SnakeERC20Panic { fn transfer_from( ref self: ContractState, from: ContractAddress, to: ContractAddress, amount: u256 ) -> bool { - panic_with_felt252('Some error'); + panic!("Some error"); false } } @@ -224,13 +225,13 @@ mod CamelERC20Panic { #[external(v0)] fn totalSupply(self: @ContractState) -> u256 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } #[external(v0)] fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } @@ -238,6 +239,6 @@ mod CamelERC20Panic { fn transferFrom( ref self: ContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256 ) { - panic_with_felt252('Some error'); + panic!("Some error"); } } diff --git a/src/tests/mocks/erc721_mocks.cairo b/src/tests/mocks/erc721_mocks.cairo index f9604f568..54f9fd8db 100644 --- a/src/tests/mocks/erc721_mocks.cairo +++ b/src/tests/mocks/erc721_mocks.cairo @@ -4,12 +4,8 @@ mod DualCaseERC721Mock { use openzeppelin::token::erc721::ERC721Component; use starknet::ContractAddress; - component!(path: SRC5Component, storage: src5, event: SRC5Event); component!(path: ERC721Component, storage: erc721, event: ERC721Event); - - // SRC5 - #[abi(embed_v0)] - impl SRC5Impl = SRC5Component::SRC5Impl; + component!(path: SRC5Component, storage: src5, event: SRC5Event); // ERC721 #[abi(embed_v0)] @@ -23,6 +19,10 @@ mod DualCaseERC721Mock { ERC721Component::ERC721MetadataCamelOnlyImpl; impl ERC721InternalImpl = ERC721Component::InternalImpl; + // SRC5 + #[abi(embed_v0)] + impl SRC5Impl = SRC5Component::SRC5Impl; + #[storage] struct Storage { #[substorage(v0)] @@ -61,12 +61,8 @@ mod SnakeERC721Mock { use openzeppelin::token::erc721::ERC721Component; use starknet::ContractAddress; - component!(path: SRC5Component, storage: src5, event: SRC5Event); component!(path: ERC721Component, storage: erc721, event: ERC721Event); - - // SRC5 - #[abi(embed_v0)] - impl SRC5Impl = SRC5Component::SRC5Impl; + component!(path: SRC5Component, storage: src5, event: SRC5Event); // ERC721 #[abi(embed_v0)] @@ -75,6 +71,10 @@ mod SnakeERC721Mock { impl ERC721MetadataImpl = ERC721Component::ERC721MetadataImpl; impl ERC721InternalImpl = ERC721Component::InternalImpl; + // SRC5 + #[abi(embed_v0)] + impl SRC5Impl = SRC5Component::SRC5Impl; + #[storage] struct Storage { #[substorage(v0)] @@ -114,12 +114,8 @@ mod CamelERC721Mock { use openzeppelin::token::erc721::ERC721Component; use starknet::ContractAddress; - component!(path: SRC5Component, storage: src5, event: SRC5Event); component!(path: ERC721Component, storage: erc721, event: ERC721Event); - - // SRC5 - #[abi(embed_v0)] - impl SRC5Impl = SRC5Component::SRC5Impl; + component!(path: SRC5Component, storage: src5, event: SRC5Event); // ERC721 #[abi(embed_v0)] @@ -129,6 +125,10 @@ mod CamelERC721Mock { ERC721Component::ERC721MetadataCamelOnlyImpl; impl ERC721InternalImpl = ERC721Component::InternalImpl; + // SRC5 + #[abi(embed_v0)] + impl SRC5Impl = SRC5Component::SRC5Impl; + #[storage] struct Storage { #[substorage(v0)] @@ -197,61 +197,61 @@ mod SnakeERC721PanicMock { #[external(v0)] impl ExternalImpl of ExternalTrait { fn name(self: @ContractState) -> felt252 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } fn symbol(self: @ContractState) -> felt252 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } fn approve(ref self: ContractState, to: ContractAddress, token_id: u256) { - panic_with_felt252('Some error'); + panic!("Some error"); } fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - panic_with_felt252('Some error'); + panic!("Some error"); false } fn token_uri(self: @ContractState, token_id: u256) -> felt252 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { - panic_with_felt252('Some error'); + panic!("Some error"); u256 { low: 3, high: 3 } } fn owner_of(self: @ContractState, token_id: u256) -> ContractAddress { - panic_with_felt252('Some error'); + panic!("Some error"); Zeroable::zero() } fn get_approved(self: @ContractState, token_id: u256) -> ContractAddress { - panic_with_felt252('Some error'); + panic!("Some error"); Zeroable::zero() } fn is_approved_for_all( self: @ContractState, owner: ContractAddress, operator: ContractAddress ) -> bool { - panic_with_felt252('Some error'); + panic!("Some error"); false } fn set_approval_for_all( ref self: ContractState, operator: ContractAddress, approved: bool ) { - panic_with_felt252('Some error'); + panic!("Some error"); } fn transfer_from( ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256 ) { - panic_with_felt252('Some error'); + panic!("Some error"); } fn safe_transfer_from( @@ -261,7 +261,7 @@ mod SnakeERC721PanicMock { token_id: u256, data: Span ) { - panic_with_felt252('Some error'); + panic!("Some error"); } } } @@ -278,45 +278,45 @@ mod CamelERC721PanicMock { #[external(v0)] impl ExternalImpl of ExternalTrait { fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - panic_with_felt252('Some error'); + panic!("Some error"); false } fn tokenURI(self: @ContractState, tokenId: u256) -> felt252 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 { - panic_with_felt252('Some error'); + panic!("Some error"); u256 { low: 3, high: 3 } } fn ownerOf(self: @ContractState, tokenId: u256) -> ContractAddress { - panic_with_felt252('Some error'); + panic!("Some error"); Zeroable::zero() } fn getApproved(self: @ContractState, tokenId: u256) -> ContractAddress { - panic_with_felt252('Some error'); + panic!("Some error"); Zeroable::zero() } fn isApprovedForAll( self: @ContractState, owner: ContractAddress, operator: ContractAddress ) -> bool { - panic_with_felt252('Some error'); + panic!("Some error"); false } fn setApprovalForAll(ref self: ContractState, operator: ContractAddress, approved: bool) { - panic_with_felt252('Some error'); + panic!("Some error"); } fn transferFrom( ref self: ContractState, from: ContractAddress, to: ContractAddress, tokenId: u256 ) { - panic_with_felt252('Some error'); + panic!("Some error"); } fn safeTransferFrom( @@ -326,7 +326,7 @@ mod CamelERC721PanicMock { tokenId: u256, data: Span ) { - panic_with_felt252('Some error'); + panic!("Some error"); } } } diff --git a/src/tests/mocks/erc721_receiver_mocks.cairo b/src/tests/mocks/erc721_receiver_mocks.cairo index 0732fc3e9..ed54696e1 100644 --- a/src/tests/mocks/erc721_receiver_mocks.cairo +++ b/src/tests/mocks/erc721_receiver_mocks.cairo @@ -6,17 +6,17 @@ mod DualCaseERC721ReceiverMock { use openzeppelin::token::erc721::ERC721ReceiverComponent; use starknet::ContractAddress; - component!(path: SRC5Component, storage: src5, event: SRC5Event); component!(path: ERC721ReceiverComponent, storage: erc721_receiver, event: ERC721ReceiverEvent); - - // SRC5 - #[abi(embed_v0)] - impl SRC5Impl = SRC5Component::SRC5Impl; + component!(path: SRC5Component, storage: src5, event: SRC5Event); // ERC721Receiver impl ERC721ReceiverImpl = ERC721ReceiverComponent::ERC721ReceiverImpl; impl ERC721ReceiverInternalImpl = ERC721ReceiverComponent::InternalImpl; + // SRC5 + #[abi(embed_v0)] + impl SRC5Impl = SRC5Component::SRC5Impl; + #[storage] struct Storage { #[substorage(v0)] @@ -72,17 +72,17 @@ mod SnakeERC721ReceiverMock { use openzeppelin::token::erc721::ERC721ReceiverComponent; use starknet::ContractAddress; - component!(path: SRC5Component, storage: src5, event: SRC5Event); component!(path: ERC721ReceiverComponent, storage: erc721_receiver, event: ERC721ReceiverEvent); - - // SRC5 - #[abi(embed_v0)] - impl SRC5Impl = SRC5Component::SRC5Impl; + component!(path: SRC5Component, storage: src5, event: SRC5Event); // ERC721Receiver impl ERC721ReceiverImpl = ERC721ReceiverComponent::ERC721ReceiverImpl; impl ERC721ReceiverInternalImpl = ERC721ReceiverComponent::InternalImpl; + // SRC5 + #[abi(embed_v0)] + impl SRC5Impl = SRC5Component::SRC5Impl; + #[storage] struct Storage { #[substorage(v0)] @@ -127,17 +127,17 @@ mod CamelERC721ReceiverMock { use openzeppelin::token::erc721::ERC721ReceiverComponent; use starknet::ContractAddress; - component!(path: SRC5Component, storage: src5, event: SRC5Event); component!(path: ERC721ReceiverComponent, storage: erc721_receiver, event: ERC721ReceiverEvent); - - // SRC5 - #[abi(embed_v0)] - impl SRC5Impl = SRC5Component::SRC5Impl; + component!(path: SRC5Component, storage: src5, event: SRC5Event); // ERC721Receiver impl ERC721ReceiverCamelImpl = ERC721ReceiverComponent::ERC721ReceiverCamelImpl; impl ERC721ReceiverInternalImpl = ERC721ReceiverComponent::InternalImpl; + // SRC5 + #[abi(embed_v0)] + impl SRC5Impl = SRC5Component::SRC5Impl; + #[storage] struct Storage { #[substorage(v0)] @@ -191,7 +191,7 @@ mod SnakeERC721ReceiverPanicMock { token_id: u256, data: Span ) -> felt252 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } } @@ -211,7 +211,7 @@ mod CamelERC721ReceiverPanicMock { tokenId: u256, data: Span ) -> felt252 { - panic_with_felt252('Some error'); + panic!("Some error"); 3 } } diff --git a/src/tests/mocks/initializable_mock.cairo b/src/tests/mocks/initializable_mocks.cairo similarity index 100% rename from src/tests/mocks/initializable_mock.cairo rename to src/tests/mocks/initializable_mocks.cairo diff --git a/src/tests/mocks/ownable_mocks.cairo b/src/tests/mocks/ownable_mocks.cairo index 5ed7e107c..e6a6a294d 100644 --- a/src/tests/mocks/ownable_mocks.cairo +++ b/src/tests/mocks/ownable_mocks.cairo @@ -107,18 +107,18 @@ mod SnakeOwnablePanicMock { #[external(v0)] fn owner(self: @ContractState) -> ContractAddress { - panic_with_felt252('Some error'); + panic!("Some error"); Zeroable::zero() } #[external(v0)] fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { - panic_with_felt252('Some error'); + panic!("Some error"); } #[external(v0)] fn renounce_ownership(ref self: ContractState) { - panic_with_felt252('Some error'); + panic!("Some error"); } } @@ -131,17 +131,17 @@ mod CamelOwnablePanicMock { #[external(v0)] fn owner(self: @ContractState) -> ContractAddress { - panic_with_felt252('Some error'); + panic!("Some error"); Zeroable::zero() } #[external(v0)] fn transferOwnership(ref self: ContractState, newOwner: ContractAddress) { - panic_with_felt252('Some error'); + panic!("Some error"); } #[external(v0)] fn renounceOwnership(ref self: ContractState) { - panic_with_felt252('Some error'); + panic!("Some error"); } } diff --git a/src/tests/mocks/pausable_mock.cairo b/src/tests/mocks/pausable_mocks.cairo similarity index 100% rename from src/tests/mocks/pausable_mock.cairo rename to src/tests/mocks/pausable_mocks.cairo diff --git a/src/tests/mocks/reentrancy_attacker_mock.cairo b/src/tests/mocks/reentrancy_attacker_mock.cairo deleted file mode 100644 index 6657cc145..000000000 --- a/src/tests/mocks/reentrancy_attacker_mock.cairo +++ /dev/null @@ -1,23 +0,0 @@ -#[starknet::interface] -trait IAttacker { - fn call_sender(self: @TState); -} - -#[starknet::contract] -mod Attacker { - use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcher; - use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcherTrait; - use starknet::ContractAddress; - use starknet::get_caller_address; - - #[storage] - struct Storage {} - - #[external(v0)] - impl IAttackerImpl of super::IAttacker { - fn call_sender(self: @ContractState) { - let caller: ContractAddress = get_caller_address(); - IReentrancyMockDispatcher { contract_address: caller }.callback(); - } - } -} diff --git a/src/tests/mocks/reentrancy_mock.cairo b/src/tests/mocks/reentrancy_mocks.cairo similarity index 79% rename from src/tests/mocks/reentrancy_mock.cairo rename to src/tests/mocks/reentrancy_mocks.cairo index 7107bb970..3cdf87c24 100644 --- a/src/tests/mocks/reentrancy_mock.cairo +++ b/src/tests/mocks/reentrancy_mocks.cairo @@ -18,10 +18,10 @@ trait IReentrancyMock { #[starknet::contract] mod ReentrancyMock { use openzeppelin::security::reentrancyguard::ReentrancyGuardComponent; - use openzeppelin::tests::mocks::reentrancy_attacker_mock::IAttackerDispatcher; - use openzeppelin::tests::mocks::reentrancy_attacker_mock::IAttackerDispatcherTrait; use starknet::ContractAddress; use starknet::get_contract_address; + use super::IAttackerDispatcher; + use super::IAttackerDispatcherTrait; use super::IReentrancyGuardedDispatcher; use super::IReentrancyGuardedDispatcherTrait; @@ -95,3 +95,31 @@ mod ReentrancyMock { } } } + +// +// Attacker +// + +#[starknet::interface] +trait IAttacker { + fn call_sender(self: @TState); +} + +#[starknet::contract] +mod Attacker { + use starknet::ContractAddress; + use starknet::get_caller_address; + use super::IReentrancyMockDispatcher; + use super::IReentrancyMockDispatcherTrait; + + #[storage] + struct Storage {} + + #[external(v0)] + impl IAttackerImpl of super::IAttacker { + fn call_sender(self: @ContractState) { + let caller: ContractAddress = get_caller_address(); + IReentrancyMockDispatcher { contract_address: caller }.callback(); + } + } +} diff --git a/src/tests/mocks/src5_mocks.cairo b/src/tests/mocks/src5_mocks.cairo index f63776568..9264264b7 100644 --- a/src/tests/mocks/src5_mocks.cairo +++ b/src/tests/mocks/src5_mocks.cairo @@ -77,7 +77,7 @@ mod SnakeSRC5PanicMock { #[external(v0)] fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { - panic_with_felt252('Some error'); + panic!("Some error"); false } } @@ -89,7 +89,7 @@ mod CamelSRC5PanicMock { #[external(v0)] fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { - panic_with_felt252('Some error'); + panic!("Some error"); false } } diff --git a/src/tests/presets/test_account.cairo b/src/tests/presets/test_account.cairo index d0d218a04..4ee96aaf2 100644 --- a/src/tests/presets/test_account.cairo +++ b/src/tests/presets/test_account.cairo @@ -56,16 +56,20 @@ fn setup_dispatcher_with_data(data: Option<@SignedTransactionData>) -> AccountAB // #[test] -#[available_gas(2000000)] fn test_constructor() { let mut state = Account::contract_state_for_testing(); Account::constructor(ref state, PUBKEY); assert_only_event_owner_added(PUBKEY, ZERO()); - assert(Account::PublicKeyImpl::get_public_key(@state) == PUBKEY, 'Should return PUBKEY'); - assert(Account::SRC5Impl::supports_interface(@state, ISRC5_ID), 'Should implement ISRC5'); - assert(Account::SRC5Impl::supports_interface(@state, ISRC6_ID), 'Should implement ISRC6'); + let public_key = Account::PublicKeyImpl::get_public_key(@state); + assert_eq!(public_key, PUBKEY); + + let supports_isrc5 = Account::SRC5Impl::supports_interface(@state, ISRC5_ID); + assert!(supports_isrc5); + + let supports_isrc6 = Account::SRC5Impl::supports_interface(@state, ISRC6_ID); + assert!(supports_isrc6); } // @@ -73,35 +77,34 @@ fn test_constructor() { // #[test] -#[available_gas(2000000)] fn test_public_key_setter_and_getter() { let dispatcher = setup_dispatcher(); testing::set_contract_address(dispatcher.contract_address); dispatcher.set_public_key(NEW_PUBKEY); - assert(dispatcher.get_public_key() == NEW_PUBKEY, 'Should return NEW_PUBKEY'); + let public_key = dispatcher.get_public_key(); + assert_eq!(public_key, NEW_PUBKEY); assert_event_owner_removed(PUBKEY, dispatcher.contract_address); assert_only_event_owner_added(NEW_PUBKEY, dispatcher.contract_address); } #[test] -#[available_gas(2000000)] fn test_public_key_setter_and_getter_camel() { let dispatcher = setup_dispatcher(); testing::set_contract_address(dispatcher.contract_address); dispatcher.setPublicKey(NEW_PUBKEY); - assert(dispatcher.getPublicKey() == NEW_PUBKEY, 'Should return NEW_PUBKEY'); + let public_key = dispatcher.getPublicKey(); + assert_eq!(public_key, NEW_PUBKEY); assert_event_owner_removed(PUBKEY, dispatcher.contract_address); assert_only_event_owner_added(NEW_PUBKEY, dispatcher.contract_address); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: unauthorized', 'ENTRYPOINT_FAILED'))] fn test_set_public_key_different_account() { let dispatcher = setup_dispatcher(); @@ -109,7 +112,6 @@ fn test_set_public_key_different_account() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: unauthorized', 'ENTRYPOINT_FAILED'))] fn test_setPublicKey_different_account() { let dispatcher = setup_dispatcher(); @@ -134,43 +136,39 @@ fn is_valid_sig_dispatcher() -> (AccountABIDispatcher, felt252, Array) } #[test] -#[available_gas(2000000)] fn test_is_valid_signature() { let (dispatcher, hash, signature) = is_valid_sig_dispatcher(); let is_valid = dispatcher.is_valid_signature(hash, signature); - assert(is_valid == starknet::VALIDATED, 'Should accept valid signature'); + assert_eq!(is_valid, starknet::VALIDATED); } #[test] -#[available_gas(2000000)] fn test_is_valid_signature_bad_sig() { let (dispatcher, hash, _) = is_valid_sig_dispatcher(); let bad_signature = array![0x987, 0x564]; let is_valid = dispatcher.is_valid_signature(hash, bad_signature.clone()); - assert(is_valid == 0, 'Should reject invalid signature'); + assert!(is_valid.is_zero(), "Should reject invalid signature"); } #[test] -#[available_gas(2000000)] fn test_isValidSignature() { let (dispatcher, hash, signature) = is_valid_sig_dispatcher(); let is_valid = dispatcher.isValidSignature(hash, signature); - assert(is_valid == starknet::VALIDATED, 'Should accept valid signature'); + assert_eq!(is_valid, starknet::VALIDATED); } #[test] -#[available_gas(2000000)] fn test_isValidSignature_bad_sig() { let (dispatcher, hash, _) = is_valid_sig_dispatcher(); let bad_signature = array![0x987, 0x564]; let is_valid = dispatcher.isValidSignature(hash, bad_signature); - assert(is_valid == 0, 'Should reject invalid signature'); + assert!(is_valid.is_zero(), "Should reject invalid signature"); } // @@ -178,12 +176,14 @@ fn test_isValidSignature_bad_sig() { // #[test] -#[available_gas(2000000)] fn test_supports_interface() { let dispatcher = setup_dispatcher(); - assert(dispatcher.supports_interface(ISRC5_ID), 'Should implement ISRC5'); - assert(dispatcher.supports_interface(ISRC6_ID), 'Should implement ISRC6'); - assert(!dispatcher.supports_interface(0x123), 'Should not implement 0x123'); + let supports_isrc5 = dispatcher.supports_interface(ISRC5_ID); + let supports_isrc6 = dispatcher.supports_interface(ISRC6_ID); + let doesnt_support_0x123 = !dispatcher.supports_interface(0x123); + assert!(supports_isrc5); + assert!(supports_isrc6); + assert!(doesnt_support_0x123); } // @@ -191,21 +191,17 @@ fn test_supports_interface() { // #[test] -#[available_gas(2000000)] fn test_validate_deploy() { let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); // `__validate_deploy__` does not directly use the passed arguments. Their // values are already integrated in the tx hash. The passed arguments in this // testing context are decoupled from the signature and have no effect on the test. - assert( - account.__validate_deploy__(CLASS_HASH(), SALT, PUBKEY) == starknet::VALIDATED, - 'Should validate correctly' - ); + let is_valid = account.__validate_deploy__(CLASS_HASH(), SALT, PUBKEY); + assert_eq!(is_valid, starknet::VALIDATED); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_deploy_invalid_signature_data() { let mut data = SIGNED_TX_DATA(); @@ -216,7 +212,6 @@ fn test_validate_deploy_invalid_signature_data() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_deploy_invalid_signature_length() { let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); @@ -228,7 +223,6 @@ fn test_validate_deploy_invalid_signature_length() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_deploy_empty_signature() { let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); @@ -239,21 +233,17 @@ fn test_validate_deploy_empty_signature() { } #[test] -#[available_gas(2000000)] fn test_validate_declare() { let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); // `__validate_declare__` does not directly use the class_hash argument. Its // value is already integrated in the tx hash. The class_hash argument in this // testing context is decoupled from the signature and has no effect on the test. - assert( - account.__validate_declare__(CLASS_HASH()) == starknet::VALIDATED, - 'Should validate correctly' - ); + let is_valid = account.__validate_declare__(CLASS_HASH()); + assert_eq!(is_valid, starknet::VALIDATED); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_declare_invalid_signature_data() { let mut data = SIGNED_TX_DATA(); @@ -264,7 +254,6 @@ fn test_validate_declare_invalid_signature_data() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_declare_invalid_signature_length() { let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); @@ -276,7 +265,6 @@ fn test_validate_declare_invalid_signature_length() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_declare_empty_signature() { let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); @@ -314,17 +302,16 @@ fn test_execute_with_version(version: Option) { let ret = account.__execute__(calls); // Assert that the transfer was successful - assert(erc20.balance_of(account.contract_address) == 800, 'Should have remainder'); - assert(erc20.balance_of(RECIPIENT()) == amount, 'Should have transferred'); + assert_eq!(erc20.balance_of(account.contract_address), 800, "Should have remainder"); + assert_eq!(erc20.balance_of(RECIPIENT()), amount, "Should have transferred"); // Test return value let mut call_serialized_retval = *ret.at(0); let call_retval = Serde::::deserialize(ref call_serialized_retval); - assert(call_retval.unwrap(), 'Should have succeeded'); + assert!(call_retval.unwrap()); } #[test] -#[available_gas(2000000)] fn test_execute() { test_execute_with_version(Option::None(())); } @@ -335,7 +322,6 @@ fn test_execute_future_version() { } #[test] -#[available_gas(2000000)] fn test_execute_query_version() { test_execute_with_version(Option::Some(QUERY_VERSION)); } @@ -347,29 +333,26 @@ fn test_execute_invalid_query_version() { } #[test] -#[available_gas(2000000)] fn test_execute_future_query_version() { test_execute_with_version(Option::Some(QUERY_VERSION + 1)); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid tx version', 'ENTRYPOINT_FAILED'))] fn test_execute_invalid_version() { test_execute_with_version(Option::Some(MIN_TRANSACTION_VERSION - 1)); } #[test] -#[available_gas(2000000)] fn test_validate() { let calls = array![]; let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); - assert(account.__validate__(calls) == starknet::VALIDATED, 'Should validate correctly'); + let is_valid = account.__validate__(calls); + assert_eq!(is_valid, starknet::VALIDATED); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid signature', 'ENTRYPOINT_FAILED'))] fn test_validate_invalid() { let calls = array![]; @@ -381,7 +364,6 @@ fn test_validate_invalid() { } #[test] -#[available_gas(20000000)] fn test_multicall() { let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); let erc20 = deploy_erc20(account.contract_address, 1000); @@ -413,33 +395,31 @@ fn test_multicall() { let ret = account.__execute__(calls); // Assert that the transfers were successful - assert(erc20.balance_of(account.contract_address) == 200, 'Should have remainder'); - assert(erc20.balance_of(recipient1) == 300, 'Should have transferred'); - assert(erc20.balance_of(recipient2) == 500, 'Should have transferred'); + assert_eq!(erc20.balance_of(account.contract_address), 200, "Should have remainder"); + assert_eq!(erc20.balance_of(recipient1), 300, "Should have transferred"); + assert_eq!(erc20.balance_of(recipient2), 500, "Should have transferred"); // Test return value let mut call1_serialized_retval = *ret.at(0); let mut call2_serialized_retval = *ret.at(1); + let call1_retval = Serde::::deserialize(ref call1_serialized_retval); + assert!(call1_retval.unwrap()); + let call2_retval = Serde::::deserialize(ref call2_serialized_retval); - assert(call1_retval.unwrap(), 'Should have succeeded'); - assert(call2_retval.unwrap(), 'Should have succeeded'); + assert!(call2_retval.unwrap()); } #[test] -#[available_gas(2000000)] fn test_multicall_zero_calls() { let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); let mut calls = array![]; - let ret = account.__execute__(calls); - - // Test return value - assert(ret.len() == 0, 'Should have an empty response'); + let response = account.__execute__(calls); + assert!(response.is_empty()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Account: invalid caller', 'ENTRYPOINT_FAILED'))] fn test_account_called_from_contract() { let account = setup_dispatcher(); @@ -458,12 +438,12 @@ fn test_account_called_from_contract() { fn assert_event_owner_removed(removed_owner_guid: felt252, contract: ContractAddress) { let event = utils::pop_log::(contract).unwrap(); - assert(event.removed_owner_guid == removed_owner_guid, 'Invalid `removed_owner_guid`'); + assert_eq!(event.removed_owner_guid, removed_owner_guid); } fn assert_event_owner_added(new_owner_guid: felt252, contract: ContractAddress) { let event = utils::pop_log::(contract).unwrap(); - assert(event.new_owner_guid == new_owner_guid, 'Invalid `new_owner_guid`'); + assert_eq!(event.new_owner_guid, new_owner_guid); } fn assert_only_event_owner_added(new_owner_guid: felt252, contract: ContractAddress) { diff --git a/src/tests/presets/test_erc20.cairo b/src/tests/presets/test_erc20.cairo index aa8174cc1..86b4ab4c9 100644 --- a/src/tests/presets/test_erc20.cairo +++ b/src/tests/presets/test_erc20.cairo @@ -3,6 +3,7 @@ use openzeppelin::presets::ERC20; use openzeppelin::tests::utils::constants::{ ZERO, OWNER, SPENDER, RECIPIENT, NAME, SYMBOL, DECIMALS, SUPPLY, VALUE }; +use openzeppelin::tests::utils::debug::DebugContractAddress; use openzeppelin::tests::utils; use openzeppelin::token::erc20::ERC20Component::{Approval, Transfer}; use openzeppelin::token::erc20::ERC20Component::{ERC20CamelOnlyImpl, ERC20Impl}; @@ -41,15 +42,14 @@ fn setup_dispatcher() -> ERC20ABIDispatcher { // #[test] -#[available_gas(2000000)] fn test_constructor() { let mut dispatcher = setup_dispatcher_with_event(); - assert(dispatcher.name() == NAME, 'Should be NAME'); - assert(dispatcher.symbol() == SYMBOL, 'Should be SYMBOL'); - assert(dispatcher.decimals() == DECIMALS, 'Should be DECIMALS'); - assert(dispatcher.total_supply() == SUPPLY, 'Should equal SUPPLY'); - assert(dispatcher.balance_of(OWNER()) == SUPPLY, 'Should equal SUPPLY'); + assert_eq!(dispatcher.name(), NAME); + assert_eq!(dispatcher.symbol(), SYMBOL); + assert_eq!(dispatcher.decimals(), DECIMALS); + assert_eq!(dispatcher.total_supply(), SUPPLY); + assert_eq!(dispatcher.balance_of(OWNER()), SUPPLY); assert_only_event_transfer(dispatcher.contract_address, ZERO(), OWNER(), SUPPLY); } @@ -58,31 +58,30 @@ fn test_constructor() { // #[test] -#[available_gas(2000000)] fn test_total_supply() { let mut dispatcher = setup_dispatcher(); - assert(dispatcher.total_supply() == SUPPLY, 'Should equal SUPPLY'); - assert(dispatcher.totalSupply() == SUPPLY, 'Should equal SUPPLY'); + assert_eq!(dispatcher.total_supply(), SUPPLY); + assert_eq!(dispatcher.totalSupply(), SUPPLY); } #[test] -#[available_gas(2000000)] fn test_balance_of() { let mut dispatcher = setup_dispatcher(); - assert(dispatcher.balance_of(OWNER()) == SUPPLY, 'Should equal SUPPLY'); - assert(dispatcher.balanceOf(OWNER()) == SUPPLY, 'Should equal SUPPLY'); + assert_eq!(dispatcher.balance_of(OWNER()), SUPPLY); + assert_eq!(dispatcher.balanceOf(OWNER()), SUPPLY); } #[test] -#[available_gas(2000000)] fn test_allowance() { let mut dispatcher = setup_dispatcher(); testing::set_contract_address(OWNER()); dispatcher.approve(SPENDER(), VALUE); - assert(dispatcher.allowance(OWNER(), SPENDER()) == VALUE, 'Should equal VALUE'); + + let allowance = dispatcher.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, VALUE); } // @@ -90,20 +89,21 @@ fn test_allowance() { // #[test] -#[available_gas(2000000)] fn test_approve() { let mut dispatcher = setup_dispatcher(); - assert(dispatcher.allowance(OWNER(), SPENDER()) == 0, 'Should equal ZERO'); + let allowance = dispatcher.allowance(OWNER(), SPENDER()); + assert!(allowance.is_zero()); testing::set_contract_address(OWNER()); - assert(dispatcher.approve(SPENDER(), VALUE), 'Should return true'); + assert!(dispatcher.approve(SPENDER(), VALUE)); + + let allowance = dispatcher.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, VALUE); - assert(dispatcher.allowance(OWNER(), SPENDER()) == VALUE, 'Should equal VALUE'); assert_only_event_approval(dispatcher.contract_address, OWNER(), SPENDER(), VALUE); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve from 0', 'ENTRYPOINT_FAILED'))] fn test_approve_from_zero() { let mut dispatcher = setup_dispatcher(); @@ -111,7 +111,6 @@ fn test_approve_from_zero() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve to 0', 'ENTRYPOINT_FAILED'))] fn test_approve_to_zero() { let mut dispatcher = setup_dispatcher(); @@ -124,21 +123,20 @@ fn test_approve_to_zero() { // #[test] -#[available_gas(2000000)] fn test_transfer() { let mut dispatcher = setup_dispatcher(); testing::set_contract_address(OWNER()); - assert(dispatcher.transfer(RECIPIENT(), VALUE), 'Should return true'); + assert!(dispatcher.transfer(RECIPIENT(), VALUE)); + + assert_eq!(dispatcher.balance_of(OWNER()), SUPPLY - VALUE); + assert_eq!(dispatcher.balance_of(RECIPIENT()), VALUE); + assert_eq!(dispatcher.total_supply(), SUPPLY); - assert(dispatcher.balance_of(OWNER()) == SUPPLY - VALUE, 'Should equal SUPPLY - VALUE'); - assert(dispatcher.balance_of(RECIPIENT()) == VALUE, 'Should equal VALUE'); - assert(dispatcher.total_supply() == SUPPLY, 'Should equal SUPPLY'); assert_only_event_transfer(dispatcher.contract_address, OWNER(), RECIPIENT(), VALUE); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', 'ENTRYPOINT_FAILED'))] fn test_transfer_not_enough_balance() { let mut dispatcher = setup_dispatcher(); @@ -149,7 +147,6 @@ fn test_transfer_not_enough_balance() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: transfer from 0', 'ENTRYPOINT_FAILED'))] fn test_transfer_from_zero() { let mut dispatcher = setup_dispatcher(); @@ -157,7 +154,6 @@ fn test_transfer_from_zero() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: transfer to 0', 'ENTRYPOINT_FAILED'))] fn test_transfer_to_zero() { let mut dispatcher = setup_dispatcher(); @@ -170,7 +166,6 @@ fn test_transfer_to_zero() { // #[test] -#[available_gas(2000000)] fn test_transfer_from() { let mut dispatcher = setup_dispatcher(); @@ -179,19 +174,18 @@ fn test_transfer_from() { utils::drop_event(dispatcher.contract_address); testing::set_contract_address(SPENDER()); - assert(dispatcher.transfer_from(OWNER(), RECIPIENT(), VALUE), 'Should return true'); + assert!(dispatcher.transfer_from(OWNER(), RECIPIENT(), VALUE)); assert_event_approval(dispatcher.contract_address, OWNER(), SPENDER(), 0); assert_only_event_transfer(dispatcher.contract_address, OWNER(), RECIPIENT(), VALUE); - assert(dispatcher.balance_of(RECIPIENT()) == VALUE, 'Should equal amount'); - assert(dispatcher.balance_of(OWNER()) == SUPPLY - VALUE, 'Should equal supply - amount'); - assert(dispatcher.allowance(OWNER(), SPENDER()) == 0, 'Should equal 0'); - assert(dispatcher.total_supply() == SUPPLY, 'Total supply should not change'); + assert_eq!(dispatcher.balance_of(RECIPIENT()), VALUE); + assert_eq!(dispatcher.balance_of(OWNER()), SUPPLY - VALUE); + assert_eq!(dispatcher.allowance(OWNER(), SPENDER()), 0); + assert_eq!(dispatcher.total_supply(), SUPPLY); } #[test] -#[available_gas(2000000)] fn test_transfer_from_doesnt_consume_infinite_allowance() { let mut dispatcher = setup_dispatcher(); @@ -201,13 +195,11 @@ fn test_transfer_from_doesnt_consume_infinite_allowance() { testing::set_contract_address(SPENDER()); dispatcher.transfer_from(OWNER(), RECIPIENT(), VALUE); - assert( - dispatcher.allowance(OWNER(), SPENDER()) == BoundedInt::max(), 'Allowance should not change' - ); + let allowance = dispatcher.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, BoundedInt::max(), "Should not decrease"); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', 'ENTRYPOINT_FAILED'))] fn test_transfer_from_greater_than_allowance() { let mut dispatcher = setup_dispatcher(); @@ -220,7 +212,6 @@ fn test_transfer_from_greater_than_allowance() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: transfer to 0', 'ENTRYPOINT_FAILED'))] fn test_transfer_from_to_zero_address() { let mut dispatcher = setup_dispatcher(); @@ -232,7 +223,6 @@ fn test_transfer_from_to_zero_address() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', 'ENTRYPOINT_FAILED'))] fn test_transfer_from_from_zero_address() { let mut dispatcher = setup_dispatcher(); @@ -240,7 +230,6 @@ fn test_transfer_from_from_zero_address() { } #[test] -#[available_gas(2000000)] fn test_transferFrom() { let mut dispatcher = setup_dispatcher(); @@ -249,19 +238,18 @@ fn test_transferFrom() { utils::drop_event(dispatcher.contract_address); testing::set_contract_address(SPENDER()); - assert(dispatcher.transferFrom(OWNER(), RECIPIENT(), VALUE), 'Should return true'); + assert!(dispatcher.transferFrom(OWNER(), RECIPIENT(), VALUE)); assert_event_approval(dispatcher.contract_address, OWNER(), SPENDER(), 0); assert_only_event_transfer(dispatcher.contract_address, OWNER(), RECIPIENT(), VALUE); - assert(dispatcher.balance_of(RECIPIENT()) == VALUE, 'Should equal amount'); - assert(dispatcher.balance_of(OWNER()) == SUPPLY - VALUE, 'Should equal supply - amount'); - assert(dispatcher.allowance(OWNER(), SPENDER()) == 0, 'Should equal 0'); - assert(dispatcher.total_supply() == SUPPLY, 'Total supply should not change'); + assert_eq!(dispatcher.balance_of(RECIPIENT()), VALUE); + assert_eq!(dispatcher.balance_of(OWNER()), SUPPLY - VALUE); + assert_eq!(dispatcher.allowance(OWNER(), SPENDER()), 0); + assert_eq!(dispatcher.total_supply(), SUPPLY); } #[test] -#[available_gas(2000000)] fn test_transferFrom_doesnt_consume_infinite_allowance() { let mut dispatcher = setup_dispatcher(); testing::set_contract_address(OWNER()); @@ -270,13 +258,11 @@ fn test_transferFrom_doesnt_consume_infinite_allowance() { testing::set_contract_address(SPENDER()); dispatcher.transferFrom(OWNER(), RECIPIENT(), VALUE); - assert( - dispatcher.allowance(OWNER(), SPENDER()) == BoundedInt::max(), 'Allowance should not change' - ); + let allowance = dispatcher.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, BoundedInt::max(), "Should not decrease"); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', 'ENTRYPOINT_FAILED'))] fn test_transferFrom_greater_than_allowance() { let mut dispatcher = setup_dispatcher(); @@ -289,7 +275,6 @@ fn test_transferFrom_greater_than_allowance() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: transfer to 0', 'ENTRYPOINT_FAILED'))] fn test_transferFrom_to_zero_address() { let mut dispatcher = setup_dispatcher(); @@ -301,7 +286,6 @@ fn test_transferFrom_to_zero_address() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', 'ENTRYPOINT_FAILED'))] fn test_transferFrom_from_zero_address() { let mut dispatcher = setup_dispatcher(); @@ -313,21 +297,21 @@ fn test_transferFrom_from_zero_address() { // #[test] -#[available_gas(2000000)] fn test_increase_allowance() { let mut dispatcher = setup_dispatcher(); testing::set_contract_address(OWNER()); dispatcher.approve(SPENDER(), VALUE); utils::drop_event(dispatcher.contract_address); - assert(dispatcher.increase_allowance(SPENDER(), VALUE), 'Should return true'); + assert!(dispatcher.increase_allowance(SPENDER(), VALUE)); assert_only_event_approval(dispatcher.contract_address, OWNER(), SPENDER(), VALUE * 2); - assert(dispatcher.allowance(OWNER(), SPENDER()) == VALUE * 2, 'Should be amount * 2'); + + let allowance = dispatcher.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, VALUE * 2); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve to 0', 'ENTRYPOINT_FAILED'))] fn test_increase_allowance_to_zero_address() { let mut dispatcher = setup_dispatcher(); @@ -336,7 +320,6 @@ fn test_increase_allowance_to_zero_address() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve from 0', 'ENTRYPOINT_FAILED'))] fn test_increase_allowance_from_zero_address() { let mut dispatcher = setup_dispatcher(); @@ -344,21 +327,21 @@ fn test_increase_allowance_from_zero_address() { } #[test] -#[available_gas(2000000)] fn test_increaseAllowance() { let mut dispatcher = setup_dispatcher(); testing::set_contract_address(OWNER()); dispatcher.approve(SPENDER(), VALUE); utils::drop_event(dispatcher.contract_address); - assert(dispatcher.increaseAllowance(SPENDER(), VALUE), 'Should return true'); + assert!(dispatcher.increaseAllowance(SPENDER(), VALUE)); assert_only_event_approval(dispatcher.contract_address, OWNER(), SPENDER(), 2 * VALUE); - assert(dispatcher.allowance(OWNER(), SPENDER()) == VALUE * 2, 'Should be amount * 2'); + + let allowance = dispatcher.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, VALUE * 2); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve to 0', 'ENTRYPOINT_FAILED'))] fn test_increaseAllowance_to_zero_address() { let mut dispatcher = setup_dispatcher(); @@ -367,7 +350,6 @@ fn test_increaseAllowance_to_zero_address() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve from 0', 'ENTRYPOINT_FAILED'))] fn test_increaseAllowance_from_zero_address() { let mut dispatcher = setup_dispatcher(); @@ -379,21 +361,21 @@ fn test_increaseAllowance_from_zero_address() { // #[test] -#[available_gas(2000000)] fn test_decrease_allowance() { let mut dispatcher = setup_dispatcher(); testing::set_contract_address(OWNER()); dispatcher.approve(SPENDER(), VALUE); utils::drop_event(dispatcher.contract_address); - assert(dispatcher.decrease_allowance(SPENDER(), VALUE), 'Should return true'); + assert!(dispatcher.decrease_allowance(SPENDER(), VALUE)); assert_only_event_approval(dispatcher.contract_address, OWNER(), SPENDER(), 0); - assert(dispatcher.allowance(OWNER(), SPENDER()) == VALUE - VALUE, 'Should be 0'); + + let allowance = dispatcher.allowance(OWNER(), SPENDER()); + assert!(allowance.is_zero()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', 'ENTRYPOINT_FAILED'))] fn test_decrease_allowance_to_zero_address() { let mut dispatcher = setup_dispatcher(); @@ -402,7 +384,6 @@ fn test_decrease_allowance_to_zero_address() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', 'ENTRYPOINT_FAILED'))] fn test_decrease_allowance_from_zero_address() { let mut dispatcher = setup_dispatcher(); @@ -410,21 +391,21 @@ fn test_decrease_allowance_from_zero_address() { } #[test] -#[available_gas(2000000)] fn test_decreaseAllowance() { let mut dispatcher = setup_dispatcher(); testing::set_contract_address(OWNER()); dispatcher.approve(SPENDER(), VALUE); utils::drop_event(dispatcher.contract_address); - assert(dispatcher.decreaseAllowance(SPENDER(), VALUE), 'Should return true'); + assert!(dispatcher.decreaseAllowance(SPENDER(), VALUE)); assert_only_event_approval(dispatcher.contract_address, OWNER(), SPENDER(), 0); - assert(dispatcher.allowance(OWNER(), SPENDER()) == VALUE - VALUE, 'Should be 0'); + + let allowance = dispatcher.allowance(OWNER(), SPENDER()); + assert!(allowance.is_zero()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', 'ENTRYPOINT_FAILED'))] fn test_decreaseAllowance_to_zero_address() { let mut dispatcher = setup_dispatcher(); @@ -433,7 +414,6 @@ fn test_decreaseAllowance_to_zero_address() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow', 'ENTRYPOINT_FAILED'))] fn test_decreaseAllowance_from_zero_address() { let mut dispatcher = setup_dispatcher(); @@ -448,9 +428,9 @@ fn assert_event_approval( contract: ContractAddress, owner: ContractAddress, spender: ContractAddress, value: u256 ) { let event = utils::pop_log::(contract).unwrap(); - assert(event.owner == owner, 'Invalid `owner`'); - assert(event.spender == spender, 'Invalid `spender`'); - assert(event.value == value, 'Invalid `value`'); + assert_eq!(event.owner, owner); + assert_eq!(event.spender, spender); + assert_eq!(event.value, value); // Check indexed keys let mut indexed_keys = array![]; @@ -470,9 +450,9 @@ fn assert_event_transfer( contract: ContractAddress, from: ContractAddress, to: ContractAddress, value: u256 ) { let event = utils::pop_log::(contract).unwrap(); - assert(event.from == from, 'Invalid `from`'); - assert(event.to == to, 'Invalid `to`'); - assert(event.value == value, 'Invalid `value`'); + assert_eq!(event.from, from); + assert_eq!(event.to, to); + assert_eq!(event.value, value); // Check indexed keys let mut indexed_keys = array![]; diff --git a/src/tests/presets/test_erc721.cairo b/src/tests/presets/test_erc721.cairo index 2f2c42e74..6d2bf3346 100644 --- a/src/tests/presets/test_erc721.cairo +++ b/src/tests/presets/test_erc721.cairo @@ -11,6 +11,7 @@ use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::utils::constants::{ ZERO, DATA, OWNER, SPENDER, RECIPIENT, OTHER, OPERATOR, PUBKEY, NAME, SYMBOL }; +use openzeppelin::tests::utils::debug::DebugContractAddress; use openzeppelin::tests::utils; use openzeppelin::token::erc721::ERC721Component::InternalImpl as ERC721ComponentInternalTrait; use openzeppelin::token::erc721::ERC721Component::{Approval, ApprovalForAll, Transfer}; @@ -88,7 +89,6 @@ fn setup_camel_account() -> ContractAddress { // #[test] -#[available_gas(2000000000)] fn test__mint_assets() { let mut state = ERC721::contract_state_for_testing(); let mut token_ids = array![TOKEN_1, TOKEN_2, TOKEN_3].span(); @@ -96,7 +96,7 @@ fn test__mint_assets() { state._mint_assets(OWNER(), token_ids, token_uris); - assert(state.erc721.balance_of(OWNER()) == TOKENS_LEN, 'Should equal IDs length'); + assert_eq!(state.erc721.balance_of(OWNER()), TOKENS_LEN); loop { if token_ids.len() == 0 { @@ -106,13 +106,12 @@ fn test__mint_assets() { let id = *token_ids.pop_front().unwrap(); let uri = *token_uris.pop_front().unwrap(); - assert(state.erc721.owner_of(id) == OWNER(), 'Should be owned by OWNER'); - assert(state.erc721.token_uri(id) == uri, 'Should equal correct URI'); + assert_eq!(state.erc721.owner_of(id), OWNER()); + assert_eq!(state.erc721.token_uri(id), uri); }; } #[test] -#[available_gas(2000000000)] #[should_panic(expected: ('Array lengths do not match',))] fn test__mint_assets_mismatched_arrays_1() { let mut state = ERC721::contract_state_for_testing(); @@ -123,7 +122,6 @@ fn test__mint_assets_mismatched_arrays_1() { } #[test] -#[available_gas(2000000000)] #[should_panic(expected: ('Array lengths do not match',))] fn test__mint_assets_mismatched_arrays_2() { let mut state = ERC721::contract_state_for_testing(); @@ -138,7 +136,6 @@ fn test__mint_assets_mismatched_arrays_2() { // #[test] -#[available_gas(2000000000)] fn test_constructor() { let dispatcher = setup_dispatcher_with_event(); @@ -149,23 +146,25 @@ fn test_constructor() { if interface_ids.len() == 0 { break; } - assert(dispatcher.supports_interface(id), 'Should support interface'); + let supports_isrc5 = dispatcher.supports_interface(id); + assert!(supports_isrc5); }; // Check token balance and owner let mut tokens = array![TOKEN_1, TOKEN_2, TOKEN_3]; - assert(dispatcher.balance_of(OWNER()) == TOKENS_LEN, 'Should equal TOKENS_LEN'); + assert_eq!(dispatcher.balance_of(OWNER()), TOKENS_LEN); + loop { let token = tokens.pop_front().unwrap(); if tokens.len() == 0 { break; } - assert(dispatcher.owner_of(token) == OWNER(), 'Should be owned by OWNER'); + let current_owner = dispatcher.owner_of(token); + assert_eq!(current_owner, OWNER()); }; } #[test] -#[available_gas(2000000000)] fn test_constructor_events() { let dispatcher = setup_dispatcher_with_event(); let mut tokens = array![TOKEN_1, TOKEN_2, TOKEN_3]; @@ -186,14 +185,12 @@ fn test_constructor_events() { // #[test] -#[available_gas(20000000)] fn test_balance_of() { let dispatcher = setup_dispatcher(); - assert(dispatcher.balance_of(OWNER()) == TOKENS_LEN, 'Should return balance'); + assert_eq!(dispatcher.balance_of(OWNER()), TOKENS_LEN); } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid account', 'ENTRYPOINT_FAILED'))] fn test_balance_of_zero() { let dispatcher = setup_dispatcher(); @@ -201,14 +198,12 @@ fn test_balance_of_zero() { } #[test] -#[available_gas(20000000)] fn test_owner_of() { let dispatcher = setup_dispatcher(); - assert(dispatcher.owner_of(TOKEN_1) == OWNER(), 'Should return owner'); + assert_eq!(dispatcher.owner_of(TOKEN_1), OWNER()); } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', 'ENTRYPOINT_FAILED'))] fn test_owner_of_non_minted() { let dispatcher = setup_dispatcher(); @@ -216,7 +211,6 @@ fn test_owner_of_non_minted() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', 'ENTRYPOINT_FAILED'))] fn test_token_uri_non_minted() { let dispatcher = setup_dispatcher(); @@ -224,20 +218,20 @@ fn test_token_uri_non_minted() { } #[test] -#[available_gas(20000000)] fn test_get_approved() { let dispatcher = setup_dispatcher(); let spender = SPENDER(); let token_id = TOKEN_1; - assert(dispatcher.get_approved(token_id) == ZERO(), 'Should return non-approval'); + let approved = dispatcher.get_approved(token_id); + assert!(approved.is_zero()); dispatcher.approve(spender, token_id); - assert(dispatcher.get_approved(token_id) == spender, 'Should return approval'); + let approved = dispatcher.get_approved(token_id); + assert_eq!(approved, spender); } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', 'ENTRYPOINT_FAILED'))] fn test_get_approved_nonexistent() { let dispatcher = setup_dispatcher(); @@ -249,18 +243,17 @@ fn test_get_approved_nonexistent() { // #[test] -#[available_gas(20000000)] fn test_approve_from_owner() { let dispatcher = setup_dispatcher(); dispatcher.approve(SPENDER(), TOKEN_1); assert_event_approval(dispatcher.contract_address, OWNER(), SPENDER(), TOKEN_1); - assert(dispatcher.get_approved(TOKEN_1) == SPENDER(), 'Spender not approved correctly'); + let approved = dispatcher.get_approved(TOKEN_1); + assert_eq!(approved, SPENDER()); } #[test] -#[available_gas(20000000)] fn test_approve_from_operator() { let dispatcher = setup_dispatcher(); @@ -271,11 +264,11 @@ fn test_approve_from_operator() { dispatcher.approve(SPENDER(), TOKEN_1); assert_event_approval(dispatcher.contract_address, OWNER(), SPENDER(), TOKEN_1); - assert(dispatcher.get_approved(TOKEN_1) == SPENDER(), 'Spender not approved correctly'); + let approved = dispatcher.get_approved(TOKEN_1); + assert_eq!(approved, SPENDER()); } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: unauthorized caller', 'ENTRYPOINT_FAILED'))] fn test_approve_from_unauthorized() { let dispatcher = setup_dispatcher(); @@ -285,7 +278,6 @@ fn test_approve_from_unauthorized() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: approval to owner', 'ENTRYPOINT_FAILED'))] fn test_approve_to_owner() { let dispatcher = setup_dispatcher(); @@ -294,7 +286,6 @@ fn test_approve_to_owner() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', 'ENTRYPOINT_FAILED'))] fn test_approve_nonexistent() { let dispatcher = setup_dispatcher(); @@ -306,25 +297,26 @@ fn test_approve_nonexistent() { // #[test] -#[available_gas(20000000)] fn test_set_approval_for_all() { let dispatcher = setup_dispatcher(); - assert(!dispatcher.is_approved_for_all(OWNER(), OPERATOR()), 'Invalid default value'); + let is_not_approved_for_all = !dispatcher.is_approved_for_all(OWNER(), OPERATOR()); + assert!(is_not_approved_for_all); dispatcher.set_approval_for_all(OPERATOR(), true); assert_event_approval_for_all(dispatcher.contract_address, OWNER(), OPERATOR(), true); - assert(dispatcher.is_approved_for_all(OWNER(), OPERATOR()), 'Operator not approved correctly'); + let is_approved_for_all = dispatcher.is_approved_for_all(OWNER(), OPERATOR()); + assert!(is_approved_for_all); dispatcher.set_approval_for_all(OPERATOR(), false); assert_event_approval_for_all(dispatcher.contract_address, OWNER(), OPERATOR(), false); - assert(!dispatcher.is_approved_for_all(OWNER(), OPERATOR()), 'Approval not revoked correctly'); + let is_not_approved_for_all = !dispatcher.is_approved_for_all(OWNER(), OPERATOR()); + assert!(is_not_approved_for_all); } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: self approval', 'ENTRYPOINT_FAILED'))] fn test_set_approval_for_all_owner_equal_operator_true() { let dispatcher = setup_dispatcher(); @@ -332,7 +324,6 @@ fn test_set_approval_for_all_owner_equal_operator_true() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: self approval', 'ENTRYPOINT_FAILED'))] fn test_set_approval_for_all_owner_equal_operator_false() { let dispatcher = setup_dispatcher(); @@ -344,7 +335,6 @@ fn test_set_approval_for_all_owner_equal_operator_false() { // #[test] -#[available_gas(20000000)] fn test_transfer_from_owner() { let dispatcher = setup_dispatcher(); let token_id = TOKEN_1; @@ -356,7 +346,9 @@ fn test_transfer_from_owner() { utils::drop_event(dispatcher.contract_address); assert_state_before_transfer(dispatcher, owner, recipient, token_id); - assert(dispatcher.get_approved(token_id) == OTHER(), 'Approval not implicitly reset'); + + let approved = dispatcher.get_approved(token_id); + assert_eq!(approved, OTHER()); dispatcher.transfer_from(owner, recipient, token_id); assert_only_event_transfer(dispatcher.contract_address, owner, recipient, token_id); @@ -365,7 +357,6 @@ fn test_transfer_from_owner() { } #[test] -#[available_gas(20000000)] fn test_transferFrom_owner() { let dispatcher = setup_dispatcher(); let token_id = TOKEN_1; @@ -377,7 +368,9 @@ fn test_transferFrom_owner() { utils::drop_event(dispatcher.contract_address); assert_state_before_transfer(dispatcher, owner, recipient, token_id); - assert(dispatcher.get_approved(token_id) == OTHER(), 'Approval not implicitly reset'); + + let approved = dispatcher.get_approved(token_id); + assert_eq!(approved, OTHER()); dispatcher.transferFrom(owner, recipient, token_id); assert_only_event_transfer(dispatcher.contract_address, owner, recipient, token_id); @@ -386,7 +379,6 @@ fn test_transferFrom_owner() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', 'ENTRYPOINT_FAILED'))] fn test_transfer_from_nonexistent() { let dispatcher = setup_dispatcher(); @@ -394,7 +386,6 @@ fn test_transfer_from_nonexistent() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', 'ENTRYPOINT_FAILED'))] fn test_transferFrom_nonexistent() { let dispatcher = setup_dispatcher(); @@ -402,7 +393,6 @@ fn test_transferFrom_nonexistent() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver', 'ENTRYPOINT_FAILED'))] fn test_transfer_from_to_zero() { let dispatcher = setup_dispatcher(); @@ -410,7 +400,6 @@ fn test_transfer_from_to_zero() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver', 'ENTRYPOINT_FAILED'))] fn test_transferFrom_to_zero() { let dispatcher = setup_dispatcher(); @@ -418,7 +407,6 @@ fn test_transferFrom_to_zero() { } #[test] -#[available_gas(20000000)] fn test_transfer_from_to_owner() { let dispatcher = setup_dispatcher(); @@ -430,7 +418,6 @@ fn test_transfer_from_to_owner() { } #[test] -#[available_gas(20000000)] fn test_transferFrom_to_owner() { let dispatcher = setup_dispatcher(); @@ -442,7 +429,6 @@ fn test_transferFrom_to_owner() { } #[test] -#[available_gas(20000000)] fn test_transfer_from_approved() { let dispatcher = setup_dispatcher(); let token_id = TOKEN_1; @@ -461,7 +447,6 @@ fn test_transfer_from_approved() { } #[test] -#[available_gas(20000000)] fn test_transferFrom_approved() { let dispatcher = setup_dispatcher(); let token_id = TOKEN_1; @@ -480,7 +465,6 @@ fn test_transferFrom_approved() { } #[test] -#[available_gas(20000000)] fn test_transfer_from_approved_for_all() { let dispatcher = setup_dispatcher(); let token_id = TOKEN_1; @@ -500,7 +484,6 @@ fn test_transfer_from_approved_for_all() { } #[test] -#[available_gas(20000000)] fn test_transferFrom_approved_for_all() { let dispatcher = setup_dispatcher(); let token_id = TOKEN_1; @@ -520,7 +503,6 @@ fn test_transferFrom_approved_for_all() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: unauthorized caller', 'ENTRYPOINT_FAILED'))] fn test_transfer_from_unauthorized() { let dispatcher = setup_dispatcher(); @@ -529,7 +511,6 @@ fn test_transfer_from_unauthorized() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: unauthorized caller', 'ENTRYPOINT_FAILED'))] fn test_transferFrom_unauthorized() { let dispatcher = setup_dispatcher(); @@ -542,7 +523,6 @@ fn test_transferFrom_unauthorized() { // #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_to_account() { let dispatcher = setup_dispatcher(); let account = setup_account(); @@ -558,7 +538,6 @@ fn test_safe_transfer_from_to_account() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_to_account() { let dispatcher = setup_dispatcher(); let account = setup_account(); @@ -574,7 +553,6 @@ fn test_safeTransferFrom_to_account() { } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_to_account_camel() { let dispatcher = setup_dispatcher(); let account = setup_camel_account(); @@ -590,7 +568,6 @@ fn test_safe_transfer_from_to_account_camel() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_to_account_camel() { let dispatcher = setup_dispatcher(); let account = setup_camel_account(); @@ -606,7 +583,6 @@ fn test_safeTransferFrom_to_account_camel() { } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_to_receiver() { let dispatcher = setup_dispatcher(); let receiver = setup_receiver(); @@ -622,7 +598,6 @@ fn test_safe_transfer_from_to_receiver() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_to_receiver() { let dispatcher = setup_dispatcher(); let receiver = setup_receiver(); @@ -638,7 +613,6 @@ fn test_safeTransferFrom_to_receiver() { } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_to_receiver_camel() { let dispatcher = setup_dispatcher(); let receiver = setup_camel_receiver(); @@ -654,7 +628,6 @@ fn test_safe_transfer_from_to_receiver_camel() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_to_receiver_camel() { let dispatcher = setup_dispatcher(); let receiver = setup_camel_receiver(); @@ -670,7 +643,6 @@ fn test_safeTransferFrom_to_receiver_camel() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: safe transfer failed', 'ENTRYPOINT_FAILED'))] fn test_safe_transfer_from_to_receiver_failure() { let dispatcher = setup_dispatcher(); @@ -682,7 +654,6 @@ fn test_safe_transfer_from_to_receiver_failure() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: safe transfer failed', 'ENTRYPOINT_FAILED'))] fn test_safeTransferFrom_to_receiver_failure() { let dispatcher = setup_dispatcher(); @@ -694,7 +665,6 @@ fn test_safeTransferFrom_to_receiver_failure() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: safe transfer failed', 'ENTRYPOINT_FAILED'))] fn test_safe_transfer_from_to_receiver_failure_camel() { let dispatcher = setup_dispatcher(); @@ -706,7 +676,6 @@ fn test_safe_transfer_from_to_receiver_failure_camel() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: safe transfer failed', 'ENTRYPOINT_FAILED'))] fn test_safeTransferFrom_to_receiver_failure_camel() { let dispatcher = setup_dispatcher(); @@ -718,7 +687,6 @@ fn test_safeTransferFrom_to_receiver_failure_camel() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', 'ENTRYPOINT_FAILED'))] fn test_safe_transfer_from_to_non_receiver() { let dispatcher = setup_dispatcher(); @@ -730,7 +698,6 @@ fn test_safe_transfer_from_to_non_receiver() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND', 'ENTRYPOINT_FAILED'))] fn test_safeTransferFrom_to_non_receiver() { let dispatcher = setup_dispatcher(); @@ -742,7 +709,6 @@ fn test_safeTransferFrom_to_non_receiver() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', 'ENTRYPOINT_FAILED'))] fn test_safe_transfer_from_nonexistent() { let dispatcher = setup_dispatcher(); @@ -750,7 +716,6 @@ fn test_safe_transfer_from_nonexistent() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID', 'ENTRYPOINT_FAILED'))] fn test_safeTransferFrom_nonexistent() { let dispatcher = setup_dispatcher(); @@ -758,7 +723,6 @@ fn test_safeTransferFrom_nonexistent() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver', 'ENTRYPOINT_FAILED'))] fn test_safe_transfer_from_to_zero() { let dispatcher = setup_dispatcher(); @@ -766,7 +730,6 @@ fn test_safe_transfer_from_to_zero() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver', 'ENTRYPOINT_FAILED'))] fn test_safeTransferFrom_to_zero() { let dispatcher = setup_dispatcher(); @@ -774,7 +737,6 @@ fn test_safeTransferFrom_to_zero() { } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_to_owner() { let dispatcher = setup_dispatcher(); let token_id = TOKEN_1; @@ -793,7 +755,6 @@ fn test_safe_transfer_from_to_owner() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_to_owner() { let dispatcher = setup_dispatcher(); let token_id = TOKEN_1; @@ -812,7 +773,6 @@ fn test_safeTransferFrom_to_owner() { } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_to_owner_camel() { let dispatcher = setup_dispatcher(); let token_id = TOKEN_1; @@ -831,7 +791,6 @@ fn test_safe_transfer_from_to_owner_camel() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_to_owner_camel() { let dispatcher = setup_dispatcher(); let token_id = TOKEN_1; @@ -850,7 +809,6 @@ fn test_safeTransferFrom_to_owner_camel() { } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_approved() { let dispatcher = setup_dispatcher(); let receiver = setup_receiver(); @@ -870,7 +828,6 @@ fn test_safe_transfer_from_approved() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_approved() { let dispatcher = setup_dispatcher(); let receiver = setup_receiver(); @@ -890,7 +847,6 @@ fn test_safeTransferFrom_approved() { } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_approved_camel() { let dispatcher = setup_dispatcher(); let receiver = setup_camel_receiver(); @@ -910,7 +866,6 @@ fn test_safe_transfer_from_approved_camel() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_approved_camel() { let dispatcher = setup_dispatcher(); let receiver = setup_camel_receiver(); @@ -930,7 +885,6 @@ fn test_safeTransferFrom_approved_camel() { } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_approved_for_all() { let dispatcher = setup_dispatcher(); let receiver = setup_receiver(); @@ -950,7 +904,6 @@ fn test_safe_transfer_from_approved_for_all() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_approved_for_all() { let dispatcher = setup_dispatcher(); let receiver = setup_receiver(); @@ -970,7 +923,6 @@ fn test_safeTransferFrom_approved_for_all() { } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_approved_for_all_camel() { let dispatcher = setup_dispatcher(); let receiver = setup_camel_receiver(); @@ -990,7 +942,6 @@ fn test_safe_transfer_from_approved_for_all_camel() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_approved_for_all_camel() { let dispatcher = setup_dispatcher(); let receiver = setup_camel_receiver(); @@ -1010,7 +961,6 @@ fn test_safeTransferFrom_approved_for_all_camel() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: unauthorized caller', 'ENTRYPOINT_FAILED'))] fn test_safe_transfer_from_unauthorized() { let dispatcher = setup_dispatcher(); @@ -1019,7 +969,6 @@ fn test_safe_transfer_from_unauthorized() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: unauthorized caller', 'ENTRYPOINT_FAILED'))] fn test_safeTransferFrom_unauthorized() { let dispatcher = setup_dispatcher(); @@ -1037,9 +986,9 @@ fn assert_state_before_transfer( recipient: ContractAddress, token_id: u256 ) { - assert(dispatcher.owner_of(token_id) == owner, 'Ownership before'); - assert(dispatcher.balance_of(owner) == TOKENS_LEN, 'Balance of owner before'); - assert(dispatcher.balance_of(recipient) == 0, 'Balance of recipient before'); + assert_eq!(dispatcher.owner_of(token_id), owner); + assert_eq!(dispatcher.balance_of(owner), TOKENS_LEN); + assert!(dispatcher.balance_of(recipient).is_zero()); } fn assert_state_after_transfer( @@ -1048,26 +997,29 @@ fn assert_state_after_transfer( recipient: ContractAddress, token_id: u256 ) { - assert(dispatcher.owner_of(token_id) == recipient, 'Ownership after'); - assert(dispatcher.balance_of(owner) == TOKENS_LEN - 1, 'Balance of owner after'); - assert(dispatcher.balance_of(recipient) == 1, 'Balance of recipient after'); - assert(dispatcher.get_approved(token_id) == ZERO(), 'Approval not implicitly reset'); + let current_owner = dispatcher.owner_of(token_id); + assert_eq!(current_owner, recipient); + assert_eq!(dispatcher.balance_of(owner), TOKENS_LEN - 1); + assert_eq!(dispatcher.balance_of(recipient), 1); + + let approved = dispatcher.get_approved(token_id); + assert!(approved.is_zero()); } fn assert_state_transfer_to_self( dispatcher: ERC721ABIDispatcher, target: ContractAddress, token_id: u256, token_balance: u256 ) { - assert(dispatcher.owner_of(token_id) == target, 'Ownership before'); - assert(dispatcher.balance_of(target) == token_balance, 'Balance of owner before'); + assert_eq!(dispatcher.owner_of(token_id), target); + assert_eq!(dispatcher.balance_of(target), token_balance); } fn assert_event_approval_for_all( contract: ContractAddress, owner: ContractAddress, operator: ContractAddress, approved: bool ) { let event = utils::pop_log::(contract).unwrap(); - assert(event.owner == owner, 'Invalid `owner`'); - assert(event.operator == operator, 'Invalid `operator`'); - assert(event.approved == approved, 'Invalid `approved`'); + assert_eq!(event.owner, owner); + assert_eq!(event.operator, operator); + assert_eq!(event.approved, approved); utils::assert_no_events_left(contract); // Check indexed keys @@ -1081,9 +1033,9 @@ fn assert_event_approval( contract: ContractAddress, owner: ContractAddress, approved: ContractAddress, token_id: u256 ) { let event = utils::pop_log::(contract).unwrap(); - assert(event.owner == owner, 'Invalid `owner`'); - assert(event.approved == approved, 'Invalid `approved`'); - assert(event.token_id == token_id, 'Invalid `token_id`'); + assert_eq!(event.owner, owner); + assert_eq!(event.approved, approved); + assert_eq!(event.token_id, token_id); utils::assert_no_events_left(contract); // Check indexed keys @@ -1098,9 +1050,9 @@ fn assert_event_transfer( contract: ContractAddress, from: ContractAddress, to: ContractAddress, token_id: u256 ) { let event = utils::pop_log::(contract).unwrap(); - assert(event.from == from, 'Invalid `from`'); - assert(event.to == to, 'Invalid `to`'); - assert(event.token_id == token_id, 'Invalid `token_id`'); + assert_eq!(event.from, from); + assert_eq!(event.to, to); + assert_eq!(event.token_id, token_id); // Check indexed keys let mut indexed_keys = array![]; diff --git a/src/tests/security/test_initializable.cairo b/src/tests/security/test_initializable.cairo index 5b70c5d7c..745b34518 100644 --- a/src/tests/security/test_initializable.cairo +++ b/src/tests/security/test_initializable.cairo @@ -1,6 +1,6 @@ use openzeppelin::security::InitializableComponent::{InitializableImpl, InternalImpl}; use openzeppelin::security::InitializableComponent; -use openzeppelin::tests::mocks::initializable_mock::InitializableMock; +use openzeppelin::tests::mocks::initializable_mocks::InitializableMock; type ComponentState = InitializableComponent::ComponentState; @@ -9,16 +9,14 @@ fn COMPONENT_STATE() -> ComponentState { } #[test] -#[available_gas(2000000)] fn test_initialize() { let mut state = COMPONENT_STATE(); - assert(!state.is_initialized(), 'Should not be initialized'); + assert!(!state.is_initialized()); state.initialize(); - assert(state.is_initialized(), 'Should be initialized'); + assert!(state.is_initialized()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Initializable: is initialized',))] fn test_initialize_when_initialized() { let mut state = COMPONENT_STATE(); diff --git a/src/tests/security/test_pausable.cairo b/src/tests/security/test_pausable.cairo index df0204160..fb675e55b 100644 --- a/src/tests/security/test_pausable.cairo +++ b/src/tests/security/test_pausable.cairo @@ -1,8 +1,9 @@ use openzeppelin::security::PausableComponent::{InternalImpl, PausableImpl}; use openzeppelin::security::PausableComponent::{Paused, Unpaused}; use openzeppelin::security::PausableComponent; -use openzeppelin::tests::mocks::pausable_mock::PausableMock; +use openzeppelin::tests::mocks::pausable_mocks::PausableMock; use openzeppelin::tests::utils::constants::{CALLER, ZERO}; +use openzeppelin::tests::utils::debug::DebugContractAddress; use openzeppelin::tests::utils; use starknet::ContractAddress; use starknet::contract_address_const; @@ -19,16 +20,15 @@ fn COMPONENT_STATE() -> ComponentState { // #[test] -#[available_gas(2000000)] fn test_is_paused() { let mut state = COMPONENT_STATE(); - assert(!state.is_paused(), 'Should not be paused'); + assert!(!state.is_paused()); state._pause(); - assert(state.is_paused(), 'Should be paused'); + assert!(state.is_paused()); state._unpause(); - assert(!state.is_paused(), 'Should not be paused'); + assert!(!state.is_paused()); } // @@ -36,7 +36,6 @@ fn test_is_paused() { // #[test] -#[available_gas(2000000)] fn test_assert_paused_when_paused() { let mut state = COMPONENT_STATE(); state._pause(); @@ -44,7 +43,6 @@ fn test_assert_paused_when_paused() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Pausable: not paused',))] fn test_assert_paused_when_not_paused() { let state = COMPONENT_STATE(); @@ -56,7 +54,6 @@ fn test_assert_paused_when_not_paused() { // #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Pausable: paused',))] fn test_assert_not_paused_when_paused() { let mut state = COMPONENT_STATE(); @@ -65,7 +62,6 @@ fn test_assert_not_paused_when_paused() { } #[test] -#[available_gas(2000000)] fn test_assert_not_paused_when_not_paused() { let state = COMPONENT_STATE(); state.assert_not_paused(); @@ -76,7 +72,6 @@ fn test_assert_not_paused_when_not_paused() { // #[test] -#[available_gas(2000000)] fn test_pause_when_unpaused() { let mut state = COMPONENT_STATE(); testing::set_caller_address(CALLER()); @@ -84,11 +79,10 @@ fn test_pause_when_unpaused() { state._pause(); assert_event_paused(CALLER()); - assert(state.is_paused(), 'Should be paused'); + assert!(state.is_paused()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Pausable: paused',))] fn test_pause_when_paused() { let mut state = COMPONENT_STATE(); @@ -101,7 +95,6 @@ fn test_pause_when_paused() { // #[test] -#[available_gas(2000000)] fn test_unpause_when_paused() { let mut state = COMPONENT_STATE(); testing::set_caller_address(CALLER()); @@ -112,15 +105,14 @@ fn test_unpause_when_paused() { state._unpause(); assert_event_unpaused(CALLER()); - assert(!state.is_paused(), 'Should not be paused'); + assert!(!state.is_paused()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Pausable: not paused',))] fn test_unpause_when_unpaused() { let mut state = COMPONENT_STATE(); - assert(!state.is_paused(), 'Should be paused'); + assert!(!state.is_paused()); state._unpause(); } @@ -130,12 +122,12 @@ fn test_unpause_when_unpaused() { fn assert_event_paused(account: ContractAddress) { let event = utils::pop_log::(ZERO()).unwrap(); - assert(event.account == account, 'Invalid `account`'); + assert_eq!(event.account, account); utils::assert_no_events_left(ZERO()); } fn assert_event_unpaused(account: ContractAddress) { let event = utils::pop_log::(ZERO()).unwrap(); - assert(event.account == account, 'Invalid `account`'); + assert_eq!(event.account, account); utils::assert_no_events_left(ZERO()); } diff --git a/src/tests/security/test_reentrancyguard.cairo b/src/tests/security/test_reentrancyguard.cairo index 4824308c4..327f72fa4 100644 --- a/src/tests/security/test_reentrancyguard.cairo +++ b/src/tests/security/test_reentrancyguard.cairo @@ -1,9 +1,8 @@ use openzeppelin::security::ReentrancyGuardComponent::InternalImpl; use openzeppelin::security::ReentrancyGuardComponent; -use openzeppelin::tests::mocks::reentrancy_attacker_mock::Attacker; -use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcher; -use openzeppelin::tests::mocks::reentrancy_mock::IReentrancyMockDispatcherTrait; -use openzeppelin::tests::mocks::reentrancy_mock::ReentrancyMock; +use openzeppelin::tests::mocks::reentrancy_mocks::{ + Attacker, ReentrancyMock, IReentrancyMockDispatcher, IReentrancyMockDispatcherTrait +}; use openzeppelin::tests::utils; use starknet::storage::StorageMemberAccessTrait; @@ -24,17 +23,19 @@ fn deploy_mock() -> IReentrancyMockDispatcher { // #[test] -#[available_gas(2000000)] fn test_reentrancy_guard_start() { let mut state = COMPONENT_STATE(); - assert(!state.ReentrancyGuard_entered.read(), 'Should not be entered'); + let not_entered = !state.ReentrancyGuard_entered.read(); + assert!(not_entered); + state.start(); - assert(state.ReentrancyGuard_entered.read(), 'Should be entered'); + + let entered = state.ReentrancyGuard_entered.read(); + assert!(entered); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ReentrancyGuard: reentrant call',))] fn test_reentrancy_guard_start_when_started() { let mut state = COMPONENT_STATE(); @@ -44,14 +45,18 @@ fn test_reentrancy_guard_start_when_started() { } #[test] -#[available_gas(2000000)] fn test_reentrancy_guard_end() { let mut state = COMPONENT_STATE(); state.start(); - assert(state.ReentrancyGuard_entered.read(), 'Should be entered'); + + let entered = state.ReentrancyGuard_entered.read(); + assert!(entered); + state.end(); - assert(!state.ReentrancyGuard_entered.read(), 'Should no longer be entered'); + + let not_entered = !state.ReentrancyGuard_entered.read(); + assert!(not_entered); } // @@ -59,7 +64,6 @@ fn test_reentrancy_guard_end() { // #[test] -#[available_gas(2000000)] #[should_panic( expected: ( 'ReentrancyGuard: reentrant call', @@ -79,7 +83,6 @@ fn test_remote_callback() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ReentrancyGuard: reentrant call', 'ENTRYPOINT_FAILED'))] fn test_local_recursion() { let contract = deploy_mock(); @@ -87,7 +90,6 @@ fn test_local_recursion() { } #[test] -#[available_gas(2000000)] #[should_panic( expected: ('ReentrancyGuard: reentrant call', 'ENTRYPOINT_FAILED', 'ENTRYPOINT_FAILED') )] @@ -97,9 +99,8 @@ fn test_external_recursion() { } #[test] -#[available_gas(2000000)] fn test_nonreentrant_function_call() { let contract = deploy_mock(); contract.callback(); - assert(contract.current_count() == 1, 'Call should execute'); + assert_eq!(contract.current_count(), 1, "Call should execute"); } diff --git a/src/tests/token/test_dual20.cairo b/src/tests/token/test_dual20.cairo index 48324ff9c..5e85fa1f2 100644 --- a/src/tests/token/test_dual20.cairo +++ b/src/tests/token/test_dual20.cairo @@ -55,16 +55,15 @@ fn setup_erc20_panic() -> (DualCaseERC20, DualCaseERC20) { // #[test] -#[available_gas(2000000)] fn test_dual_name() { let (snake_dispatcher, _) = setup_snake(); + assert_eq!(snake_dispatcher.name(), NAME); + let (camel_dispatcher, _) = setup_camel(); - assert(snake_dispatcher.name() == NAME, 'Should return name'); - assert(camel_dispatcher.name() == NAME, 'Should return name'); + assert_eq!(camel_dispatcher.name(), NAME); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_name() { let dispatcher = setup_non_erc20(); @@ -72,24 +71,21 @@ fn test_dual_no_name() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_name_exists_and_panics() { let (dispatcher, _) = setup_erc20_panic(); dispatcher.name(); } #[test] -#[available_gas(2000000)] fn test_dual_symbol() { let (snake_dispatcher, _) = setup_snake(); let (camel_dispatcher, _) = setup_camel(); - assert(snake_dispatcher.symbol() == SYMBOL, 'Should return symbol'); - assert(camel_dispatcher.symbol() == SYMBOL, 'Should return symbol'); + assert_eq!(snake_dispatcher.symbol(), SYMBOL); + assert_eq!(camel_dispatcher.symbol(), SYMBOL); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_symbol() { let dispatcher = setup_non_erc20(); @@ -97,24 +93,21 @@ fn test_dual_no_symbol() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_symbol_exists_and_panics() { let (dispatcher, _) = setup_erc20_panic(); dispatcher.symbol(); } #[test] -#[available_gas(2000000)] fn test_dual_decimals() { let (snake_dispatcher, _) = setup_snake(); let (camel_dispatcher, _) = setup_camel(); - assert(snake_dispatcher.decimals() == DECIMALS, 'Should return symbol'); - assert(camel_dispatcher.decimals() == DECIMALS, 'Should return symbol'); + assert_eq!(snake_dispatcher.decimals(), DECIMALS); + assert_eq!(camel_dispatcher.decimals(), DECIMALS); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_decimals() { let dispatcher = setup_non_erc20(); @@ -122,29 +115,26 @@ fn test_dual_no_decimals() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_decimals_exists_and_panics() { let (dispatcher, _) = setup_erc20_panic(); dispatcher.decimals(); } #[test] -#[available_gas(2000000)] fn test_dual_transfer() { let (snake_dispatcher, snake_target) = setup_snake(); set_contract_address(OWNER()); - assert(snake_dispatcher.transfer(RECIPIENT(), VALUE), 'Should return true'); - assert(snake_target.balance_of(RECIPIENT()) == VALUE, 'Should equal VALUE'); + assert!(snake_dispatcher.transfer(RECIPIENT(), VALUE)); + assert_eq!(snake_target.balance_of(RECIPIENT()), VALUE); let (camel_dispatcher, camel_target) = setup_camel(); set_contract_address(OWNER()); - assert(camel_dispatcher.transfer(RECIPIENT(), VALUE), 'Should return true'); - assert(camel_target.balanceOf(RECIPIENT()) == VALUE, 'Should equal VALUE'); + assert!(camel_dispatcher.transfer(RECIPIENT(), VALUE)); + assert_eq!(camel_target.balanceOf(RECIPIENT()), VALUE); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_transfer() { let dispatcher = setup_non_erc20(); @@ -152,29 +142,30 @@ fn test_dual_no_transfer() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_transfer_exists_and_panics() { let (dispatcher, _) = setup_erc20_panic(); dispatcher.transfer(RECIPIENT(), VALUE); } #[test] -#[available_gas(2000000)] fn test_dual_approve() { let (snake_dispatcher, snake_target) = setup_snake(); set_contract_address(OWNER()); - assert(snake_dispatcher.approve(SPENDER(), VALUE), 'Should return true'); - assert(snake_target.allowance(OWNER(), SPENDER()) == VALUE, 'Allowance should equal VALUE'); + assert!(snake_dispatcher.approve(SPENDER(), VALUE)); + + let snake_allowance = snake_target.allowance(OWNER(), SPENDER()); + assert_eq!(snake_allowance, VALUE); let (camel_dispatcher, camel_target) = setup_camel(); set_contract_address(OWNER()); - assert(camel_dispatcher.approve(SPENDER(), VALUE), 'Should return true'); - assert(camel_target.allowance(OWNER(), SPENDER()) == VALUE, 'Allowance should equal VALUE'); + assert!(camel_dispatcher.approve(SPENDER(), VALUE)); + + let camel_allowance = camel_target.allowance(OWNER(), SPENDER()); + assert_eq!(camel_allowance, VALUE); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_approve() { let dispatcher = setup_non_erc20(); @@ -182,8 +173,7 @@ fn test_dual_no_approve() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_approve_exists_and_panics() { let (dispatcher, _) = setup_erc20_panic(); dispatcher.approve(SPENDER(), VALUE); @@ -194,14 +184,12 @@ fn test_dual_approve_exists_and_panics() { // #[test] -#[available_gas(2000000)] fn test_dual_total_supply() { let (dispatcher, _) = setup_snake(); - assert(dispatcher.total_supply() == SUPPLY, 'Should return balance'); + assert_eq!(dispatcher.total_supply(), SUPPLY); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_total_supply() { let dispatcher = setup_non_erc20(); @@ -209,22 +197,19 @@ fn test_dual_no_total_supply() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_total_supply_exists_and_panics() { let (dispatcher, _) = setup_erc20_panic(); dispatcher.total_supply(); } #[test] -#[available_gas(2000000)] fn test_dual_balance_of() { let (dispatcher, _) = setup_snake(); - assert(dispatcher.balance_of(OWNER()) == SUPPLY, 'Should return balance'); + assert_eq!(dispatcher.balance_of(OWNER()), SUPPLY); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_balance_of() { let dispatcher = setup_non_erc20(); @@ -232,15 +217,13 @@ fn test_dual_no_balance_of() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_balance_of_exists_and_panics() { let (dispatcher, _) = setup_erc20_panic(); dispatcher.balance_of(OWNER()); } #[test] -#[available_gas(2000000)] fn test_dual_transfer_from() { let (dispatcher, target) = setup_snake(); set_contract_address(OWNER()); @@ -248,11 +231,10 @@ fn test_dual_transfer_from() { set_contract_address(OPERATOR()); dispatcher.transfer_from(OWNER(), RECIPIENT(), VALUE); - assert(target.balance_of(RECIPIENT()) == VALUE, 'Should transfer VALUE'); + assert_eq!(target.balance_of(RECIPIENT()), VALUE); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_transfer_from() { let dispatcher = setup_non_erc20(); @@ -260,8 +242,7 @@ fn test_dual_no_transfer_from() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_transfer_from_exists_and_panics() { let (dispatcher, _) = setup_erc20_panic(); dispatcher.transfer_from(OWNER(), RECIPIENT(), VALUE); @@ -272,37 +253,32 @@ fn test_dual_transfer_from_exists_and_panics() { // #[test] -#[available_gas(2000000)] fn test_dual_totalSupply() { let (dispatcher, _) = setup_camel(); - assert(dispatcher.total_supply() == SUPPLY, 'Should return supply'); + assert_eq!(dispatcher.total_supply(), SUPPLY); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_totalSupply_exists_and_panics() { let (_, dispatcher) = setup_erc20_panic(); dispatcher.total_supply(); } #[test] -#[available_gas(2000000)] fn test_dual_balanceOf() { let (dispatcher, _) = setup_camel(); - assert(dispatcher.balance_of(OWNER()) == SUPPLY, 'Should return balance'); + assert_eq!(dispatcher.balance_of(OWNER()), SUPPLY); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_balanceOf_exists_and_panics() { let (_, dispatcher) = setup_erc20_panic(); dispatcher.balance_of(OWNER()); } #[test] -#[available_gas(2000000)] fn test_dual_transferFrom() { let (dispatcher, target) = setup_camel(); set_contract_address(OWNER()); @@ -310,12 +286,11 @@ fn test_dual_transferFrom() { set_contract_address(OPERATOR()); dispatcher.transfer_from(OWNER(), RECIPIENT(), VALUE); - assert(target.balanceOf(RECIPIENT()) == VALUE, 'Should transfer VALUE'); + assert_eq!(target.balanceOf(RECIPIENT()), VALUE); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_transferFrom_exists_and_panics() { let (_, dispatcher) = setup_erc20_panic(); dispatcher.transfer_from(OWNER(), RECIPIENT(), VALUE); diff --git a/src/tests/token/test_dual721.cairo b/src/tests/token/test_dual721.cairo index 28e2c196b..d398b2b75 100644 --- a/src/tests/token/test_dual721.cairo +++ b/src/tests/token/test_dual721.cairo @@ -5,6 +5,7 @@ use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::utils::constants::{ DATA, OWNER, RECIPIENT, SPENDER, OPERATOR, OTHER, NAME, SYMBOL, URI, TOKEN_ID }; +use openzeppelin::tests::utils::debug::DebugContractAddress; use openzeppelin::tests::utils; use openzeppelin::token::erc721::dual721::{DualCaseERC721, DualCaseERC721Trait}; use openzeppelin::token::erc721::interface::IERC721_ID; @@ -72,16 +73,14 @@ fn setup_receiver() -> ContractAddress { // #[test] -#[available_gas(2000000)] fn test_dual_name() { let (snake_dispatcher, _) = setup_snake(); let (camel_dispatcher, _) = setup_camel(); - assert(snake_dispatcher.name() == NAME, 'Should return name'); - assert(camel_dispatcher.name() == NAME, 'Should return name'); + assert_eq!(snake_dispatcher.name(), NAME); + assert_eq!(camel_dispatcher.name(), NAME); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_name() { let dispatcher = setup_non_erc721(); @@ -89,24 +88,21 @@ fn test_dual_no_name() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_name_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.name(); } #[test] -#[available_gas(2000000)] fn test_dual_symbol() { let (snake_dispatcher, _) = setup_snake(); let (camel_dispatcher, _) = setup_camel(); - assert(snake_dispatcher.symbol() == SYMBOL, 'Should return symbol'); - assert(camel_dispatcher.symbol() == SYMBOL, 'Should return symbol'); + assert_eq!(snake_dispatcher.symbol(), SYMBOL); + assert_eq!(camel_dispatcher.symbol(), SYMBOL); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_symbol() { let dispatcher = setup_non_erc721(); @@ -114,29 +110,26 @@ fn test_dual_no_symbol() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_symbol_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.symbol(); } #[test] -#[available_gas(20000000)] fn test_dual_approve() { let (snake_dispatcher, snake_target) = setup_snake(); set_contract_address(OWNER()); snake_dispatcher.approve(SPENDER(), TOKEN_ID); - assert(snake_target.get_approved(TOKEN_ID) == SPENDER(), 'Spender not approved correctly'); + assert_eq!(snake_target.get_approved(TOKEN_ID), SPENDER()); let (camel_dispatcher, camel_target) = setup_camel(); set_contract_address(OWNER()); camel_dispatcher.approve(SPENDER(), TOKEN_ID); - assert(camel_target.getApproved(TOKEN_ID) == SPENDER(), 'Spender not approved correctly'); + assert_eq!(camel_target.getApproved(TOKEN_ID), SPENDER()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_approve() { let dispatcher = setup_non_erc721(); @@ -144,8 +137,7 @@ fn test_dual_no_approve() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_approve_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.approve(SPENDER(), TOKEN_ID); @@ -156,14 +148,12 @@ fn test_dual_approve_exists_and_panics() { // #[test] -#[available_gas(2000000)] fn test_dual_balance_of() { let (dispatcher, _) = setup_snake(); - assert(dispatcher.balance_of(OWNER()) == 1, 'Should return balance'); + assert_eq!(dispatcher.balance_of(OWNER()), 1); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_balance_of() { let dispatcher = setup_non_erc721(); @@ -171,22 +161,19 @@ fn test_dual_no_balance_of() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_balance_of_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.balance_of(OWNER()); } #[test] -#[available_gas(2000000)] fn test_dual_owner_of() { let (dispatcher, target) = setup_snake(); - assert(dispatcher.owner_of(TOKEN_ID) == OWNER(), 'Should return owner'); + assert_eq!(dispatcher.owner_of(TOKEN_ID), OWNER()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_owner_of() { let dispatcher = setup_non_erc721(); @@ -194,23 +181,20 @@ fn test_dual_no_owner_of() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_owner_of_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.owner_of(TOKEN_ID); } #[test] -#[available_gas(2000000)] fn test_dual_transfer_from() { let (dispatcher, target) = setup_snake(); dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID); - assert(target.owner_of(TOKEN_ID) == RECIPIENT(), 'Should transfer token'); + assert_eq!(target.owner_of(TOKEN_ID), RECIPIENT()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_transfer_from() { let dispatcher = setup_non_erc721(); @@ -218,24 +202,21 @@ fn test_dual_no_transfer_from() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_transfer_from_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID); } #[test] -#[available_gas(2000000)] fn test_dual_safe_transfer_from() { let (dispatcher, target) = setup_snake(); let receiver = setup_receiver(); dispatcher.safe_transfer_from(OWNER(), receiver, TOKEN_ID, DATA(true)); - assert(target.owner_of(TOKEN_ID) == receiver, 'Should transfer token'); + assert_eq!(target.owner_of(TOKEN_ID), receiver); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_safe_transfer_from() { let dispatcher = setup_non_erc721(); @@ -243,24 +224,21 @@ fn test_dual_no_safe_transfer_from() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_safe_transfer_from_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID, DATA(true)); } #[test] -#[available_gas(2000000)] fn test_dual_get_approved() { let (dispatcher, target) = setup_snake(); set_contract_address(OWNER()); target.approve(SPENDER(), TOKEN_ID); - assert(dispatcher.get_approved(TOKEN_ID) == SPENDER(), 'Should return approval'); + assert_eq!(dispatcher.get_approved(TOKEN_ID), SPENDER()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_get_approved() { let dispatcher = setup_non_erc721(); @@ -268,24 +246,23 @@ fn test_dual_no_get_approved() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_get_approved_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.get_approved(TOKEN_ID); } #[test] -#[available_gas(2000000)] fn test_dual_set_approval_for_all() { let (dispatcher, target) = setup_snake(); set_contract_address(OWNER()); dispatcher.set_approval_for_all(OPERATOR(), true); - assert(target.is_approved_for_all(OWNER(), OPERATOR()), 'Operator not approved correctly'); + + let is_approved_for_all = target.is_approved_for_all(OWNER(), OPERATOR()); + assert!(is_approved_for_all); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_set_approval_for_all() { let dispatcher = setup_non_erc721(); @@ -293,24 +270,23 @@ fn test_dual_no_set_approval_for_all() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_set_approval_for_all_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.set_approval_for_all(OPERATOR(), true); } #[test] -#[available_gas(2000000)] fn test_dual_is_approved_for_all() { let (dispatcher, target) = setup_snake(); set_contract_address(OWNER()); target.set_approval_for_all(OPERATOR(), true); - assert(dispatcher.is_approved_for_all(OWNER(), OPERATOR()), 'Operator not approved correctly'); + + let is_approved_for_all = dispatcher.is_approved_for_all(OWNER(), OPERATOR()); + assert!(is_approved_for_all); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_is_approved_for_all() { let dispatcher = setup_non_erc721(); @@ -318,22 +294,19 @@ fn test_dual_no_is_approved_for_all() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_is_approved_for_all_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.is_approved_for_all(OWNER(), OPERATOR()); } #[test] -#[available_gas(2000000)] fn test_dual_token_uri() { let (dispatcher, target) = setup_snake(); - assert(dispatcher.token_uri(TOKEN_ID) == URI, 'Should return URI'); + assert_eq!(dispatcher.token_uri(TOKEN_ID), URI); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_token_uri() { let dispatcher = setup_non_erc721(); @@ -341,22 +314,20 @@ fn test_dual_no_token_uri() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_token_uri_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.token_uri(TOKEN_ID); } #[test] -#[available_gas(2000000)] fn test_dual_supports_interface() { let (dispatcher, _) = setup_snake(); - assert(dispatcher.supports_interface(IERC721_ID), 'Should support own interface'); + let supports_ierc721 = dispatcher.supports_interface(IERC721_ID); + assert!(supports_ierc721); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_supports_interface() { let dispatcher = setup_non_erc721(); @@ -364,8 +335,7 @@ fn test_dual_no_supports_interface() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_supports_interface_exists_and_panics() { let (dispatcher, _) = setup_erc721_panic(); dispatcher.supports_interface(IERC721_ID); @@ -376,145 +346,140 @@ fn test_dual_supports_interface_exists_and_panics() { // #[test] -#[available_gas(2000000)] fn test_dual_balanceOf() { let (dispatcher, _) = setup_camel(); - assert(dispatcher.balance_of(OWNER()) == 1, 'Should return balance'); + assert_eq!(dispatcher.balance_of(OWNER()), 1); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_balanceOf_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.balance_of(OWNER()); } #[test] -#[available_gas(2000000)] fn test_dual_ownerOf() { let (dispatcher, target) = setup_camel(); - assert(dispatcher.owner_of(TOKEN_ID) == OWNER(), 'Should return owner'); + let current_owner = dispatcher.owner_of(TOKEN_ID); + assert_eq!(current_owner, OWNER()); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_ownerOf_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.owner_of(TOKEN_ID); } #[test] -#[available_gas(2000000)] fn test_dual_transferFrom() { let (dispatcher, target) = setup_camel(); set_contract_address(OWNER()); dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID); - assert(target.ownerOf(TOKEN_ID) == RECIPIENT(), 'Should transfer token'); + + let current_owner = target.ownerOf(TOKEN_ID); + assert_eq!(current_owner, RECIPIENT()); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_transferFrom_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.transfer_from(OWNER(), RECIPIENT(), TOKEN_ID); } #[test] -#[available_gas(2000000)] fn test_dual_safeTransferFrom() { let (dispatcher, target) = setup_camel(); let receiver = setup_receiver(); dispatcher.safe_transfer_from(OWNER(), receiver, TOKEN_ID, DATA(true)); - assert(target.ownerOf(TOKEN_ID) == receiver, 'Should transfer token'); + + let current_owner = target.ownerOf(TOKEN_ID); + assert_eq!(current_owner, receiver); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_safeTransferFrom_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.safe_transfer_from(OWNER(), RECIPIENT(), TOKEN_ID, DATA(true)); } #[test] -#[available_gas(2000000)] fn test_dual_getApproved() { let (dispatcher, _) = setup_camel(); set_contract_address(OWNER()); dispatcher.approve(SPENDER(), TOKEN_ID); - assert(dispatcher.get_approved(TOKEN_ID) == SPENDER(), 'Should return approval'); + + let approved = dispatcher.get_approved(TOKEN_ID); + assert_eq!(approved, SPENDER()); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_getApproved_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.get_approved(TOKEN_ID); } #[test] -#[available_gas(2000000)] fn test_dual_setApprovalForAll() { let (dispatcher, target) = setup_camel(); set_contract_address(OWNER()); dispatcher.set_approval_for_all(OPERATOR(), true); - assert(target.isApprovedForAll(OWNER(), OPERATOR()), 'Operator not approved correctly'); + + let is_approved_for_all = target.isApprovedForAll(OWNER(), OPERATOR()); + assert!(is_approved_for_all); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_setApprovalForAll_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.set_approval_for_all(OPERATOR(), true); } #[test] -#[available_gas(2000000)] fn test_dual_isApprovedForAll() { let (dispatcher, target) = setup_camel(); set_contract_address(OWNER()); target.setApprovalForAll(OPERATOR(), true); - assert(dispatcher.is_approved_for_all(OWNER(), OPERATOR()), 'Operator not approved correctly'); + + let is_approved_for_all = dispatcher.is_approved_for_all(OWNER(), OPERATOR()); + assert!(is_approved_for_all); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_isApprovedForAll_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.is_approved_for_all(OWNER(), OPERATOR()); } #[test] -#[available_gas(2000000)] fn test_dual_tokenURI() { let (dispatcher, target) = setup_camel(); - assert(dispatcher.token_uri(TOKEN_ID) == URI, 'Should return URI'); + let token_uri = dispatcher.token_uri(TOKEN_ID); + assert_eq!(token_uri, URI); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_tokenURI_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.token_uri(TOKEN_ID); } #[test] -#[available_gas(2000000)] fn test_dual_supportsInterface() { let (dispatcher, _) = setup_camel(); - assert(dispatcher.supports_interface(IERC721_ID), 'Should support own interface'); + let supports_ierc721 = dispatcher.supports_interface(IERC721_ID); + assert!(supports_ierc721); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_supportsInterface_exists_and_panics() { let (_, dispatcher) = setup_erc721_panic(); dispatcher.supports_interface(IERC721_ID); diff --git a/src/tests/token/test_dual721_receiver.cairo b/src/tests/token/test_dual721_receiver.cairo index 0ef522c9e..b201b14d3 100644 --- a/src/tests/token/test_dual721_receiver.cairo +++ b/src/tests/token/test_dual721_receiver.cairo @@ -64,18 +64,15 @@ fn setup_erc721_receiver_panic() -> (DualCaseERC721Receiver, DualCaseERC721Recei // #[test] -#[available_gas(2000000)] fn test_dual_on_erc721_received() { let (dispatcher, _) = setup_snake(); - assert( - dispatcher - .on_erc721_received(OPERATOR(), OWNER(), TOKEN_ID, DATA(true)) == IERC721_RECEIVER_ID, - 'Should return interface id' - ); + + let on_erc721_received = dispatcher + .on_erc721_received(OPERATOR(), OWNER(), TOKEN_ID, DATA(true)); + assert_eq!(on_erc721_received, IERC721_RECEIVER_ID); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_dual_no_on_erc721_received() { let dispatcher = setup_non_erc721_receiver(); @@ -83,8 +80,7 @@ fn test_dual_no_on_erc721_received() { } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_on_erc721_received_exists_and_panics() { let (dispatcher, _) = setup_erc721_receiver_panic(); dispatcher.on_erc721_received(OPERATOR(), OWNER(), TOKEN_ID, DATA(true)); @@ -95,19 +91,16 @@ fn test_dual_on_erc721_received_exists_and_panics() { // #[test] -#[available_gas(2000000)] fn test_dual_onERC721Received() { let (dispatcher, _) = setup_camel(); - assert( - dispatcher - .on_erc721_received(OPERATOR(), OWNER(), TOKEN_ID, DATA(true)) == IERC721_RECEIVER_ID, - 'Should return interface id' - ); + + let on_erc721_received = dispatcher + .on_erc721_received(OPERATOR(), OWNER(), TOKEN_ID, DATA(true)); + assert_eq!(on_erc721_received, IERC721_RECEIVER_ID); } #[test] -#[available_gas(2000000)] -#[should_panic(expected: ('Some error', 'ENTRYPOINT_FAILED',))] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] fn test_dual_onERC721Received_exists_and_panics() { let (_, dispatcher) = setup_erc721_receiver_panic(); dispatcher.on_erc721_received(OPERATOR(), OWNER(), TOKEN_ID, DATA(true)); diff --git a/src/tests/token/test_erc20.cairo b/src/tests/token/test_erc20.cairo index ed321612a..19ba9bcb0 100644 --- a/src/tests/token/test_erc20.cairo +++ b/src/tests/token/test_erc20.cairo @@ -3,6 +3,7 @@ use openzeppelin::tests::mocks::erc20_mocks::DualCaseERC20Mock; use openzeppelin::tests::utils::constants::{ ZERO, OWNER, SPENDER, RECIPIENT, NAME, SYMBOL, DECIMALS, SUPPLY, VALUE }; +use openzeppelin::tests::utils::debug::DebugContractAddress; use openzeppelin::tests::utils; use openzeppelin::token::erc20::ERC20Component::{Approval, Transfer}; use openzeppelin::token::erc20::ERC20Component::{ERC20CamelOnlyImpl, ERC20Impl}; @@ -36,15 +37,14 @@ fn setup() -> ComponentState { // #[test] -#[available_gas(2000000)] fn test_initializer() { let mut state = COMPONENT_STATE(); state.initializer(NAME, SYMBOL); - assert(state.name() == NAME, 'Should be NAME'); - assert(state.symbol() == SYMBOL, 'Should be SYMBOL'); - assert(state.decimals() == DECIMALS, 'Should be DECIMALS'); - assert(state.total_supply() == 0, 'Should equal 0'); + assert_eq!(state.name(), NAME); + assert_eq!(state.symbol(), SYMBOL); + assert_eq!(state.decimals(), DECIMALS); + assert_eq!(state.total_supply(), 0); } // @@ -52,45 +52,41 @@ fn test_initializer() { // #[test] -#[available_gas(2000000)] fn test_total_supply() { let mut state = COMPONENT_STATE(); state._mint(OWNER(), SUPPLY); - assert(state.total_supply() == SUPPLY, 'Should equal SUPPLY'); + assert_eq!(state.total_supply(), SUPPLY); } #[test] -#[available_gas(2000000)] fn test_totalSupply() { let mut state = COMPONENT_STATE(); state._mint(OWNER(), SUPPLY); - assert(state.totalSupply() == SUPPLY, 'Should equal SUPPLY'); + assert_eq!(state.totalSupply(), SUPPLY); } #[test] -#[available_gas(2000000)] fn test_balance_of() { let mut state = COMPONENT_STATE(); state._mint(OWNER(), SUPPLY); - assert(state.balance_of(OWNER()) == SUPPLY, 'Should equal SUPPLY'); + assert_eq!(state.balance_of(OWNER()), SUPPLY); } #[test] -#[available_gas(2000000)] fn test_balanceOf() { let mut state = COMPONENT_STATE(); state._mint(OWNER(), SUPPLY); - assert(state.balanceOf(OWNER()) == SUPPLY, 'Should equal SUPPLY'); + assert_eq!(state.balanceOf(OWNER()), SUPPLY); } #[test] -#[available_gas(2000000)] fn test_allowance() { let mut state = setup(); testing::set_caller_address(OWNER()); state.approve(SPENDER(), VALUE); - assert(state.allowance(OWNER(), SPENDER()) == VALUE, 'Should equal VALUE'); + let allowance = state.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, VALUE); } // @@ -98,18 +94,18 @@ fn test_allowance() { // #[test] -#[available_gas(2000000)] fn test_approve() { let mut state = setup(); testing::set_caller_address(OWNER()); - assert(state.approve(SPENDER(), VALUE), 'Should return true'); + assert!(state.approve(SPENDER(), VALUE)); assert_only_event_approval(OWNER(), SPENDER(), VALUE); - assert(state.allowance(OWNER(), SPENDER()) == VALUE, 'Spender not approved correctly'); + + let allowance = state.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, VALUE); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve from 0',))] fn test_approve_from_zero() { let mut state = setup(); @@ -117,7 +113,6 @@ fn test_approve_from_zero() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve to 0',))] fn test_approve_to_zero() { let mut state = setup(); @@ -126,18 +121,18 @@ fn test_approve_to_zero() { } #[test] -#[available_gas(2000000)] fn test__approve() { let mut state = setup(); testing::set_caller_address(OWNER()); state._approve(OWNER(), SPENDER(), VALUE); assert_only_event_approval(OWNER(), SPENDER(), VALUE); - assert(state.allowance(OWNER(), SPENDER()) == VALUE, 'Spender not approved correctly'); + + let allowance = state.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, VALUE); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve from 0',))] fn test__approve_from_zero() { let mut state = setup(); @@ -145,7 +140,6 @@ fn test__approve_from_zero() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve to 0',))] fn test__approve_to_zero() { let mut state = setup(); @@ -158,20 +152,18 @@ fn test__approve_to_zero() { // #[test] -#[available_gas(2000000)] fn test_transfer() { let mut state = setup(); testing::set_caller_address(OWNER()); - assert(state.transfer(RECIPIENT(), VALUE), 'Should return true'); + assert!(state.transfer(RECIPIENT(), VALUE)); assert_only_event_transfer(OWNER(), RECIPIENT(), VALUE); - assert(state.balance_of(RECIPIENT()) == VALUE, 'Should equal VALUE'); - assert(state.balance_of(OWNER()) == SUPPLY - VALUE, 'Should equal SUPPLY - VALUE'); - assert(state.total_supply() == SUPPLY, 'Total supply should not change'); + assert_eq!(state.balance_of(RECIPIENT()), VALUE); + assert_eq!(state.balance_of(OWNER()), SUPPLY - VALUE); + assert_eq!(state.total_supply(), SUPPLY); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow',))] fn test_transfer_not_enough_balance() { let mut state = setup(); @@ -182,7 +174,6 @@ fn test_transfer_not_enough_balance() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: transfer from 0',))] fn test_transfer_from_zero() { let mut state = setup(); @@ -190,7 +181,6 @@ fn test_transfer_from_zero() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: transfer to 0',))] fn test_transfer_to_zero() { let mut state = setup(); @@ -199,20 +189,18 @@ fn test_transfer_to_zero() { } #[test] -#[available_gas(2000000)] fn test__transfer() { let mut state = setup(); state._transfer(OWNER(), RECIPIENT(), VALUE); assert_only_event_transfer(OWNER(), RECIPIENT(), VALUE); - assert(state.balance_of(RECIPIENT()) == VALUE, 'Should equal amount'); - assert(state.balance_of(OWNER()) == SUPPLY - VALUE, 'Should equal SUPPLY - VALUE'); - assert(state.total_supply() == SUPPLY, 'Total supply should not change'); + assert_eq!(state.balance_of(RECIPIENT()), VALUE); + assert_eq!(state.balance_of(OWNER()), SUPPLY - VALUE); + assert_eq!(state.total_supply(), SUPPLY); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow',))] fn test__transfer_not_enough_balance() { let mut state = setup(); @@ -223,7 +211,6 @@ fn test__transfer_not_enough_balance() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: transfer from 0',))] fn test__transfer_from_zero() { let mut state = setup(); @@ -231,7 +218,6 @@ fn test__transfer_from_zero() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: transfer to 0',))] fn test__transfer_to_zero() { let mut state = setup(); @@ -243,7 +229,6 @@ fn test__transfer_to_zero() { // #[test] -#[available_gas(2000000)] fn test_transfer_from() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -251,19 +236,20 @@ fn test_transfer_from() { utils::drop_event(ZERO()); testing::set_caller_address(SPENDER()); - assert(state.transfer_from(OWNER(), RECIPIENT(), VALUE), 'Should return true'); + assert!(state.transfer_from(OWNER(), RECIPIENT(), VALUE)); assert_event_approval(OWNER(), SPENDER(), 0); assert_only_event_transfer(OWNER(), RECIPIENT(), VALUE); - assert(state.balance_of(RECIPIENT()) == VALUE, 'Should equal VALUE'); - assert(state.balance_of(OWNER()) == SUPPLY - VALUE, 'Should equal SUPPLY - VALUE'); - assert(state.allowance(OWNER(), SPENDER()) == 0, 'Should equal 0'); - assert(state.total_supply() == SUPPLY, 'Total supply should not change'); + let allowance = state.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, 0); + + assert_eq!(state.balance_of(RECIPIENT()), VALUE); + assert_eq!(state.balance_of(OWNER()), SUPPLY - VALUE); + assert_eq!(state.total_supply(), SUPPLY); } #[test] -#[available_gas(2000000)] fn test_transfer_from_doesnt_consume_infinite_allowance() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -272,11 +258,11 @@ fn test_transfer_from_doesnt_consume_infinite_allowance() { testing::set_caller_address(SPENDER()); state.transfer_from(OWNER(), RECIPIENT(), VALUE); - assert(state.allowance(OWNER(), SPENDER()) == BoundedInt::max(), 'Allowance should not change'); + let allowance = state.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, BoundedInt::max()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow',))] fn test_transfer_from_greater_than_allowance() { let mut state = setup(); @@ -289,7 +275,6 @@ fn test_transfer_from_greater_than_allowance() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: transfer to 0',))] fn test_transfer_from_to_zero_address() { let mut state = setup(); @@ -301,7 +286,6 @@ fn test_transfer_from_to_zero_address() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow',))] fn test_transfer_from_from_zero_address() { let mut state = setup(); @@ -309,7 +293,6 @@ fn test_transfer_from_from_zero_address() { } #[test] -#[available_gas(2000000)] fn test_transferFrom() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -317,19 +300,21 @@ fn test_transferFrom() { utils::drop_event(ZERO()); testing::set_caller_address(SPENDER()); - assert(state.transferFrom(OWNER(), RECIPIENT(), VALUE), 'Should return true'); + assert!(state.transferFrom(OWNER(), RECIPIENT(), VALUE)); assert_event_approval(OWNER(), SPENDER(), 0); assert_only_event_transfer(OWNER(), RECIPIENT(), VALUE); - assert(state.balanceOf(RECIPIENT()) == VALUE, 'Should equal VALUE'); - assert(state.balanceOf(OWNER()) == SUPPLY - VALUE, 'Should equal SUPPLY - VALUE'); - assert(state.allowance(OWNER(), SPENDER()) == 0, 'Should equal 0'); - assert(state.totalSupply() == SUPPLY, 'Total supply should not change'); + let allowance = state.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, 0); + + assert_eq!(state.balance_of(RECIPIENT()), VALUE); + assert_eq!(state.balance_of(OWNER()), SUPPLY - VALUE); + assert_eq!(state.total_supply(), SUPPLY); + assert_eq!(allowance, 0); } #[test] -#[available_gas(2000000)] fn test_transferFrom_doesnt_consume_infinite_allowance() { let mut state = setup(); testing::set_caller_address(OWNER()); @@ -338,11 +323,11 @@ fn test_transferFrom_doesnt_consume_infinite_allowance() { testing::set_caller_address(SPENDER()); state.transferFrom(OWNER(), RECIPIENT(), VALUE); - assert(state.allowance(OWNER(), SPENDER()) == BoundedInt::max(), 'Allowance should not change'); + let allowance = state.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, BoundedInt::max()); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow',))] fn test_transferFrom_greater_than_allowance() { let mut state = setup(); @@ -355,7 +340,6 @@ fn test_transferFrom_greater_than_allowance() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: transfer to 0',))] fn test_transferFrom_to_zero_address() { let mut state = setup(); @@ -367,7 +351,6 @@ fn test_transferFrom_to_zero_address() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow',))] fn test_transferFrom_from_zero_address() { let mut state = setup(); @@ -379,21 +362,21 @@ fn test_transferFrom_from_zero_address() { // #[test] -#[available_gas(2000000)] fn test_increase_allowance() { let mut state = setup(); testing::set_caller_address(OWNER()); state.approve(SPENDER(), VALUE); utils::drop_event(ZERO()); - assert(state.increase_allowance(SPENDER(), VALUE), 'Should return true'); + assert!(state.increase_allowance(SPENDER(), VALUE)); assert_only_event_approval(OWNER(), SPENDER(), VALUE * 2); - assert(state.allowance(OWNER(), SPENDER()) == VALUE * 2, 'Should equal VALUE * 2'); + + let allowance = state.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, VALUE * 2); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve to 0',))] fn test_increase_allowance_to_zero_address() { let mut state = setup(); @@ -402,7 +385,6 @@ fn test_increase_allowance_to_zero_address() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve from 0',))] fn test_increase_allowance_from_zero_address() { let mut state = setup(); @@ -410,21 +392,21 @@ fn test_increase_allowance_from_zero_address() { } #[test] -#[available_gas(2000000)] fn test_increaseAllowance() { let mut state = setup(); testing::set_caller_address(OWNER()); state.approve(SPENDER(), VALUE); utils::drop_event(ZERO()); - assert(state.increaseAllowance(SPENDER(), VALUE), 'Should return true'); + assert!(state.increaseAllowance(SPENDER(), VALUE)); assert_only_event_approval(OWNER(), SPENDER(), 2 * VALUE); - assert(state.allowance(OWNER(), SPENDER()) == VALUE * 2, 'Should equal VALUE * 2'); + + let allowance = state.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, VALUE * 2); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve to 0',))] fn test_increaseAllowance_to_zero_address() { let mut state = setup(); @@ -433,7 +415,6 @@ fn test_increaseAllowance_to_zero_address() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: approve from 0',))] fn test_increaseAllowance_from_zero_address() { let mut state = setup(); @@ -445,21 +426,21 @@ fn test_increaseAllowance_from_zero_address() { // #[test] -#[available_gas(2000000)] fn test_decrease_allowance() { let mut state = setup(); testing::set_caller_address(OWNER()); state.approve(SPENDER(), VALUE); utils::drop_event(ZERO()); - assert(state.decrease_allowance(SPENDER(), VALUE), 'Should return true'); + assert!(state.decrease_allowance(SPENDER(), VALUE)); assert_only_event_approval(OWNER(), SPENDER(), 0); - assert(state.allowance(OWNER(), SPENDER()) == VALUE - VALUE, 'Should be 0'); + + let allowance = state.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, 0); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow',))] fn test_decrease_allowance_to_zero_address() { let mut state = setup(); @@ -468,7 +449,6 @@ fn test_decrease_allowance_to_zero_address() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow',))] fn test_decrease_allowance_from_zero_address() { let mut state = setup(); @@ -476,21 +456,21 @@ fn test_decrease_allowance_from_zero_address() { } #[test] -#[available_gas(2000000)] fn test_decreaseAllowance() { let mut state = setup(); testing::set_caller_address(OWNER()); state.approve(SPENDER(), VALUE); utils::drop_event(ZERO()); - assert(state.decreaseAllowance(SPENDER(), VALUE), 'Should return true'); + assert!(state.decreaseAllowance(SPENDER(), VALUE)); assert_only_event_approval(OWNER(), SPENDER(), 0); - assert(state.allowance(OWNER(), SPENDER()) == VALUE - VALUE, 'Should be 0'); + + let allowance = state.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, 0); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow',))] fn test_decreaseAllowance_to_zero_address() { let mut state = setup(); @@ -499,7 +479,6 @@ fn test_decreaseAllowance_to_zero_address() { } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('u256_sub Overflow',))] fn test_decreaseAllowance_from_zero_address() { let mut state = setup(); @@ -511,7 +490,6 @@ fn test_decreaseAllowance_from_zero_address() { // #[test] -#[available_gas(2000000)] fn test__spend_allowance_not_unlimited() { let mut state = setup(); @@ -521,11 +499,12 @@ fn test__spend_allowance_not_unlimited() { state._spend_allowance(OWNER(), SPENDER(), VALUE); assert_only_event_approval(OWNER(), SPENDER(), SUPPLY - VALUE); - assert(state.allowance(OWNER(), SPENDER()) == SUPPLY - VALUE, 'Should equal SUPPLY - VALUE'); + + let allowance = state.allowance(OWNER(), SPENDER()); + assert_eq!(allowance, SUPPLY - VALUE); } #[test] -#[available_gas(2000000)] fn test__spend_allowance_unlimited() { let mut state = setup(); state._approve(OWNER(), SPENDER(), BoundedInt::max()); @@ -533,7 +512,8 @@ fn test__spend_allowance_unlimited() { let max_minus_one: u256 = BoundedInt::max() - 1; state._spend_allowance(OWNER(), SPENDER(), max_minus_one); - assert(state.allowance(OWNER(), SPENDER()) == BoundedInt::max(), 'Allowance should not change'); + let allowance = state.allowance(OWNER(), SPENDER()); + assert_eq!(state.allowance(OWNER(), SPENDER()), BoundedInt::max()); } // @@ -541,18 +521,16 @@ fn test__spend_allowance_unlimited() { // #[test] -#[available_gas(2000000)] fn test__mint() { let mut state = COMPONENT_STATE(); state._mint(OWNER(), VALUE); assert_only_event_transfer(ZERO(), OWNER(), VALUE); - assert(state.balance_of(OWNER()) == VALUE, 'Should equal VALUE'); - assert(state.total_supply() == VALUE, 'Should equal VALUE'); + assert_eq!(state.balance_of(OWNER()), VALUE); + assert_eq!(state.total_supply(), VALUE); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: mint to 0',))] fn test__mint_to_zero() { let mut state = COMPONENT_STATE(); @@ -564,18 +542,16 @@ fn test__mint_to_zero() { // #[test] -#[available_gas(2000000)] fn test__burn() { let mut state = setup(); state._burn(OWNER(), VALUE); assert_only_event_transfer(OWNER(), ZERO(), VALUE); - assert(state.total_supply() == SUPPLY - VALUE, 'Should equal SUPPLY - VALUE'); - assert(state.balance_of(OWNER()) == SUPPLY - VALUE, 'Should equal SUPPLY - VALUE'); + assert_eq!(state.total_supply(), SUPPLY - VALUE); + assert_eq!(state.balance_of(OWNER()), SUPPLY - VALUE); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ERC20: burn from 0',))] fn test__burn_from_zero() { let mut state = setup(); @@ -588,9 +564,9 @@ fn test__burn_from_zero() { fn assert_event_approval(owner: ContractAddress, spender: ContractAddress, value: u256) { let event = utils::pop_log::(ZERO()).unwrap(); - assert(event.owner == owner, 'Invalid `owner`'); - assert(event.spender == spender, 'Invalid `spender`'); - assert(event.value == value, 'Invalid `value`'); + assert_eq!(event.owner, owner); + assert_eq!(event.spender, spender); + assert_eq!(event.value, value); // Check indexed keys let mut indexed_keys = array![]; @@ -606,9 +582,9 @@ fn assert_only_event_approval(owner: ContractAddress, spender: ContractAddress, fn assert_event_transfer(from: ContractAddress, to: ContractAddress, value: u256) { let event = utils::pop_log::(ZERO()).unwrap(); - assert(event.from == from, 'Invalid `from`'); - assert(event.to == to, 'Invalid `to`'); - assert(event.value == value, 'Invalid `value`'); + assert_eq!(event.from, from); + assert_eq!(event.to, to); + assert_eq!(event.value, value); // Check indexed keys let mut indexed_keys = array![]; diff --git a/src/tests/token/test_erc721.cairo b/src/tests/token/test_erc721.cairo index 8a1a3376b..a96a33b6b 100644 --- a/src/tests/token/test_erc721.cairo +++ b/src/tests/token/test_erc721.cairo @@ -12,6 +12,7 @@ use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; use openzeppelin::tests::utils::constants::{ DATA, ZERO, OWNER, RECIPIENT, SPENDER, OPERATOR, OTHER, NAME, SYMBOL, URI, TOKEN_ID, PUBKEY, }; +use openzeppelin::tests::utils::debug::DebugContractAddress; use openzeppelin::tests::utils; use openzeppelin::token::erc721::ERC721Component::{ ERC721CamelOnlyImpl, ERC721MetadataCamelOnlyImpl @@ -70,25 +71,25 @@ fn setup_camel_account() -> ContractAddress { // #[test] -#[available_gas(20000000)] fn test_initialize() { let mut state = COMPONENT_STATE(); let mock_state = CONTRACT_STATE(); state.initializer(NAME, SYMBOL); - assert(state.name() == NAME, 'Name should be NAME'); - assert(state.symbol() == SYMBOL, 'Symbol should be SYMBOL'); - assert(state.balance_of(OWNER()) == 0, 'Balance should be zero'); + assert_eq!(state.name(), NAME); + assert_eq!(state.symbol(), SYMBOL); + assert!(state.balance_of(OWNER()).is_zero()); - assert(mock_state.supports_interface(erc721::interface::IERC721_ID), 'Missing interface ID'); - assert( - mock_state.supports_interface(erc721::interface::IERC721_METADATA_ID), - 'Missing interface ID' - ); - assert( - mock_state.supports_interface(introspection::interface::ISRC5_ID), 'Missing interface ID' - ); + let supports_ierc721 = mock_state.supports_interface(erc721::interface::IERC721_ID); + assert!(supports_ierc721); + + let supports_ierc721_metadata = mock_state + .supports_interface(erc721::interface::IERC721_METADATA_ID); + assert!(supports_ierc721_metadata); + + let supports_isrc5 = mock_state.supports_interface(introspection::interface::ISRC5_ID); + assert!(supports_isrc5); } // @@ -96,14 +97,12 @@ fn test_initialize() { // #[test] -#[available_gas(20000000)] fn test_balance_of() { let state = setup(); - assert(state.balance_of(OWNER()) == 1, 'Should return balance'); + assert_eq!(state.balance_of(OWNER()), 1); } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid account',))] fn test_balance_of_zero() { let state = setup(); @@ -111,14 +110,12 @@ fn test_balance_of_zero() { } #[test] -#[available_gas(20000000)] fn test_owner_of() { let state = setup(); - assert(state.owner_of(TOKEN_ID) == OWNER(), 'Should return owner'); + assert_eq!(state.owner_of(TOKEN_ID), OWNER()); } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID',))] fn test_owner_of_non_minted() { let state = setup(); @@ -126,7 +123,6 @@ fn test_owner_of_non_minted() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID',))] fn test_token_uri_non_minted() { let state = setup(); @@ -134,19 +130,17 @@ fn test_token_uri_non_minted() { } #[test] -#[available_gas(20000000)] fn test_get_approved() { let mut state = setup(); let spender = SPENDER(); let token_id = TOKEN_ID; - assert(state.get_approved(token_id) == ZERO(), 'Should return non-approval'); + assert_eq!(state.get_approved(token_id), ZERO()); state._approve(spender, token_id); - assert(state.get_approved(token_id) == spender, 'Should return approval'); + assert_eq!(state.get_approved(token_id), spender); } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID',))] fn test_get_approved_nonexistent() { let state = setup(); @@ -154,27 +148,32 @@ fn test_get_approved_nonexistent() { } #[test] -#[available_gas(20000000)] fn test__exists() { let mut state = COMPONENT_STATE(); let zero = ZERO(); let token_id = TOKEN_ID; - assert(!state._exists(token_id), 'Token should not exist'); + let not_exists = !state._exists(token_id); + assert!(not_exists); + let mut owner = state.ERC721_owners.read(token_id); - assert(owner == zero, ''); + assert!(owner.is_zero()); state._mint(RECIPIENT(), token_id); - assert(state._exists(token_id), 'Token should exist'); + let exists = state._exists(token_id); + assert!(exists); + owner = state.ERC721_owners.read(token_id); - assert(owner == RECIPIENT(), 'Invalid owner'); + assert_eq!(owner, RECIPIENT()); state._burn(token_id); - assert(!state._exists(token_id), 'Token should not exist'); + let not_exists = !state._exists(token_id); + assert!(not_exists); + owner = state.ERC721_owners.read(token_id); - assert(owner == zero, 'Invalid owner'); + assert!(owner.is_zero()); } // @@ -182,7 +181,6 @@ fn test__exists() { // #[test] -#[available_gas(20000000)] fn test_approve_from_owner() { let mut state = setup(); @@ -190,11 +188,11 @@ fn test_approve_from_owner() { state.approve(SPENDER(), TOKEN_ID); assert_event_approval(OWNER(), SPENDER(), TOKEN_ID); - assert(state.get_approved(TOKEN_ID) == SPENDER(), 'Spender not approved correctly'); + let approved = state.get_approved(TOKEN_ID); + assert_eq!(approved, SPENDER()); } #[test] -#[available_gas(20000000)] fn test_approve_from_operator() { let mut state = setup(); @@ -206,11 +204,11 @@ fn test_approve_from_operator() { state.approve(SPENDER(), TOKEN_ID); assert_event_approval(OWNER(), SPENDER(), TOKEN_ID); - assert(state.get_approved(TOKEN_ID) == SPENDER(), 'Spender not approved correctly'); + let approved = state.get_approved(TOKEN_ID); + assert_eq!(approved, SPENDER()); } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: unauthorized caller',))] fn test_approve_from_unauthorized() { let mut state = setup(); @@ -220,7 +218,6 @@ fn test_approve_from_unauthorized() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: approval to owner',))] fn test_approve_to_owner() { let mut state = setup(); @@ -230,7 +227,6 @@ fn test_approve_to_owner() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID',))] fn test_approve_nonexistent() { let mut state = COMPONENT_STATE(); @@ -238,17 +234,16 @@ fn test_approve_nonexistent() { } #[test] -#[available_gas(20000000)] fn test__approve() { let mut state = setup(); state._approve(SPENDER(), TOKEN_ID); assert_event_approval(OWNER(), SPENDER(), TOKEN_ID); - assert(state.get_approved(TOKEN_ID) == SPENDER(), 'Spender not approved correctly'); + let approved = state.get_approved(TOKEN_ID); + assert_eq!(approved, SPENDER()); } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: approval to owner',))] fn test__approve_to_owner() { let mut state = setup(); @@ -256,7 +251,6 @@ fn test__approve_to_owner() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID',))] fn test__approve_nonexistent() { let mut state = COMPONENT_STATE(); @@ -268,26 +262,27 @@ fn test__approve_nonexistent() { // #[test] -#[available_gas(20000000)] fn test_set_approval_for_all() { let mut state = COMPONENT_STATE(); testing::set_caller_address(OWNER()); - assert(!state.is_approved_for_all(OWNER(), OPERATOR()), 'Invalid default value'); + let not_approved_for_all = !state.is_approved_for_all(OWNER(), OPERATOR()); + assert!(not_approved_for_all); state.set_approval_for_all(OPERATOR(), true); assert_event_approval_for_all(OWNER(), OPERATOR(), true); - assert(state.is_approved_for_all(OWNER(), OPERATOR()), 'Operator not approved correctly'); + let is_approved_for_all = state.is_approved_for_all(OWNER(), OPERATOR()); + assert!(is_approved_for_all); state.set_approval_for_all(OPERATOR(), false); assert_event_approval_for_all(OWNER(), OPERATOR(), false); - assert(!state.is_approved_for_all(OWNER(), OPERATOR()), 'Approval not revoked correctly'); + let not_approved_for_all = !state.is_approved_for_all(OWNER(), OPERATOR()); + assert!(not_approved_for_all); } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: self approval',))] fn test_set_approval_for_all_owner_equal_operator_true() { let mut state = COMPONENT_STATE(); @@ -296,7 +291,6 @@ fn test_set_approval_for_all_owner_equal_operator_true() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: self approval',))] fn test_set_approval_for_all_owner_equal_operator_false() { let mut state = COMPONENT_STATE(); @@ -305,24 +299,26 @@ fn test_set_approval_for_all_owner_equal_operator_false() { } #[test] -#[available_gas(20000000)] fn test__set_approval_for_all() { let mut state = COMPONENT_STATE(); - assert(!state.is_approved_for_all(OWNER(), OPERATOR()), 'Invalid default value'); + + let not_approved_for_all = !state.is_approved_for_all(OWNER(), OPERATOR()); + assert!(not_approved_for_all); state._set_approval_for_all(OWNER(), OPERATOR(), true); assert_event_approval_for_all(OWNER(), OPERATOR(), true); - assert(state.is_approved_for_all(OWNER(), OPERATOR()), 'Operator not approved correctly'); + let is_approved_for_all = state.is_approved_for_all(OWNER(), OPERATOR()); + assert!(is_approved_for_all); state._set_approval_for_all(OWNER(), OPERATOR(), false); assert_event_approval_for_all(OWNER(), OPERATOR(), false); - assert(!state.is_approved_for_all(OWNER(), OPERATOR()), 'Operator not approved correctly'); + let not_approved_for_all = !state.is_approved_for_all(OWNER(), OPERATOR()); + assert!(not_approved_for_all); } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: self approval',))] fn test__set_approval_for_all_owner_equal_operator_true() { let mut state = COMPONENT_STATE(); @@ -330,7 +326,6 @@ fn test__set_approval_for_all_owner_equal_operator_true() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: self approval',))] fn test__set_approval_for_all_owner_equal_operator_false() { let mut state = COMPONENT_STATE(); @@ -342,7 +337,6 @@ fn test__set_approval_for_all_owner_equal_operator_false() { // #[test] -#[available_gas(20000000)] fn test_transfer_from_owner() { let mut state = setup(); let token_id = TOKEN_ID; @@ -353,7 +347,9 @@ fn test_transfer_from_owner() { utils::drop_event(ZERO()); assert_state_before_transfer(owner, recipient, token_id); - assert(state.get_approved(token_id) == OTHER(), 'Approval not implicitly reset'); + + let approved = state.get_approved(token_id); + assert_eq!(approved, OTHER()); testing::set_caller_address(owner); state.transfer_from(owner, recipient, token_id); @@ -363,7 +359,6 @@ fn test_transfer_from_owner() { } #[test] -#[available_gas(20000000)] fn test_transferFrom_owner() { let mut state = setup(); let token_id = TOKEN_ID; @@ -374,7 +369,9 @@ fn test_transferFrom_owner() { utils::drop_event(ZERO()); assert_state_before_transfer(owner, recipient, token_id); - assert(state.get_approved(token_id) == OTHER(), 'Approval not implicitly reset'); + + let approved = state.get_approved(token_id); + assert_eq!(approved, OTHER()); testing::set_caller_address(owner); state.transferFrom(owner, recipient, token_id); @@ -384,7 +381,6 @@ fn test_transferFrom_owner() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID',))] fn test_transfer_from_nonexistent() { let mut state = COMPONENT_STATE(); @@ -392,7 +388,6 @@ fn test_transfer_from_nonexistent() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID',))] fn test_transferFrom_nonexistent() { let mut state = COMPONENT_STATE(); @@ -400,7 +395,6 @@ fn test_transferFrom_nonexistent() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver',))] fn test_transfer_from_to_zero() { let mut state = setup(); @@ -409,7 +403,6 @@ fn test_transfer_from_to_zero() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver',))] fn test_transferFrom_to_zero() { let mut state = setup(); @@ -419,39 +412,36 @@ fn test_transferFrom_to_zero() { } #[test] -#[available_gas(20000000)] fn test_transfer_from_to_owner() { let mut state = setup(); - assert(state.owner_of(TOKEN_ID) == OWNER(), 'Ownership before'); - assert(state.balance_of(OWNER()) == 1, 'Balance of owner before'); + assert_eq!(state.owner_of(TOKEN_ID), OWNER()); + assert_eq!(state.balance_of(OWNER()), 1); testing::set_caller_address(OWNER()); state.transfer_from(OWNER(), OWNER(), TOKEN_ID); assert_event_transfer(OWNER(), OWNER(), TOKEN_ID); - assert(state.owner_of(TOKEN_ID) == OWNER(), 'Ownership after'); - assert(state.balance_of(OWNER()) == 1, 'Balance of owner after'); + assert_eq!(state.owner_of(TOKEN_ID), OWNER()); + assert_eq!(state.balance_of(OWNER()), 1); } #[test] -#[available_gas(20000000)] fn test_transferFrom_to_owner() { let mut state = setup(); - assert(state.owner_of(TOKEN_ID) == OWNER(), 'Ownership before'); - assert(state.balance_of(OWNER()) == 1, 'Balance of owner before'); + assert_eq!(state.owner_of(TOKEN_ID), OWNER()); + assert_eq!(state.balance_of(OWNER()), 1); testing::set_caller_address(OWNER()); state.transferFrom(OWNER(), OWNER(), TOKEN_ID); assert_event_transfer(OWNER(), OWNER(), TOKEN_ID); - assert(state.owner_of(TOKEN_ID) == OWNER(), 'Ownership after'); - assert(state.balance_of(OWNER()) == 1, 'Balance of owner after'); + assert_eq!(state.owner_of(TOKEN_ID), OWNER()); + assert_eq!(state.balance_of(OWNER()), 1); } #[test] -#[available_gas(20000000)] fn test_transfer_from_approved() { let mut state = setup(); let token_id = TOKEN_ID; @@ -471,7 +461,6 @@ fn test_transfer_from_approved() { } #[test] -#[available_gas(20000000)] fn test_transferFrom_approved() { let mut state = setup(); let token_id = TOKEN_ID; @@ -491,7 +480,6 @@ fn test_transferFrom_approved() { } #[test] -#[available_gas(20000000)] fn test_transfer_from_approved_for_all() { let mut state = setup(); let token_id = TOKEN_ID; @@ -512,7 +500,6 @@ fn test_transfer_from_approved_for_all() { } #[test] -#[available_gas(20000000)] fn test_transferFrom_approved_for_all() { let mut state = setup(); let token_id = TOKEN_ID; @@ -533,7 +520,6 @@ fn test_transferFrom_approved_for_all() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: unauthorized caller',))] fn test_transfer_from_unauthorized() { let mut state = setup(); @@ -542,7 +528,6 @@ fn test_transfer_from_unauthorized() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: unauthorized caller',))] fn test_transferFrom_unauthorized() { let mut state = setup(); @@ -555,7 +540,6 @@ fn test_transferFrom_unauthorized() { // #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_to_account() { let mut state = setup(); let account = setup_account(); @@ -572,7 +556,6 @@ fn test_safe_transfer_from_to_account() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_to_account() { let mut state = setup(); let account = setup_account(); @@ -589,7 +572,6 @@ fn test_safeTransferFrom_to_account() { } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_to_account_camel() { let mut state = setup(); let account = setup_camel_account(); @@ -606,7 +588,6 @@ fn test_safe_transfer_from_to_account_camel() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_to_account_camel() { let mut state = setup(); let account = setup_camel_account(); @@ -623,7 +604,6 @@ fn test_safeTransferFrom_to_account_camel() { } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_to_receiver() { let mut state = setup(); let receiver = setup_receiver(); @@ -640,7 +620,6 @@ fn test_safe_transfer_from_to_receiver() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_to_receiver() { let mut state = setup(); let receiver = setup_receiver(); @@ -657,7 +636,6 @@ fn test_safeTransferFrom_to_receiver() { } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_to_receiver_camel() { let mut state = setup(); let receiver = setup_camel_receiver(); @@ -674,7 +652,6 @@ fn test_safe_transfer_from_to_receiver_camel() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_to_receiver_camel() { let mut state = setup(); let receiver = setup_camel_receiver(); @@ -691,7 +668,6 @@ fn test_safeTransferFrom_to_receiver_camel() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: safe transfer failed',))] fn test_safe_transfer_from_to_receiver_failure() { let mut state = setup(); @@ -704,7 +680,6 @@ fn test_safe_transfer_from_to_receiver_failure() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: safe transfer failed',))] fn test_safeTransferFrom_to_receiver_failure() { let mut state = setup(); @@ -717,7 +692,6 @@ fn test_safeTransferFrom_to_receiver_failure() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: safe transfer failed',))] fn test_safe_transfer_from_to_receiver_failure_camel() { let mut state = setup(); @@ -730,7 +704,6 @@ fn test_safe_transfer_from_to_receiver_failure_camel() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: safe transfer failed',))] fn test_safeTransferFrom_to_receiver_failure_camel() { let mut state = setup(); @@ -743,7 +716,6 @@ fn test_safeTransferFrom_to_receiver_failure_camel() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_safe_transfer_from_to_non_receiver() { let mut state = setup(); @@ -756,7 +728,6 @@ fn test_safe_transfer_from_to_non_receiver() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_safeTransferFrom_to_non_receiver() { let mut state = setup(); @@ -769,7 +740,6 @@ fn test_safeTransferFrom_to_non_receiver() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID',))] fn test_safe_transfer_from_nonexistent() { let mut state = COMPONENT_STATE(); @@ -777,7 +747,6 @@ fn test_safe_transfer_from_nonexistent() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID',))] fn test_safeTransferFrom_nonexistent() { let mut state = COMPONENT_STATE(); @@ -785,7 +754,6 @@ fn test_safeTransferFrom_nonexistent() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver',))] fn test_safe_transfer_from_to_zero() { let mut state = setup(); @@ -794,7 +762,6 @@ fn test_safe_transfer_from_to_zero() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver',))] fn test_safeTransferFrom_to_zero() { let mut state = setup(); @@ -803,7 +770,6 @@ fn test_safeTransferFrom_to_zero() { } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_to_owner() { let mut state = COMPONENT_STATE(); let token_id = TOKEN_ID; @@ -812,19 +778,18 @@ fn test_safe_transfer_from_to_owner() { state._mint(owner, token_id); utils::drop_event(ZERO()); - assert(state.owner_of(token_id) == owner, 'Ownership before'); - assert(state.balance_of(owner) == 1, 'Balance of owner before'); + assert_eq!(state.owner_of(token_id), owner); + assert_eq!(state.balance_of(owner), 1); testing::set_caller_address(owner); state.safe_transfer_from(owner, owner, token_id, DATA(true)); assert_event_transfer(owner, owner, token_id); - assert(state.owner_of(token_id) == owner, 'Ownership after'); - assert(state.balance_of(owner) == 1, 'Balance of owner after'); + assert_eq!(state.owner_of(token_id), owner); + assert_eq!(state.balance_of(owner), 1); } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_to_owner() { let mut state = COMPONENT_STATE(); let token_id = TOKEN_ID; @@ -833,19 +798,18 @@ fn test_safeTransferFrom_to_owner() { state._mint(owner, token_id); utils::drop_event(ZERO()); - assert(state.owner_of(token_id) == owner, 'Ownership before'); - assert(state.balance_of(owner) == 1, 'Balance of owner before'); + assert_eq!(state.owner_of(token_id), owner); + assert_eq!(state.balance_of(owner), 1); testing::set_caller_address(owner); state.safeTransferFrom(owner, owner, token_id, DATA(true)); assert_event_transfer(owner, owner, token_id); - assert(state.owner_of(token_id) == owner, 'Ownership after'); - assert(state.balance_of(owner) == 1, 'Balance of owner after'); + assert_eq!(state.owner_of(token_id), owner); + assert_eq!(state.balance_of(owner), 1); } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_to_owner_camel() { let mut state = COMPONENT_STATE(); let token_id = TOKEN_ID; @@ -854,19 +818,18 @@ fn test_safe_transfer_from_to_owner_camel() { state._mint(owner, token_id); utils::drop_event(ZERO()); - assert(state.owner_of(token_id) == owner, 'Ownership before'); - assert(state.balance_of(owner) == 1, 'Balance of owner before'); + assert_eq!(state.owner_of(token_id), owner); + assert_eq!(state.balance_of(owner), 1); testing::set_caller_address(owner); state.safe_transfer_from(owner, owner, token_id, DATA(true)); assert_event_transfer(owner, owner, token_id); - assert(state.owner_of(token_id) == owner, 'Ownership after'); - assert(state.balance_of(owner) == 1, 'Balance of owner after'); + assert_eq!(state.owner_of(token_id), owner); + assert_eq!(state.balance_of(owner), 1); } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_to_owner_camel() { let mut state = COMPONENT_STATE(); let token_id = TOKEN_ID; @@ -875,19 +838,18 @@ fn test_safeTransferFrom_to_owner_camel() { state._mint(owner, token_id); utils::drop_event(ZERO()); - assert(state.owner_of(token_id) == owner, 'Ownership before'); - assert(state.balance_of(owner) == 1, 'Balance of owner before'); + assert_eq!(state.owner_of(token_id), owner); + assert_eq!(state.balance_of(owner), 1); testing::set_caller_address(owner); state.safeTransferFrom(owner, owner, token_id, DATA(true)); assert_event_transfer(owner, owner, token_id); - assert(state.owner_of(token_id) == owner, 'Ownership after'); - assert(state.balance_of(owner) == 1, 'Balance of owner after'); + assert_eq!(state.owner_of(token_id), owner); + assert_eq!(state.balance_of(owner), 1); } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_approved() { let mut state = setup(); let receiver = setup_receiver(); @@ -908,7 +870,6 @@ fn test_safe_transfer_from_approved() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_approved() { let mut state = setup(); let receiver = setup_receiver(); @@ -929,7 +890,6 @@ fn test_safeTransferFrom_approved() { } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_approved_camel() { let mut state = setup(); let receiver = setup_camel_receiver(); @@ -950,7 +910,6 @@ fn test_safe_transfer_from_approved_camel() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_approved_camel() { let mut state = setup(); let receiver = setup_camel_receiver(); @@ -971,7 +930,6 @@ fn test_safeTransferFrom_approved_camel() { } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_approved_for_all() { let mut state = setup(); let receiver = setup_receiver(); @@ -992,7 +950,6 @@ fn test_safe_transfer_from_approved_for_all() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_approved_for_all() { let mut state = setup(); let receiver = setup_receiver(); @@ -1013,7 +970,6 @@ fn test_safeTransferFrom_approved_for_all() { } #[test] -#[available_gas(20000000)] fn test_safe_transfer_from_approved_for_all_camel() { let mut state = setup(); let receiver = setup_camel_receiver(); @@ -1034,7 +990,6 @@ fn test_safe_transfer_from_approved_for_all_camel() { } #[test] -#[available_gas(20000000)] fn test_safeTransferFrom_approved_for_all_camel() { let mut state = setup(); let receiver = setup_camel_receiver(); @@ -1055,7 +1010,6 @@ fn test_safeTransferFrom_approved_for_all_camel() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: unauthorized caller',))] fn test_safe_transfer_from_unauthorized() { let mut state = setup(); @@ -1064,7 +1018,6 @@ fn test_safe_transfer_from_unauthorized() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: unauthorized caller',))] fn test_safeTransferFrom_unauthorized() { let mut state = setup(); @@ -1077,7 +1030,6 @@ fn test_safeTransferFrom_unauthorized() { // #[test] -#[available_gas(20000000)] fn test__transfer() { let mut state = setup(); let token_id = TOKEN_ID; @@ -1093,7 +1045,6 @@ fn test__transfer() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID',))] fn test__transfer_nonexistent() { let mut state = COMPONENT_STATE(); @@ -1101,7 +1052,6 @@ fn test__transfer_nonexistent() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver',))] fn test__transfer_to_zero() { let mut state = setup(); @@ -1109,7 +1059,6 @@ fn test__transfer_to_zero() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: wrong sender',))] fn test__transfer_from_invalid_owner() { let mut state = setup(); @@ -1121,7 +1070,6 @@ fn test__transfer_from_invalid_owner() { // #[test] -#[available_gas(20000000)] fn test__mint() { let mut state = COMPONENT_STATE(); let recipient = RECIPIENT(); @@ -1135,7 +1083,6 @@ fn test__mint() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver',))] fn test__mint_to_zero() { let mut state = COMPONENT_STATE(); @@ -1143,7 +1090,6 @@ fn test__mint_to_zero() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: token already minted',))] fn test__mint_already_exist() { let mut state = setup(); @@ -1155,7 +1101,6 @@ fn test__mint_already_exist() { // #[test] -#[available_gas(20000000)] fn test__safe_mint_to_receiver() { let mut state = COMPONENT_STATE(); let recipient = setup_receiver(); @@ -1169,7 +1114,6 @@ fn test__safe_mint_to_receiver() { } #[test] -#[available_gas(20000000)] fn test__safe_mint_to_receiver_camel() { let mut state = COMPONENT_STATE(); let recipient = setup_camel_receiver(); @@ -1183,7 +1127,6 @@ fn test__safe_mint_to_receiver_camel() { } #[test] -#[available_gas(20000000)] fn test__safe_mint_to_account() { let mut state = COMPONENT_STATE(); let account = setup_account(); @@ -1197,7 +1140,6 @@ fn test__safe_mint_to_account() { } #[test] -#[available_gas(20000000)] fn test__safe_mint_to_account_camel() { let mut state = COMPONENT_STATE(); let account = setup_camel_account(); @@ -1211,7 +1153,6 @@ fn test__safe_mint_to_account_camel() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test__safe_mint_to_non_receiver() { let mut state = COMPONENT_STATE(); @@ -1224,7 +1165,6 @@ fn test__safe_mint_to_non_receiver() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: safe mint failed',))] fn test__safe_mint_to_receiver_failure() { let mut state = COMPONENT_STATE(); @@ -1237,7 +1177,6 @@ fn test__safe_mint_to_receiver_failure() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: safe mint failed',))] fn test__safe_mint_to_receiver_failure_camel() { let mut state = COMPONENT_STATE(); @@ -1250,7 +1189,6 @@ fn test__safe_mint_to_receiver_failure_camel() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid receiver',))] fn test__safe_mint_to_zero() { let mut state = COMPONENT_STATE(); @@ -1258,7 +1196,6 @@ fn test__safe_mint_to_zero() { } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: token already minted',))] fn test__safe_mint_already_exist() { let mut state = setup(); @@ -1270,27 +1207,25 @@ fn test__safe_mint_already_exist() { // #[test] -#[available_gas(20000000)] fn test__burn() { let mut state = setup(); state._approve(OTHER(), TOKEN_ID); utils::drop_event(ZERO()); - assert(state.owner_of(TOKEN_ID) == OWNER(), 'Ownership before'); - assert(state.balance_of(OWNER()) == 1, 'Balance of owner before'); - assert(state.get_approved(TOKEN_ID) == OTHER(), 'Approval before'); + assert_eq!(state.owner_of(TOKEN_ID), OWNER()); + assert_eq!(state.balance_of(OWNER()), 1); + assert_eq!(state.get_approved(TOKEN_ID), OTHER()); state._burn(TOKEN_ID); assert_event_transfer(OWNER(), ZERO(), TOKEN_ID); - assert(state.ERC721_owners.read(TOKEN_ID) == ZERO(), 'Ownership after'); - assert(state.balance_of(OWNER()) == 0, 'Balance of owner after'); - assert(state.ERC721_token_approvals.read(TOKEN_ID) == ZERO(), 'Approval after'); + assert_eq!(state.ERC721_owners.read(TOKEN_ID), ZERO()); + assert_eq!(state.balance_of(OWNER()), 0); + assert_eq!(state.ERC721_token_approvals.read(TOKEN_ID), ZERO()); } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID',))] fn test__burn_nonexistent() { let mut state = COMPONENT_STATE(); @@ -1302,17 +1237,15 @@ fn test__burn_nonexistent() { // #[test] -#[available_gas(20000000)] fn test__set_token_uri() { let mut state = setup(); - assert(state.token_uri(TOKEN_ID) == 0, 'URI should be 0'); + assert!(state.token_uri(TOKEN_ID).is_zero()); state._set_token_uri(TOKEN_ID, URI); - assert(state.token_uri(TOKEN_ID) == URI, 'URI should be set'); + assert_eq!(state.token_uri(TOKEN_ID), URI); } #[test] -#[available_gas(20000000)] #[should_panic(expected: ('ERC721: invalid token ID',))] fn test__set_token_uri_nonexistent() { let mut state = COMPONENT_STATE(); @@ -1327,38 +1260,38 @@ fn assert_state_before_transfer( owner: ContractAddress, recipient: ContractAddress, token_id: u256 ) { let state = COMPONENT_STATE(); - assert(state.owner_of(token_id) == owner, 'Ownership before'); - assert(state.balance_of(owner) == 1, 'Balance of owner before'); - assert(state.balance_of(recipient) == 0, 'Balance of recipient before'); + assert_eq!(state.owner_of(token_id), owner); + assert_eq!(state.balance_of(owner), 1); + assert!(state.balance_of(recipient).is_zero()); } fn assert_state_after_transfer(owner: ContractAddress, recipient: ContractAddress, token_id: u256) { let state = COMPONENT_STATE(); - assert(state.owner_of(token_id) == recipient, 'Ownership after'); - assert(state.balance_of(owner) == 0, 'Balance of owner after'); - assert(state.balance_of(recipient) == 1, 'Balance of recipient after'); - assert(state.get_approved(token_id) == ZERO(), 'Approval not implicitly reset'); + assert_eq!(state.owner_of(token_id), recipient); + assert_eq!(state.balance_of(owner), 0); + assert_eq!(state.balance_of(recipient), 1); + assert!(state.get_approved(token_id).is_zero()); } fn assert_state_before_mint(recipient: ContractAddress) { let state = COMPONENT_STATE(); - assert(state.balance_of(recipient) == 0, 'Balance of recipient before'); + assert!(state.balance_of(recipient).is_zero()); } fn assert_state_after_mint(recipient: ContractAddress, token_id: u256) { let state = COMPONENT_STATE(); - assert(state.owner_of(token_id) == recipient, 'Ownership after'); - assert(state.balance_of(recipient) == 1, 'Balance of recipient after'); - assert(state.get_approved(token_id) == ZERO(), 'Approval implicitly set'); + assert_eq!(state.owner_of(token_id), recipient); + assert_eq!(state.balance_of(recipient), 1); + assert!(state.get_approved(token_id).is_zero()); } fn assert_event_approval_for_all( owner: ContractAddress, operator: ContractAddress, approved: bool ) { let event = utils::pop_log::(ZERO()).unwrap(); - assert(event.owner == owner, 'Invalid `owner`'); - assert(event.operator == operator, 'Invalid `operator`'); - assert(event.approved == approved, 'Invalid `approved`'); + assert_eq!(event.owner, owner); + assert_eq!(event.operator, operator); + assert_eq!(event.approved, approved); utils::assert_no_events_left(ZERO()); // Check indexed keys @@ -1370,9 +1303,9 @@ fn assert_event_approval_for_all( fn assert_event_approval(owner: ContractAddress, approved: ContractAddress, token_id: u256) { let event = utils::pop_log::(ZERO()).unwrap(); - assert(event.owner == owner, 'Invalid `owner`'); - assert(event.approved == approved, 'Invalid `approved`'); - assert(event.token_id == token_id, 'Invalid `token_id`'); + assert_eq!(event.owner, owner); + assert_eq!(event.approved, approved); + assert_eq!(event.token_id, token_id); utils::assert_no_events_left(ZERO()); // Check indexed keys @@ -1385,9 +1318,9 @@ fn assert_event_approval(owner: ContractAddress, approved: ContractAddress, toke fn assert_event_transfer(from: ContractAddress, to: ContractAddress, token_id: u256) { let event = utils::pop_log::(ZERO()).unwrap(); - assert(event.from == from, 'Invalid `from`'); - assert(event.to == to, 'Invalid `to`'); - assert(event.token_id == token_id, 'Invalid `token_id`'); + assert_eq!(event.from, from); + assert_eq!(event.to, to); + assert_eq!(event.token_id, token_id); utils::assert_no_events_left(ZERO()); // Check indexed keys diff --git a/src/tests/token/test_erc721_receiver.cairo b/src/tests/token/test_erc721_receiver.cairo index 529d9b2fe..c7c8c4f14 100644 --- a/src/tests/token/test_erc721_receiver.cairo +++ b/src/tests/token/test_erc721_receiver.cairo @@ -12,29 +12,29 @@ fn STATE() -> DualCaseERC721ReceiverMock::ContractState { } #[test] -#[available_gas(20000000)] fn test_initializer() { let mut state = STATE(); state.erc721_receiver.initializer(); - assert(state.src5.supports_interface(IERC721_RECEIVER_ID), 'Missing interface ID'); - assert(state.src5.supports_interface(ISRC5_ID), 'Missing interface ID'); + + let supports_ierc721_receiver = state.src5.supports_interface(IERC721_RECEIVER_ID); + let supports_isrc5 = state.src5.supports_interface(ISRC5_ID); + + assert!(supports_ierc721_receiver); + assert!(supports_isrc5); } #[test] -#[available_gas(20000000)] fn test_on_erc721_received() { let mut state = STATE(); let data = array![]; - assert( - state - .erc721_receiver - .on_erc721_received(OPERATOR(), OWNER(), TOKEN_ID, data.span()) == IERC721_RECEIVER_ID, - 'Should return receiver ID' - ); - assert( - state - .erc721_receiver - .onERC721Received(OPERATOR(), OWNER(), TOKEN_ID, data.span()) == IERC721_RECEIVER_ID, - 'Should return receiver ID' - ); + + let on_erc721_received = state + .erc721_receiver + .on_erc721_received(OPERATOR(), OWNER(), TOKEN_ID, data.span()); + assert_eq!(on_erc721_received, IERC721_RECEIVER_ID, "Should return receiver ID"); + + let onERC721Received = state + .erc721_receiver + .onERC721Received(OPERATOR(), OWNER(), TOKEN_ID, data.span()); + assert_eq!(onERC721Received, IERC721_RECEIVER_ID, "Should return receiver ID"); } diff --git a/src/tests/upgrades/test_upgradeable.cairo b/src/tests/upgrades/test_upgradeable.cairo index 26b191f3c..280b309d7 100644 --- a/src/tests/upgrades/test_upgradeable.cairo +++ b/src/tests/upgrades/test_upgradeable.cairo @@ -5,6 +5,7 @@ use openzeppelin::tests::mocks::upgrades_mocks::{ IUpgradesV2Dispatcher, IUpgradesV2DispatcherTrait, UpgradesV2 }; use openzeppelin::tests::utils::constants::{CLASS_HASH_ZERO, ZERO}; +use openzeppelin::tests::utils::debug::DebugClassHash; use openzeppelin::tests::utils; use openzeppelin::upgrades::UpgradeableComponent::Upgraded; use starknet::ClassHash; @@ -31,7 +32,6 @@ fn deploy_v1() -> IUpgradesV1Dispatcher { // #[test] -#[available_gas(2000000)] #[should_panic(expected: ('Class hash cannot be zero', 'ENTRYPOINT_FAILED',))] fn test_upgrade_with_class_hash_zero() { let v1 = deploy_v1(); @@ -39,19 +39,17 @@ fn test_upgrade_with_class_hash_zero() { } #[test] -#[available_gas(2000000)] fn test_upgraded_event() { let v1 = deploy_v1(); v1.upgrade(V2_CLASS_HASH()); let event = utils::pop_log::(v1.contract_address).unwrap(); - assert(event.class_hash == V2_CLASS_HASH(), 'Invalid class hash'); + assert_eq!(event.class_hash, V2_CLASS_HASH()); utils::assert_no_events_left(v1.contract_address); } #[test] -#[available_gas(2000000)] fn test_new_selector_after_upgrade() { let v1 = deploy_v1(); @@ -59,11 +57,10 @@ fn test_new_selector_after_upgrade() { let v2 = IUpgradesV2Dispatcher { contract_address: v1.contract_address }; v2.set_value2(VALUE); - assert(v2.get_value2() == VALUE, 'New selector should be callable'); + assert_eq!(v2.get_value2(), VALUE); } #[test] -#[available_gas(2000000)] fn test_state_persists_after_upgrade() { let v1 = deploy_v1(); v1.set_value(VALUE); @@ -71,18 +68,16 @@ fn test_state_persists_after_upgrade() { v1.upgrade(V2_CLASS_HASH()); let v2 = IUpgradesV2Dispatcher { contract_address: v1.contract_address }; - assert(v2.get_value() == VALUE, 'Should keep state after upgrade'); + assert_eq!(v2.get_value(), VALUE); } #[test] -#[available_gas(2000000)] fn test_remove_selector_passes_in_v1() { let v1 = deploy_v1(); v1.remove_selector(); } #[test] -#[available_gas(2000000)] #[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] fn test_remove_selector_fails_in_v2() { let v1 = deploy_v1(); diff --git a/src/tests/utils.cairo b/src/tests/utils.cairo index 24409ccad..adadd304a 100644 --- a/src/tests/utils.cairo +++ b/src/tests/utils.cairo @@ -1,4 +1,5 @@ mod constants; +mod debug; use starknet::ContractAddress; use starknet::testing; @@ -26,8 +27,8 @@ fn pop_log, +starknet::Event>(address: ContractAddress) -> Option keys.pop_front(); let ret = starknet::Event::deserialize(ref keys, ref data); - assert(data.is_empty(), 'Event has extra data'); - assert(keys.is_empty(), 'Event has extra keys'); + assert!(data.is_empty(), "Event has extra data"); + assert!(keys.is_empty(), "Event has extra keys"); ret } @@ -40,11 +41,11 @@ fn assert_indexed_keys, +starknet::Event>(event: T, expected_keys let mut data = array![]; event.append_keys_and_data(ref keys, ref data); - assert(expected_keys == keys.span(), 'Invalid keys'); + assert!(expected_keys == keys.span()); } fn assert_no_events_left(address: ContractAddress) { - assert(testing::pop_log_raw(address).is_none(), 'Events remaining on queue'); + assert!(testing::pop_log_raw(address).is_none(), "Events remaining on queue"); } fn drop_event(address: ContractAddress) { diff --git a/src/tests/utils/debug.cairo b/src/tests/utils/debug.cairo new file mode 100644 index 000000000..f2a859e95 --- /dev/null +++ b/src/tests/utils/debug.cairo @@ -0,0 +1,16 @@ +use core::fmt::{Debug, Formatter, Error}; +use starknet::{ContractAddress, ClassHash}; + +impl DebugContractAddress of core::fmt::Debug { + fn fmt(self: @ContractAddress, ref f: Formatter) -> Result<(), Error> { + let address: felt252 = (*self).into(); + write!(f, "{address:?}") + } +} + +impl DebugClassHash of core::fmt::Debug { + fn fmt(self: @ClassHash, ref f: Formatter) -> Result<(), Error> { + let hash: felt252 = (*self).into(); + write!(f, "{hash:?}") + } +} From 43ca5cd4c012f1dc355c6be7ea3f0ae6ee9cd14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Mon, 29 Jan 2024 21:33:46 -0300 Subject: [PATCH 3/5] Add CI version bump (#862) * add prepare-release.yml * update changelog * fix replacement * fix current version extraction * add autocommit * fix autocommit * exclude package-lock and releasing from bump * fix exclusion * Update .github/workflows/prepare-release.yml * remove unused step ids * Update RELEASING.md Co-authored-by: Andrew Fleming * Update .github/workflows/prepare-release.yml Co-authored-by: Nikita Stupin <18281368+nikitastupin@users.noreply.github.com> * add GH_PAT to workflow * update secret name * update secret name * update secret name * fix PAT setting * Update .github/workflows/prepare-release.yml Co-authored-by: Andrew Fleming --------- Co-authored-by: Andrew Fleming Co-authored-by: Nikita Stupin <18281368+nikitastupin@users.noreply.github.com> --- .github/workflows/prepare-release.yml | 34 +++++++++++++++++++++++++++ CHANGELOG.md | 1 + RELEASING.md | 12 +++++----- 3 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/prepare-release.yml diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml new file mode 100644 index 000000000..49164cae8 --- /dev/null +++ b/.github/workflows/prepare-release.yml @@ -0,0 +1,34 @@ +name: Update version on new release branch + +on: + create: + +jobs: + update_version: + if: github.ref_type == 'branch' && startsWith(github.ref, 'refs/heads/release-v') + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + token: ${{ secrets.OPENZEPPELIN_ORG_GITHUB_PAT }} + + - name: Extract current version + run: | + CURRENT_VERSION=$(grep '^version = ' Scarb.toml | sed 's/version = "\(.*\)"/\1/') + echo "CURRENT_VERSION=$CURRENT_VERSION" >> $GITHUB_ENV + + - name: Extract new version number + run: echo "NEW_VERSION=${GITHUB_REF#refs/heads/release-v}" >> $GITHUB_ENV + + - name: Replace version in files + run: | + echo "Current version: $CURRENT_VERSION" + echo "New version: $NEW_VERSION" + find . -type f -not -path '*/\.*' -not -path './CHANGELOG.md' -not -path './docs/package-lock.json' -not -path './RELEASING.md' -exec sed -i "s/$CURRENT_VERSION/$NEW_VERSION/g" {} + + + - name: Auto-commit changes + uses: stefanzweifel/git-auto-commit-action@3ea6ae190baf489ba007f7c92608f33ce20ef04a #v4.16.0 + with: + commit_message: Bump version to ${{ env.NEW_VERSION }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 44796a95b..32f8cac09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Utilities documentation (#825) - Documentation for presets (#832) - Backwards compatibility notice (#861) +- Add automatic version bump to CI (#862) ### Changed diff --git a/RELEASING.md b/RELEASING.md index 03c503d9c..2a3540cb7 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -8,22 +8,22 @@ git checkout -b release-v0.8.0 ``` -(3) Search and replace the current release version with the one to be released (e.g. `0.7.0` to `0.8.0`, or `0.8.0-beta.0` to `0.8.0-beta.1`). +(3) Create the release entry in [the changelog](CHANGELOG.md) with the contents of the _Unreleased_ section, which should be left empty. -(4) Create the release entry in [the changelog](CHANGELOG.md) with the contents of the _Unreleased_ section, which should be left empty. - -(5) Push and open a PR targeting `main` to carefully review the release changes. +(4) Push and open a PR targeting `main` to carefully review the release changes. This will trigger a Github workflow that automatically bumps the version number throughout the project. ```sh git push release-v0.8.0 ``` -(6) Once merged, create a tag on the release branch and push it to the main repository. +(5) Once merged, pull the changes from the release branch. +Then, create a tag on the release branch and push it to the main repository. ```sh +git pull git tag v0.8.0 git push origin v0.8.0 ``` -(7) Finally, go to the repo's [releases page](https://github.com/OpenZeppelin/cairo-contracts/releases/) and [create a new one](https://github.com/OpenZeppelin/cairo-contracts/releases/new) with the new tag and the base branch as target (`main` except in the event of a hotfix). +(6) Finally, go to the repo's [releases page](https://github.com/OpenZeppelin/cairo-contracts/releases/) and [create a new one](https://github.com/OpenZeppelin/cairo-contracts/releases/new) with the new tag and the base branch as target (`main` except in the event of a hotfix). Make sure to write a detailed release description and a short changelog. From 14486165ad98cb94ca1ec30d1f8dae0bd21b49df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Triay?= Date: Tue, 30 Jan 2024 13:50:25 -0300 Subject: [PATCH 4/5] Address versioning and presets issues (#879) * fix cairo version * update class hashes * fix scarb.toml version number * add presets explainer * update wording --- Scarb.lock | 2 +- Scarb.toml | 2 +- docs/modules/ROOT/pages/presets.adoc | 28 ++++++++++--------- .../ROOT/pages/utils/_class_hashes.adoc | 8 +++--- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/Scarb.lock b/Scarb.lock index e023bf036..b2c02f8ff 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -3,4 +3,4 @@ version = 1 [[package]] name = "openzeppelin" -version = "0.8.0" +version = "0.8.1" diff --git a/Scarb.toml b/Scarb.toml index 2b9288378..0f5ba460f 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -1,6 +1,6 @@ [package] name = "openzeppelin" -version = "0.8.0" +version = "0.8.1" edition = "2023_01" cairo-version = "2.4.4" authors = ["OpenZeppelin Community "] diff --git a/docs/modules/ROOT/pages/presets.adoc b/docs/modules/ROOT/pages/presets.adoc index 02a3f442d..e7c62214d 100644 --- a/docs/modules/ROOT/pages/presets.adoc +++ b/docs/modules/ROOT/pages/presets.adoc @@ -1,15 +1,24 @@ -:scarb: https://docs.swmansion.com/scarb[scarb] +:account: xref:/api/account.adoc#Account[Account.cairo] +:erc20: xref:/api/erc20.adoc#ERC20[ERC20.cairo] +:erc721: xref:/api/erc721.adoc#ERC721[ERC721.cairo] +:sierra-class-hashes: https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/class-hash[Sierra class hashes] +:starkli: https://book.starkli.rs/introduction[starkli] +:wizard: https://wizard.openzeppelin.com[Wizard for Cairo] + = Presets include::utils/_class_hashes.adoc[] -List of "ready-to-deploy" presets available and their corresponding class hashes. +Presets are ready-to-deploy contracts provided by the library. Since presets are intended to be very simple +and as generic as possible, there's no support for custom or complex contracts such as `ERC20Pausable` or `ERC721Mintable`. -:account: xref:/api/account.adoc#Account[Account.cairo] -:erc20: xref:/api/erc20.adoc#ERC20[ERC20.cairo] -:erc721: xref:/api/erc721.adoc#ERC721[ERC721.cairo] -:cairo-and-sierra: https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/cairo-and-sierra/[Cairo and Sierra] +TIP: For contract customization and combination of modules you can use {wizard}, our code-generation tool. + + +## Available presets + +List of available presets and their corresponding {sierra-class-hashes}. NOTE: Class hashes were computed using {class-hash-cairo-version}. @@ -26,11 +35,4 @@ NOTE: Class hashes were computed using {class-hash-cairo-version}. | `{erc721-class-hash}` |=== -:starkli: https://book.starkli.rs/introduction[starkli] - -To understand the compiled class hash term, check {cairo-and-sierra}. - TIP: {starkli} class-hash command can be used to compute the class hash from a compiled artifact. - -TIP: To obtain the artifact -using {scarb}, set the `casm = true` option under `\[[target.starknet-contract]]` in the `Scarb.toml` file. \ No newline at end of file diff --git a/docs/modules/ROOT/pages/utils/_class_hashes.adoc b/docs/modules/ROOT/pages/utils/_class_hashes.adoc index 837394e40..102d5276b 100644 --- a/docs/modules/ROOT/pages/utils/_class_hashes.adoc +++ b/docs/modules/ROOT/pages/utils/_class_hashes.adoc @@ -1,10 +1,10 @@ // Version -:class-hash-cairo-version: https://crates.io/crates/cairo-lang-compiler/2.3.1[cairo 2.3.1] +:class-hash-cairo-version: https://crates.io/crates/cairo-lang-compiler/2.4.4[cairo 2.4.4] // Class Hashes -:account-class-hash: 0x061dac032f228abef9c6626f995015233097ae253a7f72d68552db02f2971b8f -:erc20-class-hash: 0x046ded64ae2dead6448e247234bab192a9c483644395b66f2155f2614e5804b0 -:erc721-class-hash: 0x05e5a302b02eca41819fe263420eb8dc96bfb9770a90f55847c4c1337b551635 +:account-class-hash: 0x07a711d70338e05d7008fdf553207adc791297461fe3464b450fdc5f26f836ae +:erc20-class-hash: 0x03af5816946625d3d2c94ea451225715784762050eba736f0b0ad9186685bced +:erc721-class-hash: 0x045c96d1b24c3dc060680e4bfd4bdc32161aefe8f8939cd4be3954c5d8688d75 // Presets page :presets-page: xref:presets.adoc[Compiled class hash] From 6d26b84f133db6f723b5ed6186b39662ebf7eb7c Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 31 Jan 2024 12:06:05 +0100 Subject: [PATCH 5/5] Add EthAccount (#853) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add eth_account main logic * feat: add tests * fix: workflow * feat: change EthPublicKey to Secp256k1Point * feat: add more tests * feat: add entry to CHANGELOG * feat: add tests for preset * docs: add API Reference entries * Update src/account/eth_account/eth_account.cairo Co-authored-by: Andrew Fleming * feat: apply review updates * refactor: test * feat: apply review updates * feat: update error messages * feat: apply review updates * Update docs/modules/ROOT/pages/api/account.adoc Co-authored-by: Martín Triay * feat: add tests for upgrade * feat: add tests for signature * refactor: drop X.Y.Z in favor of last released version * feat: updated class hashes * fix: casm target * fix: versions * refactor: account directory * fix: comments * fix: class hashes --------- Co-authored-by: Andrew Fleming Co-authored-by: Martín Triay --- CHANGELOG.md | 7 +- Scarb.toml | 2 +- docs/modules/ROOT/pages/api/account.adoc | 276 +++++++- docs/modules/ROOT/pages/presets.adoc | 12 +- .../ROOT/pages/utils/_class_hashes.adoc | 3 +- src/account.cairo | 6 +- src/account/account.cairo | 40 +- src/account/dual_account.cairo | 6 +- src/account/dual_eth_account.cairo | 73 +++ src/account/eth_account.cairo | 262 ++++++++ src/account/interface.cairo | 68 ++ src/account/utils.cairo | 32 + src/account/utils/secp256k1.cairo | 69 ++ src/account/utils/signature.cairo | 44 ++ src/presets.cairo | 2 + src/presets/eth_account.cairo | 78 +++ src/tests/account.cairo | 4 + src/tests/account/test_account.cairo | 30 +- src/tests/account/test_dual_account.cairo | 2 +- src/tests/account/test_dual_eth_account.cairo | 236 +++++++ src/tests/account/test_eth_account.cairo | 614 ++++++++++++++++++ src/tests/account/test_secp256k1.cairo | 138 ++++ src/tests/account/test_signature.cairo | 127 ++++ src/tests/mocks.cairo | 1 + src/tests/mocks/eth_account_mocks.cairo | 215 ++++++ src/tests/presets.cairo | 1 + src/tests/presets/test_account.cairo | 47 +- src/tests/presets/test_eth_account.cairo | 515 +++++++++++++++ src/tests/upgrades/test_upgradeable.cairo | 19 +- src/tests/utils/constants.cairo | 10 + 30 files changed, 2844 insertions(+), 95 deletions(-) create mode 100644 src/account/dual_eth_account.cairo create mode 100644 src/account/eth_account.cairo create mode 100644 src/account/utils.cairo create mode 100644 src/account/utils/secp256k1.cairo create mode 100644 src/account/utils/signature.cairo create mode 100644 src/presets/eth_account.cairo create mode 100644 src/tests/account/test_dual_eth_account.cairo create mode 100644 src/tests/account/test_eth_account.cairo create mode 100644 src/tests/account/test_secp256k1.cairo create mode 100644 src/tests/account/test_signature.cairo create mode 100644 src/tests/mocks/eth_account_mocks.cairo create mode 100644 src/tests/presets/test_eth_account.cairo diff --git a/CHANGELOG.md b/CHANGELOG.md index 32f8cac09..357f6da75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- EthAccount component and preset (#853) + ### Changed -- Bump scarb to v2.4.4 (#864) +- Bump scarb to v2.4.4 (#853) ## 0.8.1 (2024-01-23) @@ -27,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Use ComponentState in tests (#836) - Docsite navbar (#838) +- Account events indexed keys (#853) - Support higher tx versions in Account (#858) - Bump scarb to v2.4.1 (#858) - Add security section to Upgrades docs (#861) diff --git a/Scarb.toml b/Scarb.toml index 0f5ba460f..d1fb78f7a 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -19,7 +19,7 @@ starknet = "2.4.4" [[target.starknet-contract]] allowed-libfuncs-list.name = "experimental" sierra = true -casm = true +casm = false [tool.fmt] sort-module-level-items = true diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 1438ef696..aabb1a2e3 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -63,15 +63,16 @@ Returns the short string `'VALID'` if valid, otherwise it reverts. [.contract] [[AccountComponent]] -=== `++AccountComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/account/account.cairo#L27[{github-icon},role=heading-link] +=== `++AccountComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/account/account.cairo[{github-icon},role=heading-link] :OwnerAdded: xref:AccountComponent-OwnerAdded[OwnerAdded] :OwnerRemoved: xref:AccountComponent-OwnerRemoved[OwnerRemoved] +:starknet-curve: https://docs.starknet.io/documentation/architecture_and_concepts/Cryptography/stark-curve/[Starknet curve] ```javascript use openzeppelin::account::AccountComponent; ``` -Account component implementing xref:ISRC6[`ISRC6`]. +Account component implementing xref:ISRC6[`ISRC6`] for signatures over the {starknet-curve}. NOTE: Implementing xref:api/introspection.adoc#SRC5Component[SRC5Component] is a requirement for this component to be implemented. @@ -260,6 +261,210 @@ Emitted when a `public_key` is added. Emitted when a `public_key` is removed. +[.contract] +[[EthAccountComponent]] +=== `++EthAccountComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/account/eth_account.cairo[{github-icon},role=heading-link] + +:OwnerAdded: xref:EthAccountComponent-OwnerAdded[OwnerAdded] +:OwnerRemoved: xref:EthAccountComponent-OwnerRemoved[OwnerRemoved] +:secp256k1-curve: https://en.bitcoin.it/wiki/Secp256k1[Secp256k1 curve] + +```javascript +use openzeppelin::account::eth_account::EthAccountComponent; +``` +Account component implementing xref:ISRC6[`ISRC6`] for signatures over the {secp256k1-curve}. + +NOTE: Implementing xref:api/introspection.adoc#SRC5Component[SRC5Component] is a requirement for this component to be implemented. + +NOTE: The `EthPublicKey` type is an alias for `starknet::secp256k1::Secp256k1Point`. + +[.contract-index#EthAccountComponent-Embeddable-Impls] +.Embeddable Implementations +-- +.SRC6Impl + +* xref:#EthAccountComponent-\\__execute__[`++__execute__(self, calls)++`] +* xref:#EthAccountComponent-\\__validate__[`++__validate__(self, calls)++`] +* xref:#EthAccountComponent-is_valid_signature[`++is_valid_signature(self, hash, signature)++`] + +.DeclarerImpl + +* xref:#EthAccountComponent-\\__validate_declare__[`++__validate_declare__(self, class_hash)++`] + +.DeployableImpl + +* xref:#EthAccountComponent-\\__validate_deploy__[`++__validate_deploy__(self, hash, signature)++`] + +.PublicKeyImpl + +* xref:#EthAccountComponent-get_public_key[`++get_public_key(self)++`] +* xref:#EthAccountComponent-set_public_key[`++set_public_key(self, new_public_key)++`] +-- + +[.contract-index#EthAccountComponent-Embeddable-Impls-camelCase] +.Embeddable Implementations (camelCase) +-- +.SRC6CamelOnlyImpl + +* xref:#EthAccountComponent-isValidSignature[`++isValidSignature(self, hash, signature)++`] + +.PublicKeyCamelImpl + +* xref:#EthAccountComponent-getPublicKey[`++getPublicKey(self)++`] +* xref:#EthAccountComponent-setPublicKey[`++setPublicKey(self, newPublicKey)++`] +-- + +[.contract-index] +.Internal Implementations +-- +.InternalImpl + +* xref:#EthAccountComponent-initializer[`++initializer(self, public_key)++`] +* xref:#EthAccountComponent-assert_only_self[`++assert_only_self(self)++`] +* xref:#EthAccountComponent-validate_transaction[`++validate_transaction(self)++`] +* xref:#EthAccountComponent-_set_public_key[`++_set_public_key(self, new_public_key)++`] +* xref:#EthAccountComponent-_is_valid_signature[`++_is_valid_signature(self, hash, signature)++`] +-- + +[.contract-index] +.Events +-- +* xref:#EthAccountComponent-OwnerAdded[`++OwnerAdded(new_owner_guid)++`] +* xref:#EthAccountComponent-OwnerRemoved[`++OwnerRemoved(removed_owner_guid)++`] +-- + +[#EthAccountComponent-Embeddable-Functions] +==== Embeddable Functions + +[.contract-item] +[[EthAccountComponent-__execute__]] +==== `[.contract-item-name]#++__execute__++#++(self: @ContractState, calls: Array) → Array>++` [.item-kind]#external# + +See xref:ISRC6-\\__execute__[ISRC6::\\__execute__]. + +[.contract-item] +[[EthAccountComponent-__validate__]] +==== `[.contract-item-name]#++__validate__++#++(self: @ContractState, calls: Array) → felt252++` [.item-kind]#external# + +See xref:ISRC6-\\__validate__[ISRC6::\\__validate__]. + +[.contract-item] +[[EthAccountComponent-is_valid_signature]] +==== `[.contract-item-name]#++is_valid_signature++#++(self: @ContractState, hash: felt252, signature: Array) → felt252++` [.item-kind]#external# + +See xref:ISRC6-is_valid_signature[ISRC6::is_valid_signature]. + +[.contract-item] +[[EthAccountComponent-__validate_declare__]] +==== `[.contract-item-name]#++__validate_declare__++#++(self: @ContractState, class_hash: felt252) → felt252++` [.item-kind]#external# + +Validates a https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/Blocks/transactions/#declare-transaction[`Declare` transaction]. + +Returns the short string `'VALID'` if valid, otherwise it reverts. + +[.contract-item] +[[EthAccountComponent-__validate_deploy__]] +==== `[.contract-item-name]#++__validate_deploy__++#++(self: @ContractState, class_hash: felt252, contract_address_salt: felt252, public_key: EthPublicKey) → felt252++` [.item-kind]#external# + +Validates a https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/Blocks/transactions/#deploy_account_transaction[`DeployAccount` transaction]. +See xref:/guides/deployment.adoc[Counterfactual Deployments]. + +Returns the short string `'VALID'` if valid, otherwise it reverts. + +[.contract-item] +[[EthAccountComponent-get_public_key]] +==== `[.contract-item-name]#++get_public_key++#++(self: @ContractState)++ → EthPublicKey` [.item-kind]#external# + +Returns the current public key of the account. + +[.contract-item] +[[EthAccountComponent-set_public_key]] +==== `[.contract-item-name]#++set_public_key++#++(ref self: ContractState, new_public_key: EthPublicKey)++` [.item-kind]#external# + +Sets a new public key for the account. Only accesible by the account calling itself through `\\__execute__`. + +Emits both an {OwnerRemoved} and an {OwnerAdded} event. + +[#EthAccountComponent-camelCase-Support] +==== camelCase Support + +[.contract-item] +[[EthAccountComponent-isValidSignature]] +==== `[.contract-item-name]#++isValidSignature++#++(self: @ContractState, hash: felt252, signature: Array) → felt252++` [.item-kind]#external# + +See xref:ISRC6-is_valid_signature[ISRC6::is_valid_signature]. + +[.contract-item] +[[EthAccountComponent-getPublicKey]] +==== `[.contract-item-name]#++getPublicKey++#++(self: @ContractState)++ → EthPublicKey` [.item-kind]#external# + +See xref:EthAccountComponent-get_public_key[get_public_key]. + +[.contract-item] +[[EthAccountComponent-setPublicKey]] +==== `[.contract-item-name]#++setPublicKey++#++(ref self: ContractState, newPublicKey: EthPublicKey)++` [.item-kind]#external# + +See xref:EthAccountComponent-set_public_key[set_public_key]. + +[#EthAccountComponent-Internal-Functions] +==== Internal Functions + +[.contract-item] +[[EthAccountComponent-initializer]] +==== `[.contract-item-name]#++initializer++#++(ref self: ComponentState, public_key: EthPublicKey)++` [.item-kind]#internal# + +Initializes the account with the given public key, and registers the ISRC6 interface ID. + +Emits an {OwnerAdded} event. + +[.contract-item] +[[EthAccountComponent-assert_only_self]] +==== `[.contract-item-name]#++assert_only_self++#++(self: @ComponentState)++` [.item-kind]#internal# + +Validates that the caller is the account itself. Otherwise it reverts. + +[.contract-item] +[[EthAccountComponent-validate_transaction]] +==== `[.contract-item-name]#++validate_transaction++#++(self: @ComponentState)++ → felt252` [.item-kind]#internal# + +Validates a transaction signature from the +https://github.com/starkware-libs/cairo/blob/main/corelib/src/starknet/info.cairo#L61[global context]. + +Returns the short string `'VALID'` if valid, otherwise it reverts. + +[.contract-item] +[[EthAccountComponent-_set_public_key]] +==== `[.contract-item-name]#++_set_public_key++#++(ref self: ComponentState, new_public_key: EthPublicKey)++` [.item-kind]#internal# + +Set the public key without validating the caller. + +Emits an {OwnerAdded} event. + +CAUTION: The usage of this method outside the `set_public_key` function is discouraged. + +[.contract-item] +[[EthAccountComponent-_is_valid_signature]] +==== `[.contract-item-name]#++_is_valid_signature++#++(self: @ComponentState, hash: felt252, signature: Span)++ → bool` [.item-kind]#internal# + +Validates the provided `signature` for the `hash`, using the account's current public key. + +[#EthAccountComponent-Events] +==== Events + +NOTE: The `guid` is computed as the hash of the public key, using the poseidon hash function. + +[.contract-item] +[[EthAccountComponent-OwnerAdded]] +==== `[.contract-item-name]#++OwnerAdded++#++(new_owner_guid: felt252)++` [.item-kind]#event# + +Emitted when a `public_key` is added. + +[.contract-item] +[[EthAccountComponent-OwnerRemoved]] +==== `[.contract-item-name]#++OwnerRemoved++#++(removed_owner_guid: felt252)++` [.item-kind]#event# + +Emitted when a `public_key` is removed. + == Presets [.contract] @@ -311,3 +516,70 @@ include::../utils/_class_hashes.adoc[] ==== `[.contract-item-name]#++constructor++#++(ref self: ContractState, public_key: felt252)++` [.item-kind]#constructor# Sets the account `public_key` and registers the interfaces the contract supports. + +[.contract] +[[EthAccountUpgradeable]] +=== `++EthAccountUpgradeable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.8.1/src/presets/eth_account.cairo[{github-icon},role=heading-link] + +```javascript +use openzeppelin::presets::EthAccountUpgradeable; +``` + +Account contract leveraging xref:#EthAccountComponent[EthAccountComponent]. + +NOTE: The `EthPublicKey` type is an alias for `starknet::secp256k1::Secp256k1Point`. + +include::../utils/_class_hashes.adoc[] + +[.contract-index] +.{presets-page} +-- +{eth-account-upgradeable-class-hash} +-- + +[.contract-index] +.Constructor +-- +* xref:#EthAccountUpgradeable-constructor[`++constructor(self, public_key)++`] +-- + +[.contract-index] +.Embedded Implementations +-- +.EthAccountComponent + +* xref:#EthAccountComponent-Embeddable-Impls[`++SRC6Impl++`] +* xref:#EthAccountComponent-Embeddable-Impls[`++PublicKeyImpl++`] +* xref:#EthAccountComponent-Embeddable-Impls[`++DeclarerImpl++`] +* xref:#EthAccountComponent-Embeddable-Impls[`++DeployableImpl++`] +* xref:#EthAccountComponent-Embeddable-Impls-camelCase[`++SRC6CamelOnlyImpl++`] +* xref:#EthAccountComponent-Embeddable-Impls-camelCase[`++PublicKeyCamelImpl++`] + +.SRC5Component + +* xref:api/introspection.adoc#SRC5Component-Embeddable-Impls[`++SRC5Impl++`] +-- + +[.contract-index] +.External Functions +-- +* xref:#EthAccountUpgradeable-upgrade[`++upgrade(self, new_class_hash)++`] +-- + +[#EthAccountUpgradeable-constructor-section] +==== Constructor + +[.contract-item] +[[EthAccountUpgradeable-constructor]] +==== `[.contract-item-name]#++constructor++#++(ref self: ContractState, public_key: EthPublicKey)++` [.item-kind]#constructor# + +Sets the account `public_key` and registers the interfaces the contract supports. + +[#EthAccountUpgradeable-external-functions] +==== External Functions + +[.contract-item] +[[EthAccountUpgradeable-upgrade]] +==== `[.contract-item-name]#++upgrade++#++(ref self: ContractState, new_class_hash: ClassHash)++` [.item-kind]#external# + +Upgrades the contract to a new implementation given by `new_class_hash`. diff --git a/docs/modules/ROOT/pages/presets.adoc b/docs/modules/ROOT/pages/presets.adoc index e7c62214d..8a2c79afd 100644 --- a/docs/modules/ROOT/pages/presets.adoc +++ b/docs/modules/ROOT/pages/presets.adoc @@ -1,6 +1,7 @@ -:account: xref:/api/account.adoc#Account[Account.cairo] -:erc20: xref:/api/erc20.adoc#ERC20[ERC20.cairo] -:erc721: xref:/api/erc721.adoc#ERC721[ERC721.cairo] +:account: xref:/api/account.adoc#Account[Account] +:eth-account-upgradeable: xref:/api/account.adoc#EthAccountUpgradeable[EthAccountUpgradeable] +:erc20: xref:/api/erc20.adoc#ERC20[ERC20] +:erc721: xref:/api/erc721.adoc#ERC721[ERC721] :sierra-class-hashes: https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/class-hash[Sierra class hashes] :starkli: https://book.starkli.rs/introduction[starkli] :wizard: https://wizard.openzeppelin.com[Wizard for Cairo] @@ -23,11 +24,14 @@ List of available presets and their corresponding {sierra-class-hashes}. NOTE: Class hashes were computed using {class-hash-cairo-version}. |=== -| Name | Compiled Class Hash +| Name | Sierra Class Hash | `{account}` | `{account-class-hash}` +| `{eth-account-upgradeable}` +| `{eth-account-upgradeable-class-hash}` + | `{erc20}` | `{erc20-class-hash}` diff --git a/docs/modules/ROOT/pages/utils/_class_hashes.adoc b/docs/modules/ROOT/pages/utils/_class_hashes.adoc index 102d5276b..90290e7c0 100644 --- a/docs/modules/ROOT/pages/utils/_class_hashes.adoc +++ b/docs/modules/ROOT/pages/utils/_class_hashes.adoc @@ -2,7 +2,8 @@ :class-hash-cairo-version: https://crates.io/crates/cairo-lang-compiler/2.4.4[cairo 2.4.4] // Class Hashes -:account-class-hash: 0x07a711d70338e05d7008fdf553207adc791297461fe3464b450fdc5f26f836ae +:account-class-hash: 0x0402765bcede84b1267a9d4658a7737c3c41a8caf6201984c3df95577c2298a3 +:eth-account-upgradeable-class-hash: 0x03dda9bcfa854795d91d586b1a4275a68ab1ab185b33a5c00ce647c75875b0ff :erc20-class-hash: 0x03af5816946625d3d2c94ea451225715784762050eba736f0b0ad9186685bced :erc721-class-hash: 0x045c96d1b24c3dc060680e4bfd4bdc32161aefe8f8939cd4be3954c5d8688d75 diff --git a/src/account.cairo b/src/account.cairo index 60ee4bcad..e29e379f2 100644 --- a/src/account.cairo +++ b/src/account.cairo @@ -1,7 +1,9 @@ mod account; mod dual_account; +mod dual_eth_account; +mod eth_account; mod interface; +mod utils; use account::AccountComponent; -use interface::AccountABIDispatcher; -use interface::AccountABIDispatcherTrait; +use eth_account::EthAccountComponent; diff --git a/src/account/account.cairo b/src/account/account.cairo index 9af836668..d043988b8 100644 --- a/src/account/account.cairo +++ b/src/account/account.cairo @@ -6,8 +6,9 @@ /// The Account component enables contracts to behave as accounts. #[starknet::component] mod AccountComponent { - use ecdsa::check_ecdsa_signature; use openzeppelin::account::interface; + use openzeppelin::account::utils::{MIN_TRANSACTION_VERSION, QUERY_VERSION, QUERY_OFFSET}; + use openzeppelin::account::utils::{execute_calls, is_valid_stark_signature}; use openzeppelin::introspection::src5::SRC5Component::InternalTrait as SRC5InternalTrait; use openzeppelin::introspection::src5::SRC5Component; use starknet::account::Call; @@ -15,9 +16,6 @@ mod AccountComponent { use starknet::get_contract_address; use starknet::get_tx_info; - const MIN_TRANSACTION_VERSION: u256 = 1; - const QUERY_OFFSET: u256 = 0x100000000000000000000000000000000; - #[storage] struct Storage { Account_public_key: felt252 @@ -32,11 +30,13 @@ mod AccountComponent { #[derive(Drop, starknet::Event)] struct OwnerAdded { + #[key] new_owner_guid: felt252 } #[derive(Drop, starknet::Event)] struct OwnerRemoved { + #[key] removed_owner_guid: felt252 } @@ -81,7 +81,7 @@ mod AccountComponent { assert(MIN_TRANSACTION_VERSION <= tx_version, Errors::INVALID_TX_VERSION); } - _execute_calls(calls) + execute_calls(calls) } /// Verifies the validity of the signature for the current transaction. @@ -241,34 +241,8 @@ mod AccountComponent { fn _is_valid_signature( self: @ComponentState, hash: felt252, signature: Span ) -> bool { - let valid_length = signature.len() == 2_u32; - - if valid_length { - check_ecdsa_signature( - hash, self.Account_public_key.read(), *signature.at(0_u32), *signature.at(1_u32) - ) - } else { - false - } + let public_key = self.Account_public_key.read(); + is_valid_stark_signature(hash, public_key, signature) } } - - fn _execute_calls(mut calls: Array) -> Array> { - let mut res = ArrayTrait::new(); - loop { - match calls.pop_front() { - Option::Some(call) => { - let _res = _execute_single_call(call); - res.append(_res); - }, - Option::None(_) => { break (); }, - }; - }; - res - } - - fn _execute_single_call(call: Call) -> Span { - let Call{to, selector, calldata } = call; - starknet::call_contract_syscall(to, selector, calldata.span()).unwrap() - } } diff --git a/src/account/dual_account.cairo b/src/account/dual_account.cairo index 2a86a0841..eee4738d3 100644 --- a/src/account/dual_account.cairo +++ b/src/account/dual_account.cairo @@ -24,7 +24,7 @@ trait DualCaseAccountABI { impl DualCaseAccountImpl of DualCaseAccountABI { fn set_public_key(self: @DualCaseAccount, new_public_key: felt252) { - let mut args = array![new_public_key]; + let args = array![new_public_key]; try_selector_with_fallback( *self.contract_address, selectors::set_public_key, selectors::setPublicKey, args.span() @@ -33,7 +33,7 @@ impl DualCaseAccountImpl of DualCaseAccountABI { } fn get_public_key(self: @DualCaseAccount) -> felt252 { - let mut args = array![]; + let args = array![]; try_selector_with_fallback( *self.contract_address, selectors::get_public_key, selectors::getPublicKey, args.span() @@ -57,7 +57,7 @@ impl DualCaseAccountImpl of DualCaseAccountABI { } fn supports_interface(self: @DualCaseAccount, interface_id: felt252) -> bool { - let mut args = array![interface_id]; + let args = array![interface_id]; try_selector_with_fallback( *self.contract_address, diff --git a/src/account/dual_eth_account.cairo b/src/account/dual_eth_account.cairo new file mode 100644 index 000000000..0cd4d2810 --- /dev/null +++ b/src/account/dual_eth_account.cairo @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.8.1 (account/dual_eth_account.cairo) + +use openzeppelin::account::interface::EthPublicKey; +use openzeppelin::account::utils::secp256k1::Secp256k1PointSerde; +use openzeppelin::utils::UnwrapAndCast; +use openzeppelin::utils::selectors; +use openzeppelin::utils::serde::SerializedAppend; +use openzeppelin::utils::try_selector_with_fallback; +use starknet::ContractAddress; +use starknet::SyscallResultTrait; + +#[derive(Copy, Drop)] +struct DualCaseEthAccount { + contract_address: ContractAddress +} + +trait DualCaseEthAccountABI { + fn set_public_key(self: @DualCaseEthAccount, new_public_key: EthPublicKey); + fn get_public_key(self: @DualCaseEthAccount) -> EthPublicKey; + fn is_valid_signature( + self: @DualCaseEthAccount, hash: felt252, signature: Array + ) -> felt252; + fn supports_interface(self: @DualCaseEthAccount, interface_id: felt252) -> bool; +} + +impl DualCaseEthAccountImpl of DualCaseEthAccountABI { + fn set_public_key(self: @DualCaseEthAccount, new_public_key: EthPublicKey) { + let mut args = array![]; + new_public_key.serialize(ref args); + + try_selector_with_fallback( + *self.contract_address, selectors::set_public_key, selectors::setPublicKey, args.span() + ) + .unwrap_syscall(); + } + + fn get_public_key(self: @DualCaseEthAccount) -> EthPublicKey { + let args = array![]; + + try_selector_with_fallback( + *self.contract_address, selectors::get_public_key, selectors::getPublicKey, args.span() + ) + .unwrap_and_cast() + } + + fn is_valid_signature( + self: @DualCaseEthAccount, hash: felt252, signature: Array + ) -> felt252 { + let mut args = array![hash]; + args.append_serde(signature); + + try_selector_with_fallback( + *self.contract_address, + selectors::is_valid_signature, + selectors::isValidSignature, + args.span() + ) + .unwrap_and_cast() + } + + fn supports_interface(self: @DualCaseEthAccount, interface_id: felt252) -> bool { + let args = array![interface_id]; + + try_selector_with_fallback( + *self.contract_address, + selectors::supports_interface, + selectors::supportsInterface, + args.span() + ) + .unwrap_and_cast() + } +} diff --git a/src/account/eth_account.cairo b/src/account/eth_account.cairo new file mode 100644 index 000000000..4e551f2d3 --- /dev/null +++ b/src/account/eth_account.cairo @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.8.1 (account/eth_account.cairo) + +/// # EthAccount Component +/// +/// The EthAccount component enables contracts to behave as accounts signing with Ethereum keys. +#[starknet::component] +mod EthAccountComponent { + use core::starknet::secp256_trait::Secp256PointTrait; + use openzeppelin::account::interface::EthPublicKey; + use openzeppelin::account::interface; + use openzeppelin::account::utils::secp256k1::{Secp256k1PointSerde, Secp256k1PointStorePacking}; + use openzeppelin::account::utils::{MIN_TRANSACTION_VERSION, QUERY_VERSION, QUERY_OFFSET}; + use openzeppelin::account::utils::{execute_calls, is_valid_eth_signature}; + use openzeppelin::introspection::src5::SRC5Component::InternalTrait as SRC5InternalTrait; + use openzeppelin::introspection::src5::SRC5Component; + use poseidon::poseidon_hash_span; + use starknet::account::Call; + use starknet::get_caller_address; + use starknet::get_contract_address; + use starknet::get_tx_info; + + #[storage] + struct Storage { + EthAccount_public_key: EthPublicKey + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + OwnerAdded: OwnerAdded, + OwnerRemoved: OwnerRemoved + } + + #[derive(Drop, starknet::Event)] + struct OwnerAdded { + #[key] + new_owner_guid: felt252 + } + + #[derive(Drop, starknet::Event)] + struct OwnerRemoved { + #[key] + removed_owner_guid: felt252 + } + + mod Errors { + const INVALID_CALLER: felt252 = 'EthAccount: invalid caller'; + const INVALID_SIGNATURE: felt252 = 'EthAccount: invalid signature'; + const INVALID_TX_VERSION: felt252 = 'EthAccount: invalid tx version'; + const UNAUTHORIZED: felt252 = 'EthAccount: unauthorized'; + } + + #[embeddable_as(SRC6Impl)] + impl SRC6< + TContractState, + +HasComponent, + +SRC5Component::HasComponent, + +Drop + > of interface::ISRC6> { + /// Executes a list of calls from the account. + /// + /// Requirements: + /// + /// - The transaction version must be greater than or equal to `MIN_TRANSACTION_VERSION`. + /// - If the transaction is a simulation (version than `QUERY_OFFSET`), it must be + /// greater than or equal to `QUERY_OFFSET` + `MIN_TRANSACTION_VERSION`. + fn __execute__( + self: @ComponentState, mut calls: Array + ) -> Array> { + // Avoid calls from other contracts + // https://github.com/OpenZeppelin/cairo-contracts/issues/344 + let sender = get_caller_address(); + assert(sender.is_zero(), Errors::INVALID_CALLER); + + // Check tx version + let tx_info = get_tx_info().unbox(); + let tx_version: u256 = tx_info.version.into(); + // Check if tx is a query + if (tx_version >= QUERY_OFFSET) { + assert( + QUERY_OFFSET + MIN_TRANSACTION_VERSION <= tx_version, Errors::INVALID_TX_VERSION + ); + } else { + assert(MIN_TRANSACTION_VERSION <= tx_version, Errors::INVALID_TX_VERSION); + } + + execute_calls(calls) + } + + /// Verifies the validity of the signature for the current transaction. + /// This function is used by the protocol to verify `invoke` transactions. + fn __validate__(self: @ComponentState, mut calls: Array) -> felt252 { + self.validate_transaction() + } + + /// Verifies that the given signature is valid for the given hash. + fn is_valid_signature( + self: @ComponentState, hash: felt252, signature: Array + ) -> felt252 { + if self._is_valid_signature(hash, signature.span()) { + starknet::VALIDATED + } else { + 0 + } + } + } + + #[embeddable_as(DeclarerImpl)] + impl Declarer< + TContractState, + +HasComponent, + +SRC5Component::HasComponent, + +Drop + > of interface::IDeclarer> { + /// Verifies the validity of the signature for the current transaction. + /// This function is used by the protocol to verify `declare` transactions. + fn __validate_declare__( + self: @ComponentState, class_hash: felt252 + ) -> felt252 { + self.validate_transaction() + } + } + + #[embeddable_as(DeployableImpl)] + impl Deployable< + TContractState, + +HasComponent, + +SRC5Component::HasComponent, + +Drop + > of interface::IEthDeployable> { + /// Verifies the validity of the signature for the current transaction. + /// This function is used by the protocol to verify `deploy_account` transactions. + fn __validate_deploy__( + self: @ComponentState, + class_hash: felt252, + contract_address_salt: felt252, + public_key: EthPublicKey + ) -> felt252 { + self.validate_transaction() + } + } + + #[embeddable_as(PublicKeyImpl)] + impl PublicKey< + TContractState, + +HasComponent, + +SRC5Component::HasComponent, + +Drop + > of interface::IEthPublicKey> { + /// Returns the current public key of the account. + fn get_public_key(self: @ComponentState) -> EthPublicKey { + self.EthAccount_public_key.read() + } + + /// Sets the public key of the account to `new_public_key`. + /// + /// Requirements: + /// + /// - The caller must be the contract itself. + /// + /// Emits an `OwnerRemoved` event. + fn set_public_key(ref self: ComponentState, new_public_key: EthPublicKey) { + self.assert_only_self(); + + let current_public_key: EthPublicKey = self.EthAccount_public_key.read(); + let removed_owner_guid = _get_guid_from_public_key(current_public_key); + + self.emit(OwnerRemoved { removed_owner_guid }); + self._set_public_key(new_public_key); + } + } + + /// Adds camelCase support for `ISRC6`. + #[embeddable_as(SRC6CamelOnlyImpl)] + impl SRC6CamelOnly< + TContractState, + +HasComponent, + +SRC5Component::HasComponent, + +Drop + > of interface::ISRC6CamelOnly> { + fn isValidSignature( + self: @ComponentState, hash: felt252, signature: Array + ) -> felt252 { + self.is_valid_signature(hash, signature) + } + } + + /// Adds camelCase support for `PublicKeyTrait`. + #[embeddable_as(PublicKeyCamelImpl)] + impl PublicKeyCamel< + TContractState, + +HasComponent, + +SRC5Component::HasComponent, + +Drop + > of interface::IEthPublicKeyCamel> { + fn getPublicKey(self: @ComponentState) -> EthPublicKey { + self.EthAccount_public_key.read() + } + + fn setPublicKey(ref self: ComponentState, newPublicKey: EthPublicKey) { + self.set_public_key(newPublicKey); + } + } + + #[generate_trait] + impl InternalImpl< + TContractState, + +HasComponent, + impl SRC5: SRC5Component::HasComponent, + +Drop + > of InternalTrait { + /// Initializes the account by setting the initial public key + /// and registering the ISRC6 interface Id. + fn initializer(ref self: ComponentState, public_key: EthPublicKey) { + let mut src5_component = get_dep_component_mut!(ref self, SRC5); + src5_component.register_interface(interface::ISRC6_ID); + self._set_public_key(public_key); + } + + /// Validates that the caller is the account itself. Otherwise it reverts. + fn assert_only_self(self: @ComponentState) { + let caller = get_caller_address(); + let self = get_contract_address(); + assert(self == caller, Errors::UNAUTHORIZED); + } + + /// Validates the signature for the current transaction. + /// Returns the short string `VALID` if valid, otherwise it reverts. + fn validate_transaction(self: @ComponentState) -> felt252 { + let tx_info = get_tx_info().unbox(); + let tx_hash = tx_info.transaction_hash; + let signature = tx_info.signature; + assert(self._is_valid_signature(tx_hash, signature), Errors::INVALID_SIGNATURE); + starknet::VALIDATED + } + + /// Sets the public key without validating the caller. + /// The usage of this method outside the `set_public_key` function is discouraged. + /// + /// Emits an `OwnerAdded` event. + fn _set_public_key(ref self: ComponentState, new_public_key: EthPublicKey) { + self.EthAccount_public_key.write(new_public_key); + let new_owner_guid = _get_guid_from_public_key(new_public_key); + self.emit(OwnerAdded { new_owner_guid }); + } + + /// Returns whether the given signature is valid for the given hash + /// using the account's current public key. + fn _is_valid_signature( + self: @ComponentState, hash: felt252, signature: Span + ) -> bool { + let public_key: EthPublicKey = self.EthAccount_public_key.read(); + is_valid_eth_signature(hash, public_key, signature) + } + } + + fn _get_guid_from_public_key(public_key: EthPublicKey) -> felt252 { + let (x, y) = public_key.get_coordinates().unwrap(); + poseidon_hash_span(array![x.low.into(), x.high.into(), y.low.into(), y.high.into()].span()) + } +} diff --git a/src/account/interface.cairo b/src/account/interface.cairo index 9b7063cd1..a04af7b40 100644 --- a/src/account/interface.cairo +++ b/src/account/interface.cairo @@ -1,11 +1,18 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts for Cairo v0.8.1 (account/interface.cairo) +use openzeppelin::account::utils::secp256k1::Secp256k1PointSerde; use starknet::ContractAddress; use starknet::account::Call; +type EthPublicKey = starknet::secp256k1::Secp256k1Point; + const ISRC6_ID: felt252 = 0x2ceccef7f994940b3962a6c67e0ba4fcd37df7d131417c604f91e03caecc1cd; +// +// Account +// + #[starknet::interface] trait ISRC6 { fn __execute__(self: @TState, calls: Array) -> Array>; @@ -78,3 +85,64 @@ trait AccountABI { fn getPublicKey(self: @TState) -> felt252; fn setPublicKey(ref self: TState, newPublicKey: felt252); } + +// +// EthAccount +// + +#[starknet::interface] +trait IEthDeployable { + fn __validate_deploy__( + self: @TState, class_hash: felt252, contract_address_salt: felt252, public_key: EthPublicKey + ) -> felt252; +} + +#[starknet::interface] +trait IEthPublicKey { + fn get_public_key(self: @TState) -> EthPublicKey; + fn set_public_key(ref self: TState, new_public_key: EthPublicKey); +} + + +#[starknet::interface] +trait IEthPublicKeyCamel { + fn getPublicKey(self: @TState) -> EthPublicKey; + fn setPublicKey(ref self: TState, newPublicKey: EthPublicKey); +} + +// +// EthAccount ABI +// + +#[starknet::interface] +trait EthAccountABI { + // ISRC6 + fn __execute__(self: @TState, calls: Array) -> Array>; + fn __validate__(self: @TState, calls: Array) -> felt252; + fn is_valid_signature(self: @TState, hash: felt252, signature: Array) -> felt252; + + // ISRC5 + fn supports_interface(self: @TState, interface_id: felt252) -> bool; + + // IDeclarer + fn __validate_declare__(self: @TState, class_hash: felt252) -> felt252; + + // IEthDeployable + fn __validate_deploy__( + self: @TState, class_hash: felt252, contract_address_salt: felt252, public_key: EthPublicKey + ) -> felt252; + + // IEthPublicKey + fn get_public_key(self: @TState) -> EthPublicKey; + fn set_public_key(ref self: TState, new_public_key: EthPublicKey); + + // ISRC6CamelOnly + fn isValidSignature(self: @TState, hash: felt252, signature: Array) -> felt252; + + // ISRC5Camel + fn supportsInterface(self: @TState, interfaceId: felt252) -> bool; + + // IEthPublicKeyCamel + fn getPublicKey(self: @TState) -> EthPublicKey; + fn setPublicKey(ref self: TState, newPublicKey: EthPublicKey); +} diff --git a/src/account/utils.cairo b/src/account/utils.cairo new file mode 100644 index 000000000..ee361528c --- /dev/null +++ b/src/account/utils.cairo @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.8.1 (account/utils.cairo) + +mod secp256k1; +mod signature; + +use signature::{is_valid_stark_signature, is_valid_eth_signature}; +use starknet::account::Call; + +const MIN_TRANSACTION_VERSION: u256 = 1; +const QUERY_OFFSET: u256 = 0x100000000000000000000000000000000; +// QUERY_OFFSET + TRANSACTION_VERSION +const QUERY_VERSION: u256 = 0x100000000000000000000000000000001; + +fn execute_calls(mut calls: Array) -> Array> { + let mut res = ArrayTrait::new(); + loop { + match calls.pop_front() { + Option::Some(call) => { + let _res = execute_single_call(call); + res.append(_res); + }, + Option::None(_) => { break (); }, + }; + }; + res +} + +fn execute_single_call(call: Call) -> Span { + let Call{to, selector, calldata } = call; + starknet::call_contract_syscall(to, selector, calldata.span()).unwrap() +} diff --git a/src/account/utils/secp256k1.cairo b/src/account/utils/secp256k1.cairo new file mode 100644 index 000000000..dc7ea4805 --- /dev/null +++ b/src/account/utils/secp256k1.cairo @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.8.1 (account/utils/secp256k1.cairo) + +use core::fmt::{Debug, Formatter, Error}; +use starknet::SyscallResultTrait; +use starknet::secp256_trait::Secp256PointTrait; +use starknet::secp256k1::{ + Secp256k1Point, secp256k1_get_point_from_x_syscall, secp256k1_new_syscall +}; + +/// Packs a Secp256k1Point into a (felt252, felt252). +/// +/// The packing is done as follows: +/// - First felt contains x.low (x being the x-coordinate of the point). +/// - Second felt contains x.high and the parity bit, at the least significant bits (2 * x.high + parity). +impl Secp256k1PointStorePacking of starknet::StorePacking { + fn pack(value: Secp256k1Point) -> (felt252, felt252) { + let (x, y) = value.get_coordinates().unwrap(); + + let parity = y % 2; + let xhigh_and_parity = 2 * x.high.into() + parity.try_into().unwrap(); + + (x.low.into(), xhigh_and_parity) + } + + fn unpack(value: (felt252, felt252)) -> Secp256k1Point { + let (xlow, xhigh_and_parity) = value; + let xhigh_and_parity: u256 = xhigh_and_parity.into(); + + let x = u256 { + low: xlow.try_into().unwrap(), high: (xhigh_and_parity / 2).try_into().unwrap(), + }; + let parity = xhigh_and_parity % 2 == 1; + + // Expects parity odd to be true + secp256k1_get_point_from_x_syscall(x, parity) + .unwrap_syscall() + .expect('Secp256k1Point: Invalid point.') + } +} + +impl Secp256k1PointSerde of Serde { + fn serialize(self: @Secp256k1Point, ref output: Array) { + let point = (*self).get_coordinates().unwrap(); + point.serialize(ref output) + } + fn deserialize(ref serialized: Span) -> Option { + let (x, y) = Serde::<(u256, u256)>::deserialize(ref serialized)?; + secp256k1_new_syscall(x, y).unwrap_syscall() + } +} + +impl Secp256k1PointPartialEq of PartialEq { + #[inline(always)] + fn eq(lhs: @Secp256k1Point, rhs: @Secp256k1Point) -> bool { + (*lhs).get_coordinates().unwrap() == (*rhs).get_coordinates().unwrap() + } + #[inline(always)] + fn ne(lhs: @Secp256k1Point, rhs: @Secp256k1Point) -> bool { + !(lhs == rhs) + } +} + +impl DebugSecp256k1Point of core::fmt::Debug { + fn fmt(self: @Secp256k1Point, ref f: Formatter) -> Result<(), Error> { + let (x, y) = (*self).get_coordinates().unwrap(); + write!(f, "({x:?},{y:?})") + } +} diff --git a/src/account/utils/signature.cairo b/src/account/utils/signature.cairo new file mode 100644 index 000000000..1164d0e56 --- /dev/null +++ b/src/account/utils/signature.cairo @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.8.1 (account/utils/signature.cairo) + +use ecdsa::check_ecdsa_signature; +use openzeppelin::account::interface::EthPublicKey; +use openzeppelin::account::utils::secp256k1::Secp256k1PointPartialEq; +use starknet::eth_signature::Signature; +use starknet::secp256_trait::{is_signature_entry_valid, recover_public_key}; +use starknet::secp256k1::Secp256k1Point; + +fn is_valid_stark_signature( + msg_hash: felt252, public_key: felt252, signature: Span +) -> bool { + let valid_length = signature.len() == 2; + + if valid_length { + check_ecdsa_signature(msg_hash, public_key, *signature.at(0_u32), *signature.at(1_u32)) + } else { + false + } +} + +fn is_valid_eth_signature( + msg_hash: felt252, public_key: EthPublicKey, signature: Span +) -> bool { + let mut signature = signature; + let signature: Signature = Serde::deserialize(ref signature) + .expect('Signature: Invalid format.'); + + // Signature out of range + if !is_signature_entry_valid::(signature.r) { + return false; + } + if !is_signature_entry_valid::(signature.s) { + return false; + } + + let public_key_point: Secp256k1Point = recover_public_key(msg_hash.into(), signature).unwrap(); + if public_key_point != public_key { + // Invalid signature + return false; + } + true +} diff --git a/src/presets.cairo b/src/presets.cairo index 6d3ddc6f6..1a0804706 100644 --- a/src/presets.cairo +++ b/src/presets.cairo @@ -1,7 +1,9 @@ mod account; mod erc20; mod erc721; +mod eth_account; use account::Account; use erc20::ERC20; use erc721::ERC721; +use eth_account::EthAccountUpgradeable; diff --git a/src/presets/eth_account.cairo b/src/presets/eth_account.cairo new file mode 100644 index 000000000..71bc87c4d --- /dev/null +++ b/src/presets/eth_account.cairo @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts for Cairo v0.8.1 (presets/eth_account.cairo) + +/// # EthAccount Preset +/// +/// OpenZeppelin's account which can change its public key and declare, +/// deploy, or call contracts, using Ethereum signing keys. +#[starknet::contract] +mod EthAccountUpgradeable { + use openzeppelin::account::EthAccountComponent; + use openzeppelin::account::interface::EthPublicKey; + use openzeppelin::account::utils::secp256k1::Secp256k1PointSerde; + use openzeppelin::introspection::src5::SRC5Component; + use openzeppelin::upgrades::UpgradeableComponent; + use openzeppelin::upgrades::interface::IUpgradeable; + use starknet::ClassHash; + + component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent); + component!(path: SRC5Component, storage: src5, event: SRC5Event); + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent); + + // EthAccount + #[abi(embed_v0)] + impl SRC6Impl = EthAccountComponent::SRC6Impl; + #[abi(embed_v0)] + impl SRC6CamelOnlyImpl = EthAccountComponent::SRC6CamelOnlyImpl; + #[abi(embed_v0)] + impl PublicKeyImpl = EthAccountComponent::PublicKeyImpl; + #[abi(embed_v0)] + impl PublicKeyCamelImpl = + EthAccountComponent::PublicKeyCamelImpl; + #[abi(embed_v0)] + impl DeclarerImpl = EthAccountComponent::DeclarerImpl; + #[abi(embed_v0)] + impl DeployableImpl = EthAccountComponent::DeployableImpl; + impl EthAccountInternalImpl = EthAccountComponent::InternalImpl; + + // SRC5 + #[abi(embed_v0)] + impl SRC5Impl = SRC5Component::SRC5Impl; + + // Upgradeable + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl; + + #[storage] + struct Storage { + #[substorage(v0)] + eth_account: EthAccountComponent::Storage, + #[substorage(v0)] + src5: SRC5Component::Storage, + #[substorage(v0)] + upgradeable: UpgradeableComponent::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + EthAccountEvent: EthAccountComponent::Event, + #[flat] + SRC5Event: SRC5Component::Event, + #[flat] + UpgradeableEvent: UpgradeableComponent::Event + } + + #[constructor] + fn constructor(ref self: ContractState, public_key: EthPublicKey) { + self.eth_account.initializer(public_key); + } + + #[external(v0)] + impl UpgradeableImpl of IUpgradeable { + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) { + self.eth_account.assert_only_self(); + self.upgradeable._upgrade(new_class_hash); + } + } +} diff --git a/src/tests/account.cairo b/src/tests/account.cairo index 1708ec912..56f9059dd 100644 --- a/src/tests/account.cairo +++ b/src/tests/account.cairo @@ -1,2 +1,6 @@ mod test_account; mod test_dual_account; +mod test_dual_eth_account; +mod test_eth_account; +mod test_secp256k1; +mod test_signature; diff --git a/src/tests/account/test_account.cairo b/src/tests/account/test_account.cairo index 309c777a8..7f87eaa6a 100644 --- a/src/tests/account/test_account.cairo +++ b/src/tests/account/test_account.cairo @@ -2,8 +2,8 @@ use openzeppelin::account::AccountComponent::{InternalTrait, SRC6CamelOnlyImpl}; use openzeppelin::account::AccountComponent::{OwnerAdded, OwnerRemoved}; use openzeppelin::account::AccountComponent::{PublicKeyCamelImpl, PublicKeyImpl}; use openzeppelin::account::AccountComponent; +use openzeppelin::account::interface::{AccountABIDispatcherTrait, AccountABIDispatcher}; use openzeppelin::account::interface::{ISRC6, ISRC6_ID}; -use openzeppelin::account::{AccountABIDispatcherTrait, AccountABIDispatcher}; use openzeppelin::introspection::interface::{ISRC5, ISRC5_ID}; use openzeppelin::tests::mocks::account_mocks::DualCaseAccountMock; use openzeppelin::tests::mocks::erc20_mocks::DualCaseERC20Mock; @@ -28,6 +28,16 @@ struct SignedTransactionData { s: felt252 } +fn SIGNED_TX_DATA() -> SignedTransactionData { + SignedTransactionData { + private_key: 1234, + public_key: 0x1f3c942d7f492a37608cde0d77b884a5aa9e11d2919225968557370ddb5a5aa, + transaction_hash: 0x601d3d2e265c10ff645e1554c435e72ce6721f0ba5fc96f0c650bfc6231191a, + r: 0x6c8be1fb0fb5c730fbd7abaecbed9d980376ff2e660dfcd157e158d2b026891, + s: 0x76b4669998eb933f44a59eace12b41328ab975ceafddf92602b21eb23e22e35 + } +} + // // Constants // @@ -40,16 +50,6 @@ fn ACCOUNT_ADDRESS() -> ContractAddress { contract_address_const::<0x111111>() } -fn SIGNED_TX_DATA() -> SignedTransactionData { - SignedTransactionData { - private_key: 1234, - public_key: 0x1f3c942d7f492a37608cde0d77b884a5aa9e11d2919225968557370ddb5a5aa, - transaction_hash: 0x601d3d2e265c10ff645e1554c435e72ce6721f0ba5fc96f0c650bfc6231191a, - r: 0x6c8be1fb0fb5c730fbd7abaecbed9d980376ff2e660dfcd157e158d2b026891, - s: 0x76b4669998eb933f44a59eace12b41328ab975ceafddf92602b21eb23e22e35 - } -} - // // Setup // @@ -541,11 +541,19 @@ fn test__set_public_key() { fn assert_event_owner_removed(contract: ContractAddress, removed_owner_guid: felt252) { let event = utils::pop_log::(contract).unwrap(); assert_eq!(event.removed_owner_guid, removed_owner_guid); + + // Check indexed keys + let indexed_keys = array![removed_owner_guid]; + utils::assert_indexed_keys(event, indexed_keys.span()); } fn assert_event_owner_added(contract: ContractAddress, new_owner_guid: felt252) { let event = utils::pop_log::(contract).unwrap(); assert_eq!(event.new_owner_guid, new_owner_guid); + + // Check indexed keys + let indexed_keys = array![new_owner_guid]; + utils::assert_indexed_keys(event, indexed_keys.span()); } fn assert_only_event_owner_added(contract: ContractAddress, new_owner_guid: felt252) { diff --git a/src/tests/account/test_dual_account.cairo b/src/tests/account/test_dual_account.cairo index 08e711c24..f7faca55c 100644 --- a/src/tests/account/test_dual_account.cairo +++ b/src/tests/account/test_dual_account.cairo @@ -1,5 +1,5 @@ use openzeppelin::account::dual_account::{DualCaseAccountABI, DualCaseAccount}; -use openzeppelin::account::{AccountABIDispatcherTrait, AccountABIDispatcher}; +use openzeppelin::account::interface::{AccountABIDispatcherTrait, AccountABIDispatcher}; use openzeppelin::introspection::interface::ISRC5_ID; use openzeppelin::tests::account::test_account::SIGNED_TX_DATA; use openzeppelin::tests::mocks::account_mocks::{ diff --git a/src/tests/account/test_dual_eth_account.cairo b/src/tests/account/test_dual_eth_account.cairo new file mode 100644 index 000000000..cabb8d32f --- /dev/null +++ b/src/tests/account/test_dual_eth_account.cairo @@ -0,0 +1,236 @@ +use openzeppelin::account::dual_eth_account::{DualCaseEthAccountABI, DualCaseEthAccount}; +use openzeppelin::account::interface::{EthAccountABIDispatcherTrait, EthAccountABIDispatcher}; +use openzeppelin::account::utils::secp256k1::{ + DebugSecp256k1Point, Secp256k1PointPartialEq, Secp256k1PointSerde +}; +use openzeppelin::introspection::interface::ISRC5_ID; +use openzeppelin::tests::account::test_eth_account::SIGNED_TX_DATA; +use openzeppelin::tests::mocks::eth_account_mocks::{ + CamelEthAccountPanicMock, CamelEthAccountMock, SnakeEthAccountMock, SnakeEthAccountPanicMock +}; +use openzeppelin::tests::mocks::non_implementing_mock::NonImplementingMock; +use openzeppelin::tests::utils::constants::{ETH_PUBKEY, NEW_ETH_PUBKEY}; +use openzeppelin::tests::utils; +use openzeppelin::utils::serde::SerializedAppend; +use starknet::eth_signature::Signature; +use starknet::testing; + +// +// Setup +// + +fn setup_snake() -> (DualCaseEthAccount, EthAccountABIDispatcher) { + let mut calldata = array![]; + calldata.append_serde(ETH_PUBKEY()); + + let target = utils::deploy(SnakeEthAccountMock::TEST_CLASS_HASH, calldata); + ( + DualCaseEthAccount { contract_address: target }, + EthAccountABIDispatcher { contract_address: target } + ) +} + +fn setup_camel() -> (DualCaseEthAccount, EthAccountABIDispatcher) { + let mut calldata = array![]; + calldata.append_serde(ETH_PUBKEY()); + + let target = utils::deploy(CamelEthAccountMock::TEST_CLASS_HASH, calldata); + ( + DualCaseEthAccount { contract_address: target }, + EthAccountABIDispatcher { contract_address: target } + ) +} + +fn setup_non_account() -> DualCaseEthAccount { + let calldata = array![]; + let target = utils::deploy(NonImplementingMock::TEST_CLASS_HASH, calldata); + DualCaseEthAccount { contract_address: target } +} + +fn setup_account_panic() -> (DualCaseEthAccount, DualCaseEthAccount) { + let snake_target = utils::deploy(SnakeEthAccountPanicMock::TEST_CLASS_HASH, array![]); + let camel_target = utils::deploy(CamelEthAccountPanicMock::TEST_CLASS_HASH, array![]); + ( + DualCaseEthAccount { contract_address: snake_target }, + DualCaseEthAccount { contract_address: camel_target } + ) +} + +// +// snake_case target +// + +#[test] +fn test_dual_set_public_key() { + let (snake_dispatcher, target) = setup_snake(); + + testing::set_contract_address(snake_dispatcher.contract_address); + + let new_public_key = NEW_ETH_PUBKEY(); + snake_dispatcher.set_public_key(new_public_key); + assert_eq!(target.get_public_key(), new_public_key); +} + +#[test] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] +fn test_dual_no_set_public_key() { + let dispatcher = setup_non_account(); + dispatcher.set_public_key(NEW_ETH_PUBKEY()); +} + +#[test] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] +fn test_dual_set_public_key_exists_and_panics() { + let (dispatcher, _) = setup_account_panic(); + dispatcher.set_public_key(NEW_ETH_PUBKEY()); +} + +#[test] +fn test_dual_get_public_key() { + let (snake_dispatcher, _) = setup_snake(); + assert_eq!(snake_dispatcher.get_public_key(), ETH_PUBKEY()); +} + +#[test] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] +fn test_dual_no_get_public_key() { + let dispatcher = setup_non_account(); + dispatcher.get_public_key(); +} + +#[test] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] +fn test_dual_get_public_key_exists_and_panics() { + let (dispatcher, _) = setup_account_panic(); + dispatcher.get_public_key(); +} + +#[test] +fn test_dual_is_valid_signature() { + let (snake_dispatcher, target) = setup_snake(); + + let data = SIGNED_TX_DATA(); + let hash = data.transaction_hash; + let mut serialized_signature = array![]; + data.signature.serialize(ref serialized_signature); + + testing::set_contract_address(snake_dispatcher.contract_address); + target.set_public_key(data.public_key); + + let is_valid = snake_dispatcher.is_valid_signature(hash, serialized_signature); + assert_eq!(is_valid, starknet::VALIDATED); +} + +#[test] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] +fn test_dual_no_is_valid_signature() { + let hash = 0x0; + let signature = array![]; + + let dispatcher = setup_non_account(); + dispatcher.is_valid_signature(hash, signature); +} + +#[test] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] +fn test_dual_is_valid_signature_exists_and_panics() { + let hash = 0x0; + let signature = array![]; + + let (dispatcher, _) = setup_account_panic(); + dispatcher.is_valid_signature(hash, signature); +} + +#[test] +fn test_dual_supports_interface() { + let (snake_dispatcher, target) = setup_snake(); + assert!(snake_dispatcher.supports_interface(ISRC5_ID), "Should implement ISRC5"); +} + +#[test] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] +fn test_dual_no_supports_interface() { + let dispatcher = setup_non_account(); + dispatcher.supports_interface(ISRC5_ID); +} + +#[test] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] +fn test_dual_supports_interface_exists_and_panics() { + let (dispatcher, _) = setup_account_panic(); + dispatcher.supports_interface(ISRC5_ID); +} + +// +// camelCase target +// + +#[test] +fn test_dual_setPublicKey() { + let (camel_dispatcher, target) = setup_camel(); + let new_public_key = NEW_ETH_PUBKEY(); + + testing::set_contract_address(camel_dispatcher.contract_address); + + camel_dispatcher.set_public_key(new_public_key); + assert_eq!(target.getPublicKey(), new_public_key); +} + +#[test] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] +fn test_dual_setPublicKey_exists_and_panics() { + let (_, dispatcher) = setup_account_panic(); + dispatcher.set_public_key(NEW_ETH_PUBKEY()); +} + +#[test] +fn test_dual_getPublicKey() { + let (camel_dispatcher, _) = setup_camel(); + assert_eq!(camel_dispatcher.get_public_key(), ETH_PUBKEY()); +} + +#[test] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] +fn test_dual_getPublicKey_exists_and_panics() { + let (_, dispatcher) = setup_account_panic(); + dispatcher.get_public_key(); +} + +#[test] +fn test_dual_isValidSignature() { + let (camel_dispatcher, target) = setup_camel(); + + let data = SIGNED_TX_DATA(); + let hash = data.transaction_hash; + let mut serialized_signature = array![]; + data.signature.serialize(ref serialized_signature); + + testing::set_contract_address(camel_dispatcher.contract_address); + target.setPublicKey(data.public_key); + + let is_valid = camel_dispatcher.is_valid_signature(hash, serialized_signature); + assert_eq!(is_valid, starknet::VALIDATED); +} + +#[test] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] +fn test_dual_isValidSignature_exists_and_panics() { + let hash = 0x0; + let signature = array![]; + + let (_, dispatcher) = setup_account_panic(); + dispatcher.is_valid_signature(hash, signature); +} + +#[test] +fn test_dual_supportsInterface() { + let (camel_dispatcher, _) = setup_camel(); + assert!(camel_dispatcher.supports_interface(ISRC5_ID), "Should implement ISRC5"); +} + +#[test] +#[should_panic(expected: ("Some error", 'ENTRYPOINT_FAILED',))] +fn test_dual_supportsInterface_exists_and_panics() { + let (_, dispatcher) = setup_account_panic(); + dispatcher.supports_interface(ISRC5_ID); +} diff --git a/src/tests/account/test_eth_account.cairo b/src/tests/account/test_eth_account.cairo new file mode 100644 index 000000000..308ddaac3 --- /dev/null +++ b/src/tests/account/test_eth_account.cairo @@ -0,0 +1,614 @@ +use core::starknet::secp256_trait::Secp256PointTrait; +use openzeppelin::account::EthAccountComponent::{InternalTrait, SRC6CamelOnlyImpl}; +use openzeppelin::account::EthAccountComponent::{OwnerAdded, OwnerRemoved}; +use openzeppelin::account::EthAccountComponent::{PublicKeyCamelImpl, PublicKeyImpl}; +use openzeppelin::account::EthAccountComponent; +use openzeppelin::account::interface::EthPublicKey; +use openzeppelin::account::interface::{EthAccountABIDispatcherTrait, EthAccountABIDispatcher}; +use openzeppelin::account::interface::{ISRC6, ISRC6_ID}; +use openzeppelin::account::utils::secp256k1::{ + DebugSecp256k1Point, Secp256k1PointPartialEq, Secp256k1PointSerde +}; +use openzeppelin::introspection::interface::{ISRC5, ISRC5_ID}; +use openzeppelin::tests::mocks::erc20_mocks::DualCaseERC20Mock; +use openzeppelin::tests::mocks::eth_account_mocks::DualCaseEthAccountMock; +use openzeppelin::tests::utils::constants::{ + ETH_PUBKEY, NEW_ETH_PUBKEY, SALT, ZERO, OTHER, RECIPIENT, CALLER, QUERY_VERSION, + MIN_TRANSACTION_VERSION +}; +use openzeppelin::tests::utils; +use openzeppelin::token::erc20::interface::{IERC20DispatcherTrait, IERC20Dispatcher}; +use openzeppelin::utils::selectors; +use openzeppelin::utils::serde::SerializedAppend; +use poseidon::poseidon_hash_span; +use starknet::ContractAddress; +use starknet::account::Call; +use starknet::eth_signature::Signature; +use starknet::secp256k1::secp256k1_new_syscall; +use starknet::testing; + +#[derive(Drop)] +struct SignedTransactionData { + private_key: u256, + public_key: EthPublicKey, + transaction_hash: felt252, + signature: Signature +} + +/// This signature was computed using ethers.js. +fn SIGNED_TX_DATA() -> SignedTransactionData { + SignedTransactionData { + private_key: 0x45397ee6ca34cb49060f1c303c6cb7ee2d6123e617601ef3e31ccf7bf5bef1f9, + public_key: secp256k1_new_syscall( + 0x829307f82a1883c2414503ba85fc85037f22c6fc6f80910801f6b01a4131da1e, + 0x2a23f7bddf3715d11767b1247eccc68c89e11b926e2615268db6ad1af8d8da96 + ) + .unwrap() + .unwrap(), + transaction_hash: 0x008f882c63d0396d216d57529fe29ad5e70b6cd51b47bd2458b0a4ccb2ba0957, + signature: Signature { + r: 0x82bb3efc0554ec181405468f273b0dbf935cca47182b22da78967d0770f7dcc3, + s: 0x6719fef30c11c74add873e4da0e1234deb69eae6a6bd4daa44b816dc199f3e86, + y_parity: true + } + } +} + +// +// Constants +// + +fn CLASS_HASH() -> felt252 { + DualCaseEthAccountMock::TEST_CLASS_HASH +} + +fn ACCOUNT_ADDRESS() -> ContractAddress { + Zeroable::zero() +} + +// +// Setup +// + +type ComponentState = EthAccountComponent::ComponentState; + +fn CONTRACT_STATE() -> DualCaseEthAccountMock::ContractState { + DualCaseEthAccountMock::contract_state_for_testing() +} + +fn COMPONENT_STATE() -> ComponentState { + EthAccountComponent::component_state_for_testing() +} + +fn setup() -> ComponentState { + let mut state = COMPONENT_STATE(); + state.initializer(ETH_PUBKEY()); + utils::drop_event(ZERO()); + state +} + +fn setup_dispatcher(data: Option<@SignedTransactionData>) -> EthAccountABIDispatcher { + testing::set_version(MIN_TRANSACTION_VERSION); + + let mut calldata = array![]; + if data.is_some() { + let data = data.unwrap(); + let mut serialized_signature = array![]; + data.signature.serialize(ref serialized_signature); + + testing::set_signature(serialized_signature.span()); + testing::set_transaction_hash(*data.transaction_hash); + + calldata.append_serde(*data.public_key); + } else { + calldata.append_serde(ETH_PUBKEY()); + } + let address = utils::deploy(CLASS_HASH(), calldata); + EthAccountABIDispatcher { contract_address: address } +} + +fn deploy_erc20(recipient: ContractAddress, initial_supply: u256) -> IERC20Dispatcher { + let name = 0; + let symbol = 0; + let mut calldata = array![]; + + calldata.append_serde(name); + calldata.append_serde(symbol); + calldata.append_serde(initial_supply); + calldata.append_serde(recipient); + + let address = utils::deploy(DualCaseERC20Mock::TEST_CLASS_HASH, calldata); + IERC20Dispatcher { contract_address: address } +} + +// +// is_valid_signature & isValidSignature +// + +#[test] +fn test_is_valid_signature() { + let mut state = COMPONENT_STATE(); + let data = SIGNED_TX_DATA(); + let hash = data.transaction_hash; + let mut bad_signature = data.signature; + + bad_signature.r += 1; + + let mut serialized_good_signature = array![]; + let mut serialized_bad_signature = array![]; + + data.signature.serialize(ref serialized_good_signature); + bad_signature.serialize(ref serialized_bad_signature); + + state.initializer(data.public_key); + + let is_valid = state.is_valid_signature(hash, serialized_good_signature); + assert_eq!(is_valid, starknet::VALIDATED); + + let is_valid = state.is_valid_signature(hash, serialized_bad_signature); + assert_eq!(is_valid, 0, "Should reject invalid signature"); +} + +#[test] +fn test_isValidSignature() { + let mut state = COMPONENT_STATE(); + let data = SIGNED_TX_DATA(); + let hash = data.transaction_hash; + + let mut bad_signature = data.signature; + + bad_signature.r += 1; + + let mut serialized_good_signature = array![]; + let mut serialized_bad_signature = array![]; + + data.signature.serialize(ref serialized_good_signature); + bad_signature.serialize(ref serialized_bad_signature); + + state.initializer(data.public_key); + + let is_valid = state.isValidSignature(hash, serialized_good_signature); + assert_eq!(is_valid, starknet::VALIDATED); + + let is_valid = state.isValidSignature(hash, serialized_bad_signature); + assert_eq!(is_valid, 0, "Should reject invalid signature"); +} + +// +// Entry points +// + +#[test] +fn test_validate_deploy() { + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + + // `__validate_deploy__` does not directly use the passed arguments. Their + // values are already integrated in the tx hash. The passed arguments in this + // testing context are decoupled from the signature and have no effect on the test. + let is_valid = account.__validate_deploy__(CLASS_HASH(), SALT, ETH_PUBKEY()); + assert_eq!(is_valid, starknet::VALIDATED); +} + +#[test] +#[should_panic(expected: ('EthAccount: invalid signature', 'ENTRYPOINT_FAILED'))] +fn test_validate_deploy_invalid_signature_data() { + let mut data = SIGNED_TX_DATA(); + data.transaction_hash += 1; + let account = setup_dispatcher(Option::Some(@data)); + + account.__validate_deploy__(CLASS_HASH(), SALT, ETH_PUBKEY()); +} + +#[test] +#[should_panic(expected: ('Signature: Invalid format.', 'ENTRYPOINT_FAILED'))] +fn test_validate_deploy_invalid_signature_length() { + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + let signature = array![0x1]; + + testing::set_signature(signature.span()); + + account.__validate_deploy__(CLASS_HASH(), SALT, ETH_PUBKEY()); +} + +#[test] +#[should_panic(expected: ('Signature: Invalid format.', 'ENTRYPOINT_FAILED'))] +fn test_validate_deploy_empty_signature() { + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + let empty_sig = array![]; + + testing::set_signature(empty_sig.span()); + account.__validate_deploy__(CLASS_HASH(), SALT, ETH_PUBKEY()); +} + +#[test] +fn test_validate_declare() { + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + + // `__validate_declare__` does not directly use the class_hash argument. Its + // value is already integrated in the tx hash. The class_hash argument in this + // testing context is decoupled from the signature and has no effect on the test. + let is_valid = account.__validate_declare__(CLASS_HASH()); + assert_eq!(is_valid, starknet::VALIDATED); +} + +#[test] +#[should_panic(expected: ('EthAccount: invalid signature', 'ENTRYPOINT_FAILED'))] +fn test_validate_declare_invalid_signature_data() { + let mut data = SIGNED_TX_DATA(); + data.transaction_hash += 1; + let account = setup_dispatcher(Option::Some(@data)); + + account.__validate_declare__(CLASS_HASH()); +} + +#[test] +#[should_panic(expected: ('Signature: Invalid format.', 'ENTRYPOINT_FAILED'))] +fn test_validate_declare_invalid_signature_length() { + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + let mut signature = array![]; + + signature.append(0x1); + testing::set_signature(signature.span()); + + account.__validate_declare__(CLASS_HASH()); +} + +#[test] +#[should_panic(expected: ('Signature: Invalid format.', 'ENTRYPOINT_FAILED'))] +fn test_validate_declare_empty_signature() { + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + let empty_sig = array![]; + + testing::set_signature(empty_sig.span()); + + account.__validate_declare__(CLASS_HASH()); +} + +fn test_execute_with_version(version: Option) { + let data = SIGNED_TX_DATA(); + let account = setup_dispatcher(Option::Some(@data)); + let erc20 = deploy_erc20(account.contract_address, 1000); + let recipient = RECIPIENT(); + + // Craft call and add to calls array + let mut calldata = array![]; + let amount: u256 = 200; + calldata.append_serde(recipient); + calldata.append_serde(amount); + let call = Call { + to: erc20.contract_address, selector: selectors::transfer, calldata: calldata + }; + let mut calls = array![]; + calls.append(call); + + // Handle version for test + if version.is_some() { + testing::set_version(version.unwrap()); + } + + // Execute + let ret = account.__execute__(calls); + + // Assert that the transfer was successful + assert_eq!(erc20.balance_of(account.contract_address), 800, "Should have remainder"); + assert_eq!(erc20.balance_of(recipient), amount, "Should have transferred"); + + // Test return value + let mut call_serialized_retval = *ret.at(0); + let call_retval = Serde::::deserialize(ref call_serialized_retval); + assert!(call_retval.unwrap()); +} + +#[test] +fn test_execute() { + test_execute_with_version(Option::None(())); +} + +#[test] +fn test_execute_query_version() { + test_execute_with_version(Option::Some(QUERY_VERSION)); +} + +#[test] +#[should_panic(expected: ('EthAccount: invalid tx version', 'ENTRYPOINT_FAILED'))] +fn test_execute_invalid_version() { + test_execute_with_version(Option::Some(MIN_TRANSACTION_VERSION - 1)); +} + +#[test] +fn test_validate() { + let calls = array![]; + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + + let is_valid = account.__validate__(calls); + assert_eq!(is_valid, starknet::VALIDATED); +} + +#[test] +#[should_panic(expected: ('EthAccount: invalid signature', 'ENTRYPOINT_FAILED'))] +fn test_validate_invalid() { + let calls = array![]; + let mut data = SIGNED_TX_DATA(); + data.transaction_hash += 1; + let account = setup_dispatcher(Option::Some(@data)); + + account.__validate__(calls); +} + +#[test] +fn test_multicall() { + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + let erc20 = deploy_erc20(account.contract_address, 1000); + let recipient1 = RECIPIENT(); + let recipient2 = OTHER(); + let mut calls = array![]; + + // Craft call1 + let mut calldata1 = array![]; + let amount1: u256 = 300; + calldata1.append_serde(recipient1); + calldata1.append_serde(amount1); + let call1 = Call { + to: erc20.contract_address, selector: selectors::transfer, calldata: calldata1 + }; + + // Craft call2 + let mut calldata2 = array![]; + let amount2: u256 = 500; + calldata2.append_serde(recipient2); + calldata2.append_serde(amount2); + let call2 = Call { + to: erc20.contract_address, selector: selectors::transfer, calldata: calldata2 + }; + + // Bundle calls and exeute + calls.append(call1); + calls.append(call2); + let ret = account.__execute__(calls); + + // Assert that the transfers were successful + assert_eq!(erc20.balance_of(account.contract_address), 200, "Should have remainder"); + assert_eq!(erc20.balance_of(recipient1), 300, "Should have transferred in call 1"); + assert_eq!(erc20.balance_of(recipient2), 500, "Should have transferred in call 2"); + + // Test return value + let mut call1_serialized_retval = *ret.at(0); + let mut call2_serialized_retval = *ret.at(1); + let call1_retval = Serde::::deserialize(ref call1_serialized_retval); + let call2_retval = Serde::::deserialize(ref call2_serialized_retval); + assert!(call1_retval.unwrap()); + assert!(call2_retval.unwrap()); +} + +#[test] +fn test_multicall_zero_calls() { + let account = setup_dispatcher(Option::Some(@SIGNED_TX_DATA())); + let mut calls = array![]; + + let ret = account.__execute__(calls); + + // Test return value + assert_eq!(ret.len(), 0, "Should have an empty response"); +} + +#[test] +#[should_panic(expected: ('EthAccount: invalid caller',))] +fn test_account_called_from_contract() { + let state = setup(); + let calls = array![]; + + testing::set_contract_address(ACCOUNT_ADDRESS()); + testing::set_caller_address(CALLER()); + + state.__execute__(calls); +} + +// +// set_public_key & get_public_key +// + +#[test] +#[should_panic(expected: ('Secp256k1Point: Invalid point.',))] +fn test_cannot_get_without_initialize() { + let mut state = COMPONENT_STATE(); + state.get_public_key(); +} + +#[test] +#[should_panic(expected: ('Secp256k1Point: Invalid point.',))] +fn test_cannot_set_without_initialize() { + let mut state = COMPONENT_STATE(); + let new_public_key = NEW_ETH_PUBKEY(); + + testing::set_contract_address(ACCOUNT_ADDRESS()); + testing::set_caller_address(ACCOUNT_ADDRESS()); + + state.set_public_key(new_public_key); +} + +#[test] +fn test_public_key_setter_and_getter() { + let mut state = COMPONENT_STATE(); + let public_key = ETH_PUBKEY(); + let new_public_key = NEW_ETH_PUBKEY(); + + testing::set_contract_address(ACCOUNT_ADDRESS()); + testing::set_caller_address(ACCOUNT_ADDRESS()); + + state.initializer(public_key); + utils::drop_event(ACCOUNT_ADDRESS()); + + // Check default + let current = state.get_public_key(); + assert_eq!(current, public_key); + + // Set key + state.set_public_key(new_public_key); + + assert_event_owner_removed(ACCOUNT_ADDRESS(), current); + assert_only_event_owner_added(ACCOUNT_ADDRESS(), new_public_key); + + let public_key = state.get_public_key(); + assert_eq!(public_key, new_public_key); +} + +#[test] +#[should_panic(expected: ('EthAccount: unauthorized',))] +fn test_public_key_setter_different_account() { + let mut state = COMPONENT_STATE(); + testing::set_contract_address(ACCOUNT_ADDRESS()); + testing::set_caller_address(CALLER()); + + state.set_public_key(NEW_ETH_PUBKEY()); +} + +// +// setPublicKey & getPublicKey +// + +#[test] +fn test_public_key_setter_and_getter_camel() { + let mut state = COMPONENT_STATE(); + let public_key = ETH_PUBKEY(); + let new_public_key = NEW_ETH_PUBKEY(); + + testing::set_contract_address(ACCOUNT_ADDRESS()); + testing::set_caller_address(ACCOUNT_ADDRESS()); + + state.initializer(public_key); + utils::drop_event(ACCOUNT_ADDRESS()); + + let current = state.getPublicKey(); + assert_eq!(current, public_key); + + state.setPublicKey(new_public_key); + + assert_event_owner_removed(ACCOUNT_ADDRESS(), public_key); + assert_only_event_owner_added(ACCOUNT_ADDRESS(), new_public_key); + + let public_key = state.getPublicKey(); + assert_eq!(public_key, new_public_key); +} + +#[test] +#[should_panic(expected: ('EthAccount: unauthorized',))] +fn test_public_key_setter_different_account_camel() { + let mut state = COMPONENT_STATE(); + testing::set_contract_address(ACCOUNT_ADDRESS()); + testing::set_caller_address(CALLER()); + + state.setPublicKey(NEW_ETH_PUBKEY()); +} + +// +// Test internals +// + +#[test] +fn test_initializer() { + let mut state = COMPONENT_STATE(); + let mock_state = CONTRACT_STATE(); + let public_key = ETH_PUBKEY(); + + state.initializer(public_key); + + assert_only_event_owner_added(ZERO(), public_key); + + assert_eq!(state.get_public_key(), public_key); + + let supports_default_interface = mock_state.supports_interface(ISRC5_ID); + assert!(supports_default_interface, "Should support ISRC5"); + + let supports_account_interface = mock_state.supports_interface(ISRC6_ID); + assert!(supports_account_interface, "Should support ISRC6"); +} + +#[test] +fn test_assert_only_self_true() { + let mut state = COMPONENT_STATE(); + + testing::set_contract_address(ACCOUNT_ADDRESS()); + testing::set_caller_address(ACCOUNT_ADDRESS()); + state.assert_only_self(); +} + +#[test] +#[should_panic(expected: ('EthAccount: unauthorized',))] +fn test_assert_only_self_false() { + let mut state = COMPONENT_STATE(); + + testing::set_contract_address(ACCOUNT_ADDRESS()); + testing::set_caller_address(OTHER()); + state.assert_only_self(); +} + +#[test] +fn test__is_valid_signature() { + let mut state = COMPONENT_STATE(); + let data = SIGNED_TX_DATA(); + let hash = data.transaction_hash; + + let mut bad_signature = data.signature; + + bad_signature.r += 1; + + let mut serialized_good_signature = array![]; + let mut serialized_bad_signature = array![]; + + data.signature.serialize(ref serialized_good_signature); + bad_signature.serialize(ref serialized_bad_signature); + + state.initializer(data.public_key); + + let is_valid = state._is_valid_signature(hash, serialized_good_signature.span()); + assert!(is_valid); + + let is_not_valid = !state._is_valid_signature(hash, serialized_bad_signature.span()); + assert!(is_not_valid); +} + +#[test] +fn test__set_public_key() { + let mut state = COMPONENT_STATE(); + let public_key = ETH_PUBKEY(); + state._set_public_key(public_key); + + assert_only_event_owner_added(ZERO(), public_key); + + let public_key = state.get_public_key(); + assert_eq!(public_key, ETH_PUBKEY()); +} + +// +// Helpers +// + +fn assert_event_owner_added(contract: ContractAddress, public_key: EthPublicKey) { + let event = utils::pop_log::(contract).unwrap(); + let guid = get_guid_from_public_key(public_key); + assert_eq!(event.new_owner_guid, guid); + + // Check indexed keys + let indexed_keys = array![guid]; + utils::assert_indexed_keys(event, indexed_keys.span()); +} + +fn assert_only_event_owner_added(contract: ContractAddress, public_key: EthPublicKey) { + assert_event_owner_added(contract, public_key); + utils::assert_no_events_left(contract); +} + +fn assert_event_owner_removed(contract: ContractAddress, public_key: EthPublicKey) { + let event = utils::pop_log::(contract).unwrap(); + let guid = get_guid_from_public_key(public_key); + assert_eq!(event.removed_owner_guid, guid); + + // Check indexed keys + let indexed_keys = array![guid]; + utils::assert_indexed_keys(event, indexed_keys.span()); +} + +fn get_guid_from_public_key(public_key: EthPublicKey) -> felt252 { + let (x, y) = public_key.get_coordinates().unwrap(); + poseidon_hash_span(array![x.low.into(), x.high.into(), y.low.into(), y.high.into()].span()) +} diff --git a/src/tests/account/test_secp256k1.cairo b/src/tests/account/test_secp256k1.cairo new file mode 100644 index 000000000..47ff2b208 --- /dev/null +++ b/src/tests/account/test_secp256k1.cairo @@ -0,0 +1,138 @@ +use openzeppelin::account::utils::secp256k1::{ + SyscallResultTrait, Secp256k1Point, DebugSecp256k1Point, Secp256k1PointSerde, + Secp256k1PointPartialEq, Secp256k1PointStorePacking as StorePacking +}; +use starknet::secp256_trait::Secp256PointTrait; +use starknet::secp256k1::Secp256k1Impl; + +#[test] +fn test_pack_big_secp256k1_points() { + let (big_point_1, big_point_2) = get_points(); + let curve_size = Secp256k1Impl::get_curve_size(); + + // Check point 1 + + let (xlow, xhigh_and_parity) = StorePacking::pack(big_point_1); + let xhigh_and_parity: u256 = xhigh_and_parity.into(); + + let x = u256 { + low: xlow.try_into().unwrap(), high: (xhigh_and_parity / 2).try_into().unwrap() + }; + let parity = xhigh_and_parity % 2 == 1; + + assert_eq!(x, curve_size); + assert_eq!(parity, true, "Parity should be odd"); + + // Check point 2 + + let (xlow, xhigh_and_parity) = StorePacking::pack(big_point_2); + let xhigh_and_parity: u256 = xhigh_and_parity.into(); + + let x = u256 { + low: xlow.try_into().unwrap(), high: (xhigh_and_parity / 2).try_into().unwrap() + }; + let parity = xhigh_and_parity % 2 == 1; + + assert_eq!(x, curve_size); + assert_eq!(parity, false, "Parity should be even"); +} + +#[test] +fn test_unpack_big_secp256k1_points() { + let (big_point_1, big_point_2) = get_points(); + let curve_size = Secp256k1Impl::get_curve_size(); + + // Check point 1 + + let (expected_x, expected_y) = big_point_1.get_coordinates().unwrap(); + + let (xlow, xhigh_and_parity) = StorePacking::pack(big_point_1); + let (x, y) = StorePacking::unpack((xlow, xhigh_and_parity)).get_coordinates().unwrap(); + + assert_eq!(x, expected_x); + assert_eq!(y, expected_y); + + // Check point 2 + + let (expected_x, expected_y) = big_point_2.get_coordinates().unwrap(); + + let (xlow, xhigh_and_parity) = StorePacking::pack(big_point_2); + let (x, y) = StorePacking::unpack((xlow, xhigh_and_parity)).get_coordinates().unwrap(); + + assert_eq!(x, expected_x); +} + +#[test] +fn test_secp256k1_serialization() { + let (big_point_1, big_point_2) = get_points(); + let curve_size = Secp256k1Impl::get_curve_size(); + + let mut serialized_point = array![]; + let mut expected_serialization = array![]; + + // Check point 1 + + big_point_1.serialize(ref serialized_point); + big_point_1.get_coordinates().unwrap().serialize(ref expected_serialization); + + assert!(serialized_point == expected_serialization); + + // Check point 2 + + big_point_2.serialize(ref serialized_point); + big_point_2.get_coordinates().unwrap().serialize(ref expected_serialization); + + assert!(serialized_point == expected_serialization); +} + +#[test] +fn test_secp256k1_deserialization() { + let (big_point_1, big_point_2) = get_points(); + let curve_size = Secp256k1Impl::get_curve_size(); + + // Check point 1 + + let mut expected_serialization = array![]; + + big_point_1.get_coordinates().unwrap().serialize(ref expected_serialization); + let mut expected_serialization = expected_serialization.span(); + let deserialized_point = Secp256k1PointSerde::deserialize(ref expected_serialization).unwrap(); + + assert_eq!(big_point_1, deserialized_point); + + // Check point 2 + + let mut expected_serialization = array![]; + + big_point_2.get_coordinates().unwrap().serialize(ref expected_serialization); + let mut expected_serialization = expected_serialization.span(); + let deserialized_point = Secp256k1PointSerde::deserialize(ref expected_serialization).unwrap(); + + assert_eq!(big_point_2, deserialized_point); +} + +#[test] +fn test_partial_eq() { + let (big_point_1, big_point_2) = get_points(); + + assert_eq!(big_point_1, big_point_1); + assert_eq!(big_point_2, big_point_2); + assert!(big_point_1 != big_point_2); + assert!(big_point_2 != big_point_1); +} + +// +// Helpers +// + +fn get_points() -> (Secp256k1Point, Secp256k1Point) { + let curve_size = Secp256k1Impl::get_curve_size(); + let point_1 = Secp256k1Impl::secp256_ec_get_point_from_x_syscall(curve_size, true) + .unwrap_syscall() + .unwrap(); + let point_2 = Secp256k1Impl::secp256_ec_get_point_from_x_syscall(curve_size, false) + .unwrap_syscall() + .unwrap(); + + (point_1, point_2) +} diff --git a/src/tests/account/test_signature.cairo b/src/tests/account/test_signature.cairo new file mode 100644 index 000000000..6a246f125 --- /dev/null +++ b/src/tests/account/test_signature.cairo @@ -0,0 +1,127 @@ +use openzeppelin::account::utils::signature::{is_valid_stark_signature, is_valid_eth_signature}; +use openzeppelin::tests::account::test_account::SIGNED_TX_DATA as stark_signature_data; +use openzeppelin::tests::account::test_eth_account::SIGNED_TX_DATA as eth_signature_data; +use starknet::secp256k1::Secp256k1Impl; + +// +// is_valid_stark_signature +// + +#[test] +fn test_is_valid_stark_signature_good_sig() { + let data = stark_signature_data(); + let hash = data.transaction_hash; + + let mut good_signature = array![data.r, data.s].span(); + + let is_valid = is_valid_stark_signature(hash, data.public_key, good_signature); + assert!(is_valid); +} + +#[test] +fn test_is_valid_stark_signature_bad_sig() { + let data = stark_signature_data(); + let hash = data.transaction_hash; + + let mut bad_signature = array![0x987, 0x564].span(); + + let is_invalid = !is_valid_stark_signature(hash, data.public_key, bad_signature); + assert!(is_invalid); +} + +#[test] +fn test_is_valid_stark_signature_invalid_len_sig() { + let data = stark_signature_data(); + let hash = data.transaction_hash; + + let mut bad_signature = array![0x987].span(); + + let is_invalid = !is_valid_stark_signature(hash, data.public_key, bad_signature); + assert!(is_invalid); +} + +// +// is_valid_eth_signature +// + +#[test] +fn test_is_valid_eth_signature_good_sig() { + let data = eth_signature_data(); + let hash = data.transaction_hash; + + let mut serialized_good_signature = array![]; + + data.signature.serialize(ref serialized_good_signature); + + let is_valid = is_valid_eth_signature(hash, data.public_key, serialized_good_signature.span()); + assert!(is_valid); +} + +#[test] +fn test_is_valid_eth_signature_bad_sig() { + let data = eth_signature_data(); + let hash = data.transaction_hash; + let mut bad_signature = data.signature; + + bad_signature.r += 1; + + let mut serialized_bad_signature = array![]; + + bad_signature.serialize(ref serialized_bad_signature); + + let is_invalid = !is_valid_eth_signature( + hash, data.public_key, serialized_bad_signature.span() + ); + assert!(is_invalid); +} + +#[test] +#[should_panic(expected: ('Signature: Invalid format.',))] +fn test_is_valid_eth_signature_invalid_format_sig() { + let data = eth_signature_data(); + let hash = data.transaction_hash; + + let mut serialized_bad_signature = array![0x1]; + + is_valid_eth_signature(hash, data.public_key, serialized_bad_signature.span()); +} + +#[test] +fn test_signature_r_out_of_range() { + let data = eth_signature_data(); + let hash = data.transaction_hash; + let mut bad_signature = data.signature; + + let curve_size = Secp256k1Impl::get_curve_size(); + + bad_signature.r = curve_size + 1; + + let mut serialized_bad_signature = array![]; + + bad_signature.serialize(ref serialized_bad_signature); + + let is_invalid = !is_valid_eth_signature( + hash, data.public_key, serialized_bad_signature.span() + ); + assert!(is_invalid); +} + +#[test] +fn test_signature_s_out_of_range() { + let data = eth_signature_data(); + let hash = data.transaction_hash; + let mut bad_signature = data.signature; + + let curve_size = Secp256k1Impl::get_curve_size(); + + bad_signature.s = curve_size + 1; + + let mut serialized_bad_signature = array![]; + + bad_signature.serialize(ref serialized_bad_signature); + + let is_invalid = !is_valid_eth_signature( + hash, data.public_key, serialized_bad_signature.span() + ); + assert!(is_invalid); +} diff --git a/src/tests/mocks.cairo b/src/tests/mocks.cairo index 7eeb6c8c8..99da97b15 100644 --- a/src/tests/mocks.cairo +++ b/src/tests/mocks.cairo @@ -3,6 +3,7 @@ mod account_mocks; mod erc20_mocks; mod erc721_mocks; mod erc721_receiver_mocks; +mod eth_account_mocks; mod initializable_mocks; mod non_implementing_mock; mod ownable_mocks; diff --git a/src/tests/mocks/eth_account_mocks.cairo b/src/tests/mocks/eth_account_mocks.cairo new file mode 100644 index 000000000..839706fc9 --- /dev/null +++ b/src/tests/mocks/eth_account_mocks.cairo @@ -0,0 +1,215 @@ +#[starknet::contract] +mod DualCaseEthAccountMock { + use openzeppelin::account::EthAccountComponent; + use openzeppelin::account::interface::EthPublicKey; + use openzeppelin::account::utils::secp256k1::Secp256k1PointSerde; + use openzeppelin::introspection::src5::SRC5Component; + + component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent); + component!(path: SRC5Component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl SRC6Impl = EthAccountComponent::SRC6Impl; + #[abi(embed_v0)] + impl SRC6CamelOnlyImpl = EthAccountComponent::SRC6CamelOnlyImpl; + #[abi(embed_v0)] + impl DeclarerImpl = EthAccountComponent::DeclarerImpl; + #[abi(embed_v0)] + impl DeployableImpl = EthAccountComponent::DeployableImpl; + #[abi(embed_v0)] + impl SRC5Impl = SRC5Component::SRC5Impl; + impl EthAccountInternalImpl = EthAccountComponent::InternalImpl; + + #[storage] + struct Storage { + #[substorage(v0)] + eth_account: EthAccountComponent::Storage, + #[substorage(v0)] + src5: SRC5Component::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + EthAccountEvent: EthAccountComponent::Event, + #[flat] + SRC5Event: SRC5Component::Event + } + + #[constructor] + fn constructor(ref self: ContractState, public_key: EthPublicKey) { + self.eth_account.initializer(public_key); + } +} + +#[starknet::contract] +mod SnakeEthAccountMock { + use openzeppelin::account::EthAccountComponent; + use openzeppelin::account::interface::EthPublicKey; + use openzeppelin::account::utils::secp256k1::Secp256k1PointSerde; + use openzeppelin::introspection::src5::SRC5Component; + + component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent); + component!(path: SRC5Component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl SRC6Impl = EthAccountComponent::SRC6Impl; + #[abi(embed_v0)] + impl PublicKeyImpl = EthAccountComponent::PublicKeyImpl; + #[abi(embed_v0)] + impl SRC5Impl = SRC5Component::SRC5Impl; + impl EthAccountInternalImpl = EthAccountComponent::InternalImpl; + + #[storage] + struct Storage { + #[substorage(v0)] + eth_account: EthAccountComponent::Storage, + #[substorage(v0)] + src5: SRC5Component::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + EthAccountEvent: EthAccountComponent::Event, + #[flat] + SRC5Event: SRC5Component::Event + } + + #[constructor] + fn constructor(ref self: ContractState, public_key: EthPublicKey) { + self.eth_account.initializer(public_key); + } +} + +#[starknet::contract] +mod CamelEthAccountMock { + use openzeppelin::account::EthAccountComponent; + use openzeppelin::account::interface::EthPublicKey; + use openzeppelin::account::utils::secp256k1::Secp256k1PointSerde; + use openzeppelin::introspection::src5::SRC5Component; + use starknet::account::Call; + + component!(path: EthAccountComponent, storage: eth_account, event: EthAccountEvent); + component!(path: SRC5Component, storage: src5, event: SRC5Event); + + #[abi(embed_v0)] + impl SRC6CamelOnlyImpl = EthAccountComponent::SRC6CamelOnlyImpl; + #[abi(embed_v0)] + impl PublicKeyCamelImpl = + EthAccountComponent::PublicKeyCamelImpl; + #[abi(embed_v0)] + impl SRC5Impl = SRC5Component::SRC5Impl; + impl SRC6Impl = EthAccountComponent::SRC6Impl; + impl EthAccountInternalImpl = EthAccountComponent::InternalImpl; + + #[storage] + struct Storage { + #[substorage(v0)] + eth_account: EthAccountComponent::Storage, + #[substorage(v0)] + src5: SRC5Component::Storage + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + EthAccountEvent: EthAccountComponent::Event, + #[flat] + SRC5Event: SRC5Component::Event + } + + #[constructor] + fn constructor(ref self: ContractState, publicKey: EthPublicKey) { + self.eth_account.initializer(publicKey); + } + + #[external(v0)] + #[generate_trait] + impl ExternalImpl of ExternalTrait { + fn __execute__(self: @ContractState, mut calls: Array) -> Array> { + self.eth_account.__execute__(calls) + } + + fn __validate__(self: @ContractState, mut calls: Array) -> felt252 { + self.eth_account.__validate__(calls) + } + } +} + +// Although these modules are designed to panic, functions +// still need a valid return value. We chose: +// +// 3 for felt252 +// false for bool + +#[starknet::contract] +mod SnakeEthAccountPanicMock { + use openzeppelin::account::interface::EthPublicKey; + use openzeppelin::account::utils::secp256k1::Secp256k1PointSerde; + use starknet::secp256k1::secp256k1_new_syscall; + + #[storage] + struct Storage {} + + #[external(v0)] + fn set_public_key(ref self: ContractState, new_public_key: EthPublicKey) { + panic!("Some error"); + } + + #[external(v0)] + fn get_public_key(self: @ContractState) -> EthPublicKey { + panic!("Some error"); + secp256k1_new_syscall(3, 3).unwrap().unwrap() + } + + #[external(v0)] + fn is_valid_signature( + self: @ContractState, hash: felt252, signature: Array + ) -> felt252 { + panic!("Some error"); + 3 + } + + #[external(v0)] + fn supports_interface(self: @ContractState, interface_id: felt252) -> bool { + panic!("Some error"); + false + } +} + +#[starknet::contract] +mod CamelEthAccountPanicMock { + use openzeppelin::account::interface::EthPublicKey; + use openzeppelin::account::utils::secp256k1::Secp256k1PointSerde; + use starknet::secp256k1::secp256k1_new_syscall; + + #[storage] + struct Storage {} + + #[external(v0)] + fn setPublicKey(ref self: ContractState, newPublicKey: EthPublicKey) { + panic!("Some error"); + } + + #[external(v0)] + fn getPublicKey(self: @ContractState) -> EthPublicKey { + panic!("Some error"); + secp256k1_new_syscall(3, 3).unwrap().unwrap() + } + + #[external(v0)] + fn isValidSignature(self: @ContractState, hash: felt252, signature: Array) -> felt252 { + panic!("Some error"); + 3 + } + + #[external(v0)] + fn supportsInterface(self: @ContractState, interfaceId: felt252) -> bool { + panic!("Some error"); + false + } +} diff --git a/src/tests/presets.cairo b/src/tests/presets.cairo index 15f206215..91046a8a8 100644 --- a/src/tests/presets.cairo +++ b/src/tests/presets.cairo @@ -1,3 +1,4 @@ mod test_account; mod test_erc20; mod test_erc721; +mod test_eth_account; diff --git a/src/tests/presets/test_account.cairo b/src/tests/presets/test_account.cairo index 4ee96aaf2..ea515453a 100644 --- a/src/tests/presets/test_account.cairo +++ b/src/tests/presets/test_account.cairo @@ -1,13 +1,17 @@ use openzeppelin::account::AccountComponent::{OwnerAdded, OwnerRemoved}; use openzeppelin::account::interface::ISRC6_ID; -use openzeppelin::account::{AccountABIDispatcherTrait, AccountABIDispatcher}; +use openzeppelin::account::interface::{AccountABIDispatcherTrait, AccountABIDispatcher}; use openzeppelin::introspection::interface::ISRC5_ID; use openzeppelin::presets::Account; +use openzeppelin::tests::account::test_account::{ + assert_only_event_owner_added, assert_event_owner_removed +}; use openzeppelin::tests::account::test_account::{ deploy_erc20, SIGNED_TX_DATA, SignedTransactionData }; use openzeppelin::tests::utils::constants::{ - PUBKEY, NEW_PUBKEY, SALT, ZERO, QUERY_OFFSET, QUERY_VERSION, RECIPIENT, MIN_TRANSACTION_VERSION + PUBKEY, NEW_PUBKEY, SALT, ZERO, CALLER, RECIPIENT, OTHER, QUERY_OFFSET, QUERY_VERSION, + MIN_TRANSACTION_VERSION }; use openzeppelin::tests::utils; use openzeppelin::token::erc20::interface::{IERC20DispatcherTrait, IERC20Dispatcher}; @@ -15,7 +19,6 @@ use openzeppelin::utils::selectors; use openzeppelin::utils::serde::SerializedAppend; use starknet::ContractAddress; use starknet::account::Call; -use starknet::contract_address_const; use starknet::testing; fn CLASS_HASH() -> felt252 { @@ -27,7 +30,7 @@ fn CLASS_HASH() -> felt252 { // fn setup_dispatcher() -> AccountABIDispatcher { - let mut calldata = array![PUBKEY]; + let calldata = array![PUBKEY]; let target = utils::deploy(CLASS_HASH(), calldata); utils::drop_event(target); @@ -60,7 +63,7 @@ fn test_constructor() { let mut state = Account::contract_state_for_testing(); Account::constructor(ref state, PUBKEY); - assert_only_event_owner_added(PUBKEY, ZERO()); + assert_only_event_owner_added(ZERO(), PUBKEY); let public_key = Account::PublicKeyImpl::get_public_key(@state); assert_eq!(public_key, PUBKEY); @@ -86,8 +89,8 @@ fn test_public_key_setter_and_getter() { let public_key = dispatcher.get_public_key(); assert_eq!(public_key, NEW_PUBKEY); - assert_event_owner_removed(PUBKEY, dispatcher.contract_address); - assert_only_event_owner_added(NEW_PUBKEY, dispatcher.contract_address); + assert_event_owner_removed(dispatcher.contract_address, PUBKEY); + assert_only_event_owner_added(dispatcher.contract_address, NEW_PUBKEY); } #[test] @@ -100,8 +103,8 @@ fn test_public_key_setter_and_getter_camel() { let public_key = dispatcher.getPublicKey(); assert_eq!(public_key, NEW_PUBKEY); - assert_event_owner_removed(PUBKEY, dispatcher.contract_address); - assert_only_event_owner_added(NEW_PUBKEY, dispatcher.contract_address); + assert_event_owner_removed(dispatcher.contract_address, PUBKEY); + assert_only_event_owner_added(dispatcher.contract_address, NEW_PUBKEY); } #[test] @@ -367,8 +370,8 @@ fn test_validate_invalid() { fn test_multicall() { let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); let erc20 = deploy_erc20(account.contract_address, 1000); - let recipient1 = contract_address_const::<0x123>(); - let recipient2 = contract_address_const::<0x456>(); + let recipient1 = RECIPIENT(); + let recipient2 = OTHER(); let mut calls = array![]; // Craft call1 @@ -424,29 +427,9 @@ fn test_multicall_zero_calls() { fn test_account_called_from_contract() { let account = setup_dispatcher(); let calls = array![]; - let caller = contract_address_const::<0x123>(); testing::set_contract_address(account.contract_address); - testing::set_caller_address(caller); + testing::set_caller_address(CALLER()); account.__execute__(calls); } - -// -// Helpers -// - -fn assert_event_owner_removed(removed_owner_guid: felt252, contract: ContractAddress) { - let event = utils::pop_log::(contract).unwrap(); - assert_eq!(event.removed_owner_guid, removed_owner_guid); -} - -fn assert_event_owner_added(new_owner_guid: felt252, contract: ContractAddress) { - let event = utils::pop_log::(contract).unwrap(); - assert_eq!(event.new_owner_guid, new_owner_guid); -} - -fn assert_only_event_owner_added(new_owner_guid: felt252, contract: ContractAddress) { - assert_event_owner_added(new_owner_guid, contract); - utils::assert_no_events_left(contract); -} diff --git a/src/tests/presets/test_eth_account.cairo b/src/tests/presets/test_eth_account.cairo new file mode 100644 index 000000000..9154c4433 --- /dev/null +++ b/src/tests/presets/test_eth_account.cairo @@ -0,0 +1,515 @@ +use core::serde::Serde; +use core::traits::TryInto; +use openzeppelin::account::EthAccountComponent::{OwnerAdded, OwnerRemoved}; +use openzeppelin::account::interface::ISRC6_ID; +use openzeppelin::account::interface::{EthAccountABIDispatcherTrait, EthAccountABIDispatcher}; +use openzeppelin::account::utils::secp256k1::{ + DebugSecp256k1Point, Secp256k1PointSerde, Secp256k1PointPartialEq +}; +use openzeppelin::introspection::interface::ISRC5_ID; +use openzeppelin::presets::EthAccountUpgradeable; +use openzeppelin::tests::account::test_eth_account::{ + assert_only_event_owner_added, assert_event_owner_removed +}; +use openzeppelin::tests::account::test_eth_account::{ + deploy_erc20, SIGNED_TX_DATA, SignedTransactionData +}; +use openzeppelin::tests::account::test_secp256k1::get_points; +use openzeppelin::tests::mocks::eth_account_mocks::SnakeEthAccountMock; +use openzeppelin::tests::upgrades::test_upgradeable::assert_only_event_upgraded; +use openzeppelin::tests::utils::constants::{ + CLASS_HASH_ZERO, ETH_PUBKEY, NEW_ETH_PUBKEY, SALT, ZERO, RECIPIENT, QUERY_VERSION, + MIN_TRANSACTION_VERSION +}; +use openzeppelin::tests::utils; +use openzeppelin::token::erc20::interface::IERC20DispatcherTrait; +use openzeppelin::upgrades::interface::{IUpgradeableDispatcherTrait, IUpgradeableDispatcher}; +use openzeppelin::utils::selectors; +use openzeppelin::utils::serde::SerializedAppend; +use starknet::account::Call; +use starknet::contract_address_const; +use starknet::testing; +use starknet::{ContractAddress, ClassHash}; + +fn CLASS_HASH() -> felt252 { + EthAccountUpgradeable::TEST_CLASS_HASH +} + +fn V2_CLASS_HASH() -> ClassHash { + SnakeEthAccountMock::TEST_CLASS_HASH.try_into().unwrap() +} + +// +// Setup +// + +fn setup_dispatcher() -> EthAccountABIDispatcher { + let mut calldata = array![]; + calldata.append_serde(ETH_PUBKEY()); + + let target = utils::deploy(CLASS_HASH(), calldata); + utils::drop_event(target); + + EthAccountABIDispatcher { contract_address: target } +} + +fn setup_dispatcher_with_data(data: Option<@SignedTransactionData>) -> EthAccountABIDispatcher { + testing::set_version(MIN_TRANSACTION_VERSION); + + let mut calldata = array![]; + if data.is_some() { + let data = data.unwrap(); + let mut serialized_signature = array![]; + data.signature.serialize(ref serialized_signature); + + testing::set_signature(serialized_signature.span()); + testing::set_transaction_hash(*data.transaction_hash); + + calldata.append_serde(*data.public_key); + } else { + calldata.append_serde(ETH_PUBKEY()); + } + let address = utils::deploy(CLASS_HASH(), calldata); + EthAccountABIDispatcher { contract_address: address } +} + +fn setup_upgradeable() -> IUpgradeableDispatcher { + let mut calldata = array![]; + calldata.append_serde(ETH_PUBKEY()); + + let target = utils::deploy(CLASS_HASH(), calldata); + utils::drop_event(target); + + IUpgradeableDispatcher { contract_address: target } +} + +// +// constructor +// + +#[test] +fn test_constructor() { + let mut state = EthAccountUpgradeable::contract_state_for_testing(); + let public_key = ETH_PUBKEY(); + + EthAccountUpgradeable::constructor(ref state, public_key); + + assert_only_event_owner_added(ZERO(), public_key); + assert( + EthAccountUpgradeable::PublicKeyImpl::get_public_key(@state) == public_key, + 'Should return public_key' + ); + assert( + EthAccountUpgradeable::SRC5Impl::supports_interface(@state, ISRC5_ID), + 'Should implement ISRC5' + ); + assert( + EthAccountUpgradeable::SRC5Impl::supports_interface(@state, ISRC6_ID), + 'Should implement ISRC6' + ); +} + +// +// set_public_key & setPublicKey +// + +#[test] +fn test_public_key_setter_and_getter() { + let dispatcher = setup_dispatcher(); + let new_public_key = NEW_ETH_PUBKEY(); + + testing::set_contract_address(dispatcher.contract_address); + + dispatcher.set_public_key(new_public_key); + assert(dispatcher.get_public_key() == new_public_key, 'Should return new_public_key'); + + assert_event_owner_removed(dispatcher.contract_address, ETH_PUBKEY()); + assert_only_event_owner_added(dispatcher.contract_address, new_public_key); +} + +#[test] +fn test_public_key_setter_and_getter_camel() { + let dispatcher = setup_dispatcher(); + let new_public_key = NEW_ETH_PUBKEY(); + + testing::set_contract_address(dispatcher.contract_address); + + dispatcher.setPublicKey(new_public_key); + assert(dispatcher.getPublicKey() == new_public_key, 'Should return new_public_key'); + + assert_event_owner_removed(dispatcher.contract_address, ETH_PUBKEY()); + assert_only_event_owner_added(dispatcher.contract_address, new_public_key); +} + +#[test] +#[should_panic(expected: ('EthAccount: unauthorized', 'ENTRYPOINT_FAILED'))] +fn test_set_public_key_different_account() { + let dispatcher = setup_dispatcher(); + dispatcher.set_public_key(NEW_ETH_PUBKEY()); +} + +#[test] +#[should_panic(expected: ('EthAccount: unauthorized', 'ENTRYPOINT_FAILED'))] +fn test_setPublicKey_different_account() { + let dispatcher = setup_dispatcher(); + dispatcher.setPublicKey(NEW_ETH_PUBKEY()); +} + +// +// is_valid_signature & isValidSignature +// + +fn is_valid_sig_dispatcher() -> (EthAccountABIDispatcher, felt252, Array) { + let dispatcher = setup_dispatcher(); + + let data = SIGNED_TX_DATA(); + let hash = data.transaction_hash; + let mut serialized_signature = array![]; + data.signature.serialize(ref serialized_signature); + + testing::set_contract_address(dispatcher.contract_address); + dispatcher.set_public_key(data.public_key); + + (dispatcher, hash, serialized_signature) +} + +#[test] +fn test_is_valid_signature() { + let (dispatcher, hash, signature) = is_valid_sig_dispatcher(); + + let is_valid = dispatcher.is_valid_signature(hash, signature); + assert(is_valid == starknet::VALIDATED, 'Should accept valid signature'); +} + +#[test] +fn test_is_valid_signature_bad_sig() { + let (dispatcher, hash, signature) = is_valid_sig_dispatcher(); + + let is_valid = dispatcher.is_valid_signature(hash + 1, signature); + assert(is_valid == 0, 'Should reject invalid signature'); +} + +#[test] +fn test_isValidSignature() { + let (dispatcher, hash, signature) = is_valid_sig_dispatcher(); + + let is_valid = dispatcher.isValidSignature(hash, signature); + assert(is_valid == starknet::VALIDATED, 'Should accept valid signature'); +} + +#[test] +fn test_isValidSignature_bad_sig() { + let (dispatcher, hash, signature) = is_valid_sig_dispatcher(); + + let is_valid = dispatcher.isValidSignature(hash + 1, signature); + assert(is_valid == 0, 'Should reject invalid signature'); +} + +// +// supports_interface +// + +#[test] +fn test_supports_interface() { + let dispatcher = setup_dispatcher(); + assert(dispatcher.supports_interface(ISRC5_ID), 'Should implement ISRC5'); + assert(dispatcher.supports_interface(ISRC6_ID), 'Should implement ISRC6'); + assert(!dispatcher.supports_interface(0x123), 'Should not implement 0x123'); +} + +// +// Entry points +// + +#[test] +fn test_validate_deploy() { + let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); + + // `__validate_deploy__` does not directly use the passed arguments. Their + // values are already integrated in the tx hash. The passed arguments in this + // testing context are decoupled from the signature and have no effect on the test. + assert( + account.__validate_deploy__(CLASS_HASH(), SALT, ETH_PUBKEY()) == starknet::VALIDATED, + 'Should validate correctly' + ); +} + +#[test] +#[should_panic(expected: ('EthAccount: invalid signature', 'ENTRYPOINT_FAILED'))] +fn test_validate_deploy_invalid_signature_data() { + let mut data = SIGNED_TX_DATA(); + data.transaction_hash += 1; + let account = setup_dispatcher_with_data(Option::Some(@data)); + + account.__validate_deploy__(CLASS_HASH(), SALT, ETH_PUBKEY()); +} + +#[test] +#[should_panic(expected: ('Signature: Invalid format.', 'ENTRYPOINT_FAILED'))] +fn test_validate_deploy_invalid_signature_length() { + let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); + let mut signature = array![0x1]; + + testing::set_signature(signature.span()); + + account.__validate_deploy__(CLASS_HASH(), SALT, ETH_PUBKEY()); +} + +#[test] +#[should_panic(expected: ('Signature: Invalid format.', 'ENTRYPOINT_FAILED'))] +fn test_validate_deploy_empty_signature() { + let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); + let empty_sig = array![]; + + testing::set_signature(empty_sig.span()); + account.__validate_deploy__(CLASS_HASH(), SALT, ETH_PUBKEY()); +} + +#[test] +fn test_validate_declare() { + let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); + + // `__validate_declare__` does not directly use the class_hash argument. Its + // value is already integrated in the tx hash. The class_hash argument in this + // testing context is decoupled from the signature and has no effect on the test. + assert( + account.__validate_declare__(CLASS_HASH()) == starknet::VALIDATED, + 'Should validate correctly' + ); +} + +#[test] +#[should_panic(expected: ('EthAccount: invalid signature', 'ENTRYPOINT_FAILED'))] +fn test_validate_declare_invalid_signature_data() { + let mut data = SIGNED_TX_DATA(); + data.transaction_hash += 1; + let account = setup_dispatcher_with_data(Option::Some(@data)); + + account.__validate_declare__(CLASS_HASH()); +} + +#[test] +#[should_panic(expected: ('Signature: Invalid format.', 'ENTRYPOINT_FAILED'))] +fn test_validate_declare_invalid_signature_length() { + let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); + let mut signature = array![0x1]; + + testing::set_signature(signature.span()); + + account.__validate_declare__(CLASS_HASH()); +} + +#[test] +#[should_panic(expected: ('Signature: Invalid format.', 'ENTRYPOINT_FAILED'))] +fn test_validate_declare_empty_signature() { + let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); + let empty_sig = array![]; + + testing::set_signature(empty_sig.span()); + + account.__validate_declare__(CLASS_HASH()); +} + +fn test_execute_with_version(version: Option) { + let data = SIGNED_TX_DATA(); + let account = setup_dispatcher_with_data(Option::Some(@data)); + let erc20 = deploy_erc20(account.contract_address, 1000); + + let amount: u256 = 200; + + let mut calldata = array![]; + calldata.append_serde(RECIPIENT()); + calldata.append_serde(amount); + + let call = Call { + to: erc20.contract_address, selector: selectors::transfer, calldata: calldata + }; + let mut calls = array![]; + calls.append(call); + + if version.is_some() { + testing::set_version(version.unwrap()); + } + + let ret = account.__execute__(calls); + + assert(erc20.balance_of(account.contract_address) == 800, 'Should have remainder'); + assert(erc20.balance_of(RECIPIENT()) == amount, 'Should have transferred'); + + let mut call_serialized_retval = *ret.at(0); + let call_retval = Serde::::deserialize(ref call_serialized_retval); + assert(call_retval.unwrap(), 'Should have succeeded'); +} + +#[test] +fn test_execute() { + test_execute_with_version(Option::None(())); +} + +#[test] +fn test_execute_query_version() { + test_execute_with_version(Option::Some(QUERY_VERSION)); +} + +#[test] +#[should_panic(expected: ('EthAccount: invalid tx version', 'ENTRYPOINT_FAILED'))] +fn test_execute_invalid_version() { + test_execute_with_version(Option::Some(MIN_TRANSACTION_VERSION - 1)); +} + +#[test] +fn test_validate() { + let calls = array![]; + let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); + + assert(account.__validate__(calls) == starknet::VALIDATED, 'Should validate correctly'); +} + +#[test] +#[should_panic(expected: ('EthAccount: invalid signature', 'ENTRYPOINT_FAILED'))] +fn test_validate_invalid() { + let calls = array![]; + let mut data = SIGNED_TX_DATA(); + data.transaction_hash += 1; + let account = setup_dispatcher_with_data(Option::Some(@data)); + + account.__validate__(calls); +} + +#[test] +fn test_multicall() { + let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); + let erc20 = deploy_erc20(account.contract_address, 1000); + let recipient1 = contract_address_const::<0x123>(); + let recipient2 = contract_address_const::<0x456>(); + let mut calls = array![]; + + let mut calldata1 = array![]; + let amount1: u256 = 300; + calldata1.append_serde(recipient1); + calldata1.append_serde(amount1); + let call1 = Call { + to: erc20.contract_address, selector: selectors::transfer, calldata: calldata1 + }; + + let mut calldata2 = array![]; + let amount2: u256 = 500; + calldata2.append_serde(recipient2); + calldata2.append_serde(amount2); + let call2 = Call { + to: erc20.contract_address, selector: selectors::transfer, calldata: calldata2 + }; + + calls.append(call1); + calls.append(call2); + let ret = account.__execute__(calls); + + assert(erc20.balance_of(account.contract_address) == 200, 'Should have remainder'); + assert(erc20.balance_of(recipient1) == 300, 'Should have transferred'); + assert(erc20.balance_of(recipient2) == 500, 'Should have transferred'); + + let mut call1_serialized_retval = *ret.at(0); + let mut call2_serialized_retval = *ret.at(1); + let call1_retval = Serde::::deserialize(ref call1_serialized_retval); + let call2_retval = Serde::::deserialize(ref call2_serialized_retval); + assert(call1_retval.unwrap(), 'Should have succeeded'); + assert(call2_retval.unwrap(), 'Should have succeeded'); +} + +#[test] +fn test_multicall_zero_calls() { + let account = setup_dispatcher_with_data(Option::Some(@SIGNED_TX_DATA())); + let mut calls = array![]; + + let ret = account.__execute__(calls); + + assert(ret.len() == 0, 'Should have an empty response'); +} + +#[test] +#[should_panic(expected: ('EthAccount: invalid caller', 'ENTRYPOINT_FAILED'))] +fn test_account_called_from_contract() { + let account = setup_dispatcher(); + let calls = array![]; + let caller = contract_address_const::<0x123>(); + + testing::set_contract_address(account.contract_address); + testing::set_caller_address(caller); + + account.__execute__(calls); +} + + +// +// upgrade +// + +#[test] +#[should_panic(expected: ('EthAccount: unauthorized', 'ENTRYPOINT_FAILED',))] +fn test_upgrade_access_control() { + let v1 = setup_upgradeable(); + v1.upgrade(CLASS_HASH_ZERO()); +} + +#[test] +#[should_panic(expected: ('Class hash cannot be zero', 'ENTRYPOINT_FAILED',))] +fn test_upgrade_with_class_hash_zero() { + let v1 = setup_upgradeable(); + + set_contract_and_caller(v1.contract_address); + v1.upgrade(CLASS_HASH_ZERO()); +} + +#[test] +fn test_upgraded_event() { + let v1 = setup_upgradeable(); + let v2_class_hash = V2_CLASS_HASH(); + + set_contract_and_caller(v1.contract_address); + v1.upgrade(v2_class_hash); + + assert_only_event_upgraded(v2_class_hash, v1.contract_address); +} + +#[test] +#[should_panic(expected: ('ENTRYPOINT_NOT_FOUND',))] +fn test_v2_missing_camel_selector() { + let v1 = setup_upgradeable(); + let v2_class_hash = V2_CLASS_HASH(); + + set_contract_and_caller(v1.contract_address); + v1.upgrade(v2_class_hash); + + let dispatcher = EthAccountABIDispatcher { contract_address: v1.contract_address }; + dispatcher.getPublicKey(); +} + +#[test] +fn test_state_persists_after_upgrade() { + let v1 = setup_upgradeable(); + let v2_class_hash = V2_CLASS_HASH(); + + set_contract_and_caller(v1.contract_address); + let dispatcher = EthAccountABIDispatcher { contract_address: v1.contract_address }; + + let (point, _) = get_points(); + + dispatcher.set_public_key(point); + + let camel_public_key = dispatcher.getPublicKey(); + assert_eq!(camel_public_key, point); + + v1.upgrade(v2_class_hash); + let snake_public_key = dispatcher.get_public_key(); + + assert_eq!(snake_public_key, camel_public_key); +} + +// +// Helpers +// + +fn set_contract_and_caller(address: ContractAddress) { + testing::set_contract_address(address); + testing::set_caller_address(address); +} diff --git a/src/tests/upgrades/test_upgradeable.cairo b/src/tests/upgrades/test_upgradeable.cairo index 280b309d7..4323a3970 100644 --- a/src/tests/upgrades/test_upgradeable.cairo +++ b/src/tests/upgrades/test_upgradeable.cairo @@ -43,10 +43,7 @@ fn test_upgraded_event() { let v1 = deploy_v1(); v1.upgrade(V2_CLASS_HASH()); - let event = utils::pop_log::(v1.contract_address).unwrap(); - assert_eq!(event.class_hash, V2_CLASS_HASH()); - - utils::assert_no_events_left(v1.contract_address); + assert_only_event_upgraded(V2_CLASS_HASH(), v1.contract_address); } #[test] @@ -85,3 +82,17 @@ fn test_remove_selector_fails_in_v2() { // We use the v1 dispatcher because remove_selector is not in v2 interface v1.remove_selector(); } + +// +// Helpers +// + +fn assert_event_upgraded(class_hash: ClassHash, contract: ContractAddress) { + let event = utils::pop_log::(contract).unwrap(); + assert!(event.class_hash == class_hash); +} + +fn assert_only_event_upgraded(class_hash: ClassHash, contract: ContractAddress) { + assert_event_upgraded(class_hash, contract); + utils::assert_no_events_left(ZERO()); +} diff --git a/src/tests/utils/constants.cairo b/src/tests/utils/constants.cairo index 52c190fc0..7dd146ada 100644 --- a/src/tests/utils/constants.cairo +++ b/src/tests/utils/constants.cairo @@ -1,7 +1,9 @@ +use openzeppelin::account::interface::EthPublicKey; use starknet::ClassHash; use starknet::ContractAddress; use starknet::class_hash_const; use starknet::contract_address_const; +use starknet::secp256k1::secp256k1_get_point_from_x_syscall; const NAME: felt252 = 'NAME'; const SYMBOL: felt252 = 'SYMBOL'; @@ -23,6 +25,14 @@ const QUERY_OFFSET: felt252 = 0x100000000000000000000000000000000; // QUERY_OFFSET + MIN_TRANSACTION_VERSION const QUERY_VERSION: felt252 = 0x100000000000000000000000000000001; +fn ETH_PUBKEY() -> EthPublicKey { + secp256k1_get_point_from_x_syscall(3, false).unwrap().unwrap() +} + +fn NEW_ETH_PUBKEY() -> EthPublicKey { + secp256k1_get_point_from_x_syscall(4, false).unwrap().unwrap() +} + fn ADMIN() -> ContractAddress { contract_address_const::<'ADMIN'>() }