From 18e50b5b7387413001512818fed4f236c2c5b0c3 Mon Sep 17 00:00:00 2001
From: karim-en <karim@aurora.dev>
Date: Tue, 10 Sep 2024 23:50:12 +0100
Subject: [PATCH 1/5] Make view method pausable

---
 .../tests/contracts/pausable/src/lib.rs              |  1 +
 near-plugins-derive/tests/pausable.rs                | 12 ++++++++++++
 2 files changed, 13 insertions(+)

diff --git a/near-plugins-derive/tests/contracts/pausable/src/lib.rs b/near-plugins-derive/tests/contracts/pausable/src/lib.rs
index 9d7fec9..8c66f4a 100644
--- a/near-plugins-derive/tests/contracts/pausable/src/lib.rs
+++ b/near-plugins-derive/tests/contracts/pausable/src/lib.rs
@@ -57,6 +57,7 @@ impl Counter {
     }
 
     /// Returns the value of the counter.
+    #[pause]
     pub fn get_counter(&self) -> u64 {
         self.counter
     }
diff --git a/near-plugins-derive/tests/pausable.rs b/near-plugins-derive/tests/pausable.rs
index 6f5604a..446285f 100644
--- a/near-plugins-derive/tests/pausable.rs
+++ b/near-plugins-derive/tests/pausable.rs
@@ -341,6 +341,18 @@ async fn test_not_paused_with_different_key() -> anyhow::Result<()> {
     Ok(())
 }
 
+#[tokio::test]
+async fn test_view_call_of_pausable_method() -> anyhow::Result<()> {
+    let setup = Setup::new().await?;
+    let res = setup
+        .call_counter_modifier(&setup.unauth_account, "increase_1")
+        .await?;
+    assert_success_with_unit_return(res);
+    assert_eq!(setup.get_counter().await?, 1);
+
+    Ok(())
+}
+
 #[tokio::test]
 async fn test_work_after_unpause() -> anyhow::Result<()> {
     let setup = Setup::new().await?;

From 2849dddd28ee118499569d0ef78ce97ebab96801 Mon Sep 17 00:00:00 2001
From: karim-en <karim@aurora.dev>
Date: Wed, 11 Sep 2024 00:34:54 +0100
Subject: [PATCH 2/5] Fix near-sdk version

---
 Cargo.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Cargo.toml b/Cargo.toml
index e5a4c57..1717d53 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -23,7 +23,7 @@ keywords = ["near", "smart contract", "plugin"]
 
 [workspace.dependencies]
 bitflags = "1.3"
-near-sdk = "5.2"
+near-sdk = "=5.2"
 near-plugins = { path = "near-plugins" }
 near-plugins-derive = { path = "near-plugins-derive" }
 serde = "1"

From c1d074b04e113b56cb1924dd390b7d3a3c744ad6 Mon Sep 17 00:00:00 2001
From: karim-en <karim@aurora.dev>
Date: Wed, 11 Sep 2024 01:51:56 +0100
Subject: [PATCH 3/5] Skip except roles verification if it is empty

---
 near-plugins-derive/src/pausable.rs       | 28 +++++++++++++----------
 near-plugins-derive/tests/common/utils.rs | 10 ++++++++
 near-plugins-derive/tests/pausable.rs     | 15 +++++++++++-
 3 files changed, 40 insertions(+), 13 deletions(-)

diff --git a/near-plugins-derive/src/pausable.rs b/near-plugins-derive/src/pausable.rs
index bda149b..0429ac0 100644
--- a/near-plugins-derive/src/pausable.rs
+++ b/near-plugins-derive/src/pausable.rs
@@ -201,16 +201,20 @@ pub fn if_paused(attrs: TokenStream, item: TokenStream) -> TokenStream {
 }
 
 fn get_bypass_condition(args: &ExceptSubArgs) -> proc_macro2::TokenStream {
-    let except_roles = args.roles.clone();
-    quote!(
-        let __except_roles: Vec<&str> = vec![#(#except_roles.into()),*];
-        let __except_roles: Vec<String> = __except_roles.iter().map(|&x| x.into()).collect();
-        let may_bypass = self.acl_has_any_role(
-            __except_roles,
-            ::near_sdk::env::predecessor_account_id()
-        );
-        if may_bypass {
-            __check_paused = false;
-        }
-    )
+    if args.roles.len() > 0 {
+        let except_roles = args.roles.clone();
+        quote!(
+            let __except_roles: Vec<&str> = vec![#(#except_roles.into()),*];
+            let __except_roles: Vec<String> = __except_roles.iter().map(|&x| x.into()).collect();
+            let may_bypass = self.acl_has_any_role(
+                __except_roles,
+                ::near_sdk::env::predecessor_account_id()
+            );
+            if may_bypass {
+                __check_paused = false;
+            }
+        )
+    } else {
+        quote!()
+    }
 }
diff --git a/near-plugins-derive/tests/common/utils.rs b/near-plugins-derive/tests/common/utils.rs
index 2fb95a9..bbacb85 100644
--- a/near-plugins-derive/tests/common/utils.rs
+++ b/near-plugins-derive/tests/common/utils.rs
@@ -110,6 +110,16 @@ pub fn assert_method_is_paused(res: ExecutionFinalResult) {
     );
 }
 
+pub fn assert_view_method_is_paused(err: anyhow::Error) {
+    let err = format!("{:?}", err);
+    let must_contain = "Pausable: Method is paused";
+    assert!(
+        err.contains(must_contain),
+        "Expected method to be paused, instead it failed with: {}",
+        err
+    );
+}
+
 pub fn assert_pausable_escape_hatch_is_closed(res: ExecutionFinalResult, feature: &str) {
     let must_contain = format!("Pausable: {feature} must be paused to use this function");
     assert_failure_with(res, &must_contain);
diff --git a/near-plugins-derive/tests/pausable.rs b/near-plugins-derive/tests/pausable.rs
index 446285f..d01bb71 100644
--- a/near-plugins-derive/tests/pausable.rs
+++ b/near-plugins-derive/tests/pausable.rs
@@ -7,6 +7,7 @@ use common::pausable_contract::PausableContract;
 use common::utils::{
     assert_failure_with, assert_insufficient_acl_permissions, assert_method_is_paused,
     assert_pausable_escape_hatch_is_closed, assert_success_with, assert_success_with_unit_return,
+    assert_view_method_is_paused,
 };
 use near_sdk::serde_json::json;
 use near_workspaces::network::Sandbox;
@@ -319,6 +320,11 @@ async fn test_pause_with_all_allows_except() -> anyhow::Result<()> {
         .call_counter_modifier(&exempted_account, "increase_4")
         .await?;
     assert_success_with_unit_return(res);
+    let res = setup
+        .pausable_contract
+        .pa_unpause_feature(&setup.pause_manager, "ALL")
+        .await?;
+    assert_success_with(res, true);
     assert_eq!(setup.get_counter().await?, 4);
     Ok(())
 }
@@ -342,7 +348,7 @@ async fn test_not_paused_with_different_key() -> anyhow::Result<()> {
 }
 
 #[tokio::test]
-async fn test_view_call_of_pausable_method() -> anyhow::Result<()> {
+async fn test_pause_view_method() -> anyhow::Result<()> {
     let setup = Setup::new().await?;
     let res = setup
         .call_counter_modifier(&setup.unauth_account, "increase_1")
@@ -350,6 +356,13 @@ async fn test_view_call_of_pausable_method() -> anyhow::Result<()> {
     assert_success_with_unit_return(res);
     assert_eq!(setup.get_counter().await?, 1);
 
+    let res = setup
+        .pausable_contract
+        .pa_pause_feature(&setup.pause_manager, "get_counter")
+        .await?;
+    assert_success_with(res, true);
+    assert_view_method_is_paused(setup.get_counter().await.unwrap_err());
+
     Ok(())
 }
 

From a9bc76f04ab8879671a6fc152a00735866eff29f Mon Sep 17 00:00:00 2001
From: karim-en <karim@aurora.dev>
Date: Wed, 11 Sep 2024 02:22:43 +0100
Subject: [PATCH 4/5] Improve `near-sdk` version

---
 Cargo.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Cargo.toml b/Cargo.toml
index 1717d53..747d1cb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -23,7 +23,7 @@ keywords = ["near", "smart contract", "plugin"]
 
 [workspace.dependencies]
 bitflags = "1.3"
-near-sdk = "=5.2"
+near-sdk = ">=5.2, <5.4"
 near-plugins = { path = "near-plugins" }
 near-plugins-derive = { path = "near-plugins-derive" }
 serde = "1"

From 61a9c369f14f3df3c15b87e4940a119ef499efc9 Mon Sep 17 00:00:00 2001
From: karim-en <karim@aurora.dev>
Date: Wed, 11 Sep 2024 02:42:10 +0100
Subject: [PATCH 5/5] Replace `if/else` with early return

---
 near-plugins-derive/src/pausable.rs | 30 ++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/near-plugins-derive/src/pausable.rs b/near-plugins-derive/src/pausable.rs
index 0429ac0..3c109e4 100644
--- a/near-plugins-derive/src/pausable.rs
+++ b/near-plugins-derive/src/pausable.rs
@@ -201,20 +201,20 @@ pub fn if_paused(attrs: TokenStream, item: TokenStream) -> TokenStream {
 }
 
 fn get_bypass_condition(args: &ExceptSubArgs) -> proc_macro2::TokenStream {
-    if args.roles.len() > 0 {
-        let except_roles = args.roles.clone();
-        quote!(
-            let __except_roles: Vec<&str> = vec![#(#except_roles.into()),*];
-            let __except_roles: Vec<String> = __except_roles.iter().map(|&x| x.into()).collect();
-            let may_bypass = self.acl_has_any_role(
-                __except_roles,
-                ::near_sdk::env::predecessor_account_id()
-            );
-            if may_bypass {
-                __check_paused = false;
-            }
-        )
-    } else {
-        quote!()
+    if args.roles.len() == 0 {
+        return quote!();
     }
+
+    let except_roles = args.roles.clone();
+    quote!(
+        let __except_roles: Vec<&str> = vec![#(#except_roles.into()),*];
+        let __except_roles: Vec<String> = __except_roles.iter().map(|&x| x.into()).collect();
+        let may_bypass = self.acl_has_any_role(
+            __except_roles,
+            ::near_sdk::env::predecessor_account_id()
+        );
+        if may_bypass {
+            __check_paused = false;
+        }
+    )
 }