|
@@ -121,6 +121,33 @@ pub fn parse_token(stream: ParseStream) -> ParseResult<ConstraintToken> {
|
|
_ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
|
|
_ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ "associated_token" => {
|
|
|
|
+ stream.parse::<Token![:]>()?;
|
|
|
|
+ stream.parse::<Token![:]>()?;
|
|
|
|
+ let kw = stream.call(Ident::parse_any)?.to_string();
|
|
|
|
+ stream.parse::<Token![=]>()?;
|
|
|
|
+
|
|
|
|
+ let span = ident
|
|
|
|
+ .span()
|
|
|
|
+ .join(stream.span())
|
|
|
|
+ .unwrap_or_else(|| ident.span());
|
|
|
|
+
|
|
|
|
+ match kw.as_str() {
|
|
|
|
+ "mint" => ConstraintToken::AssociatedTokenMint(Context::new(
|
|
|
|
+ span,
|
|
|
|
+ ConstraintTokenMint {
|
|
|
|
+ mint: stream.parse()?,
|
|
|
|
+ },
|
|
|
|
+ )),
|
|
|
|
+ "authority" => ConstraintToken::AssociatedTokenAuthority(Context::new(
|
|
|
|
+ span,
|
|
|
|
+ ConstraintTokenAuthority {
|
|
|
|
+ auth: stream.parse()?,
|
|
|
|
+ },
|
|
|
|
+ )),
|
|
|
|
+ _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
"bump" => {
|
|
"bump" => {
|
|
let bump = {
|
|
let bump = {
|
|
if stream.peek(Token![=]) {
|
|
if stream.peek(Token![=]) {
|
|
@@ -246,6 +273,8 @@ pub struct ConstraintGroupBuilder<'ty> {
|
|
pub address: Option<Context<ConstraintAddress>>,
|
|
pub address: Option<Context<ConstraintAddress>>,
|
|
pub token_mint: Option<Context<ConstraintTokenMint>>,
|
|
pub token_mint: Option<Context<ConstraintTokenMint>>,
|
|
pub token_authority: Option<Context<ConstraintTokenAuthority>>,
|
|
pub token_authority: Option<Context<ConstraintTokenAuthority>>,
|
|
|
|
+ pub associated_token_mint: Option<Context<ConstraintTokenMint>>,
|
|
|
|
+ pub associated_token_authority: Option<Context<ConstraintTokenAuthority>>,
|
|
pub mint_authority: Option<Context<ConstraintMintAuthority>>,
|
|
pub mint_authority: Option<Context<ConstraintMintAuthority>>,
|
|
pub mint_decimals: Option<Context<ConstraintMintDecimals>>,
|
|
pub mint_decimals: Option<Context<ConstraintMintDecimals>>,
|
|
pub bump: Option<Context<ConstraintTokenBump>>,
|
|
pub bump: Option<Context<ConstraintTokenBump>>,
|
|
@@ -273,6 +302,8 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
|
address: None,
|
|
address: None,
|
|
token_mint: None,
|
|
token_mint: None,
|
|
token_authority: None,
|
|
token_authority: None,
|
|
|
|
+ associated_token_mint: None,
|
|
|
|
+ associated_token_authority: None,
|
|
mint_authority: None,
|
|
mint_authority: None,
|
|
mint_decimals: None,
|
|
mint_decimals: None,
|
|
bump: None,
|
|
bump: None,
|
|
@@ -307,7 +338,8 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
|
// When initializing a non-PDA account, the account being
|
|
// When initializing a non-PDA account, the account being
|
|
// initialized must sign to invoke the system program's create
|
|
// initialized must sign to invoke the system program's create
|
|
// account instruction.
|
|
// account instruction.
|
|
- if self.signer.is_none() && self.seeds.is_none() {
|
|
|
|
|
|
+ if self.signer.is_none() && self.seeds.is_none() && self.associated_token_mint.is_none()
|
|
|
|
+ {
|
|
self.signer
|
|
self.signer
|
|
.replace(Context::new(i.span(), ConstraintSigner {}));
|
|
.replace(Context::new(i.span(), ConstraintSigner {}));
|
|
}
|
|
}
|
|
@@ -425,6 +457,8 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
|
address,
|
|
address,
|
|
token_mint,
|
|
token_mint,
|
|
token_authority,
|
|
token_authority,
|
|
|
|
+ associated_token_mint,
|
|
|
|
+ associated_token_authority,
|
|
mint_authority,
|
|
mint_authority,
|
|
mint_decimals,
|
|
mint_decimals,
|
|
bump,
|
|
bump,
|
|
@@ -469,6 +503,17 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
|
)),
|
|
)),
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
+ } else if let Some(tm) = &associated_token_mint {
|
|
|
|
+ InitKind::AssociatedToken {
|
|
|
|
+ mint: tm.clone().into_inner().mint,
|
|
|
|
+ owner: match &associated_token_authority {
|
|
|
|
+ Some(a) => a.clone().into_inner().auth,
|
|
|
|
+ None => return Err(ParseError::new(
|
|
|
|
+ tm.span(),
|
|
|
|
+ "authority must be provided to initialize a token program derived address"
|
|
|
|
+ )),
|
|
|
|
+ },
|
|
|
|
+ }
|
|
} else if let Some(d) = &mint_decimals {
|
|
} else if let Some(d) = &mint_decimals {
|
|
InitKind::Mint {
|
|
InitKind::Mint {
|
|
decimals: d.clone().into_inner().decimals,
|
|
decimals: d.clone().into_inner().decimals,
|
|
@@ -522,6 +567,8 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
|
ConstraintToken::Address(c) => self.add_address(c),
|
|
ConstraintToken::Address(c) => self.add_address(c),
|
|
ConstraintToken::TokenAuthority(c) => self.add_token_authority(c),
|
|
ConstraintToken::TokenAuthority(c) => self.add_token_authority(c),
|
|
ConstraintToken::TokenMint(c) => self.add_token_mint(c),
|
|
ConstraintToken::TokenMint(c) => self.add_token_mint(c),
|
|
|
|
+ ConstraintToken::AssociatedTokenAuthority(c) => self.add_associated_token_authority(c),
|
|
|
|
+ ConstraintToken::AssociatedTokenMint(c) => self.add_associated_token_mint(c),
|
|
ConstraintToken::MintAuthority(c) => self.add_mint_authority(c),
|
|
ConstraintToken::MintAuthority(c) => self.add_mint_authority(c),
|
|
ConstraintToken::MintDecimals(c) => self.add_mint_decimals(c),
|
|
ConstraintToken::MintDecimals(c) => self.add_mint_decimals(c),
|
|
ConstraintToken::Bump(c) => self.add_bump(c),
|
|
ConstraintToken::Bump(c) => self.add_bump(c),
|
|
@@ -585,6 +632,12 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
|
if self.token_mint.is_some() {
|
|
if self.token_mint.is_some() {
|
|
return Err(ParseError::new(c.span(), "token mint already provided"));
|
|
return Err(ParseError::new(c.span(), "token mint already provided"));
|
|
}
|
|
}
|
|
|
|
+ if self.associated_token_mint.is_some() {
|
|
|
|
+ return Err(ParseError::new(
|
|
|
|
+ c.span(),
|
|
|
|
+ "associated token mint already provided",
|
|
|
|
+ ));
|
|
|
|
+ }
|
|
if self.init.is_none() {
|
|
if self.init.is_none() {
|
|
return Err(ParseError::new(
|
|
return Err(ParseError::new(
|
|
c.span(),
|
|
c.span(),
|
|
@@ -595,6 +648,26 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ fn add_associated_token_mint(&mut self, c: Context<ConstraintTokenMint>) -> ParseResult<()> {
|
|
|
|
+ if self.associated_token_mint.is_some() {
|
|
|
|
+ return Err(ParseError::new(
|
|
|
|
+ c.span(),
|
|
|
|
+ "associated token mint already provided",
|
|
|
|
+ ));
|
|
|
|
+ }
|
|
|
|
+ if self.token_mint.is_some() {
|
|
|
|
+ return Err(ParseError::new(c.span(), "token mint already provided"));
|
|
|
|
+ }
|
|
|
|
+ if self.init.is_none() {
|
|
|
|
+ return Err(ParseError::new(
|
|
|
|
+ c.span(),
|
|
|
|
+ "init must be provided before token",
|
|
|
|
+ ));
|
|
|
|
+ }
|
|
|
|
+ self.associated_token_mint.replace(c);
|
|
|
|
+ Ok(())
|
|
|
|
+ }
|
|
|
|
+
|
|
fn add_bump(&mut self, c: Context<ConstraintTokenBump>) -> ParseResult<()> {
|
|
fn add_bump(&mut self, c: Context<ConstraintTokenBump>) -> ParseResult<()> {
|
|
if self.bump.is_some() {
|
|
if self.bump.is_some() {
|
|
return Err(ParseError::new(c.span(), "bump already provided"));
|
|
return Err(ParseError::new(c.span(), "bump already provided"));
|
|
@@ -626,6 +699,32 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ fn add_associated_token_authority(
|
|
|
|
+ &mut self,
|
|
|
|
+ c: Context<ConstraintTokenAuthority>,
|
|
|
|
+ ) -> ParseResult<()> {
|
|
|
|
+ if self.associated_token_authority.is_some() {
|
|
|
|
+ return Err(ParseError::new(
|
|
|
|
+ c.span(),
|
|
|
|
+ "associated token authority already provided",
|
|
|
|
+ ));
|
|
|
|
+ }
|
|
|
|
+ if self.token_authority.is_some() {
|
|
|
|
+ return Err(ParseError::new(
|
|
|
|
+ c.span(),
|
|
|
|
+ "token authority already provided",
|
|
|
|
+ ));
|
|
|
|
+ }
|
|
|
|
+ if self.init.is_none() {
|
|
|
|
+ return Err(ParseError::new(
|
|
|
|
+ c.span(),
|
|
|
|
+ "init must be provided before token authority",
|
|
|
|
+ ));
|
|
|
|
+ }
|
|
|
|
+ self.associated_token_authority.replace(c);
|
|
|
|
+ Ok(())
|
|
|
|
+ }
|
|
|
|
+
|
|
fn add_mint_authority(&mut self, c: Context<ConstraintMintAuthority>) -> ParseResult<()> {
|
|
fn add_mint_authority(&mut self, c: Context<ConstraintMintAuthority>) -> ParseResult<()> {
|
|
if self.mint_authority.is_some() {
|
|
if self.mint_authority.is_some() {
|
|
return Err(ParseError::new(c.span(), "mint authority already provided"));
|
|
return Err(ParseError::new(c.span(), "mint authority already provided"));
|