diff --git a/Cargo.lock b/Cargo.lock index cd88c53..079d204 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,7 +40,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -61,7 +61,7 @@ checksum = "7c7db3d5a9718568e4cf4a537cfd7070e6e6ff7481510d0237fb529ac850f6d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -144,9 +144,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anstyle-parse" @@ -178,9 +178,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355" [[package]] name = "arbitrary" @@ -216,18 +216,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -286,6 +286,7 @@ dependencies = [ "ethabi", "hex", "near-contract-standards", + "near-plugins", "near-sdk", "rand 0.8.5", "rlp", @@ -318,7 +319,7 @@ dependencies = [ [[package]] name = "aurora-workspace-eth-connector" version = "0.4.1" -source = "git+https://github.com/aurora-is-near/aurora-workspace.git?rev=16d6263d6561cbc1f838016ae15416eadc88ec90#16d6263d6561cbc1f838016ae15416eadc88ec90" +source = "git+https://github.com/aurora-is-near/aurora-workspace?rev=1d883cd9695fbd82e2c3f024d3f127769a48dfeb#1d883cd9695fbd82e2c3f024d3f127769a48dfeb" dependencies = [ "anyhow", "aurora-engine-types", @@ -333,7 +334,7 @@ dependencies = [ [[package]] name = "aurora-workspace-utils" version = "0.4.1" -source = "git+https://github.com/aurora-is-near/aurora-workspace.git?rev=16d6263d6561cbc1f838016ae15416eadc88ec90#16d6263d6561cbc1f838016ae15416eadc88ec90" +source = "git+https://github.com/aurora-is-near/aurora-workspace?rev=1d883cd9695fbd82e2c3f024d3f127769a48dfeb#1d883cd9695fbd82e2c3f024d3f127769a48dfeb" dependencies = [ "anyhow", "aurora-engine-types", @@ -510,7 +511,7 @@ dependencies = [ "proc-macro-crate 2.0.1", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", "syn_derive", ] @@ -826,7 +827,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -964,14 +965,38 @@ dependencies = [ "zeroize", ] +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core 0.13.4", + "darling_macro 0.13.4", +] + [[package]] name = "darling" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.3", + "darling_macro 0.20.3", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", ] [[package]] @@ -985,7 +1010,18 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.41", + "syn 2.0.42", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core 0.13.4", + "quote", + "syn 1.0.109", ] [[package]] @@ -994,9 +1030,9 @@ version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ - "darling_core", + "darling_core 0.20.3", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -1026,7 +1062,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -1166,7 +1202,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -2194,6 +2230,29 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "near-plugins" +version = "0.1.0" +source = "git+https://github.com/aurora-is-near/near-plugins?tag=v0.1.0#64c512f96d4b51ccdd1a1aed683ed90fd1ca8c57" +dependencies = [ + "bitflags 1.3.2", + "near-plugins-derive", + "near-sdk", + "serde", +] + +[[package]] +name = "near-plugins-derive" +version = "0.1.0" +source = "git+https://github.com/aurora-is-near/near-plugins?tag=v0.1.0#64c512f96d4b51ccdd1a1aed683ed90fd1ca8c57" +dependencies = [ + "darling 0.13.4", + "proc-macro-crate 0.1.5", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "near-primitives" version = "0.17.0" @@ -2261,7 +2320,7 @@ checksum = "84c1eda300e2e78f4f945ae58117d49e806899f4a51ee2faa09eda5ebc2e6571" dependencies = [ "quote", "serde", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -2273,7 +2332,7 @@ dependencies = [ "fs2", "near-rpc-error-core", "serde", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -2586,7 +2645,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -2792,7 +2851,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -2809,9 +2868,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" [[package]] name = "plain" @@ -2905,9 +2964,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" dependencies = [ "unicode-ident", ] @@ -3340,7 +3399,7 @@ checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -3421,7 +3480,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -3454,7 +3513,7 @@ checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -3492,17 +3551,17 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" dependencies = [ - "darling", + "darling 0.20.3", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] name = "serde_yaml" -version = "0.9.27" +version = "0.9.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c" +checksum = "a15e0ef66bf939a7c890a0bf6d5a733c70202225f9888a89ed5c62298b019129" dependencies = [ "indexmap 2.1.0", "itoa", @@ -3759,9 +3818,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.41" +version = "2.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" +checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8" dependencies = [ "proc-macro2", "quote", @@ -3777,7 +3836,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -3863,7 +3922,7 @@ checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -3966,7 +4025,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -4162,7 +4221,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -4411,7 +4470,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", "wasm-bindgen-shared", ] @@ -4445,7 +4504,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4721,22 +4780,22 @@ checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" [[package]] name = "zerocopy" -version = "0.7.31" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.31" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -4756,7 +4815,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index c0aa429..70fc59a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ license = "CC0 1.0" [workspace.dependencies] aurora-engine-types = { git = "https://github.com/aurora-is-near/aurora-engine.git", tag = "3.5.0", default-features = false } near-sdk = "4.1" +near-plugins = { git = "https://github.com/aurora-is-near/near-plugins", tag = "v0.1.0" } near-primitives = "0.17" near-contract-standards = "4.1" byte-slice-cast = "1" diff --git a/eth-connector-tests/Cargo.toml b/eth-connector-tests/Cargo.toml index 5e33993..3cbb7b9 100644 --- a/eth-connector-tests/Cargo.toml +++ b/eth-connector-tests/Cargo.toml @@ -28,8 +28,8 @@ hex = "0.4.3" ethabi = "18.0" rlp = { version = "0.5.0", default-features = false } aurora-engine-migration-tool = { git = "https://github.com/aurora-is-near/aurora-engine-migration-tool.git", tag = "0.2.2" } -aurora-workspace-eth-connector = { git = "https://github.com/aurora-is-near/aurora-workspace.git", rev = "16d6263d6561cbc1f838016ae15416eadc88ec90" } -aurora-workspace-utils = { git = "https://github.com/aurora-is-near/aurora-workspace.git", rev = "16d6263d6561cbc1f838016ae15416eadc88ec90" } +aurora-workspace-eth-connector = { git = "https://github.com/aurora-is-near/aurora-workspace", rev = "1d883cd9695fbd82e2c3f024d3f127769a48dfeb" } +aurora-workspace-utils = { git = "https://github.com/aurora-is-near/aurora-workspace", rev = "1d883cd9695fbd82e2c3f024d3f127769a48dfeb" } [features] migration-tests = [] diff --git a/eth-connector-tests/src/connector.rs b/eth-connector-tests/src/connector.rs index 25232c5..2b7e5a2 100644 --- a/eth-connector-tests/src/connector.rs +++ b/eth-connector-tests/src/connector.rs @@ -181,7 +181,7 @@ async fn test_withdraw_eth_from_near_engine() { .transact() .await .unwrap_err(); - assert!(contract.check_error_message(&res, "ERR_ACCESS_RIGHT")); + assert!(contract.check_error_message(&res, "Method can be called only by aurora engine")); // The purpose of this withdraw variant is that it can withdraw on behalf of a user. // In this example the contract itself withdraws on behalf of the user @@ -252,7 +252,10 @@ async fn test_deposit_eth_to_aurora_balance_total_supply() { .await .unwrap(); - contract.call_deposit_eth_to_aurora().await.unwrap(); + contract + .call_deposit_eth_to_aurora(&contract.contract) + .await + .unwrap(); assert!( contract.call_is_used_proof(PROOF_DATA_ETH).await.unwrap(), "Expected not to fail because the proof should have been already used", @@ -480,16 +483,18 @@ async fn test_set_and_check_engine_account() { .transact() .await .unwrap_err(); - assert!(contract.check_error_message(&res, "ERR_ACCESS_RIGHT")); + assert!(contract.check_error_message(&res, "Insufficient permissions for method")); contract .set_and_check_access_right(user_acc.id()) .await .unwrap(); - let res = user_acc + let res = contract + .contract .set_engine_account(contract.contract.id()) .max_gas() + .deposit(ONE_YOCTO) .transact() .await .unwrap(); @@ -639,32 +644,21 @@ async fn test_ft_transfer_call_without_relayer() { #[tokio::test] async fn test_admin_controlled_only_admin_can_pause() { - use aurora_eth_connector::admin_controlled::PAUSE_DEPOSIT; - let contract = TestContract::new_with_custodian_and_owner(CUSTODIAN_ADDRESS, "owner.root") .await .unwrap(); let owner_acc = contract.contract_account("owner").await.unwrap(); let user_acc = contract.contract_account("eth_recipient").await.unwrap(); let res = user_acc - .set_paused_flags(PAUSE_DEPOSIT) + .pa_pause_feature("deposit".to_string()) .max_gas() .transact() .await .unwrap_err(); - assert!(contract.check_error_message(&res, "ERR_ACCESS_RIGHT")); - - let res = contract - .contract - .set_paused_flags(PAUSE_DEPOSIT) - .max_gas() - .transact() - .await - .unwrap(); - assert!(res.is_success()); + assert!(contract.check_error_message(&res, "Insufficient permissions for method")); let res = owner_acc - .set_paused_flags(PAUSE_DEPOSIT) + .pa_pause_feature("deposit".to_string()) .max_gas() .transact() .await @@ -674,8 +668,6 @@ async fn test_admin_controlled_only_admin_can_pause() { #[tokio::test] async fn test_admin_controlled_admin_can_perform_actions_when_paused() { - use aurora_eth_connector::admin_controlled::{PAUSE_DEPOSIT, PAUSE_WITHDRAW}; - // 1st deposit call when unpaused - should succeed let contract = TestContract::new_with_custodian_and_owner(CUSTODIAN_ADDRESS, "owner.root") .await @@ -705,10 +697,18 @@ async fn test_admin_controlled_admin_can_perform_actions_when_paused() { assert_eq!(data.amount, withdraw_amount); assert_eq!(data.eth_custodian_address, custodian_addr); + let res = user_acc + .ft_transfer(&owner_acc.id().to_string(), U128(2 * withdraw_amount), None) + .max_gas() + .deposit(ONE_YOCTO) + .transact() + .await + .unwrap(); + assert!(res.is_success()); + // Pause deposit - let res = contract - .contract - .set_paused_flags(PAUSE_DEPOSIT) + let res = owner_acc + .pa_pause_feature("deposit".to_string()) .max_gas() .transact() .await @@ -718,16 +718,29 @@ async fn test_admin_controlled_admin_can_perform_actions_when_paused() { // 2nd deposit call when paused, but the admin is calling it - should succeed // NB: We can use `PROOF_DATA_ETH` this will be just a different proof but the same deposit // method which should be paused - contract + owner_acc .set_engine_account(contract.contract.id()) + .max_gas() + .deposit(ONE_YOCTO) + .transact() + .await + .unwrap(); + contract + .call_deposit_eth_to_aurora(&owner_acc) .await .unwrap(); - contract.call_deposit_eth_to_aurora().await.unwrap(); // Pause withdraw - let res = contract - .contract - .set_paused_flags(PAUSE_WITHDRAW) + let res = owner_acc + .pa_pause_feature("withdraw".to_string()) + .max_gas() + .transact() + .await + .unwrap(); + assert!(res.is_success()); + + let res = owner_acc + .pa_pause_feature("engine_withdraw".to_string()) .max_gas() .transact() .await @@ -735,9 +748,8 @@ async fn test_admin_controlled_admin_can_perform_actions_when_paused() { assert!(res.is_success()); // 2nd withdraw call when paused, but the admin is calling it - should succeed - let res = contract - .contract - .engine_withdraw(&sender_id, recipient_addr, withdraw_amount) + let res = owner_acc + .withdraw(recipient_addr, withdraw_amount) .max_gas() .deposit(ONE_YOCTO) .transact() @@ -758,10 +770,10 @@ async fn test_admin_controlled_admin_can_perform_actions_when_paused() { .transact() .await .unwrap_err(); - assert!(contract.check_error_message(&res, "ERR_ACCESS_RIGHT")); + assert!(contract.check_error_message(&res, "Pausable: Method is paused")); let res = owner_acc - .engine_withdraw(&sender_id, recipient_addr, withdraw_amount) + .withdraw(recipient_addr, withdraw_amount) .max_gas() .deposit(ONE_YOCTO) .transact() @@ -809,8 +821,6 @@ async fn test_deposit_with_proof_lower_than_acceptance_height() { #[tokio::test] async fn test_deposit_pausability() { - use aurora_eth_connector::admin_controlled::{PAUSE_DEPOSIT, UNPAUSE_ALL}; - let contract = TestContract::new_with_custodian_and_owner(CUSTODIAN_ADDRESS, "owner.root") .await .unwrap(); @@ -819,7 +829,7 @@ async fn test_deposit_pausability() { let user_acc = contract.contract_account("eth_recipient").await.unwrap(); contract - .set_and_check_access_right(user_acc.id()) + .user_set_and_check_access_right(user_acc.id(), &owner_acc) .await .unwrap(); @@ -832,9 +842,8 @@ async fn test_deposit_pausability() { assert!(res.is_success()); // Pause deposit - let res = contract - .contract - .set_paused_flags(PAUSE_DEPOSIT) + let res = owner_acc + .pa_pause_feature("deposit".to_string()) .max_gas() .transact() .await @@ -847,7 +856,7 @@ async fn test_deposit_pausability() { .user_deposit_with_proof(&user_acc, proof2) .await .unwrap_err(); - assert!(contract.check_error_message(&res, "ERR_PAUSED")); + assert!(contract.check_error_message(&res, "Pausable: Method is paused")); let proof3 = contract.mock_proof(user_acc.id(), 30, 3, 0); let res = contract @@ -857,9 +866,16 @@ async fn test_deposit_pausability() { assert!(res.is_success()); // Unpause all - let res = contract - .contract - .set_paused_flags(UNPAUSE_ALL) + let res = owner_acc + .pa_unpause_feature("withdraw".to_string()) + .max_gas() + .transact() + .await + .unwrap(); + assert!(res.is_success()); + + let res = owner_acc + .pa_unpause_feature("deposit".to_string()) .max_gas() .transact() .await @@ -878,8 +894,6 @@ async fn test_deposit_pausability() { #[tokio::test] async fn test_withdraw_from_near_pausability() { - use aurora_eth_connector::admin_controlled::{PAUSE_WITHDRAW, UNPAUSE_ALL}; - let contract = TestContract::new().await.unwrap(); contract.call_deposit_eth_to_near().await.unwrap(); contract.call_deposit_contract().await.unwrap(); @@ -910,7 +924,7 @@ async fn test_withdraw_from_near_pausability() { // Pause withdraw let res = contract .contract - .set_paused_flags(PAUSE_WITHDRAW) + .pa_pause_feature("withdraw".to_string()) .max_gas() .transact() .await @@ -925,12 +939,21 @@ async fn test_withdraw_from_near_pausability() { .transact() .await .unwrap_err(); - assert!(contract.check_error_message(&res, "WithdrawErrorPaused")); + assert!(contract.check_error_message(&res, "Pausable: Method is paused")); // Unpause all let res = contract .contract - .set_paused_flags(UNPAUSE_ALL) + .pa_unpause_feature("withdraw".to_string()) + .max_gas() + .transact() + .await + .unwrap(); + assert!(res.is_success()); + + let res = contract + .contract + .pa_unpause_feature("deposit".to_string()) .max_gas() .transact() .await @@ -1229,7 +1252,7 @@ async fn test_access_rights() { .transact() .await .unwrap_err(); - assert!(contract.check_error_message(&res, "ERR_ACCESS_RIGHT")); + assert!(contract.check_error_message(&res, "Method can be called only by aurora engine")); assert_eq!( DEPOSITED_AMOUNT + transfer_amount1.0, @@ -1261,8 +1284,7 @@ async fn test_access_rights() { .await .unwrap(); - let res = contract - .contract + let res = user_acc .engine_withdraw(contract.contract.id(), recipient_addr, withdraw_amount) .max_gas() .deposit(ONE_YOCTO) @@ -1350,7 +1372,7 @@ async fn test_engine_ft_transfer() { .transact() .await .unwrap_err(); - assert!(contract.check_error_message(&res, "ERR_ACCESS_RIGHT")); + assert!(contract.check_error_message(&res, "Method can be called only by aurora engine")); assert_eq!( DEPOSITED_AMOUNT, @@ -1428,7 +1450,7 @@ async fn test_engine_ft_transfer_call() { .transact() .await; if let Err(err) = res { - assert!(contract.check_error_message(&err, "ERR_ACCESS_RIGHT")); + assert!(contract.check_error_message(&err, "Method can be called only by aurora engine")); } assert_eq!( @@ -1493,7 +1515,7 @@ async fn test_engine_storage_deposit() { .transact() .await; if let Err(err) = res { - assert!(contract.check_error_message(&err, "ERR_ACCESS_RIGHT")); + assert!(contract.check_error_message(&err, "Method can be called only by aurora engine")); } contract @@ -1501,8 +1523,7 @@ async fn test_engine_storage_deposit() { .await .unwrap(); - let res = contract - .contract + let res = user_acc .engine_storage_deposit(user_acc.id(), Some(user_acc.id()), None) .max_gas() .deposit(NearToken::from_yoctonear(bounds.min.0)) @@ -1544,7 +1565,7 @@ async fn test_engine_storage_withdraw() { .transact() .await; if let Err(err) = res { - assert!(contract.check_error_message(&err, "ERR_ACCESS_RIGHT")); + assert!(contract.check_error_message(&err, "Method can be called only by aurora engine")); } contract @@ -1552,8 +1573,7 @@ async fn test_engine_storage_withdraw() { .await .unwrap(); - let res = contract - .contract + let res = user_acc .engine_storage_deposit(user_acc.id(), Some(user_acc.id()), None) .max_gas() .deposit(NearToken::from_yoctonear(bounds.min.0)) @@ -1596,15 +1616,14 @@ async fn test_engine_storage_unregister() { .transact() .await .unwrap_err(); - assert!(contract.check_error_message(&res, "ERR_ACCESS_RIGHT")); + assert!(contract.check_error_message(&res, "Method can be called only by aurora engine")); contract .set_and_check_access_right(user_acc.id()) .await .unwrap(); - let res = contract - .contract + let res = user_acc .engine_storage_deposit(user_acc.id(), Some(user_acc.id()), None) .max_gas() .deposit(NearToken::from_yoctonear(bounds.min.0)) @@ -1678,6 +1697,7 @@ async fn test_manage_engine_accounts() { .contract .remove_engine_account(&acc1) .max_gas() + .deposit(ONE_YOCTO) .transact() .await .unwrap(); diff --git a/eth-connector-tests/src/migration.rs b/eth-connector-tests/src/migration.rs index 9a0d86a..63a602a 100644 --- a/eth-connector-tests/src/migration.rs +++ b/eth-connector-tests/src/migration.rs @@ -123,10 +123,10 @@ async fn test_migration_state() { // INCREASED! // assert!(accounts_gas_burnt as f64 / 1_000_000_000_000. < 1520.); assert!( - to_tera(accounts_gas_burnt) < 1987., + to_tera(accounts_gas_burnt) < 1992., "{:?} < {:?}", to_tera(accounts_gas_burnt), - 1987. + 1992. ); total_gas_burnt += accounts_gas_burnt; diff --git a/eth-connector-tests/src/utils.rs b/eth-connector-tests/src/utils.rs index 0af29cc..b391da9 100644 --- a/eth-connector-tests/src/utils.rs +++ b/eth-connector-tests/src/utils.rs @@ -20,6 +20,8 @@ pub const DEPOSITED_EVM_FEE: u128 = 200; pub const DEPOSITED_EVM_AMOUNT: u128 = 10200; pub const CONTRACT_ACC: &str = "eth_connector.root"; +const ONE_YOCTO: NearToken = NearToken::from_yoctonear(near_sdk::ONE_YOCTO); + pub struct TestContract { pub contract: EthConnectorContract, pub root_account: Account, @@ -140,9 +142,12 @@ impl TestContract { .result) } - pub async fn call_deposit_eth_to_aurora(&self) -> anyhow::Result<()> { + pub async fn call_deposit_eth_to_aurora( + &self, + owner_acc: &EthConnectorContract, + ) -> anyhow::Result<()> { let proof = self.get_proof(PROOF_DATA_ETH); - let res = self.deposit_with_proof(&proof).await?; + let res = self.user_deposit_with_proof(owner_acc, proof).await?; assert!(res.is_success(), "call_deposit_eth_to_aurora: {res:#?}"); Ok(()) } @@ -200,23 +205,29 @@ impl TestContract { Ok(account_id) } - pub async fn set_and_check_access_right(&self, acc: &AccountId) -> anyhow::Result<()> { - let res = self - .contract - .set_access_right(&acc) + pub async fn user_set_and_check_access_right( + &self, + acc: &AccountId, + owner: &EthConnectorContract, + ) -> anyhow::Result<()> { + let res = owner + .set_aurora_engine_account_id(acc.to_string()) .max_gas() + .deposit(ONE_YOCTO) .transact() .await?; + if res.is_failure() { anyhow::bail!("set_access_right failed"); } let res: String = self .contract - .get_account_with_access_right() + .get_aurora_engine_account_id() .await? .result .into(); + let acc_id = AccountId::try_from(res.clone())?; if &acc_id != acc { @@ -225,11 +236,17 @@ impl TestContract { Ok(()) } + pub async fn set_and_check_access_right(&self, acc: &AccountId) -> anyhow::Result<()> { + self.user_set_and_check_access_right(acc, &self.contract) + .await + } + pub async fn set_engine_account(&self, engine_account: &AccountId) -> anyhow::Result<()> { let res = self .contract .set_engine_account(engine_account) .max_gas() + .deposit(ONE_YOCTO) .transact() .await .unwrap(); diff --git a/eth-connector/.catalog-info.yaml b/eth-connector/.catalog-info.yaml index d1f705f..87f453f 100644 --- a/eth-connector/.catalog-info.yaml +++ b/eth-connector/.catalog-info.yaml @@ -13,8 +13,8 @@ metadata: annotations: aurora.dev/security-tier: "1" spec: - owner: protocol-team + owner: bridge-team type: contract lifecycle: production - system: aurora-engine + system: bridge-connectors interactsWith: [] diff --git a/eth-connector/Cargo.toml b/eth-connector/Cargo.toml index e5bf19f..d1ee131 100644 --- a/eth-connector/Cargo.toml +++ b/eth-connector/Cargo.toml @@ -18,6 +18,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] aurora-engine-types = { workspace = true, features = ["impl-serde"] } near-contract-standards.workspace = true +near-plugins.workspace = true near-sdk.workspace = true byte-slice-cast.workspace = true diff --git a/eth-connector/src/admin_controlled.rs b/eth-connector/src/admin_controlled.rs deleted file mode 100644 index 659ae36..0000000 --- a/eth-connector/src/admin_controlled.rs +++ /dev/null @@ -1,133 +0,0 @@ -use near_sdk::AccountId; - -pub type PausedMask = u8; - -/// Admin control flow flag indicates that all control flow unpause (unblocked). -pub const UNPAUSE_ALL: PausedMask = 0; -/// Admin control flow flag indicates that the deposit is paused. -pub const PAUSE_DEPOSIT: PausedMask = 1 << 0; -/// Admin control flow flag indicates that withdrawal is paused. -pub const PAUSE_WITHDRAW: PausedMask = 1 << 1; - -pub trait AdminControlled { - /// Return the current mask representing all paused events. - fn get_paused_flags(&self) -> PausedMask; - - /// Update mask with all paused events. - /// Implementor is responsible for guaranteeing that this function can only be - /// called by owner of the contract. - fn set_paused_flags(&mut self, paused: PausedMask); - - /// Return if the contract is paused for the current flag. - /// If it's owner, result always `false` - unpaused. - fn is_paused(&self, flag: PausedMask) -> bool { - (self.get_paused_flags() & flag) != 0 && !self.is_owner() - } - - /// Asserts the passed paused flag is not set. Returns `PausedError` if paused. - /// - /// # Errors - /// - /// Error is returned if the smart contract is paused. - fn assert_not_paused(&self, flag: PausedMask) -> Result<(), error::AdminControlledError> { - if self.is_paused(flag) { - Err(error::AdminControlledError::Paused) - } else { - Ok(()) - } - } - - /// Set account access right for contract - fn set_access_right(&mut self, account: &AccountId); - - /// Get account access right for contract - fn get_account_with_access_right(&self) -> AccountId; - - /// Check access right for predecessor account - /// - /// # Errors - /// - /// Error is returned if the caller hasn't rights. - fn assert_access_right(&self) -> Result<(), error::AdminControlledError> { - if self.get_account_with_access_right() == near_sdk::env::predecessor_account_id() - || self.is_owner() - { - Ok(()) - } else { - Err(error::AdminControlledError::AccessRight) - } - } - - /// Assert only owners of contract access right - /// - /// # Errors - /// - /// Error is returned if the caller isn't owner. - fn assert_owner_access_right(&self) -> Result<(), error::AdminControlledError> { - if self.is_owner() { - Ok(()) - } else { - Err(error::AdminControlledError::AccessRight) - } - } - - /// Check is predecessor account ID is owner - fn is_owner(&self) -> bool; -} - -pub mod error { - pub const ERR_PAUSED: &[u8; 10] = b"ERR_PAUSED"; - pub const ERR_ACCESS_RIGHT: &[u8; 16] = b"ERR_ACCESS_RIGHT"; - - pub enum AdminControlledError { - Paused, - AccessRight, - } - - impl AsRef<[u8]> for AdminControlledError { - fn as_ref(&self) -> &[u8] { - match self { - Self::Paused => ERR_PAUSED, - Self::AccessRight => ERR_ACCESS_RIGHT, - } - } - } -} - -#[test] -fn test_pause_control() { - use crate::connector_impl::EthConnector; - - let mut connector = EthConnector { - prover_account: "prover".parse().unwrap(), - eth_custodian_address: aurora_engine_types::types::Address::default(), - paused_mask: UNPAUSE_ALL, - account_with_access_right: "aurora".parse().unwrap(), - owner_id: "aurora".parse().unwrap(), - min_proof_acceptance_height: 0, - }; - - assert!(connector.assert_not_paused(PAUSE_DEPOSIT).is_ok()); - assert!(connector.assert_not_paused(PAUSE_WITHDRAW).is_ok()); - - connector.set_paused_flags(PAUSE_DEPOSIT); - - assert!(connector.assert_not_paused(PAUSE_DEPOSIT).is_err()); - assert!(connector.assert_not_paused(PAUSE_WITHDRAW).is_ok()); - - connector.set_paused_flags(UNPAUSE_ALL); - connector.set_paused_flags(PAUSE_WITHDRAW); - - assert!(connector.assert_not_paused(PAUSE_DEPOSIT).is_ok()); - assert!(connector.assert_not_paused(PAUSE_WITHDRAW).is_err()); - - connector.set_paused_flags(PAUSE_WITHDRAW | PAUSE_DEPOSIT); - - assert!(connector.assert_not_paused(PAUSE_DEPOSIT).is_err()); - assert!(connector.assert_not_paused(PAUSE_WITHDRAW).is_err()); - - connector.set_paused_flags(UNPAUSE_ALL); - - assert!(connector.assert_not_paused(PAUSE_DEPOSIT).is_ok()); - assert!(connector.assert_not_paused(PAUSE_WITHDRAW).is_ok()); -} diff --git a/eth-connector/src/connector.rs b/eth-connector/src/connector.rs index 1bcd710..8b8b0e3 100644 --- a/eth-connector/src/connector.rs +++ b/eth-connector/src/connector.rs @@ -50,7 +50,7 @@ pub trait EngineConnectorWithdraw { } /// Engin compatible methods for NEP-141 -#[ext_contract(ext_enine_ft)] +#[ext_contract(ext_engine_ft)] pub trait EngineFungibleToken { fn engine_ft_transfer( &mut self, @@ -71,7 +71,7 @@ pub trait EngineFungibleToken { } /// Engin compatible methods for NEP-141 -#[ext_contract(ext_enine_storage)] +#[ext_contract(ext_engine_storage)] pub trait EngineStorageManagement { fn engine_storage_deposit( &mut self, diff --git a/eth-connector/src/connector_impl.rs b/eth-connector/src/connector_impl.rs index 4c4504f..506eb63 100644 --- a/eth-connector/src/connector_impl.rs +++ b/eth-connector/src/connector_impl.rs @@ -1,11 +1,9 @@ use crate::{ - admin_controlled::PAUSE_DEPOSIT, connector::{ext_funds_finish, ext_proof_verifier}, deposit_event::{DepositedEvent, TokenMessageData}, errors, log, panic_err, proof::{Proof, VerifyProofArgs}, types::SdkUnwrap, - AdminControlled, PausedMask, }; use aurora_engine_types::types::Address; use near_sdk::{ @@ -52,47 +50,17 @@ pub struct EthConnector { pub prover_account: AccountId, /// The ETH address is used in the Deposit and Withdraw logic. pub eth_custodian_address: Address, - /// Admin controlled. - pub paused_mask: PausedMask, /// Account with access right for the current contract. - pub account_with_access_right: AccountId, - /// Owner's account id. - pub owner_id: AccountId, + pub aurora_engine_account_id: AccountId, /// Proofs from blocks that are below the acceptance height will be rejected. // If `minBlockAcceptanceHeight` value is zero - proofs from block with any height are accepted. pub min_proof_acceptance_height: u64, } -impl AdminControlled for EthConnector { - fn get_paused_flags(&self) -> PausedMask { - self.paused_mask - } - - fn set_paused_flags(&mut self, paused: PausedMask) { - self.paused_mask = paused; - } - - fn set_access_right(&mut self, account: &AccountId) { - self.account_with_access_right = account.clone(); - } - - fn get_account_with_access_right(&self) -> AccountId { - self.account_with_access_right.clone() - } - - fn is_owner(&self) -> bool { - self.owner_id == env::predecessor_account_id() - || env::current_account_id() == env::predecessor_account_id() - } -} - impl EthConnector { pub(crate) fn deposit(&mut self, proof: Proof) -> Promise { let current_account_id = env::current_account_id(); - // Check is current flow paused. If it's owner account just skip it. - self.assert_not_paused(PAUSE_DEPOSIT).sdk_unwrap(); - log!("[Deposit tokens]"); // Fetch event data from Proof @@ -139,7 +107,7 @@ impl EthConnector { // account as the recipient when depositing to the EVM, // so here we override the receiver_id for backward compatibility. if receiver_id == current_account_id { - receiver_id = self.get_account_with_access_right(); + receiver_id = self.aurora_engine_account_id.clone(); } // Transfer to self and then transfer ETH in `ft_on_transfer` // address - is NEAR account diff --git a/eth-connector/src/deposit_event.rs b/eth-connector/src/deposit_event.rs index 7e60c49..ded28f1 100644 --- a/eth-connector/src/deposit_event.rs +++ b/eth-connector/src/deposit_event.rs @@ -3,7 +3,6 @@ use aurora_engine_types::{ types::{address::error::AddressError, Address, Fee, NEP141Wei}, U256, }; -use byte_slice_cast::AsByteSlice; use ethabi::{Event, EventParam, Hash, Log, ParamType, RawLog}; use near_sdk::{ borsh::{self, BorshDeserialize, BorshSerialize}, @@ -80,9 +79,10 @@ impl FtTransferMessageData { // The first data section should contain fee data. // Pay attention, that for compatibility reasons we used U256 type // it means 32 bytes for fee data - let mut data = U256::from(self.fee.as_u128()).as_byte_slice().to_vec(); + let mut data = [0; 52]; + U256::from(self.fee.as_u128()).to_little_endian(&mut data[..32]); // Second data section should contain Eth address - data.extend(self.recipient.as_bytes()); + data[32..].copy_from_slice(self.recipient.as_bytes()); // Add `:` separator between relayer_id and data message [self.relayer.as_ref(), &hex::encode(data)].join(":") } diff --git a/eth-connector/src/lib.rs b/eth-connector/src/lib.rs index 2b6008b..1ad5590 100644 --- a/eth-connector/src/lib.rs +++ b/eth-connector/src/lib.rs @@ -1,7 +1,6 @@ #![deny(clippy::pedantic, clippy::nursery)] #![allow(clippy::module_name_repetitions)] -use crate::admin_controlled::{AdminControlled, PausedMask, PAUSE_WITHDRAW, UNPAUSE_ALL}; use crate::connector::{ Deposit, EngineConnectorWithdraw, EngineFungibleToken, EngineStorageManagement, FundsFinish, KnownEngineAccountsManagement, Withdraw, @@ -20,6 +19,10 @@ use near_contract_standards::fungible_token::metadata::{ use near_contract_standards::fungible_token::receiver::ext_ft_receiver; use near_contract_standards::fungible_token::resolver::{ext_ft_resolver, FungibleTokenResolver}; use near_contract_standards::fungible_token::FungibleToken; +use near_plugins::{ + access_control, access_control_any, pause, AccessControlRole, AccessControllable, Pausable, + Upgradable, +}; use near_sdk::{ assert_one_yocto, borsh::{self, BorshDeserialize, BorshSerialize}, @@ -29,9 +32,9 @@ use near_sdk::{ near_bindgen, require, AccountId, Balance, BorshStorageKey, Gas, PanicOnDefault, Promise, PromiseOrValue, }; +use serde::{Deserialize, Serialize}; use std::collections::HashSet; -pub mod admin_controlled; pub mod connector; pub mod connector_impl; pub mod deposit_event; @@ -44,13 +47,39 @@ pub mod types; const GAS_FOR_RESOLVE_TRANSFER: Gas = Gas(5 * Gas::ONE_TERA.0); const GAS_FOR_FT_TRANSFER_CALL: Gas = Gas(25 * Gas::ONE_TERA.0 + GAS_FOR_RESOLVE_TRANSFER.0); +#[derive(BorshSerialize, BorshStorageKey)] +enum StorageKey { + FungibleToken = 0x1, + Proof = 0x2, + Metadata = 0x3, + EngineAccounts = 0x4, +} + +#[derive(AccessControlRole, Deserialize, Serialize, Copy, Clone)] +#[serde(crate = "near_sdk::serde")] +pub enum Role { + PauseManager, + UpgradableCodeStager, + UpgradableCodeDeployer, + DAO, +} + /// Eth-connector contract data. It's stored in the storage. /// Contains: /// * connector specific data /// * Fungible token data /// * paused_mask - admin control flow data #[near_bindgen] -#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)] +#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault, Pausable, Upgradable)] +#[access_control(role_type(Role))] +#[pausable(manager_roles(Role::PauseManager, Role::DAO))] +#[upgradable(access_control_roles( + code_stagers(Role::UpgradableCodeStager, Role::DAO), + code_deployers(Role::UpgradableCodeDeployer, Role::DAO), + duration_initializers(Role::DAO), + duration_update_stagers(Role::DAO), + duration_update_appliers(Role::DAO), +))] pub struct EthConnectorContract { connector: EthConnector, ft: FungibleToken, @@ -59,14 +88,6 @@ pub struct EthConnectorContract { known_engine_accounts: LookupSet, } -#[derive(BorshSerialize, BorshStorageKey)] -enum StorageKey { - FungibleToken = 0x1, - Proof = 0x2, - Metadata = 0x3, - EngineAccounts = 0x4, -} - impl EthConnectorContract { /// Mint `nETH` tokens fn mint_eth_on_near(&mut self, owner_id: &AccountId, amount: Balance) { @@ -143,9 +164,13 @@ impl EthConnectorContract { // to avoid verification panics inside `ft_on_transfer`. // Allowed empty message if `receiver_id != known_engin_accounts`. if self.known_engine_accounts.contains(&receiver_id) { - let _ = FtTransferMessageData::parse_on_transfer_message(&msg).sdk_unwrap(); + let _: FtTransferMessageData = + FtTransferMessageData::parse_on_transfer_message(&msg).sdk_unwrap(); } + let balance = self.ft.ft_balance_of(sender_id.clone()); + require!(balance.0 >= amount, "Insufficient sender balance"); + // Special case, we do not fail if `sender_id == receiver_id` // if `predecessor_account_id` call `ft_transfer_call` as receiver itself // to call `ft_on_transfer`. @@ -157,8 +182,6 @@ impl EthConnectorContract { amount > 0, "The amount should be a positive non zero number" ); - let balance = self.ft.ft_balance_of(sender_id.clone()); - require!(balance.0 >= amount, "Insufficient sender balance"); } else { self.ft .internal_transfer(&sender_id, &receiver_id, amount, memo); @@ -179,6 +202,14 @@ impl EthConnectorContract { ) .into() } + + // Check if predecessor account is the aurora engine + fn assert_aurora_engine_access_right(&self) { + require!( + env::predecessor_account_id() == self.connector.aurora_engine_account_id, + "Method can be called only by aurora engine" + ); + } } #[near_bindgen] @@ -196,15 +227,13 @@ impl EthConnectorContract { metadata.assert_valid(); // Get initial Eth Connector arguments - let paused_mask = UNPAUSE_ALL; let connector_data = EthConnector { prover_account, - paused_mask, eth_custodian_address, - account_with_access_right, - owner_id: owner_id.clone(), + aurora_engine_account_id: account_with_access_right, min_proof_acceptance_height, }; + let mut this = Self { ft: FungibleToken { accounts: near_sdk::collections::LookupMap::new(StorageKey::FungibleToken), @@ -218,6 +247,10 @@ impl EthConnectorContract { }; this.register_if_not_exists(&env::current_account_id()); this.register_if_not_exists(owner_id); + + this.acl_init_super_admin(env::predecessor_account_id()); + this.acl_grant_role("DAO".to_string(), owner_id.clone()); + this } @@ -248,17 +281,31 @@ impl EthConnectorContract { pub fn get_bridge_prover(&self) -> AccountId { self.connector.prover_account.clone() } + + #[payable] + #[access_control_any(roles(Role::DAO))] + pub fn set_aurora_engine_account_id(&mut self, new_aurora_engine_account_id: AccountId) { + assert_one_yocto(); + self.connector.aurora_engine_account_id = new_aurora_engine_account_id; + } + + #[must_use] + pub fn get_aurora_engine_account_id(&self) -> AccountId { + self.connector.aurora_engine_account_id.clone() + } } #[near_bindgen] impl FungibleTokenCore for EthConnectorContract { #[payable] + #[pause(except(roles(Role::DAO)))] fn ft_transfer(&mut self, receiver_id: AccountId, amount: U128, memo: Option) { self.ft.storage_deposit(Some(receiver_id.clone()), None); self.ft.ft_transfer(receiver_id, amount, memo); } #[payable] + #[pause(except(roles(Role::DAO)))] fn ft_transfer_call( &mut self, receiver_id: AccountId, @@ -293,6 +340,7 @@ impl FungibleTokenCore for EthConnectorContract { #[near_bindgen] impl EngineFungibleToken for EthConnectorContract { #[payable] + #[pause(name = "engine")] fn engine_ft_transfer( &mut self, sender_id: AccountId, @@ -300,8 +348,9 @@ impl EngineFungibleToken for EthConnectorContract { amount: U128, memo: Option, ) { - self.assert_access_right().sdk_unwrap(); + self.assert_aurora_engine_access_right(); self.ft.storage_deposit(Some(receiver_id.clone()), None); + assert_one_yocto(); let amount: Balance = amount.into(); self.ft @@ -309,6 +358,7 @@ impl EngineFungibleToken for EthConnectorContract { } #[payable] + #[pause(name = "engine")] fn engine_ft_transfer_call( &mut self, sender_id: AccountId, @@ -317,12 +367,13 @@ impl EngineFungibleToken for EthConnectorContract { memo: Option, msg: String, ) -> PromiseOrValue { + self.assert_aurora_engine_access_right(); + assert_one_yocto(); require!( env::prepaid_gas() > GAS_FOR_FT_TRANSFER_CALL, "More gas is required" ); - self.assert_access_right().sdk_unwrap(); self.ft.storage_deposit(Some(receiver_id.clone()), None); self.internal_ft_transfer_call(sender_id, receiver_id, amount, memo, msg) } @@ -331,13 +382,17 @@ impl EngineFungibleToken for EthConnectorContract { /// Management for a known Engine accounts #[near_bindgen] impl KnownEngineAccountsManagement for EthConnectorContract { + #[payable] + #[access_control_any(roles(Role::DAO))] fn set_engine_account(&mut self, engine_account: &AccountId) { - self.assert_access_right().sdk_unwrap(); + assert_one_yocto(); self.known_engine_accounts.insert(engine_account); } + #[payable] + #[access_control_any(roles(Role::DAO))] fn remove_engine_account(&mut self, engine_account: &AccountId) { - self.assert_access_right().sdk_unwrap(); + assert_one_yocto(); self.known_engine_accounts.remove(engine_account); } @@ -371,7 +426,13 @@ impl EthConnectorContract { if balance == 0 || force { self.ft.accounts.remove(&account_id); self.ft.total_supply -= balance; - Promise::new(account_id.clone()).transfer(self.storage_balance_bounds().min.0 + 1); + let withdraw_amount = self + .storage_balance_bounds() + .min + .0 + .checked_add(1) + .expect("Overflow in withdrawal amount calculation"); + Promise::new(account_id.clone()).transfer(withdraw_amount); Some((account_id, balance)) } else { env::panic_str( @@ -398,13 +459,15 @@ impl EngineStorageManagement for EthConnectorContract { /// If the attached deposit is less then the balance of the smart contract. #[allow(unused_variables)] #[payable] + #[pause(name = "engine")] fn engine_storage_deposit( &mut self, sender_id: AccountId, account_id: Option, registration_only: Option, ) -> StorageBalance { - self.assert_access_right().sdk_unwrap(); + self.assert_aurora_engine_access_right(); + let amount: Balance = env::attached_deposit(); let account_id = account_id.unwrap_or_else(|| sender_id.clone()); if self.ft.accounts.contains_key(&account_id) { @@ -428,12 +491,14 @@ impl EngineStorageManagement for EthConnectorContract { } #[payable] + #[pause(name = "engine")] fn engine_storage_withdraw( &mut self, sender_id: AccountId, amount: Option, ) -> StorageBalance { - self.assert_access_right().sdk_unwrap(); + self.assert_aurora_engine_access_right(); + assert_one_yocto(); let predecessor_account_id = sender_id; self.internal_storage_balance_of(&predecessor_account_id) @@ -454,8 +519,10 @@ impl EngineStorageManagement for EthConnectorContract { } #[payable] + #[pause(name = "engine")] fn engine_storage_unregister(&mut self, sender_id: AccountId, force: Option) -> bool { - self.assert_access_right().sdk_unwrap(); + self.assert_aurora_engine_access_right(); + self.internal_storage_unregister(sender_id, force).is_some() } } @@ -490,36 +557,11 @@ impl FungibleTokenMetadataProvider for EthConnectorContract { } } -#[near_bindgen] -impl AdminControlled for EthConnectorContract { - #[result_serializer(borsh)] - fn get_paused_flags(&self) -> PausedMask { - self.connector.get_paused_flags() - } - - fn set_paused_flags(&mut self, #[serializer(borsh)] paused: PausedMask) { - self.connector.assert_owner_access_right().sdk_unwrap(); - self.connector.set_paused_flags(paused); - } - - fn set_access_right(&mut self, account: &AccountId) { - self.connector.assert_owner_access_right().sdk_unwrap(); - self.connector.set_access_right(account); - } - - fn get_account_with_access_right(&self) -> AccountId { - self.connector.get_account_with_access_right() - } - - fn is_owner(&self) -> bool { - self.connector.is_owner() - } -} - #[near_bindgen] impl Withdraw for EthConnectorContract { #[payable] #[result_serializer(borsh)] + #[pause(except(roles(Role::DAO)))] fn withdraw( &mut self, #[serializer(borsh)] recipient_address: Address, @@ -527,11 +569,6 @@ impl Withdraw for EthConnectorContract { ) -> WithdrawResult { assert_one_yocto(); - // Check is current flow paused. If it's owner just skip assertion. - self.assert_not_paused(PAUSE_WITHDRAW) - .map_err(|_| "WithdrawErrorPaused") - .sdk_unwrap(); - let sender_id = env::predecessor_account_id(); // Burn tokens to recipient self.ft.internal_withdraw(&sender_id, amount); @@ -547,19 +584,17 @@ impl Withdraw for EthConnectorContract { impl EngineConnectorWithdraw for EthConnectorContract { #[payable] #[result_serializer(borsh)] + #[pause] fn engine_withdraw( &mut self, #[serializer(borsh)] sender_id: AccountId, #[serializer(borsh)] recipient_address: Address, #[serializer(borsh)] amount: Balance, ) -> WithdrawResult { - self.assert_access_right().sdk_unwrap(); + self.assert_aurora_engine_access_right(); + assert_one_yocto(); - // Check is current flow paused. If it's owner just skip assertion. - self.assert_not_paused(PAUSE_WITHDRAW) - .map_err(|_| "WithdrawErrorPaused") - .sdk_unwrap(); // Burn tokens to recipient self.ft.internal_withdraw(&sender_id, amount); WithdrawResult { @@ -573,6 +608,7 @@ impl EngineConnectorWithdraw for EthConnectorContract { #[near_bindgen] impl Deposit for EthConnectorContract { #[payable] + #[pause(except(roles(Role::DAO)))] fn deposit(&mut self, #[serializer(borsh)] proof: Proof) -> Promise { self.connector.deposit(proof) } @@ -749,7 +785,7 @@ mod tests { fn test_storage_balance_bounds() { let contract = create_contract(); let storage_balance = contract - .storage_balance_of(contract.connector.owner_id.clone()) + .storage_balance_of(contract.acl_get_grantees("DAO".to_string(), 0, 1)[0].clone()) .unwrap(); assert_eq!(storage_balance.total.0, 0); assert_eq!(storage_balance.available.0, 0); diff --git a/rust-toolchain b/rust-toolchain index 27c161a..5482513 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,5 @@ [toolchain] channel = "1.74.1" -components = ["minimal", "rustfmt", "clippy"] +components = ["rustfmt", "clippy"] targets = ["wasm32-unknown-unknown"] +profile = "minimal"