constraints.rs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029
  1. use crate::*;
  2. use syn::ext::IdentExt;
  3. use syn::parse::{Error as ParseError, Parse, ParseStream, Result as ParseResult};
  4. use syn::punctuated::Punctuated;
  5. use syn::spanned::Spanned;
  6. use syn::token::Comma;
  7. use syn::{bracketed, Expr, Ident, LitStr, Token};
  8. pub fn parse(f: &syn::Field, f_ty: Option<&Ty>) -> ParseResult<ConstraintGroup> {
  9. let mut constraints = ConstraintGroupBuilder::new(f_ty);
  10. for attr in f.attrs.iter().filter(is_account) {
  11. for c in attr.parse_args_with(Punctuated::<ConstraintToken, Comma>::parse_terminated)? {
  12. constraints.add(c)?;
  13. }
  14. }
  15. let account_constraints = constraints.build()?;
  16. Ok(account_constraints)
  17. }
  18. pub fn is_account(attr: &&syn::Attribute) -> bool {
  19. attr.path
  20. .get_ident()
  21. .map_or(false, |ident| ident == "account")
  22. }
  23. // Parses a single constraint from a parse stream for `#[account(<STREAM>)]`.
  24. pub fn parse_token(stream: ParseStream) -> ParseResult<ConstraintToken> {
  25. let is_lit = stream.peek(LitStr);
  26. if is_lit {
  27. let lit: LitStr = stream.parse()?;
  28. let c = ConstraintToken::Literal(Context::new(lit.span(), ConstraintLiteral { lit }));
  29. return Ok(c);
  30. }
  31. let ident = stream.call(Ident::parse_any)?;
  32. let kw = ident.to_string();
  33. let c = match kw.as_str() {
  34. "init" => ConstraintToken::Init(Context::new(
  35. ident.span(),
  36. ConstraintInit { if_needed: false },
  37. )),
  38. "init_if_needed" => ConstraintToken::Init(Context::new(
  39. ident.span(),
  40. ConstraintInit { if_needed: true },
  41. )),
  42. "zero" => ConstraintToken::Zeroed(Context::new(ident.span(), ConstraintZeroed {})),
  43. "mut" => ConstraintToken::Mut(Context::new(
  44. ident.span(),
  45. ConstraintMut {
  46. error: parse_optional_custom_error(&stream)?,
  47. },
  48. )),
  49. "signer" => ConstraintToken::Signer(Context::new(
  50. ident.span(),
  51. ConstraintSigner {
  52. error: parse_optional_custom_error(&stream)?,
  53. },
  54. )),
  55. "executable" => {
  56. ConstraintToken::Executable(Context::new(ident.span(), ConstraintExecutable {}))
  57. }
  58. "mint" => {
  59. stream.parse::<Token![:]>()?;
  60. stream.parse::<Token![:]>()?;
  61. let kw = stream.call(Ident::parse_any)?.to_string();
  62. stream.parse::<Token![=]>()?;
  63. let span = ident
  64. .span()
  65. .join(stream.span())
  66. .unwrap_or_else(|| ident.span());
  67. match kw.as_str() {
  68. "authority" => ConstraintToken::MintAuthority(Context::new(
  69. span,
  70. ConstraintMintAuthority {
  71. mint_auth: stream.parse()?,
  72. },
  73. )),
  74. "freeze_authority" => ConstraintToken::MintFreezeAuthority(Context::new(
  75. span,
  76. ConstraintMintFreezeAuthority {
  77. mint_freeze_auth: stream.parse()?,
  78. },
  79. )),
  80. "decimals" => ConstraintToken::MintDecimals(Context::new(
  81. span,
  82. ConstraintMintDecimals {
  83. decimals: stream.parse()?,
  84. },
  85. )),
  86. _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
  87. }
  88. }
  89. "token" => {
  90. stream.parse::<Token![:]>()?;
  91. stream.parse::<Token![:]>()?;
  92. let kw = stream.call(Ident::parse_any)?.to_string();
  93. stream.parse::<Token![=]>()?;
  94. let span = ident
  95. .span()
  96. .join(stream.span())
  97. .unwrap_or_else(|| ident.span());
  98. match kw.as_str() {
  99. "mint" => ConstraintToken::TokenMint(Context::new(
  100. span,
  101. ConstraintTokenMint {
  102. mint: stream.parse()?,
  103. },
  104. )),
  105. "authority" => ConstraintToken::TokenAuthority(Context::new(
  106. span,
  107. ConstraintTokenAuthority {
  108. auth: stream.parse()?,
  109. },
  110. )),
  111. _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
  112. }
  113. }
  114. "associated_token" => {
  115. stream.parse::<Token![:]>()?;
  116. stream.parse::<Token![:]>()?;
  117. let kw = stream.call(Ident::parse_any)?.to_string();
  118. stream.parse::<Token![=]>()?;
  119. let span = ident
  120. .span()
  121. .join(stream.span())
  122. .unwrap_or_else(|| ident.span());
  123. match kw.as_str() {
  124. "mint" => ConstraintToken::AssociatedTokenMint(Context::new(
  125. span,
  126. ConstraintTokenMint {
  127. mint: stream.parse()?,
  128. },
  129. )),
  130. "authority" => ConstraintToken::AssociatedTokenAuthority(Context::new(
  131. span,
  132. ConstraintTokenAuthority {
  133. auth: stream.parse()?,
  134. },
  135. )),
  136. _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
  137. }
  138. }
  139. "bump" => {
  140. let bump = {
  141. if stream.peek(Token![=]) {
  142. stream.parse::<Token![=]>()?;
  143. Some(stream.parse()?)
  144. } else {
  145. None
  146. }
  147. };
  148. ConstraintToken::Bump(Context::new(ident.span(), ConstraintTokenBump { bump }))
  149. }
  150. "seeds" => {
  151. if stream.peek(Token![:]) {
  152. stream.parse::<Token![:]>()?;
  153. stream.parse::<Token![:]>()?;
  154. let kw = stream.call(Ident::parse_any)?.to_string();
  155. stream.parse::<Token![=]>()?;
  156. let span = ident
  157. .span()
  158. .join(stream.span())
  159. .unwrap_or_else(|| ident.span());
  160. match kw.as_str() {
  161. "program" => ConstraintToken::ProgramSeed(Context::new(
  162. span,
  163. ConstraintProgramSeed {
  164. program_seed: stream.parse()?,
  165. },
  166. )),
  167. _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
  168. }
  169. } else {
  170. stream.parse::<Token![=]>()?;
  171. let span = ident
  172. .span()
  173. .join(stream.span())
  174. .unwrap_or_else(|| ident.span());
  175. let seeds;
  176. let bracket = bracketed!(seeds in stream);
  177. ConstraintToken::Seeds(Context::new(
  178. span.join(bracket.span).unwrap_or(span),
  179. ConstraintSeeds {
  180. seeds: seeds.parse_terminated(Expr::parse)?,
  181. },
  182. ))
  183. }
  184. }
  185. _ => {
  186. stream.parse::<Token![=]>()?;
  187. let span = ident
  188. .span()
  189. .join(stream.span())
  190. .unwrap_or_else(|| ident.span());
  191. match kw.as_str() {
  192. "has_one" => ConstraintToken::HasOne(Context::new(
  193. span,
  194. ConstraintHasOne {
  195. join_target: stream.parse()?,
  196. error: parse_optional_custom_error(&stream)?,
  197. },
  198. )),
  199. "owner" => ConstraintToken::Owner(Context::new(
  200. span,
  201. ConstraintOwner {
  202. owner_address: stream.parse()?,
  203. error: parse_optional_custom_error(&stream)?,
  204. },
  205. )),
  206. "rent_exempt" => ConstraintToken::RentExempt(Context::new(
  207. span,
  208. match stream.parse::<Ident>()?.to_string().as_str() {
  209. "skip" => ConstraintRentExempt::Skip,
  210. "enforce" => ConstraintRentExempt::Enforce,
  211. _ => {
  212. return Err(ParseError::new(
  213. span,
  214. "rent_exempt must be either skip or enforce",
  215. ))
  216. }
  217. },
  218. )),
  219. "state" => ConstraintToken::State(Context::new(
  220. span,
  221. ConstraintState {
  222. program_target: stream.parse()?,
  223. },
  224. )),
  225. "payer" => ConstraintToken::Payer(Context::new(
  226. span,
  227. ConstraintPayer {
  228. target: stream.parse()?,
  229. },
  230. )),
  231. "space" => ConstraintToken::Space(Context::new(
  232. span,
  233. ConstraintSpace {
  234. space: stream.parse()?,
  235. },
  236. )),
  237. "constraint" => ConstraintToken::Raw(Context::new(
  238. span,
  239. ConstraintRaw {
  240. raw: stream.parse()?,
  241. error: parse_optional_custom_error(&stream)?,
  242. },
  243. )),
  244. "close" => ConstraintToken::Close(Context::new(
  245. span,
  246. ConstraintClose {
  247. sol_dest: stream.parse()?,
  248. },
  249. )),
  250. "address" => ConstraintToken::Address(Context::new(
  251. span,
  252. ConstraintAddress {
  253. address: stream.parse()?,
  254. error: parse_optional_custom_error(&stream)?,
  255. },
  256. )),
  257. _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
  258. }
  259. }
  260. };
  261. Ok(c)
  262. }
  263. fn parse_optional_custom_error(stream: &ParseStream) -> ParseResult<Option<Expr>> {
  264. if stream.peek(Token![@]) {
  265. stream.parse::<Token![@]>()?;
  266. stream.parse().map(Some)
  267. } else {
  268. Ok(None)
  269. }
  270. }
  271. #[derive(Default)]
  272. pub struct ConstraintGroupBuilder<'ty> {
  273. pub f_ty: Option<&'ty Ty>,
  274. pub init: Option<Context<ConstraintInit>>,
  275. pub zeroed: Option<Context<ConstraintZeroed>>,
  276. pub mutable: Option<Context<ConstraintMut>>,
  277. pub signer: Option<Context<ConstraintSigner>>,
  278. pub has_one: Vec<Context<ConstraintHasOne>>,
  279. pub literal: Vec<Context<ConstraintLiteral>>,
  280. pub raw: Vec<Context<ConstraintRaw>>,
  281. pub owner: Option<Context<ConstraintOwner>>,
  282. pub rent_exempt: Option<Context<ConstraintRentExempt>>,
  283. pub seeds: Option<Context<ConstraintSeeds>>,
  284. pub executable: Option<Context<ConstraintExecutable>>,
  285. pub state: Option<Context<ConstraintState>>,
  286. pub payer: Option<Context<ConstraintPayer>>,
  287. pub space: Option<Context<ConstraintSpace>>,
  288. pub close: Option<Context<ConstraintClose>>,
  289. pub address: Option<Context<ConstraintAddress>>,
  290. pub token_mint: Option<Context<ConstraintTokenMint>>,
  291. pub token_authority: Option<Context<ConstraintTokenAuthority>>,
  292. pub associated_token_mint: Option<Context<ConstraintTokenMint>>,
  293. pub associated_token_authority: Option<Context<ConstraintTokenAuthority>>,
  294. pub mint_authority: Option<Context<ConstraintMintAuthority>>,
  295. pub mint_freeze_authority: Option<Context<ConstraintMintFreezeAuthority>>,
  296. pub mint_decimals: Option<Context<ConstraintMintDecimals>>,
  297. pub bump: Option<Context<ConstraintTokenBump>>,
  298. pub program_seed: Option<Context<ConstraintProgramSeed>>,
  299. }
  300. impl<'ty> ConstraintGroupBuilder<'ty> {
  301. pub fn new(f_ty: Option<&'ty Ty>) -> Self {
  302. Self {
  303. f_ty,
  304. init: None,
  305. zeroed: None,
  306. mutable: None,
  307. signer: None,
  308. has_one: Vec::new(),
  309. literal: Vec::new(),
  310. raw: Vec::new(),
  311. owner: None,
  312. rent_exempt: None,
  313. seeds: None,
  314. executable: None,
  315. state: None,
  316. payer: None,
  317. space: None,
  318. close: None,
  319. address: None,
  320. token_mint: None,
  321. token_authority: None,
  322. associated_token_mint: None,
  323. associated_token_authority: None,
  324. mint_authority: None,
  325. mint_freeze_authority: None,
  326. mint_decimals: None,
  327. bump: None,
  328. program_seed: None,
  329. }
  330. }
  331. pub fn build(mut self) -> ParseResult<ConstraintGroup> {
  332. // Init.
  333. if let Some(i) = &self.init {
  334. if cfg!(not(feature = "init-if-needed")) && i.if_needed {
  335. return Err(ParseError::new(
  336. i.span(),
  337. "init_if_needed requires that anchor-lang be imported \
  338. with the init-if-needed cargo feature enabled. \
  339. Carefully read the init_if_needed docs before using this feature \
  340. to make sure you know how to protect yourself against \
  341. re-initialization attacks.",
  342. ));
  343. }
  344. match self.mutable {
  345. Some(m) => {
  346. return Err(ParseError::new(
  347. m.span(),
  348. "mut cannot be provided with init",
  349. ))
  350. }
  351. None => self
  352. .mutable
  353. .replace(Context::new(i.span(), ConstraintMut { error: None })),
  354. };
  355. // Rent exempt if not explicitly skipped.
  356. if self.rent_exempt.is_none() {
  357. self.rent_exempt
  358. .replace(Context::new(i.span(), ConstraintRentExempt::Enforce));
  359. }
  360. if self.payer.is_none() {
  361. return Err(ParseError::new(
  362. i.span(),
  363. "payer must be provided when initializing an account",
  364. ));
  365. }
  366. // When initializing a non-PDA account, the account being
  367. // initialized must sign to invoke the system program's create
  368. // account instruction.
  369. if self.signer.is_none() && self.seeds.is_none() && self.associated_token_mint.is_none()
  370. {
  371. self.signer
  372. .replace(Context::new(i.span(), ConstraintSigner { error: None }));
  373. }
  374. // Assert a bump target is not given on init.
  375. if let Some(b) = &self.bump {
  376. if b.bump.is_some() {
  377. return Err(ParseError::new(
  378. b.span(),
  379. "bump targets should not be provided with init. Please use bump without a target."
  380. ));
  381. }
  382. }
  383. // TokenAccount.
  384. if let Some(token_mint) = &self.token_mint {
  385. if self.token_authority.is_none() {
  386. return Err(ParseError::new(
  387. token_mint.span(),
  388. "when initializing, token authority must be provided if token mint is",
  389. ));
  390. }
  391. }
  392. if let Some(token_authority) = &self.token_authority {
  393. if self.token_mint.is_none() {
  394. return Err(ParseError::new(
  395. token_authority.span(),
  396. "when initializing, token mint must be provided if token authority is",
  397. ));
  398. }
  399. }
  400. // Mint.
  401. if let Some(mint_decimals) = &self.mint_decimals {
  402. if self.mint_authority.is_none() {
  403. return Err(ParseError::new(
  404. mint_decimals.span(),
  405. "when initializing, mint authority must be provided if mint decimals is",
  406. ));
  407. }
  408. }
  409. if let Some(mint_authority) = &self.mint_authority {
  410. if self.mint_decimals.is_none() {
  411. return Err(ParseError::new(
  412. mint_authority.span(),
  413. "when initializing, mint decimals must be provided if mint authority is",
  414. ));
  415. }
  416. }
  417. }
  418. // Zero.
  419. if let Some(z) = &self.zeroed {
  420. match self.mutable {
  421. Some(m) => {
  422. return Err(ParseError::new(
  423. m.span(),
  424. "mut cannot be provided with zeroed",
  425. ))
  426. }
  427. None => self
  428. .mutable
  429. .replace(Context::new(z.span(), ConstraintMut { error: None })),
  430. };
  431. // Rent exempt if not explicitly skipped.
  432. if self.rent_exempt.is_none() {
  433. self.rent_exempt
  434. .replace(Context::new(z.span(), ConstraintRentExempt::Enforce));
  435. }
  436. }
  437. // Seeds.
  438. if let Some(i) = &self.seeds {
  439. if self.init.is_some() && self.payer.is_none() {
  440. return Err(ParseError::new(
  441. i.span(),
  442. "payer must be provided when creating a program derived address",
  443. ));
  444. }
  445. if self.bump.is_none() {
  446. return Err(ParseError::new(
  447. i.span(),
  448. "bump must be provided with seeds",
  449. ));
  450. }
  451. }
  452. // Space.
  453. if let Some(i) = &self.init {
  454. let initializing_token_program_acc = self.token_mint.is_some()
  455. || self.mint_authority.is_some()
  456. || self.token_authority.is_some()
  457. || self.associated_token_authority.is_some();
  458. match (self.space.is_some(), initializing_token_program_acc) {
  459. (true, true) => {
  460. return Err(ParseError::new(
  461. self.space.as_ref().unwrap().span(),
  462. "space is not required for initializing an spl account",
  463. ));
  464. }
  465. (false, false) => {
  466. return Err(ParseError::new(
  467. i.span(),
  468. "space must be provided with init",
  469. ));
  470. }
  471. _ => (),
  472. }
  473. }
  474. let ConstraintGroupBuilder {
  475. f_ty: _,
  476. init,
  477. zeroed,
  478. mutable,
  479. signer,
  480. has_one,
  481. literal,
  482. raw,
  483. owner,
  484. rent_exempt,
  485. seeds,
  486. executable,
  487. state,
  488. payer,
  489. space,
  490. close,
  491. address,
  492. token_mint,
  493. token_authority,
  494. associated_token_mint,
  495. associated_token_authority,
  496. mint_authority,
  497. mint_freeze_authority,
  498. mint_decimals,
  499. bump,
  500. program_seed,
  501. } = self;
  502. // Converts Option<Context<T>> -> Option<T>.
  503. macro_rules! into_inner {
  504. ($opt:ident) => {
  505. $opt.map(|c| c.into_inner())
  506. };
  507. ($opt:expr) => {
  508. $opt.map(|c| c.into_inner())
  509. };
  510. }
  511. // Converts Vec<Context<T>> - Vec<T>.
  512. macro_rules! into_inner_vec {
  513. ($opt:ident) => {
  514. $opt.into_iter().map(|c| c.into_inner()).collect()
  515. };
  516. }
  517. let is_init = init.is_some();
  518. let seeds = seeds.map(|c| ConstraintSeedsGroup {
  519. is_init,
  520. seeds: c.seeds.clone(),
  521. bump: into_inner!(bump)
  522. .map(|b| b.bump)
  523. .expect("bump must be provided with seeds"),
  524. program_seed: into_inner!(program_seed).map(|id| id.program_seed),
  525. });
  526. let associated_token = match (associated_token_mint, associated_token_authority) {
  527. (Some(mint), Some(auth)) => Some(ConstraintAssociatedToken {
  528. wallet: auth.into_inner().auth,
  529. mint: mint.into_inner().mint,
  530. }),
  531. (Some(mint), None) => return Err(ParseError::new(
  532. mint.span(),
  533. "authority must be provided to specify an associated token program derived address",
  534. )),
  535. (None, Some(auth)) => {
  536. return Err(ParseError::new(
  537. auth.span(),
  538. "mint must be provided to specify an associated token program derived address",
  539. ))
  540. }
  541. _ => None,
  542. };
  543. if let Some(associated_token) = &associated_token {
  544. if seeds.is_some() {
  545. return Err(ParseError::new(
  546. associated_token.mint.span(),
  547. "'associated_token' constraints cannot be used with the 'seeds' constraint",
  548. ));
  549. }
  550. }
  551. let token_account = match (&token_mint, &token_authority) {
  552. (None, None) => None,
  553. _ => Some(ConstraintTokenAccountGroup {
  554. mint: token_mint.as_ref().map(|a| a.clone().into_inner().mint),
  555. authority: token_authority
  556. .as_ref()
  557. .map(|a| a.clone().into_inner().auth),
  558. }),
  559. };
  560. let mint = match (&mint_decimals, &mint_authority, &mint_freeze_authority) {
  561. (None, None, None) => None,
  562. _ => Some(ConstraintTokenMintGroup {
  563. decimals: mint_decimals
  564. .as_ref()
  565. .map(|a| a.clone().into_inner().decimals),
  566. mint_authority: mint_authority
  567. .as_ref()
  568. .map(|a| a.clone().into_inner().mint_auth),
  569. freeze_authority: mint_freeze_authority
  570. .as_ref()
  571. .map(|a| a.clone().into_inner().mint_freeze_auth),
  572. }),
  573. };
  574. Ok(ConstraintGroup {
  575. init: init.as_ref().map(|i| Ok(ConstraintInitGroup {
  576. if_needed: i.if_needed,
  577. seeds: seeds.clone(),
  578. payer: into_inner!(payer.clone()).unwrap().target,
  579. space: space.clone().map(|s| s.space.clone()),
  580. kind: if let Some(tm) = &token_mint {
  581. InitKind::Token {
  582. mint: tm.clone().into_inner().mint,
  583. owner: match &token_authority {
  584. Some(a) => a.clone().into_inner().auth,
  585. None => return Err(ParseError::new(
  586. tm.span(),
  587. "authority must be provided to initialize a token program derived address"
  588. )),
  589. },
  590. }
  591. } else if let Some(at) = &associated_token {
  592. InitKind::AssociatedToken {
  593. mint: at.mint.clone(),
  594. owner: at.wallet.clone()
  595. }
  596. } else if let Some(d) = &mint_decimals {
  597. InitKind::Mint {
  598. decimals: d.clone().into_inner().decimals,
  599. owner: match &mint_authority {
  600. Some(a) => a.clone().into_inner().mint_auth,
  601. None => return Err(ParseError::new(
  602. d.span(),
  603. "authority must be provided to initialize a mint program derived address"
  604. ))
  605. },
  606. freeze_authority: mint_freeze_authority.map(|fa| fa.into_inner().mint_freeze_auth)
  607. }
  608. } else {
  609. InitKind::Program {
  610. owner: owner.as_ref().map(|o| o.owner_address.clone()),
  611. }
  612. },
  613. })).transpose()?,
  614. zeroed: into_inner!(zeroed),
  615. mutable: into_inner!(mutable),
  616. signer: into_inner!(signer),
  617. has_one: into_inner_vec!(has_one),
  618. literal: into_inner_vec!(literal),
  619. raw: into_inner_vec!(raw),
  620. owner: into_inner!(owner),
  621. rent_exempt: into_inner!(rent_exempt),
  622. executable: into_inner!(executable),
  623. state: into_inner!(state),
  624. close: into_inner!(close),
  625. address: into_inner!(address),
  626. associated_token: if !is_init { associated_token } else { None },
  627. seeds,
  628. token_account: if !is_init {token_account} else {None},
  629. mint: if !is_init {mint} else {None},
  630. })
  631. }
  632. pub fn add(&mut self, c: ConstraintToken) -> ParseResult<()> {
  633. match c {
  634. ConstraintToken::Init(c) => self.add_init(c),
  635. ConstraintToken::Zeroed(c) => self.add_zeroed(c),
  636. ConstraintToken::Mut(c) => self.add_mut(c),
  637. ConstraintToken::Signer(c) => self.add_signer(c),
  638. ConstraintToken::HasOne(c) => self.add_has_one(c),
  639. ConstraintToken::Literal(c) => self.add_literal(c),
  640. ConstraintToken::Raw(c) => self.add_raw(c),
  641. ConstraintToken::Owner(c) => self.add_owner(c),
  642. ConstraintToken::RentExempt(c) => self.add_rent_exempt(c),
  643. ConstraintToken::Seeds(c) => self.add_seeds(c),
  644. ConstraintToken::Executable(c) => self.add_executable(c),
  645. ConstraintToken::State(c) => self.add_state(c),
  646. ConstraintToken::Payer(c) => self.add_payer(c),
  647. ConstraintToken::Space(c) => self.add_space(c),
  648. ConstraintToken::Close(c) => self.add_close(c),
  649. ConstraintToken::Address(c) => self.add_address(c),
  650. ConstraintToken::TokenAuthority(c) => self.add_token_authority(c),
  651. ConstraintToken::TokenMint(c) => self.add_token_mint(c),
  652. ConstraintToken::AssociatedTokenAuthority(c) => self.add_associated_token_authority(c),
  653. ConstraintToken::AssociatedTokenMint(c) => self.add_associated_token_mint(c),
  654. ConstraintToken::MintAuthority(c) => self.add_mint_authority(c),
  655. ConstraintToken::MintFreezeAuthority(c) => self.add_mint_freeze_authority(c),
  656. ConstraintToken::MintDecimals(c) => self.add_mint_decimals(c),
  657. ConstraintToken::Bump(c) => self.add_bump(c),
  658. ConstraintToken::ProgramSeed(c) => self.add_program_seed(c),
  659. }
  660. }
  661. fn add_init(&mut self, c: Context<ConstraintInit>) -> ParseResult<()> {
  662. if self.init.is_some() {
  663. return Err(ParseError::new(c.span(), "init already provided"));
  664. }
  665. if self.zeroed.is_some() {
  666. return Err(ParseError::new(c.span(), "zeroed already provided"));
  667. }
  668. if self.token_mint.is_some() {
  669. return Err(ParseError::new(
  670. c.span(),
  671. "init must be provided before token mint",
  672. ));
  673. }
  674. if self.token_authority.is_some() {
  675. return Err(ParseError::new(
  676. c.span(),
  677. "init must be provided before token authority",
  678. ));
  679. }
  680. if self.mint_authority.is_some() {
  681. return Err(ParseError::new(
  682. c.span(),
  683. "init must be provided before mint authority",
  684. ));
  685. }
  686. if self.mint_freeze_authority.is_some() {
  687. return Err(ParseError::new(
  688. c.span(),
  689. "init must be provided before mint freeze authority",
  690. ));
  691. }
  692. if self.mint_decimals.is_some() {
  693. return Err(ParseError::new(
  694. c.span(),
  695. "init must be provided before mint decimals",
  696. ));
  697. }
  698. if self.associated_token_mint.is_some() {
  699. return Err(ParseError::new(
  700. c.span(),
  701. "init must be provided before associated token mint",
  702. ));
  703. }
  704. if self.associated_token_authority.is_some() {
  705. return Err(ParseError::new(
  706. c.span(),
  707. "init must be provided before associated token authority",
  708. ));
  709. }
  710. self.init.replace(c);
  711. Ok(())
  712. }
  713. fn add_zeroed(&mut self, c: Context<ConstraintZeroed>) -> ParseResult<()> {
  714. if self.zeroed.is_some() {
  715. return Err(ParseError::new(c.span(), "zeroed already provided"));
  716. }
  717. if self.init.is_some() {
  718. return Err(ParseError::new(c.span(), "init already provided"));
  719. }
  720. self.zeroed.replace(c);
  721. Ok(())
  722. }
  723. fn add_close(&mut self, c: Context<ConstraintClose>) -> ParseResult<()> {
  724. if !matches!(self.f_ty, Some(Ty::ProgramAccount(_)))
  725. && !matches!(self.f_ty, Some(Ty::Account(_)))
  726. && !matches!(self.f_ty, Some(Ty::Loader(_)))
  727. && !matches!(self.f_ty, Some(Ty::AccountLoader(_)))
  728. {
  729. return Err(ParseError::new(
  730. c.span(),
  731. "close must be on an Account, ProgramAccount, or Loader",
  732. ));
  733. }
  734. if self.mutable.is_none() {
  735. return Err(ParseError::new(
  736. c.span(),
  737. "mut must be provided before close",
  738. ));
  739. }
  740. if self.close.is_some() {
  741. return Err(ParseError::new(c.span(), "close already provided"));
  742. }
  743. self.close.replace(c);
  744. Ok(())
  745. }
  746. fn add_address(&mut self, c: Context<ConstraintAddress>) -> ParseResult<()> {
  747. if self.address.is_some() {
  748. return Err(ParseError::new(c.span(), "address already provided"));
  749. }
  750. self.address.replace(c);
  751. Ok(())
  752. }
  753. fn add_token_mint(&mut self, c: Context<ConstraintTokenMint>) -> ParseResult<()> {
  754. if self.token_mint.is_some() {
  755. return Err(ParseError::new(c.span(), "token mint already provided"));
  756. }
  757. if self.associated_token_mint.is_some() {
  758. return Err(ParseError::new(
  759. c.span(),
  760. "associated token mint already provided",
  761. ));
  762. }
  763. self.token_mint.replace(c);
  764. Ok(())
  765. }
  766. fn add_associated_token_mint(&mut self, c: Context<ConstraintTokenMint>) -> ParseResult<()> {
  767. if self.associated_token_mint.is_some() {
  768. return Err(ParseError::new(
  769. c.span(),
  770. "associated token mint already provided",
  771. ));
  772. }
  773. if self.token_mint.is_some() {
  774. return Err(ParseError::new(c.span(), "token mint already provided"));
  775. }
  776. self.associated_token_mint.replace(c);
  777. Ok(())
  778. }
  779. fn add_bump(&mut self, c: Context<ConstraintTokenBump>) -> ParseResult<()> {
  780. if self.bump.is_some() {
  781. return Err(ParseError::new(c.span(), "bump already provided"));
  782. }
  783. if self.seeds.is_none() {
  784. return Err(ParseError::new(
  785. c.span(),
  786. "seeds must be provided before bump",
  787. ));
  788. }
  789. self.bump.replace(c);
  790. Ok(())
  791. }
  792. fn add_program_seed(&mut self, c: Context<ConstraintProgramSeed>) -> ParseResult<()> {
  793. if self.program_seed.is_some() {
  794. return Err(ParseError::new(c.span(), "seeds::program already provided"));
  795. }
  796. if self.seeds.is_none() {
  797. return Err(ParseError::new(
  798. c.span(),
  799. "seeds must be provided before seeds::program",
  800. ));
  801. }
  802. if let Some(ref init) = self.init {
  803. if init.if_needed {
  804. return Err(ParseError::new(
  805. c.span(),
  806. "seeds::program cannot be used with init_if_needed",
  807. ));
  808. } else {
  809. return Err(ParseError::new(
  810. c.span(),
  811. "seeds::program cannot be used with init",
  812. ));
  813. }
  814. }
  815. self.program_seed.replace(c);
  816. Ok(())
  817. }
  818. fn add_token_authority(&mut self, c: Context<ConstraintTokenAuthority>) -> ParseResult<()> {
  819. if self.token_authority.is_some() {
  820. return Err(ParseError::new(
  821. c.span(),
  822. "token authority already provided",
  823. ));
  824. }
  825. self.token_authority.replace(c);
  826. Ok(())
  827. }
  828. fn add_associated_token_authority(
  829. &mut self,
  830. c: Context<ConstraintTokenAuthority>,
  831. ) -> ParseResult<()> {
  832. if self.associated_token_authority.is_some() {
  833. return Err(ParseError::new(
  834. c.span(),
  835. "associated token authority already provided",
  836. ));
  837. }
  838. if self.token_authority.is_some() {
  839. return Err(ParseError::new(
  840. c.span(),
  841. "token authority already provided",
  842. ));
  843. }
  844. self.associated_token_authority.replace(c);
  845. Ok(())
  846. }
  847. fn add_mint_authority(&mut self, c: Context<ConstraintMintAuthority>) -> ParseResult<()> {
  848. if self.mint_authority.is_some() {
  849. return Err(ParseError::new(c.span(), "mint authority already provided"));
  850. }
  851. self.mint_authority.replace(c);
  852. Ok(())
  853. }
  854. fn add_mint_freeze_authority(
  855. &mut self,
  856. c: Context<ConstraintMintFreezeAuthority>,
  857. ) -> ParseResult<()> {
  858. if self.mint_freeze_authority.is_some() {
  859. return Err(ParseError::new(
  860. c.span(),
  861. "mint freeze_authority already provided",
  862. ));
  863. }
  864. self.mint_freeze_authority.replace(c);
  865. Ok(())
  866. }
  867. fn add_mint_decimals(&mut self, c: Context<ConstraintMintDecimals>) -> ParseResult<()> {
  868. if self.mint_decimals.is_some() {
  869. return Err(ParseError::new(c.span(), "mint decimals already provided"));
  870. }
  871. self.mint_decimals.replace(c);
  872. Ok(())
  873. }
  874. fn add_mut(&mut self, c: Context<ConstraintMut>) -> ParseResult<()> {
  875. if self.mutable.is_some() {
  876. return Err(ParseError::new(c.span(), "mut already provided"));
  877. }
  878. self.mutable.replace(c);
  879. Ok(())
  880. }
  881. fn add_signer(&mut self, c: Context<ConstraintSigner>) -> ParseResult<()> {
  882. if self.signer.is_some() {
  883. return Err(ParseError::new(c.span(), "signer already provided"));
  884. }
  885. self.signer.replace(c);
  886. Ok(())
  887. }
  888. fn add_has_one(&mut self, c: Context<ConstraintHasOne>) -> ParseResult<()> {
  889. if self
  890. .has_one
  891. .iter()
  892. .filter(|item| item.join_target == c.join_target)
  893. .count()
  894. > 0
  895. {
  896. return Err(ParseError::new(c.span(), "has_one target already provided"));
  897. }
  898. self.has_one.push(c);
  899. Ok(())
  900. }
  901. fn add_literal(&mut self, c: Context<ConstraintLiteral>) -> ParseResult<()> {
  902. self.literal.push(c);
  903. Ok(())
  904. }
  905. fn add_raw(&mut self, c: Context<ConstraintRaw>) -> ParseResult<()> {
  906. self.raw.push(c);
  907. Ok(())
  908. }
  909. fn add_owner(&mut self, c: Context<ConstraintOwner>) -> ParseResult<()> {
  910. if self.owner.is_some() {
  911. return Err(ParseError::new(c.span(), "owner already provided"));
  912. }
  913. self.owner.replace(c);
  914. Ok(())
  915. }
  916. fn add_rent_exempt(&mut self, c: Context<ConstraintRentExempt>) -> ParseResult<()> {
  917. if self.rent_exempt.is_some() {
  918. return Err(ParseError::new(c.span(), "rent already provided"));
  919. }
  920. self.rent_exempt.replace(c);
  921. Ok(())
  922. }
  923. fn add_seeds(&mut self, c: Context<ConstraintSeeds>) -> ParseResult<()> {
  924. if self.seeds.is_some() {
  925. return Err(ParseError::new(c.span(), "seeds already provided"));
  926. }
  927. self.seeds.replace(c);
  928. Ok(())
  929. }
  930. fn add_executable(&mut self, c: Context<ConstraintExecutable>) -> ParseResult<()> {
  931. if self.executable.is_some() {
  932. return Err(ParseError::new(c.span(), "executable already provided"));
  933. }
  934. self.executable.replace(c);
  935. Ok(())
  936. }
  937. fn add_state(&mut self, c: Context<ConstraintState>) -> ParseResult<()> {
  938. if self.state.is_some() {
  939. return Err(ParseError::new(c.span(), "state already provided"));
  940. }
  941. self.state.replace(c);
  942. Ok(())
  943. }
  944. fn add_payer(&mut self, c: Context<ConstraintPayer>) -> ParseResult<()> {
  945. if self.init.is_none() {
  946. return Err(ParseError::new(
  947. c.span(),
  948. "init must be provided before payer",
  949. ));
  950. }
  951. if self.payer.is_some() {
  952. return Err(ParseError::new(c.span(), "payer already provided"));
  953. }
  954. self.payer.replace(c);
  955. Ok(())
  956. }
  957. fn add_space(&mut self, c: Context<ConstraintSpace>) -> ParseResult<()> {
  958. if self.init.is_none() {
  959. return Err(ParseError::new(
  960. c.span(),
  961. "init must be provided before space",
  962. ));
  963. }
  964. if self.space.is_some() {
  965. return Err(ParseError::new(c.span(), "space already provided"));
  966. }
  967. self.space.replace(c);
  968. Ok(())
  969. }
  970. }