lang, ts: fix init_if_needed missing ATA address check (#1221)
This commit is contained in:
parent
4013ec9337
commit
b3720a0b84
|
@ -14,7 +14,8 @@ incremented for features.
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|
||||||
* ts: Change commitment message `recent` to `processed` and `max` to `finalized` ([#1128](https://github.com/project-serum/anchor/pull/1128))
|
* ts: Change commitment message `recent` to `processed` and `max` to `finalized` ([#1128](https://github.com/project-serum/anchor/pull/1128))
|
||||||
* ts: fix `translateAddress` which currently leads to failing browser code. Now uses `PublicKey` constructor instead of prototype chain constructor name checking which doesn't work in the presence of code minifying/mangling([1138](https://github.com/project-serum/anchor/pull/1138))
|
* ts: fix `translateAddress` which currently leads to failing browser code. Now uses `PublicKey` constructor instead of prototype chain constructor name checking which doesn't work in the presence of code minifying/mangling([#1138](https://github.com/project-serum/anchor/pull/1138))
|
||||||
|
* lang: add missing check that verifies that account is ATA when using `init_if_needed` and init is not needed([#1221](https://github.com/project-serum/anchor/pull/1221))
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
|
|
|
@ -422,7 +422,7 @@ impl FromStr for Config {
|
||||||
cluster: cfg.provider.cluster.parse()?,
|
cluster: cfg.provider.cluster.parse()?,
|
||||||
wallet: shellexpand::tilde(&cfg.provider.wallet).parse()?,
|
wallet: shellexpand::tilde(&cfg.provider.wallet).parse()?,
|
||||||
},
|
},
|
||||||
scripts: cfg.scripts.unwrap_or_else(BTreeMap::new),
|
scripts: cfg.scripts.unwrap_or_default(),
|
||||||
test: cfg.test,
|
test: cfg.test,
|
||||||
programs: cfg.programs.map_or(Ok(BTreeMap::new()), deser_programs)?,
|
programs: cfg.programs.map_or(Ok(BTreeMap::new()), deser_programs)?,
|
||||||
workspace: cfg.workspace.unwrap_or_default(),
|
workspace: cfg.workspace.unwrap_or_default(),
|
||||||
|
|
|
@ -142,6 +142,9 @@ pub enum ErrorCode {
|
||||||
/// 3013 - The given account is not a program data account
|
/// 3013 - The given account is not a program data account
|
||||||
#[msg("The given account is not a program data account")]
|
#[msg("The given account is not a program data account")]
|
||||||
AccountNotProgramData,
|
AccountNotProgramData,
|
||||||
|
/// 3014 - The given account is not the associated token account
|
||||||
|
#[msg("The given account is not the associated token account")]
|
||||||
|
AccountNotAssociatedTokenAccount,
|
||||||
|
|
||||||
// State.
|
// State.
|
||||||
/// 4000 - The given state account does not have the correct address
|
/// 4000 - The given state account does not have the correct address
|
||||||
|
|
|
@ -488,6 +488,10 @@ pub fn generate_init(
|
||||||
if pa.owner != #owner.key() {
|
if pa.owner != #owner.key() {
|
||||||
return Err(anchor_lang::__private::ErrorCode::ConstraintTokenOwner.into());
|
return Err(anchor_lang::__private::ErrorCode::ConstraintTokenOwner.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pa.key() != anchor_spl::associated_token::get_associated_token_address(&#owner.key(), &#mint.key()) {
|
||||||
|
return Err(anchor_lang::__private::ErrorCode::AccountNotAssociatedTokenAccount.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pa
|
pa
|
||||||
};
|
};
|
||||||
|
|
|
@ -1282,6 +1282,70 @@ describe("misc", () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("init_if_needed throws if token exists with correct owner and mint but is not the ATA", async () => {
|
||||||
|
const mint = anchor.web3.Keypair.generate();
|
||||||
|
await program.rpc.testInitMint({
|
||||||
|
accounts: {
|
||||||
|
mint: mint.publicKey,
|
||||||
|
payer: program.provider.wallet.publicKey,
|
||||||
|
systemProgram: anchor.web3.SystemProgram.programId,
|
||||||
|
tokenProgram: TOKEN_PROGRAM_ID,
|
||||||
|
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
||||||
|
},
|
||||||
|
signers: [mint],
|
||||||
|
});
|
||||||
|
|
||||||
|
const associatedToken = await Token.getAssociatedTokenAddress(
|
||||||
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||||
|
TOKEN_PROGRAM_ID,
|
||||||
|
mint.publicKey,
|
||||||
|
program.provider.wallet.publicKey
|
||||||
|
);
|
||||||
|
|
||||||
|
await program.rpc.testInitAssociatedToken({
|
||||||
|
accounts: {
|
||||||
|
token: associatedToken,
|
||||||
|
mint: mint.publicKey,
|
||||||
|
payer: program.provider.wallet.publicKey,
|
||||||
|
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
||||||
|
systemProgram: anchor.web3.SystemProgram.programId,
|
||||||
|
tokenProgram: TOKEN_PROGRAM_ID,
|
||||||
|
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const token = anchor.web3.Keypair.generate();
|
||||||
|
await program.rpc.testInitToken({
|
||||||
|
accounts: {
|
||||||
|
token: token.publicKey,
|
||||||
|
mint: mint.publicKey,
|
||||||
|
payer: program.provider.wallet.publicKey,
|
||||||
|
systemProgram: anchor.web3.SystemProgram.programId,
|
||||||
|
tokenProgram: TOKEN_PROGRAM_ID,
|
||||||
|
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
||||||
|
},
|
||||||
|
signers: [token],
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await program.rpc.testInitAssociatedTokenIfNeeded({
|
||||||
|
accounts: {
|
||||||
|
token: token.publicKey,
|
||||||
|
mint: mint.publicKey,
|
||||||
|
payer: program.provider.wallet.publicKey,
|
||||||
|
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
||||||
|
systemProgram: anchor.web3.SystemProgram.programId,
|
||||||
|
tokenProgram: TOKEN_PROGRAM_ID,
|
||||||
|
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||||
|
authority: program.provider.wallet.publicKey,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
assert.ok(false);
|
||||||
|
} catch (err) {
|
||||||
|
assert.equal(err.code, 3014);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it("Can use multidimensional array", async () => {
|
it("Can use multidimensional array", async () => {
|
||||||
const array2d = new Array(10).fill(new Array(10).fill(99));
|
const array2d = new Array(10).fill(new Array(10).fill(99));
|
||||||
const data = anchor.web3.Keypair.generate();
|
const data = anchor.web3.Keypair.generate();
|
||||||
|
|
|
@ -98,6 +98,7 @@ const LangErrorCode = {
|
||||||
AccountNotSystemOwned: 3011,
|
AccountNotSystemOwned: 3011,
|
||||||
AccountNotInitialized: 3012,
|
AccountNotInitialized: 3012,
|
||||||
AccountNotProgramData: 3013,
|
AccountNotProgramData: 3013,
|
||||||
|
AccountNotAssociatedTokenAccount: 3014,
|
||||||
// State.
|
// State.
|
||||||
StateInvalidAddress: 4000,
|
StateInvalidAddress: 4000,
|
||||||
|
|
||||||
|
@ -207,6 +208,10 @@ const LangErrorMessage = new Map([
|
||||||
LangErrorCode.AccountNotProgramData,
|
LangErrorCode.AccountNotProgramData,
|
||||||
"The given account is not a program data account",
|
"The given account is not a program data account",
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
LangErrorCode.AccountNotAssociatedTokenAccount,
|
||||||
|
"The given account is not the associated token account",
|
||||||
|
],
|
||||||
|
|
||||||
// State.
|
// State.
|
||||||
[
|
[
|
||||||
|
|
Loading…
Reference in New Issue