@layerzerolabs/framework-solana-anchor-trait 0.2.98 → 0.2.100
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/README.md +16 -12
- package/package.json +5 -5
- package/src/assembly.rs +11 -7
- package/src/generation.rs +6 -9
- package/src/overrides.rs +9 -2
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ InstructionSpec {
|
|
|
33
33
|
}
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
**Provided** — The trait supplies a complete default implementation
|
|
36
|
+
**Provided** — The trait supplies a complete default implementation: an accounts struct and a handler `impl`. Both are emitted unconditionally. This is analogous to a default method in a Rust trait.
|
|
37
37
|
|
|
38
38
|
```rust
|
|
39
39
|
InstructionSpec {
|
|
@@ -54,7 +54,7 @@ For provided instructions, the implementor may accept the default or supply a cu
|
|
|
54
54
|
- To **reuse** the default accounts struct, declare `Context<StdSetPeer>`.
|
|
55
55
|
- To use **custom** accounts, declare `Context<MyCustomAccounts>`.
|
|
56
56
|
|
|
57
|
-
The framework does not distinguish between these cases — the default struct
|
|
57
|
+
The framework does not distinguish between these cases — both the default struct and its `apply` impl are always emitted, so an override handler can reuse the default by calling `<accounts>::apply(ctx, params)?`. For example, with `Context<StdSetPeer>` the override can run `StdSetPeer::apply(ctx, params)?` before or after its own logic.
|
|
58
58
|
|
|
59
59
|
For required instructions, no default exists. The implementor must provide a handler.
|
|
60
60
|
|
|
@@ -202,22 +202,26 @@ pub fn my_macro_impl(attr: TokenStream, item: TokenStream) -> syn::Result<TokenS
|
|
|
202
202
|
### Assembly output structure
|
|
203
203
|
|
|
204
204
|
```text
|
|
205
|
-
<prelude>
|
|
206
|
-
<
|
|
207
|
-
<
|
|
208
|
-
<
|
|
209
|
-
<
|
|
210
|
-
|
|
205
|
+
<prelude> — domain-specific definitions (emitted by the macro crate)
|
|
206
|
+
<default_impls> — generated default accounts structs + handler impls
|
|
207
|
+
<extend_macro> — macro_rules! for extending default accounts (if configured)
|
|
208
|
+
<original_outer_attrs> — preserved outer module attributes
|
|
209
|
+
<extra_mod_attrs> — additional attributes (e.g., #[program])
|
|
210
|
+
— any outer attr whose last path segment is `program`
|
|
211
|
+
is stripped from the input and re-emitted here
|
|
211
212
|
[vis] mod <name> {
|
|
213
|
+
<original_inner_attrs> — preserved inner module attributes
|
|
212
214
|
use super::*;
|
|
213
|
-
<filtered_items>
|
|
214
|
-
<
|
|
215
|
+
<filtered_items> — original module items, excluding relocated handlers
|
|
216
|
+
<wrapper_defs> — relocated override handler modules (kept inside so handlers
|
|
217
|
+
can reach the user's nested same-module helpers)
|
|
218
|
+
<entrypoints> — generated instruction entrypoints
|
|
215
219
|
}
|
|
216
220
|
```
|
|
217
221
|
|
|
218
222
|
## Extending Default Accounts
|
|
219
223
|
|
|
220
|
-
For provided instructions, the framework generates a `macro_rules!` (named via `Assembly::extend_macro_name`) that lets users create extended accounts structs — the default fields plus extra accounts — without duplicating the base implementation.
|
|
224
|
+
For provided instructions, the framework generates a `macro_rules!` (named via `Assembly::extend_macro_name`) that lets users create extended accounts structs — the default fields plus extra accounts — without duplicating the base implementation. **Extension is additive**: the default struct and its `apply` impl remain emitted alongside any extended struct (see [How it works](#how-it-works)). For example, defining `ExtSetPeer` does not replace or hide `StdSetPeer`.
|
|
221
225
|
|
|
222
226
|
### Usage
|
|
223
227
|
|
|
@@ -243,7 +247,7 @@ my_domain_extend_accounts!(set_peer, ExtSetPeer, {
|
|
|
243
247
|
|
|
244
248
|
### How it works
|
|
245
249
|
|
|
246
|
-
Each provided instruction's `DefaultAccounts` produces two outputs: the concrete `Std*` struct (via `to_definition()`, which emits the `ItemStruct` and `ItemImpl` as-is) and a `macro_rules!` arm (via `to_extend_rule()`, which decomposes the struct into attrs/fields, replaces the name with `$name`, and appends `$($extra)*`). `Assembly` collects all arms into one `macro_rules!` named by `extend_macro_name`.
|
|
250
|
+
Each provided instruction's `DefaultAccounts` produces two outputs: the concrete `Std*` struct (via `to_definition()`, which emits the `ItemStruct` and `ItemImpl` as-is) and a `macro_rules!` arm (via `to_extend_rule()`, which decomposes the struct into attrs/fields, replaces the name with `$name`, and appends `$($extra)*`). The arm also re-emits the default's `impl` items, so the extended struct gets an independent copy of `apply` — e.g., `ExtSetPeer::apply` is a parallel method, not a re-export of `StdSetPeer::apply`. `Assembly` collects all arms into one `macro_rules!` named by `extend_macro_name`.
|
|
247
251
|
|
|
248
252
|
## Reference
|
|
249
253
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@layerzerolabs/framework-solana-anchor-trait",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.100",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
"rustfmt.toml"
|
|
15
15
|
],
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@layerzerolabs/build-utils-solana": "0.2.
|
|
18
|
-
"@layerzerolabs/
|
|
19
|
-
"@layerzerolabs/
|
|
20
|
-
"@layerzerolabs/
|
|
17
|
+
"@layerzerolabs/build-utils-solana": "0.2.100",
|
|
18
|
+
"@layerzerolabs/typescript-configuration": "0.2.100",
|
|
19
|
+
"@layerzerolabs/tsup-configuration": "0.2.100",
|
|
20
|
+
"@layerzerolabs/vm-tooling-solana": "0.2.100"
|
|
21
21
|
},
|
|
22
22
|
"publishConfig": {
|
|
23
23
|
"access": "restricted",
|
package/src/assembly.rs
CHANGED
|
@@ -28,9 +28,10 @@ impl<Ix: InstructionSet> Assembly<Ix> {
|
|
|
28
28
|
///
|
|
29
29
|
/// `#[program]` is always emitted as the innermost attribute on the module so
|
|
30
30
|
/// that Anchor expands last — after all instruction macros have injected their
|
|
31
|
-
/// code.
|
|
32
|
-
///
|
|
33
|
-
///
|
|
31
|
+
/// code. Any outer module attribute whose last path segment is `program` is
|
|
32
|
+
/// stripped and re-emitted at the correct position; this catches qualified
|
|
33
|
+
/// forms like `#[anchor_lang::program]` and leaves inner `#![…program]`
|
|
34
|
+
/// untouched. This keeps stacking order irrelevant for any combination of
|
|
34
35
|
/// domain macros (e.g. `#[oapp]` + `#[composer]`).
|
|
35
36
|
///
|
|
36
37
|
/// ```text
|
|
@@ -75,11 +76,14 @@ impl<Ix: InstructionSet> Assembly<Ix> {
|
|
|
75
76
|
|
|
76
77
|
let ItemMod { attrs: mod_attrs, vis: mod_vis, ident: mod_ident, .. } = &source_mod;
|
|
77
78
|
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
// Partition first: only outer `#[...program]` attrs are framework-owned and re-emitted
|
|
80
|
+
// below. Inner attrs (`#![...]`, `//!`) must stay inside the module body unchanged.
|
|
81
|
+
let (inner_attrs, outer_attrs): (Vec<_>, Vec<_>) =
|
|
82
|
+
mod_attrs.iter().partition(|a| matches!(a.style, AttrStyle::Inner(_)));
|
|
83
|
+
let outer_attrs: Vec<_> = outer_attrs
|
|
84
|
+
.into_iter()
|
|
81
85
|
.filter(|a| a.path().segments.last().is_none_or(|s| s.ident != "program"))
|
|
82
|
-
.
|
|
86
|
+
.collect();
|
|
83
87
|
|
|
84
88
|
quote! {
|
|
85
89
|
#prelude
|
package/src/generation.rs
CHANGED
|
@@ -40,16 +40,13 @@ pub struct DefaultImpl<Ctx> {
|
|
|
40
40
|
|
|
41
41
|
/// Complete accounts struct and its handler impl block.
|
|
42
42
|
///
|
|
43
|
-
///
|
|
44
|
-
///
|
|
45
|
-
///
|
|
46
|
-
/// name with `$name` via [`to_extend_rule`](Self::to_extend_rule).
|
|
43
|
+
/// Produces two outputs: the concrete struct + impl via [`to_definition`](Self::to_definition),
|
|
44
|
+
/// and a `macro_rules!` rule via [`to_extend_rule`](Self::to_extend_rule) (which reconstructs
|
|
45
|
+
/// the type as `pub struct $name<'info>` / `impl $name<'_>`).
|
|
47
46
|
///
|
|
48
|
-
///
|
|
49
|
-
///
|
|
50
|
-
///
|
|
51
|
-
/// non-`'info` generics would be silently dropped and produce malformed
|
|
52
|
-
/// output.
|
|
47
|
+
/// **Constraint:** `struct_type` must carry exactly `'info` — no type or const generics.
|
|
48
|
+
/// Extra generics are silently dropped by both codegen paths, surfacing as type errors at
|
|
49
|
+
/// the extend-macro call site.
|
|
53
50
|
pub struct DefaultAccounts {
|
|
54
51
|
/// Complete struct definition including attributes, name, generics, and fields.
|
|
55
52
|
pub struct_type: ItemStruct,
|
package/src/overrides.rs
CHANGED
|
@@ -110,8 +110,15 @@ impl<Ix: InstructionSet> InstructionOverrides<Ix> {
|
|
|
110
110
|
quote!(#(#kept)*)
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
///
|
|
114
|
-
///
|
|
113
|
+
/// Wraps a handler fn in a generated module
|
|
114
|
+
/// (`mod __<attr>__<instr>_handler { use super::*; ... }`) and returns
|
|
115
|
+
/// its [`HandlerMeta`]. The override attribute (e.g. `#[oapp_instruction]`)
|
|
116
|
+
/// is stripped; other attributes ride along on the cloned fn.
|
|
117
|
+
///
|
|
118
|
+
/// Each attribute expands inside the wrapper module rather than at the
|
|
119
|
+
/// fn's original location, so any code it generates is inserted there
|
|
120
|
+
/// and resolves names against the wrapper's scope (which reaches the
|
|
121
|
+
/// parent via `use super::*;`).
|
|
115
122
|
fn wrap_handler(&mut self, target: Ix, fn_item: &ItemFn) -> syn::Result<HandlerMeta> {
|
|
116
123
|
let context_type = infer_context_type(fn_item)?;
|
|
117
124
|
let fn_generics = fn_item.sig.generics.clone();
|