@layerzerolabs/protocol-stellar-v2 0.2.9 → 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +245 -199
- package/.turbo/turbo-lint.log +79 -107
- package/.turbo/turbo-test.log +1017 -841
- package/Cargo.lock +13 -5
- package/contracts/common-macros/src/contract_impl.rs +6 -3
- package/contracts/common-macros/src/error.rs +9 -17
- package/contracts/common-macros/src/event.rs +4 -4
- package/contracts/common-macros/src/lib.rs +2 -2
- package/contracts/common-macros/src/ownable.rs +9 -5
- package/contracts/common-macros/src/tests/contract_impl.rs +178 -86
- package/contracts/common-macros/src/tests/error.rs +168 -0
- package/contracts/common-macros/src/tests/mod.rs +2 -4
- package/contracts/common-macros/src/tests/ownable.rs +37 -60
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__contract_impl__snapshot_generated_contract_impl_code.snap +16 -6
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__error__snapshot_generated_contract_error_code.snap +20 -0
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ownable__snapshot_generated_ownable_code.snap +3 -1
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ownable__snapshot_only_owner_preserves_function_signature.snap +12 -2
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ttl_configurable__snapshot_generated_ttl_configurable_code.snap +5 -1
- package/contracts/common-macros/src/tests/utils.rs +267 -0
- package/contracts/common-macros/src/ttl_configurable.rs +15 -12
- package/contracts/common-macros/src/utils.rs +35 -6
- package/contracts/message-libs/uln-302/src/receive_uln.rs +1 -1
- package/contracts/message-libs/uln-302/src/send_uln.rs +2 -2
- package/contracts/message-libs/uln-302/src/uln302.rs +2 -2
- package/contracts/oapp-macros/src/oapp_core.rs +1 -1
- package/contracts/oapps/oft/integration-tests/setup.rs +4 -3
- package/contracts/oapps/oft/src/default_oft_impl.rs +146 -0
- package/contracts/oapps/oft/src/extensions/mod.rs +3 -0
- package/contracts/oapps/oft/src/extensions/oft_fee.rs +164 -0
- package/contracts/oapps/oft/src/extensions/pausable.rs +50 -0
- package/contracts/oapps/oft/src/extensions/rate_limiter.rs +198 -0
- package/contracts/oapps/oft/src/lib.rs +2 -3
- package/contracts/oapps/oft/src/oft.rs +16 -85
- package/contracts/oapps/oft/src/oft_types/mint_burn.rs +1 -1
- package/contracts/oapps/oft/src/tests/extensions/mod.rs +11 -0
- package/contracts/oapps/oft/src/tests/extensions/setup.rs +888 -0
- package/contracts/oapps/oft/src/tests/extensions/test_oft_fee.rs +749 -0
- package/contracts/oapps/oft/src/tests/extensions/test_pausable.rs +432 -0
- package/contracts/oapps/oft/src/tests/extensions/test_rate_limiter.rs +1078 -0
- package/contracts/oapps/oft/src/tests/mod.rs +2 -0
- package/contracts/oapps/oft/src/tests/test_utils.rs +24 -6
- package/contracts/oapps/{oft-mint-burn → oft-std}/Cargo.toml +1 -8
- package/contracts/oapps/oft-std/src/lib.rs +5 -0
- package/contracts/oapps/oft-std/src/oft.rs +59 -0
- package/contracts/utils/src/ownable.rs +2 -2
- package/contracts/utils/src/tests/ownable.rs +0 -63
- package/contracts/utils/src/ttl.rs +19 -1
- package/contracts/workers/dvn/src/auth.rs +91 -27
- package/contracts/workers/dvn/src/dvn.rs +22 -20
- package/contracts/workers/dvn/src/interfaces/dvn.rs +48 -3
- package/contracts/workers/dvn/src/interfaces/multisig.rs +41 -0
- package/contracts/workers/dvn/src/lib.rs +6 -8
- package/contracts/workers/dvn/src/multisig.rs +6 -3
- package/contracts/workers/dvn/src/tests/auth.rs +1 -1
- package/contracts/workers/dvn/src/tests/dvn.rs +3 -4
- package/contracts/workers/dvn-fee-lib/Cargo.toml +2 -1
- package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +4 -3
- package/contracts/workers/dvn-fee-lib/src/tests/dvn_fee_lib.rs +8 -6
- package/contracts/workers/executor/src/interfaces/executor.rs +5 -2
- package/contracts/workers/executor/src/lz_executor.rs +6 -6
- package/contracts/workers/price-feed/Cargo.toml +21 -0
- package/contracts/workers/price-feed/src/errors.rs +9 -0
- package/contracts/workers/price-feed/src/events.rs +30 -0
- package/contracts/workers/price-feed/src/lib.rs +11 -0
- package/contracts/workers/price-feed/src/price_feed.rs +265 -0
- package/contracts/workers/price-feed/src/storage.rs +42 -0
- package/contracts/workers/price-feed/src/types.rs +59 -0
- package/contracts/workers/worker/src/interfaces/dvn_fee_lib.rs +2 -1
- package/package.json +3 -3
- package/sdk/dist/generated/bml.js +3 -1
- package/sdk/dist/generated/counter.d.ts +102 -0
- package/sdk/dist/generated/counter.js +13 -1
- package/sdk/dist/generated/endpoint.js +3 -1
- package/sdk/dist/generated/sml.js +3 -1
- package/sdk/dist/generated/uln302.js +3 -1
- package/sdk/package.json +1 -1
- package/contracts/oapps/oft/src/macro_tests/mod.rs +0 -2
- package/contracts/oapps/oft/src/macro_tests/test_all_default.rs +0 -41
- package/contracts/oapps/oft/src/macro_tests/test_override.rs +0 -83
- package/contracts/oapps/oft-mint-burn/src/lib.rs +0 -3
- package/contracts/oapps/oft-mint-burn/src/oft.rs +0 -28
- package/contracts/oapps/oft-mint-burn/src/tests/mod.rs +0 -1
- package/contracts/workers/dvn/src/types.rs +0 -26
package/Cargo.lock
CHANGED
|
@@ -613,6 +613,7 @@ dependencies = [
|
|
|
613
613
|
"common-macros",
|
|
614
614
|
"message-lib-common",
|
|
615
615
|
"soroban-sdk",
|
|
616
|
+
"utils",
|
|
616
617
|
"worker",
|
|
617
618
|
]
|
|
618
619
|
|
|
@@ -1176,18 +1177,14 @@ dependencies = [
|
|
|
1176
1177
|
]
|
|
1177
1178
|
|
|
1178
1179
|
[[package]]
|
|
1179
|
-
name = "oft-
|
|
1180
|
+
name = "oft-std"
|
|
1180
1181
|
version = "0.0.1"
|
|
1181
1182
|
dependencies = [
|
|
1182
|
-
"assert_unordered",
|
|
1183
1183
|
"common-macros",
|
|
1184
1184
|
"endpoint-v2",
|
|
1185
|
-
"executor",
|
|
1186
|
-
"message-lib-common",
|
|
1187
1185
|
"oapp",
|
|
1188
1186
|
"oapp-macros",
|
|
1189
1187
|
"oft",
|
|
1190
|
-
"simple-message-lib",
|
|
1191
1188
|
"soroban-sdk",
|
|
1192
1189
|
"utils",
|
|
1193
1190
|
]
|
|
@@ -1257,6 +1254,17 @@ dependencies = [
|
|
|
1257
1254
|
"syn 2.0.108",
|
|
1258
1255
|
]
|
|
1259
1256
|
|
|
1257
|
+
[[package]]
|
|
1258
|
+
name = "price-feed"
|
|
1259
|
+
version = "0.0.1"
|
|
1260
|
+
dependencies = [
|
|
1261
|
+
"common-macros",
|
|
1262
|
+
"endpoint-v2",
|
|
1263
|
+
"soroban-sdk",
|
|
1264
|
+
"utils",
|
|
1265
|
+
"worker",
|
|
1266
|
+
]
|
|
1267
|
+
|
|
1260
1268
|
[[package]]
|
|
1261
1269
|
name = "primeorder"
|
|
1262
1270
|
version = "0.13.6"
|
|
@@ -18,12 +18,15 @@ pub fn contract_impl(attr: TokenStream, input: TokenStream) -> TokenStream {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
// Skip methods without Env parameter
|
|
21
|
-
let Some(
|
|
21
|
+
let Some(env_param) = utils::find_env_param(&method.sig.inputs) else { continue };
|
|
22
|
+
|
|
23
|
+
// Get a reference to env (handles both `Env` and `&Env` parameter types)
|
|
24
|
+
let env_ref = env_param.as_ref_tokens();
|
|
25
|
+
let env_ident = env_param.ident;
|
|
22
26
|
|
|
23
|
-
// TODO: should support Env instead of &Env?
|
|
24
27
|
// Use fully qualified syntax to call ttl_configs from TtlConfigurable trait
|
|
25
28
|
let extend_ttl_stmt = parse_quote! {
|
|
26
|
-
if let Some(instance_ttl) = utils::ttl::TtlConfigStorage::instance(#
|
|
29
|
+
if let Some(instance_ttl) = utils::ttl::TtlConfigStorage::instance(#env_ref) {
|
|
27
30
|
#env_ident.storage().instance().extend_ttl(instance_ttl.threshold, instance_ttl.extend_to);
|
|
28
31
|
}
|
|
29
32
|
};
|
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
use
|
|
1
|
+
use proc_macro2::TokenStream;
|
|
2
2
|
use quote::quote;
|
|
3
|
-
use syn::{
|
|
4
|
-
|
|
5
|
-
/// The default starting value for error enum discriminants when no explicit value is provided.
|
|
6
|
-
/// This ensures error codes start from 1 instead of 0.
|
|
7
|
-
const DEFAULT_OFFSET: u32 = 1;
|
|
3
|
+
use syn::{parse_quote, spanned::Spanned, ExprLit, Fields, ItemEnum, Lit, Token};
|
|
8
4
|
|
|
9
5
|
pub fn generate_error(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
10
6
|
assert!(attr.is_empty(), "contract_error attribute is not supported");
|
|
11
7
|
|
|
12
|
-
let mut data_enum =
|
|
8
|
+
let mut data_enum: ItemEnum = syn::parse2(item).unwrap_or_else(|e| panic!("failed to parse enum: {}", e));
|
|
13
9
|
|
|
14
|
-
|
|
10
|
+
// For variants without an explicit discriminant, assign sequential error codes starting at 1
|
|
11
|
+
// (by initializing the counter to 0 and incrementing before assignment).
|
|
12
|
+
let mut current_value = 0;
|
|
15
13
|
for variant in &mut data_enum.variants {
|
|
16
14
|
assert!(matches!(variant.fields, Fields::Unit), "Error enum variants must be unit variants");
|
|
17
15
|
|
|
@@ -19,15 +17,12 @@ pub fn generate_error(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
|
19
17
|
if let Some((_, disc)) = &variant.discriminant {
|
|
20
18
|
// Explicit discriminant - validate it's greater than previous and update counter
|
|
21
19
|
let val = parse_discriminant_value(disc);
|
|
22
|
-
assert!(
|
|
23
|
-
|
|
24
|
-
"Error enum discriminant must be greater than or equal to the previous discriminant"
|
|
25
|
-
);
|
|
26
|
-
current_value = val + 1;
|
|
20
|
+
assert!(val > current_value, "Error enum discriminant must be greater than the previous discriminant");
|
|
21
|
+
current_value = val;
|
|
27
22
|
} else {
|
|
28
23
|
// No discriminant - assign the next sequential value
|
|
29
|
-
variant.discriminant = Some((Token), parse_quote!(#current_value)));
|
|
30
24
|
current_value += 1;
|
|
25
|
+
variant.discriminant = Some((Token), parse_quote!(#current_value)));
|
|
31
26
|
}
|
|
32
27
|
}
|
|
33
28
|
|
|
@@ -37,7 +32,6 @@ pub fn generate_error(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
|
37
32
|
#[repr(u32)]
|
|
38
33
|
#data_enum
|
|
39
34
|
}
|
|
40
|
-
.into()
|
|
41
35
|
}
|
|
42
36
|
|
|
43
37
|
/// Parses a discriminant value from a variant, returning the u32 value if valid.
|
|
@@ -49,5 +43,3 @@ fn parse_discriminant_value(disc: &syn::Expr) -> u32 {
|
|
|
49
43
|
panic!("Error enum discriminant must be an integer literal")
|
|
50
44
|
}
|
|
51
45
|
}
|
|
52
|
-
|
|
53
|
-
// TODO: add test for this
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
use
|
|
1
|
+
use proc_macro2::TokenStream;
|
|
2
2
|
use quote::quote;
|
|
3
|
-
use syn::
|
|
3
|
+
use syn::DeriveInput;
|
|
4
4
|
|
|
5
5
|
pub fn generate_event(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
6
|
-
let input =
|
|
6
|
+
let input: DeriveInput = syn::parse2(item).unwrap_or_else(|e| panic!("failed to parse input: {}", e));
|
|
7
7
|
let struct_name = input.ident.to_string();
|
|
8
8
|
|
|
9
9
|
let expanded = quote! {
|
|
@@ -12,5 +12,5 @@ pub fn generate_event(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
|
12
12
|
#input
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
expanded
|
|
16
16
|
}
|
|
@@ -115,7 +115,7 @@ pub fn storage(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
|
115
115
|
/// ```
|
|
116
116
|
#[proc_macro_attribute]
|
|
117
117
|
pub fn event(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
118
|
-
event::generate_event(attr, item)
|
|
118
|
+
event::generate_event(attr.into(), item.into()).into()
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
// ============================================================================
|
|
@@ -149,7 +149,7 @@ pub fn event(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
|
149
149
|
/// ```
|
|
150
150
|
#[proc_macro_attribute]
|
|
151
151
|
pub fn contract_error(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
152
|
-
error::generate_error(attr, item)
|
|
152
|
+
error::generate_error(attr.into(), item.into()).into()
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
// ============================================================================
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
use crate::utils
|
|
1
|
+
use crate::utils;
|
|
2
2
|
use proc_macro2::TokenStream;
|
|
3
3
|
use quote::{quote, ToTokens};
|
|
4
4
|
use syn::{parse_quote, ItemFn, ItemStruct};
|
|
@@ -20,16 +20,18 @@ pub fn generate_ownable_impl(input: TokenStream) -> TokenStream {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/// Implement the Ownable trait for the contract.
|
|
23
|
-
#[
|
|
23
|
+
#[common_macros::contract_impl]
|
|
24
24
|
impl utils::ownable::Ownable for #name {
|
|
25
25
|
fn owner(env: &soroban_sdk::Env) -> Option<soroban_sdk::Address> {
|
|
26
26
|
utils::ownable::DefaultOwnable::owner(env)
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
#[common_macros::only_owner]
|
|
29
30
|
fn transfer_ownership(env: &soroban_sdk::Env, new_owner: &soroban_sdk::Address) {
|
|
30
31
|
utils::ownable::DefaultOwnable::transfer_ownership(env, new_owner)
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
#[common_macros::only_owner]
|
|
33
35
|
fn renounce_ownership(env: &soroban_sdk::Env) {
|
|
34
36
|
utils::ownable::DefaultOwnable::renounce_ownership(env)
|
|
35
37
|
}
|
|
@@ -46,10 +48,12 @@ pub fn generate_ownable_impl(input: TokenStream) -> TokenStream {
|
|
|
46
48
|
pub fn prepend_only_owner_check(input: TokenStream) -> TokenStream {
|
|
47
49
|
let mut input_fn: ItemFn = syn::parse2(input).unwrap_or_else(|e| panic!("failed to parse function: {}", e));
|
|
48
50
|
|
|
49
|
-
let
|
|
51
|
+
let env_param = utils::expect_env_param(&input_fn.sig.inputs);
|
|
52
|
+
|
|
53
|
+
// Get a reference to env (handles both `Env` and `&Env` parameter types)
|
|
54
|
+
let env_ref = env_param.as_ref_tokens();
|
|
50
55
|
|
|
51
|
-
// TODO: should support Env instead of &Env?
|
|
52
56
|
// Insert the owner authentication check at the beginning of the function body
|
|
53
|
-
input_fn.block.stmts.insert(0, parse_quote!(utils::ownable::require_owner_auth::<Self>(#
|
|
57
|
+
input_fn.block.stmts.insert(0, parse_quote!(utils::ownable::require_owner_auth::<Self>(#env_ref);));
|
|
54
58
|
input_fn.into_token_stream()
|
|
55
59
|
}
|
|
@@ -30,7 +30,7 @@ fn snapshot_generated_contract_impl_code() {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/// Public method with Env not as first parameter - should have TTL extension
|
|
33
|
-
pub fn env_second(value: u32, env: Env) -> u32 {
|
|
33
|
+
pub fn env_second(value: u32, env: &Env) -> u32 {
|
|
34
34
|
value * 2
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -67,6 +67,12 @@ fn snapshot_generated_contract_impl_code() {
|
|
|
67
67
|
fn trait_method_without_env(value: u32) -> u32 {
|
|
68
68
|
value * 4
|
|
69
69
|
}
|
|
70
|
+
|
|
71
|
+
/// Trait method with macro attribute - should have TTL extension
|
|
72
|
+
#[common_macros::only_owner]
|
|
73
|
+
fn trait_method_with_only_owner_attribute(env: Env, value: u32) -> u32 {
|
|
74
|
+
value * 5
|
|
75
|
+
}
|
|
70
76
|
}
|
|
71
77
|
};
|
|
72
78
|
|
|
@@ -79,7 +85,7 @@ fn snapshot_generated_contract_impl_code() {
|
|
|
79
85
|
let contracttrait_input = quote! {
|
|
80
86
|
impl AnotherTrait for MyContract {
|
|
81
87
|
/// Trait method with contracttrait attr - should have TTL extension
|
|
82
|
-
fn contracttrait_method(env: Env, value: u32) -> u32 {
|
|
88
|
+
fn contracttrait_method(env: &Env, value: u32) -> u32 {
|
|
83
89
|
value * 3
|
|
84
90
|
}
|
|
85
91
|
}
|
|
@@ -193,97 +199,183 @@ fn test_adds_soroban_contractimpl_attribute_with_attr() {
|
|
|
193
199
|
);
|
|
194
200
|
}
|
|
195
201
|
|
|
196
|
-
///
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
202
|
+
/// Expected TTL extension behavior for a test case
|
|
203
|
+
#[derive(Clone)]
|
|
204
|
+
enum TtlExpectation {
|
|
205
|
+
/// TTL extension should NOT be inserted
|
|
206
|
+
None,
|
|
207
|
+
/// TTL extension should be inserted with the given env patterns
|
|
208
|
+
/// - `instance_arg`: pattern in `TtlConfigStorage::instance(...)` (e.g., "& env" for owned, "env" for ref)
|
|
209
|
+
/// - `storage_ident`: identifier for `.storage()` call
|
|
210
|
+
Present { instance_arg: &'static str, storage_ident: &'static str },
|
|
211
|
+
}
|
|
200
212
|
|
|
201
|
-
|
|
213
|
+
struct TtlTestCase {
|
|
214
|
+
name: &'static str,
|
|
215
|
+
input: TokenStream,
|
|
216
|
+
expectation: TtlExpectation,
|
|
217
|
+
}
|
|
202
218
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
219
|
+
impl TtlTestCase {
|
|
220
|
+
fn expect_ttl(
|
|
221
|
+
name: &'static str,
|
|
222
|
+
input: TokenStream,
|
|
223
|
+
instance_arg: &'static str,
|
|
224
|
+
storage_ident: &'static str,
|
|
225
|
+
) -> Self {
|
|
226
|
+
Self { name, input, expectation: TtlExpectation::Present { instance_arg, storage_ident } }
|
|
227
|
+
}
|
|
211
228
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
229
|
+
fn expect_no_ttl(name: &'static str, input: TokenStream) -> Self {
|
|
230
|
+
Self { name, input, expectation: TtlExpectation::None }
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
fn run(&self) {
|
|
234
|
+
let result = crate::contract_impl::contract_impl(TokenStream::new(), self.input.clone());
|
|
235
|
+
let result_str = result.to_string();
|
|
236
|
+
let has_ttl = result_str.contains("TtlConfigStorage :: instance");
|
|
237
|
+
|
|
238
|
+
match &self.expectation {
|
|
239
|
+
TtlExpectation::None => {
|
|
240
|
+
assert!(!has_ttl, "{}: TTL extension should NOT be present, but was found", self.name);
|
|
241
|
+
}
|
|
242
|
+
TtlExpectation::Present { instance_arg, storage_ident } => {
|
|
243
|
+
assert!(has_ttl, "{}: TTL extension should be present, but was not found", self.name);
|
|
244
|
+
assert!(result_str.contains("extend_ttl"), "{}: should insert extend_ttl call", self.name);
|
|
245
|
+
|
|
246
|
+
let instance_pattern = format!("TtlConfigStorage :: instance ({})", instance_arg);
|
|
247
|
+
assert!(
|
|
248
|
+
result_str.contains(&instance_pattern),
|
|
249
|
+
"{}: expected '{}' in TtlConfigStorage::instance call. Got: {}",
|
|
250
|
+
self.name,
|
|
251
|
+
instance_arg,
|
|
252
|
+
result_str
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
let storage_pattern = format!("{} . storage ()", storage_ident);
|
|
256
|
+
assert!(
|
|
257
|
+
result_str.contains(&storage_pattern),
|
|
258
|
+
"{}: expected '{}.storage()' call",
|
|
259
|
+
self.name,
|
|
260
|
+
storage_ident
|
|
261
|
+
);
|
|
262
|
+
}
|
|
226
263
|
}
|
|
227
264
|
}
|
|
228
265
|
}
|
|
229
266
|
|
|
230
267
|
#[test]
|
|
231
|
-
fn
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
(
|
|
245
|
-
"private method with Env",
|
|
246
|
-
quote! {
|
|
247
|
-
impl MyContract {
|
|
248
|
-
fn private_method(env: Env) { let x = 1; }
|
|
249
|
-
}
|
|
250
|
-
},
|
|
251
|
-
false,
|
|
252
|
-
None,
|
|
253
|
-
),
|
|
254
|
-
(
|
|
255
|
-
"public method without Env",
|
|
256
|
-
quote! {
|
|
257
|
-
impl MyContract {
|
|
258
|
-
pub fn no_env_method(value: u32) -> u32 { value }
|
|
259
|
-
}
|
|
260
|
-
},
|
|
261
|
-
false,
|
|
262
|
-
None,
|
|
263
|
-
),
|
|
264
|
-
(
|
|
265
|
-
"custom Env identifier",
|
|
266
|
-
quote! {
|
|
267
|
-
impl MyContract {
|
|
268
|
-
pub fn my_method(my_custom_env: Env) { let x = 1; }
|
|
269
|
-
}
|
|
270
|
-
},
|
|
271
|
-
true,
|
|
272
|
-
Some("my_custom_env"),
|
|
273
|
-
),
|
|
274
|
-
(
|
|
275
|
-
"trait impl method with Env",
|
|
276
|
-
quote! {
|
|
277
|
-
impl SomeTrait for MyContract {
|
|
278
|
-
fn trait_method(env: Env) { let x = 1; }
|
|
279
|
-
}
|
|
280
|
-
},
|
|
281
|
-
true,
|
|
282
|
-
Some("env"),
|
|
283
|
-
),
|
|
284
|
-
];
|
|
268
|
+
fn test_ttl_extension_with_owned_env() {
|
|
269
|
+
TtlTestCase::expect_ttl(
|
|
270
|
+
"public method with owned Env",
|
|
271
|
+
quote! {
|
|
272
|
+
impl MyContract {
|
|
273
|
+
pub fn my_method(env: Env) { let x = 1; }
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
"& env", // instance takes reference
|
|
277
|
+
"env", // storage called on ident
|
|
278
|
+
)
|
|
279
|
+
.run();
|
|
280
|
+
}
|
|
285
281
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
282
|
+
#[test]
|
|
283
|
+
fn test_ttl_extension_with_ref_env() {
|
|
284
|
+
TtlTestCase::expect_ttl(
|
|
285
|
+
"public method with ref Env",
|
|
286
|
+
quote! {
|
|
287
|
+
impl MyContract {
|
|
288
|
+
pub fn my_method(env: &Env) { let x = 1; }
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
"env", // instance takes ident directly (already a ref)
|
|
292
|
+
"env",
|
|
293
|
+
)
|
|
294
|
+
.run();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
#[test]
|
|
298
|
+
fn test_ttl_extension_with_custom_env_ident_owned() {
|
|
299
|
+
TtlTestCase::expect_ttl(
|
|
300
|
+
"custom Env identifier (owned)",
|
|
301
|
+
quote! {
|
|
302
|
+
impl MyContract {
|
|
303
|
+
pub fn my_method(my_custom_env: Env) { let x = 1; }
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
"& my_custom_env",
|
|
307
|
+
"my_custom_env",
|
|
308
|
+
)
|
|
309
|
+
.run();
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
#[test]
|
|
313
|
+
fn test_ttl_extension_with_custom_env_ident_ref() {
|
|
314
|
+
TtlTestCase::expect_ttl(
|
|
315
|
+
"custom Env identifier (ref)",
|
|
316
|
+
quote! {
|
|
317
|
+
impl MyContract {
|
|
318
|
+
pub fn my_method(my_custom_env: &Env) { let x = 1; }
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
"my_custom_env",
|
|
322
|
+
"my_custom_env",
|
|
323
|
+
)
|
|
324
|
+
.run();
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
#[test]
|
|
328
|
+
fn test_ttl_extension_for_trait_impl_owned_env() {
|
|
329
|
+
TtlTestCase::expect_ttl(
|
|
330
|
+
"trait impl method with owned Env",
|
|
331
|
+
quote! {
|
|
332
|
+
impl SomeTrait for MyContract {
|
|
333
|
+
fn trait_method(env: Env) { let x = 1; }
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
"& env",
|
|
337
|
+
"env",
|
|
338
|
+
)
|
|
339
|
+
.run();
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
#[test]
|
|
343
|
+
fn test_ttl_extension_for_trait_impl_ref_env() {
|
|
344
|
+
TtlTestCase::expect_ttl(
|
|
345
|
+
"trait impl method with ref Env",
|
|
346
|
+
quote! {
|
|
347
|
+
impl SomeTrait for MyContract {
|
|
348
|
+
fn trait_method(env: &Env) { let x = 1; }
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
"env",
|
|
352
|
+
"env",
|
|
353
|
+
)
|
|
354
|
+
.run();
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
#[test]
|
|
358
|
+
fn test_no_ttl_extension_for_private_method() {
|
|
359
|
+
TtlTestCase::expect_no_ttl(
|
|
360
|
+
"private method with Env",
|
|
361
|
+
quote! {
|
|
362
|
+
impl MyContract {
|
|
363
|
+
fn private_method(env: Env) { let x = 1; }
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
)
|
|
367
|
+
.run();
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
#[test]
|
|
371
|
+
fn test_no_ttl_extension_without_env_param() {
|
|
372
|
+
TtlTestCase::expect_no_ttl(
|
|
373
|
+
"public method without Env",
|
|
374
|
+
quote! {
|
|
375
|
+
impl MyContract {
|
|
376
|
+
pub fn no_env_method(value: u32) -> u32 { value }
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
)
|
|
380
|
+
.run();
|
|
289
381
|
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
use quote::quote;
|
|
2
|
+
|
|
3
|
+
use crate::tests::test_helpers::{assert_panics_contains, non_enum_item_inputs};
|
|
4
|
+
|
|
5
|
+
// ============================================
|
|
6
|
+
// Error Cases: Invalid Inputs
|
|
7
|
+
// ============================================
|
|
8
|
+
|
|
9
|
+
#[test]
|
|
10
|
+
fn test_contract_error_rejects_non_enum_inputs() {
|
|
11
|
+
for (case, input) in non_enum_item_inputs() {
|
|
12
|
+
assert_panics_contains(case, "failed to parse enum", || {
|
|
13
|
+
crate::error::generate_error(quote! {}, input.clone());
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
#[test]
|
|
19
|
+
fn test_contract_error_rejects_attr_arguments() {
|
|
20
|
+
let input = quote! {
|
|
21
|
+
pub enum MyError {
|
|
22
|
+
A,
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
assert_panics_contains("attr not empty", "contract_error attribute is not supported", || {
|
|
26
|
+
crate::error::generate_error(quote! { some_attr }, input);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#[test]
|
|
31
|
+
fn test_contract_error_requires_unit_variants() {
|
|
32
|
+
let cases = vec![("tuple variant", quote! { A(u32) }), ("struct variant", quote! { A { x: u32 } })];
|
|
33
|
+
|
|
34
|
+
for (case, variant) in cases {
|
|
35
|
+
let input = quote! {
|
|
36
|
+
pub enum MyError {
|
|
37
|
+
#variant,
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
assert_panics_contains(case, "Error enum variants must be unit variants", || {
|
|
41
|
+
crate::error::generate_error(quote! {}, input.clone());
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
#[test]
|
|
47
|
+
fn test_contract_error_discriminant_must_be_integer_literal() {
|
|
48
|
+
let cases = vec![
|
|
49
|
+
("binary expr", quote! { 1 + 1 }),
|
|
50
|
+
("path expr", quote! { SOME_CONST }),
|
|
51
|
+
("negative integer (unary expr)", quote! { -1 }),
|
|
52
|
+
("paren expr", quote! { (1) }),
|
|
53
|
+
("bool literal", quote! { true }),
|
|
54
|
+
("string literal", quote! { "1" }),
|
|
55
|
+
("float literal", quote! { 1.0 }),
|
|
56
|
+
("char literal", quote! { 'a' }),
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
for (case, expr) in cases {
|
|
60
|
+
let input = quote! {
|
|
61
|
+
pub enum MyError {
|
|
62
|
+
A = #expr,
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
assert_panics_contains(case, "Error enum discriminant must be an integer literal", || {
|
|
66
|
+
crate::error::generate_error(quote! {}, input.clone());
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
#[test]
|
|
72
|
+
fn test_contract_error_discriminant_must_fit_u32() {
|
|
73
|
+
let input = quote! {
|
|
74
|
+
pub enum MyError {
|
|
75
|
+
A = 4294967296,
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
assert_panics_contains("u32::MAX + 1", "Error enum discriminant must be a valid u32 integer", || {
|
|
80
|
+
crate::error::generate_error(quote! {}, input);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
#[test]
|
|
85
|
+
fn test_contract_error_discriminants_ordering_rejections_table_driven() {
|
|
86
|
+
let cases = vec![
|
|
87
|
+
(
|
|
88
|
+
"explicit value is less than previous",
|
|
89
|
+
quote! {
|
|
90
|
+
// A is assigned 1 by default; B cannot go backwards.
|
|
91
|
+
A,
|
|
92
|
+
B = 1,
|
|
93
|
+
},
|
|
94
|
+
),
|
|
95
|
+
(
|
|
96
|
+
"explicit zero",
|
|
97
|
+
quote! {
|
|
98
|
+
A = 0,
|
|
99
|
+
},
|
|
100
|
+
),
|
|
101
|
+
(
|
|
102
|
+
"explicit equal to previous explicit",
|
|
103
|
+
quote! {
|
|
104
|
+
A = 1,
|
|
105
|
+
B = 1,
|
|
106
|
+
},
|
|
107
|
+
),
|
|
108
|
+
(
|
|
109
|
+
"explicit decreases after explicit",
|
|
110
|
+
quote! {
|
|
111
|
+
A = 5,
|
|
112
|
+
B = 4,
|
|
113
|
+
},
|
|
114
|
+
),
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
for (case, variants) in cases {
|
|
118
|
+
let input = quote! {
|
|
119
|
+
pub enum MyError {
|
|
120
|
+
#variants
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
assert_panics_contains(case, "Error enum discriminant must be greater than the previous discriminant", || {
|
|
124
|
+
crate::error::generate_error(quote! {}, input.clone());
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
#[test]
|
|
130
|
+
fn test_contract_error_max_not_last_panics_overflow() {
|
|
131
|
+
let input = quote! {
|
|
132
|
+
pub enum MyError {
|
|
133
|
+
A = 4294967295,
|
|
134
|
+
B,
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
assert_panics_contains("max not last overflows", "attempt to add with overflow", || {
|
|
138
|
+
crate::error::generate_error(quote! {}, input);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ============================================
|
|
143
|
+
// Valid Cases: Snapshot Tests for Generated Code
|
|
144
|
+
// ============================================
|
|
145
|
+
|
|
146
|
+
#[test]
|
|
147
|
+
fn snapshot_generated_contract_error_code() {
|
|
148
|
+
let input = quote! {
|
|
149
|
+
/// Example error enum
|
|
150
|
+
pub enum MyError {
|
|
151
|
+
/// Implicit (should start at 1)
|
|
152
|
+
A,
|
|
153
|
+
/// Implicit (should be 2)
|
|
154
|
+
B,
|
|
155
|
+
/// Explicit (must be >= previous + 1)
|
|
156
|
+
C = 10,
|
|
157
|
+
/// Implicit (should be 11)
|
|
158
|
+
D,
|
|
159
|
+
/// Explicit max boundary (u32::MAX)
|
|
160
|
+
E = 4294967295,
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
let result = crate::error::generate_error(quote! {}, input);
|
|
165
|
+
let formatted = prettyplease::unparse(&syn::parse2::<syn::File>(result).expect("failed to parse generated code"));
|
|
166
|
+
|
|
167
|
+
insta::assert_snapshot!(formatted);
|
|
168
|
+
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
mod contract_impl;
|
|
2
|
+
mod error;
|
|
2
3
|
mod ownable;
|
|
3
4
|
mod storage;
|
|
4
5
|
mod test_helpers;
|
|
5
6
|
mod ttl_configurable;
|
|
6
|
-
|
|
7
|
-
// Note: error.rs and event.rs use proc_macro::TokenStream which cannot be tested
|
|
8
|
-
// outside of a procedural macro context. These macros are tested via integration
|
|
9
|
-
// tests in the contracts that use them (e.g., utils crate).
|
|
7
|
+
mod utils;
|