constraints.rs 40 KB

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