From 0a2afd3bdaec200c4a2aad2163687ef36430fa84 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Fri, 22 Oct 2021 22:18:04 +0300 Subject: [PATCH 1/5] lang: Add custom error for `has_one` constraint --- CHANGELOG.md | 2 +- lang/derive/accounts/src/lib.rs | 2 +- lang/syn/src/codegen/accounts/constraints.rs | 3 ++- lang/syn/src/lib.rs | 1 + lang/syn/src/parser/accounts/constraints.rs | 1 + 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1601cbaa91..6290e930d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ incremented for features. * lang: Add `mint::freeze_authority` keyword for mint initialization within `#[derive(Accounts)]` ([#835](https://github.com/project-serum/anchor/pull/835)). * lang: Add `AccountLoader` type for `zero_copy` accounts with support for CPI ([#792](https://github.com/project-serum/anchor/pull/792)). * lang: Add `#[account(init_if_needed)]` keyword for allowing one to invoke the same instruction even if the account was created already ([#906](https://github.com/project-serum/anchor/pull/906)). -* lang: Add custom errors support for raw constraints ([#905](https://github.com/project-serum/anchor/pull/905)). +* lang: Add custom errors support for raw constraints and `has_one` ([#905](https://github.com/project-serum/anchor/pull/905), [#913](https://github.com/project-serum/anchor/pull/913)). ### Breaking diff --git a/lang/derive/accounts/src/lib.rs b/lang/derive/accounts/src/lib.rs index 32888c5046..a80433378f 100644 --- a/lang/derive/accounts/src/lib.rs +++ b/lang/derive/accounts/src/lib.rs @@ -42,7 +42,7 @@ use syn::parse_macro_input; /// | `#[account(init)]` | On `ProgramAccount` structs. | Marks the account as being initialized, creating the account via the system program. | /// | `#[account(zero)]` | On `ProgramAccount` structs. | Asserts the account discriminator is zero. | /// | `#[account(close = )]` | On `ProgramAccount` and `Loader` structs. | Marks the account as being closed at the end of the instruction's execution, sending the rent exemption lamports to the specified . | -/// | `#[account(has_one = )]` | On `ProgramAccount` or `CpiAccount` structs | Checks the `target` field on the account matches the `target` field in the struct deriving `Accounts`. | +/// | `#[account(has_one = )]`

`#[account(has_one = @ )]` | On `ProgramAccount` or `CpiAccount` structs | Checks the `target` field on the account matches the `target` field in the struct deriving `Accounts`. Custom errors are supported via `@`. | /// | `#[account(seeds = [], bump? = , payer? = , space? = , owner? = )]` | On `AccountInfo` structs | Seeds for the program derived address an `AccountInfo` struct represents. If bump is provided, then appends it to the seeds. On initialization, validates the given bump is the bump provided by `Pubkey::find_program_address`.| /// | `#[account(constraint = )]`

`#[account(constraint = @ )]` | On any type deriving `Accounts` | Executes the given code as a constraint. The expression should evaluate to a boolean. Custom errors are supported via `@`. | /// | `#[account("")]` | Deprecated | Executes the given code literal as a constraint. The literal should evaluate to a boolean. | diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs index dd414b09e8..83aa6bd5d0 100644 --- a/lang/syn/src/codegen/accounts/constraints.rs +++ b/lang/syn/src/codegen/accounts/constraints.rs @@ -190,9 +190,10 @@ pub fn generate_constraint_has_one(f: &Field, c: &ConstraintHasOne) -> proc_macr Ty::AccountLoader(_) => quote! {#ident.load()?}, _ => quote! {#ident}, }; + let error = generate_custom_error(&c.error, quote! { ConstraintHasOne }); quote! { if &#field.#target != #target.to_account_info().key { - return Err(anchor_lang::__private::ErrorCode::ConstraintHasOne.into()); + return Err(#error); } } } diff --git a/lang/syn/src/lib.rs b/lang/syn/src/lib.rs index cd7d7dcc41..a73553759e 100644 --- a/lang/syn/src/lib.rs +++ b/lang/syn/src/lib.rs @@ -613,6 +613,7 @@ pub struct ConstraintSigner {} #[derive(Debug, Clone)] pub struct ConstraintHasOne { pub join_target: Expr, + pub error: Option, } #[derive(Debug, Clone)] diff --git a/lang/syn/src/parser/accounts/constraints.rs b/lang/syn/src/parser/accounts/constraints.rs index d63a284459..8b21b3c4aa 100644 --- a/lang/syn/src/parser/accounts/constraints.rs +++ b/lang/syn/src/parser/accounts/constraints.rs @@ -183,6 +183,7 @@ pub fn parse_token(stream: ParseStream) -> ParseResult { span, ConstraintHasOne { join_target: stream.parse()?, + error: parse_optional_custom_error(&stream)?, }, )), "owner" => ConstraintToken::Owner(Context::new( From 716c2c9cf263b057cfb11cab63610254a9bbcf6d Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Fri, 22 Oct 2021 22:56:24 +0300 Subject: [PATCH 2/5] lang: Add custom error for `mut` --- CHANGELOG.md | 2 +- lang/derive/accounts/src/lib.rs | 2 +- lang/syn/src/codegen/accounts/constraints.rs | 5 +++-- lang/syn/src/lib.rs | 4 +++- lang/syn/src/parser/accounts/constraints.rs | 11 ++++++++--- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6290e930d2..8a99f43280 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ incremented for features. * lang: Add `mint::freeze_authority` keyword for mint initialization within `#[derive(Accounts)]` ([#835](https://github.com/project-serum/anchor/pull/835)). * lang: Add `AccountLoader` type for `zero_copy` accounts with support for CPI ([#792](https://github.com/project-serum/anchor/pull/792)). * lang: Add `#[account(init_if_needed)]` keyword for allowing one to invoke the same instruction even if the account was created already ([#906](https://github.com/project-serum/anchor/pull/906)). -* lang: Add custom errors support for raw constraints and `has_one` ([#905](https://github.com/project-serum/anchor/pull/905), [#913](https://github.com/project-serum/anchor/pull/913)). +* lang: Add custom errors support for raw constraints, `has_one` and `mut` ([#905](https://github.com/project-serum/anchor/pull/905), [#913](https://github.com/project-serum/anchor/pull/913)). ### Breaking diff --git a/lang/derive/accounts/src/lib.rs b/lang/derive/accounts/src/lib.rs index a80433378f..43e96fac49 100644 --- a/lang/derive/accounts/src/lib.rs +++ b/lang/derive/accounts/src/lib.rs @@ -38,7 +38,7 @@ use syn::parse_macro_input; /// | Attribute | Location | Description | /// |:--|:--|:--| /// | `#[account(signer)]` | On raw `AccountInfo` structs. | Checks the given account signed the transaction. | -/// | `#[account(mut)]` | On `AccountInfo`, `ProgramAccount` or `CpiAccount` structs. | Marks the account as mutable and persists the state transition. | +/// | `#[account(mut)]`

`#[account(mut @ )]` | On `AccountInfo`, `ProgramAccount` or `CpiAccount` structs. | Marks the account as mutable and persists the state transition. Custom errors are supported via `@`. | /// | `#[account(init)]` | On `ProgramAccount` structs. | Marks the account as being initialized, creating the account via the system program. | /// | `#[account(zero)]` | On `ProgramAccount` structs. | Asserts the account discriminator is zero. | /// | `#[account(close = )]` | On `ProgramAccount` and `Loader` structs. | Marks the account as being closed at the end of the instruction's execution, sending the rent exemption lamports to the specified . | diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs index 83aa6bd5d0..cf74763b24 100644 --- a/lang/syn/src/codegen/accounts/constraints.rs +++ b/lang/syn/src/codegen/accounts/constraints.rs @@ -173,11 +173,12 @@ pub fn generate_constraint_close(f: &Field, c: &ConstraintClose) -> proc_macro2: } } -pub fn generate_constraint_mut(f: &Field, _c: &ConstraintMut) -> proc_macro2::TokenStream { +pub fn generate_constraint_mut(f: &Field, c: &ConstraintMut) -> proc_macro2::TokenStream { let ident = &f.ident; + let error = generate_custom_error(&c.error, quote! { ConstraintMut }); quote! { if !#ident.to_account_info().is_writable { - return Err(anchor_lang::__private::ErrorCode::ConstraintMut.into()); + return Err(#error); } } } diff --git a/lang/syn/src/lib.rs b/lang/syn/src/lib.rs index a73553759e..8712a96281 100644 --- a/lang/syn/src/lib.rs +++ b/lang/syn/src/lib.rs @@ -605,7 +605,9 @@ pub struct ConstraintInitIfNeeded {} pub struct ConstraintZeroed {} #[derive(Debug, Clone)] -pub struct ConstraintMut {} +pub struct ConstraintMut { + pub error: Option, +} #[derive(Debug, Clone)] pub struct ConstraintSigner {} diff --git a/lang/syn/src/parser/accounts/constraints.rs b/lang/syn/src/parser/accounts/constraints.rs index 8b21b3c4aa..04019e4174 100644 --- a/lang/syn/src/parser/accounts/constraints.rs +++ b/lang/syn/src/parser/accounts/constraints.rs @@ -69,7 +69,12 @@ pub fn parse_token(stream: ParseStream) -> ParseResult { ConstraintInit { if_needed: true }, )), "zero" => ConstraintToken::Zeroed(Context::new(ident.span(), ConstraintZeroed {})), - "mut" => ConstraintToken::Mut(Context::new(ident.span(), ConstraintMut {})), + "mut" => ConstraintToken::Mut(Context::new( + ident.span(), + ConstraintMut { + error: parse_optional_custom_error(&stream)?, + }, + )), "signer" => ConstraintToken::Signer(Context::new(ident.span(), ConstraintSigner {})), "executable" => { ConstraintToken::Executable(Context::new(ident.span(), ConstraintExecutable {})) @@ -341,7 +346,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> { } None => self .mutable - .replace(Context::new(i.span(), ConstraintMut {})), + .replace(Context::new(i.span(), ConstraintMut { error: None })), }; // Rent exempt if not explicitly skipped. if self.rent_exempt.is_none() { @@ -375,7 +380,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> { } None => self .mutable - .replace(Context::new(z.span(), ConstraintMut {})), + .replace(Context::new(z.span(), ConstraintMut { error: None })), }; // Rent exempt if not explicitly skipped. if self.rent_exempt.is_none() { From d91c187f2772ccd13fea040b42b5c3e0714d262f Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Fri, 22 Oct 2021 23:00:15 +0300 Subject: [PATCH 3/5] lang: Add custom error for signer --- CHANGELOG.md | 2 +- lang/derive/accounts/src/lib.rs | 2 +- lang/syn/src/codegen/accounts/constraints.rs | 5 +++-- lang/syn/src/lib.rs | 4 +++- lang/syn/src/parser/accounts/constraints.rs | 9 +++++++-- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a99f43280..a52bb0833b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ incremented for features. * lang: Add `mint::freeze_authority` keyword for mint initialization within `#[derive(Accounts)]` ([#835](https://github.com/project-serum/anchor/pull/835)). * lang: Add `AccountLoader` type for `zero_copy` accounts with support for CPI ([#792](https://github.com/project-serum/anchor/pull/792)). * lang: Add `#[account(init_if_needed)]` keyword for allowing one to invoke the same instruction even if the account was created already ([#906](https://github.com/project-serum/anchor/pull/906)). -* lang: Add custom errors support for raw constraints, `has_one` and `mut` ([#905](https://github.com/project-serum/anchor/pull/905), [#913](https://github.com/project-serum/anchor/pull/913)). +* lang: Add custom errors support for `signer`, `mut`, `has_one` and raw constraints ([#905](https://github.com/project-serum/anchor/pull/905), [#913](https://github.com/project-serum/anchor/pull/913)). ### Breaking diff --git a/lang/derive/accounts/src/lib.rs b/lang/derive/accounts/src/lib.rs index 43e96fac49..45fc8ee0b0 100644 --- a/lang/derive/accounts/src/lib.rs +++ b/lang/derive/accounts/src/lib.rs @@ -37,7 +37,7 @@ use syn::parse_macro_input; /// /// | Attribute | Location | Description | /// |:--|:--|:--| -/// | `#[account(signer)]` | On raw `AccountInfo` structs. | Checks the given account signed the transaction. | +/// | `#[account(signer)]`

`#[account(signer @ )]` | On raw `AccountInfo` structs. | Checks the given account signed the transaction. Custom errors are supported via `@`. | /// | `#[account(mut)]`

`#[account(mut @ )]` | On `AccountInfo`, `ProgramAccount` or `CpiAccount` structs. | Marks the account as mutable and persists the state transition. Custom errors are supported via `@`. | /// | `#[account(init)]` | On `ProgramAccount` structs. | Marks the account as being initialized, creating the account via the system program. | /// | `#[account(zero)]` | On `ProgramAccount` structs. | Asserts the account discriminator is zero. | diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs index cf74763b24..027ad2f627 100644 --- a/lang/syn/src/codegen/accounts/constraints.rs +++ b/lang/syn/src/codegen/accounts/constraints.rs @@ -199,7 +199,7 @@ pub fn generate_constraint_has_one(f: &Field, c: &ConstraintHasOne) -> proc_macr } } -pub fn generate_constraint_signer(f: &Field, _c: &ConstraintSigner) -> proc_macro2::TokenStream { +pub fn generate_constraint_signer(f: &Field, c: &ConstraintSigner) -> proc_macro2::TokenStream { let ident = &f.ident; let info = match f.ty { Ty::AccountInfo => quote! { #ident }, @@ -210,9 +210,10 @@ pub fn generate_constraint_signer(f: &Field, _c: &ConstraintSigner) -> proc_macr Ty::CpiAccount(_) => quote! { #ident.to_account_info() }, _ => panic!("Invalid syntax: signer cannot be specified."), }; + let error = generate_custom_error(&c.error, quote! { ConstraintSigner }); quote! { if !#info.to_account_info().is_signer { - return Err(anchor_lang::__private::ErrorCode::ConstraintSigner.into()); + return Err(#error); } } } diff --git a/lang/syn/src/lib.rs b/lang/syn/src/lib.rs index 8712a96281..ab557f8470 100644 --- a/lang/syn/src/lib.rs +++ b/lang/syn/src/lib.rs @@ -610,7 +610,9 @@ pub struct ConstraintMut { } #[derive(Debug, Clone)] -pub struct ConstraintSigner {} +pub struct ConstraintSigner { + pub error: Option, +} #[derive(Debug, Clone)] pub struct ConstraintHasOne { diff --git a/lang/syn/src/parser/accounts/constraints.rs b/lang/syn/src/parser/accounts/constraints.rs index 04019e4174..e73a29b43f 100644 --- a/lang/syn/src/parser/accounts/constraints.rs +++ b/lang/syn/src/parser/accounts/constraints.rs @@ -75,7 +75,12 @@ pub fn parse_token(stream: ParseStream) -> ParseResult { error: parse_optional_custom_error(&stream)?, }, )), - "signer" => ConstraintToken::Signer(Context::new(ident.span(), ConstraintSigner {})), + "signer" => ConstraintToken::Signer(Context::new( + ident.span(), + ConstraintSigner { + error: parse_optional_custom_error(&stream)?, + }, + )), "executable" => { ConstraintToken::Executable(Context::new(ident.span(), ConstraintExecutable {})) } @@ -365,7 +370,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> { if self.signer.is_none() && self.seeds.is_none() && self.associated_token_mint.is_none() { self.signer - .replace(Context::new(i.span(), ConstraintSigner {})); + .replace(Context::new(i.span(), ConstraintSigner { error: None })); } } From 6047550ec0b1b17fd9c0fee12242483af0432153 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Sat, 23 Oct 2021 01:05:46 +0300 Subject: [PATCH 4/5] lang: custom error for `address` --- CHANGELOG.md | 2 +- lang/derive/accounts/src/lib.rs | 2 +- lang/syn/src/codegen/accounts/constraints.rs | 3 ++- lang/syn/src/lib.rs | 1 + lang/syn/src/parser/accounts/constraints.rs | 1 + 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a52bb0833b..3f76dce094 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ incremented for features. * lang: Add `mint::freeze_authority` keyword for mint initialization within `#[derive(Accounts)]` ([#835](https://github.com/project-serum/anchor/pull/835)). * lang: Add `AccountLoader` type for `zero_copy` accounts with support for CPI ([#792](https://github.com/project-serum/anchor/pull/792)). * lang: Add `#[account(init_if_needed)]` keyword for allowing one to invoke the same instruction even if the account was created already ([#906](https://github.com/project-serum/anchor/pull/906)). -* lang: Add custom errors support for `signer`, `mut`, `has_one` and raw constraints ([#905](https://github.com/project-serum/anchor/pull/905), [#913](https://github.com/project-serum/anchor/pull/913)). +* lang: Add custom errors support for `signer`, `mut`, `has_one`, raw constraints and `address` ([#905](https://github.com/project-serum/anchor/pull/905), [#913](https://github.com/project-serum/anchor/pull/913)). ### Breaking diff --git a/lang/derive/accounts/src/lib.rs b/lang/derive/accounts/src/lib.rs index 45fc8ee0b0..7e4c7aa35f 100644 --- a/lang/derive/accounts/src/lib.rs +++ b/lang/derive/accounts/src/lib.rs @@ -50,7 +50,7 @@ use syn::parse_macro_input; /// | `#[account(executable)]` | On `AccountInfo` structs | Checks the given account is an executable program. | /// | `#[account(state = )]` | On `CpiState` structs | Checks the given state is the canonical state account for the target program. | /// | `#[account(owner = )]` | On `CpiState`, `CpiAccount`, and `AccountInfo` | Checks the account owner matches the target. | -/// | `#[account(address = )]` | On `AccountInfo` and `Account` | Checks the account key matches the pubkey. | +/// | `#[account(address = )]`

`#[account(address = @ )]` | On `AccountInfo` and `Account` | Checks the account key matches the pubkey. Custom errors are supported via `@`. | // TODO: How do we make the markdown render correctly without putting everything // on absurdly long lines? #[proc_macro_derive(Accounts, attributes(account, instruction))] diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs index 027ad2f627..880d400afc 100644 --- a/lang/syn/src/codegen/accounts/constraints.rs +++ b/lang/syn/src/codegen/accounts/constraints.rs @@ -134,9 +134,10 @@ fn generate_constraint_composite(_f: &CompositeField, c: &Constraint) -> proc_ma fn generate_constraint_address(f: &Field, c: &ConstraintAddress) -> proc_macro2::TokenStream { let field = &f.ident; let addr = &c.address; + let error = generate_custom_error(&c.error, quote! { ConstraintAddress }); quote! { if #field.to_account_info().key != &#addr { - return Err(anchor_lang::__private::ErrorCode::ConstraintAddress.into()); + return Err(#error); } } } diff --git a/lang/syn/src/lib.rs b/lang/syn/src/lib.rs index ab557f8470..0e4a7067e9 100644 --- a/lang/syn/src/lib.rs +++ b/lang/syn/src/lib.rs @@ -639,6 +639,7 @@ pub struct ConstraintOwner { #[derive(Debug, Clone)] pub struct ConstraintAddress { pub address: Expr, + pub error: Option, } #[derive(Debug, Clone)] diff --git a/lang/syn/src/parser/accounts/constraints.rs b/lang/syn/src/parser/accounts/constraints.rs index e73a29b43f..6a4b9d0399 100644 --- a/lang/syn/src/parser/accounts/constraints.rs +++ b/lang/syn/src/parser/accounts/constraints.rs @@ -260,6 +260,7 @@ pub fn parse_token(stream: ParseStream) -> ParseResult { span, ConstraintAddress { address: stream.parse()?, + error: parse_optional_custom_error(&stream)?, }, )), _ => return Err(ParseError::new(ident.span(), "Invalid attribute")), From f13a9ab6e04d16307ccc705490e7465462da0c82 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Sat, 23 Oct 2021 01:09:40 +0300 Subject: [PATCH 5/5] lang: add custom error for `owner` --- CHANGELOG.md | 2 +- lang/derive/accounts/src/lib.rs | 2 +- lang/syn/src/codegen/accounts/constraints.rs | 3 ++- lang/syn/src/lib.rs | 1 + lang/syn/src/parser/accounts/constraints.rs | 1 + 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f76dce094..bec5a2a820 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ incremented for features. * lang: Add `mint::freeze_authority` keyword for mint initialization within `#[derive(Accounts)]` ([#835](https://github.com/project-serum/anchor/pull/835)). * lang: Add `AccountLoader` type for `zero_copy` accounts with support for CPI ([#792](https://github.com/project-serum/anchor/pull/792)). * lang: Add `#[account(init_if_needed)]` keyword for allowing one to invoke the same instruction even if the account was created already ([#906](https://github.com/project-serum/anchor/pull/906)). -* lang: Add custom errors support for `signer`, `mut`, `has_one`, raw constraints and `address` ([#905](https://github.com/project-serum/anchor/pull/905), [#913](https://github.com/project-serum/anchor/pull/913)). +* lang: Add custom errors support for `signer`, `mut`, `has_one`, `owner`, raw constraints and `address` ([#905](https://github.com/project-serum/anchor/pull/905), [#913](https://github.com/project-serum/anchor/pull/913)). ### Breaking diff --git a/lang/derive/accounts/src/lib.rs b/lang/derive/accounts/src/lib.rs index 7e4c7aa35f..f176e57d59 100644 --- a/lang/derive/accounts/src/lib.rs +++ b/lang/derive/accounts/src/lib.rs @@ -49,7 +49,7 @@ use syn::parse_macro_input; /// | `#[account(rent_exempt = )]` | On `AccountInfo` or `ProgramAccount` structs | Optional attribute to skip the rent exemption check. By default, all accounts marked with `#[account(init)]` will be rent exempt, and so this should rarely (if ever) be used. Similarly, omitting `= skip` will mark the account rent exempt. | /// | `#[account(executable)]` | On `AccountInfo` structs | Checks the given account is an executable program. | /// | `#[account(state = )]` | On `CpiState` structs | Checks the given state is the canonical state account for the target program. | -/// | `#[account(owner = )]` | On `CpiState`, `CpiAccount`, and `AccountInfo` | Checks the account owner matches the target. | +/// | `#[account(owner = )]`

`#[account(owner = @ )]` | On `CpiState`, `CpiAccount`, and `AccountInfo` | Checks the account owner matches the target. Custom errors are supported via `@`. | /// | `#[account(address = )]`

`#[account(address = @ )]` | On `AccountInfo` and `Account` | Checks the account key matches the pubkey. Custom errors are supported via `@`. | // TODO: How do we make the markdown render correctly without putting everything // on absurdly long lines? diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs index 880d400afc..6118fd3f2c 100644 --- a/lang/syn/src/codegen/accounts/constraints.rs +++ b/lang/syn/src/codegen/accounts/constraints.rs @@ -250,9 +250,10 @@ pub fn generate_constraint_raw(c: &ConstraintRaw) -> proc_macro2::TokenStream { pub fn generate_constraint_owner(f: &Field, c: &ConstraintOwner) -> proc_macro2::TokenStream { let ident = &f.ident; let owner_address = &c.owner_address; + let error = generate_custom_error(&c.error, quote! { ConstraintOwner }); quote! { if #ident.to_account_info().owner != &#owner_address { - return Err(anchor_lang::__private::ErrorCode::ConstraintOwner.into()); + return Err(#error); } } } diff --git a/lang/syn/src/lib.rs b/lang/syn/src/lib.rs index 0e4a7067e9..b69e5d82d4 100644 --- a/lang/syn/src/lib.rs +++ b/lang/syn/src/lib.rs @@ -634,6 +634,7 @@ pub struct ConstraintRaw { #[derive(Debug, Clone)] pub struct ConstraintOwner { pub owner_address: Expr, + pub error: Option, } #[derive(Debug, Clone)] diff --git a/lang/syn/src/parser/accounts/constraints.rs b/lang/syn/src/parser/accounts/constraints.rs index 6a4b9d0399..119814d5bf 100644 --- a/lang/syn/src/parser/accounts/constraints.rs +++ b/lang/syn/src/parser/accounts/constraints.rs @@ -200,6 +200,7 @@ pub fn parse_token(stream: ParseStream) -> ParseResult { span, ConstraintOwner { owner_address: stream.parse()?, + error: parse_optional_custom_error(&stream)?, }, )), "rent_exempt" => ConstraintToken::RentExempt(Context::new(