Compare commits
4 Commits
c9e147d7c2
...
fe11f6710b
Author | SHA1 | Date |
---|---|---|
Jimii | fe11f6710b | |
acheron | 257b560109 | |
acheron | 95c4959287 | |
Jimii | 037a618fd7 |
|
@ -44,6 +44,7 @@ The minor version will be incremented upon a breaking change and the patch versi
|
|||
- idl: Store deployment addresses for other clusters ([#2892](https://github.com/coral-xyz/anchor/pull/2892)).
|
||||
- lang: Add `Event` utility type to get events from bytes ([#2897](https://github.com/coral-xyz/anchor/pull/2897)).
|
||||
- lang, spl: Add support for [token extensions](https://solana.com/solutions/token-extensions) ([#2789](https://github.com/coral-xyz/anchor/pull/2789)).
|
||||
- lang: Return overflow error from `Lamports` trait operations ([#2907](https://github.com/coral-xyz/anchor/pull/2907)).
|
||||
|
||||
### Fixes
|
||||
|
||||
|
@ -71,7 +72,8 @@ The minor version will be incremented upon a breaking change and the patch versi
|
|||
- avm, cli: Fix `stdsimd` feature compilation error from `ahash` when installing the CLI using newer Rust versions ([#2867](https://github.com/coral-xyz/anchor/pull/2867)).
|
||||
- spl: Fix not being able to deserialize newer token 2022 extensions ([#2876](https://github.com/coral-xyz/anchor/pull/2876)).
|
||||
- spl: Remove `solana-program` dependency ([#2900](https://github.com/coral-xyz/anchor/pull/2900)).
|
||||
- spl: Make TokenAccount and Mint Copy ([#2904])(https://github.com/coral-xyz/anchor/pull/2904)
|
||||
- spl: Make `TokenAccount` and ` Mint` `Copy` ([#2904](https://github.com/coral-xyz/anchor/pull/2904)).
|
||||
- ts: Add missing errors ([#2906](https://github.com/coral-xyz/anchor/pull/2906)).
|
||||
|
||||
### Breaking
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ extern crate self as anchor_lang;
|
|||
use bytemuck::{Pod, Zeroable};
|
||||
use solana_program::account_info::AccountInfo;
|
||||
use solana_program::instruction::AccountMeta;
|
||||
use solana_program::program_error::ProgramError;
|
||||
use solana_program::pubkey::Pubkey;
|
||||
use std::{collections::BTreeSet, fmt::Debug, io::Write};
|
||||
|
||||
|
@ -197,7 +198,10 @@ pub trait Lamports<'info>: AsRef<AccountInfo<'info>> {
|
|||
///
|
||||
/// See [`Lamports::sub_lamports`] for subtracting lamports.
|
||||
fn add_lamports(&self, amount: u64) -> Result<&Self> {
|
||||
**self.as_ref().try_borrow_mut_lamports()? += amount;
|
||||
**self.as_ref().try_borrow_mut_lamports()? = self
|
||||
.get_lamports()
|
||||
.checked_add(amount)
|
||||
.ok_or(ProgramError::ArithmeticOverflow)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
|
@ -215,7 +219,10 @@ pub trait Lamports<'info>: AsRef<AccountInfo<'info>> {
|
|||
///
|
||||
/// See [`Lamports::add_lamports`] for adding lamports.
|
||||
fn sub_lamports(&self, amount: u64) -> Result<&Self> {
|
||||
**self.as_ref().try_borrow_mut_lamports()? -= amount;
|
||||
**self.as_ref().try_borrow_mut_lamports()? = self
|
||||
.get_lamports()
|
||||
.checked_sub(amount)
|
||||
.ok_or(ProgramError::ArithmeticOverflow)?;
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ stake = ["borsh"]
|
|||
token = ["spl-token"]
|
||||
token_2022 = ["spl-token-2022"]
|
||||
token_2022_extensions = ["spl-token-2022", "spl-token-group-interface", "spl-token-metadata-interface", "spl-pod"]
|
||||
mpl_core = ["mpl-core"]
|
||||
|
||||
[dependencies]
|
||||
anchor-lang = { path = "../lang", version = "0.29.0", features = ["derive"] }
|
||||
|
@ -38,3 +39,4 @@ spl-token-2022 = { version = "3", features = ["no-entrypoint"], optional = true
|
|||
spl-token-group-interface = { version = "0.2.3", optional = true }
|
||||
spl-token-metadata-interface = { version = "0.3.3", optional = true }
|
||||
spl-pod = { version = "0.2.2", optional = true }
|
||||
mpl-core = { version = "0.4.4", optional = true}
|
||||
|
|
|
@ -37,3 +37,6 @@ pub mod memo;
|
|||
|
||||
#[cfg(feature = "idl-build")]
|
||||
mod idl_build;
|
||||
|
||||
#[cfg(feature = "mpl_core")]
|
||||
mod mpl_core;
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
use anchor_lang::error::ErrorCode;
|
||||
use std::ops::Deref;
|
||||
|
||||
pub use mpl_core;
|
||||
pub use mpl_core::ID;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct AssetAccount(mpl_core::Asset);
|
||||
|
||||
impl anchor_lang::AccountDeserialize for AssetAccount {
|
||||
fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
|
||||
let asset = Self::try_deserialize_unchecked(buf)?;
|
||||
if asset.base.key == mpl_core::types::Key::Uninitialized {
|
||||
return Err(ErrorCode::AccountNotInitialized.into());
|
||||
}
|
||||
|
||||
Ok(asset)
|
||||
}
|
||||
|
||||
fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
|
||||
let asset = mpl_core::Asset::deserialize(buf)?;
|
||||
Ok(Self(asset))
|
||||
}
|
||||
}
|
||||
|
||||
impl anchor_lang::AccountSerialize for AssetAccount {}
|
||||
|
||||
impl anchor_lang::Owner for AssetAccount {
|
||||
fn owner() -> Pubkey {
|
||||
ID
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for AssetAccount {
|
||||
type Target = mpl_core::Asset;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct BaseAssetV1Account(mpl_core::accounts::BaseAssetV1);
|
||||
|
||||
impl anchor_lang::AccountDeserialize for BaseAssetV1Account {
|
||||
fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
|
||||
let base_asset = Self::try_deserialize_unchecked(buf)?;
|
||||
if base_asset.key == mpl_core::types::Key::Uninitialized {
|
||||
return Err(ErrorCode::AccountNotInitialized.into());
|
||||
}
|
||||
|
||||
Ok(base_asset)
|
||||
}
|
||||
|
||||
fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
|
||||
let base_asset = mpl_core::accounts::BaseAssetV1::deserialize(buf)?;
|
||||
Ok(Self(base_asset))
|
||||
}
|
||||
}
|
||||
|
||||
impl anchor_lang::AccountSerialize for BaseAssetV1Account {}
|
||||
|
||||
impl anchor_lang::Owner for BaseAssetV1Account {
|
||||
fn owner() -> Pubkey {
|
||||
ID
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for BaseAssetV1Account {
|
||||
type Target = mpl_core::accounts::BaseAssetV1;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MplCore;
|
||||
|
||||
impl anchor_lang::Id for MplCore {
|
||||
fn id() -> Pubkey {
|
||||
mpl_core::ID
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ declare_id!("Lamports11111111111111111111111111111111111");
|
|||
pub mod lamports {
|
||||
use super::*;
|
||||
|
||||
pub fn test_lamports_trait(ctx: Context<TestLamportsTrait>, amount: u64) -> Result<()> {
|
||||
pub fn transfer(ctx: Context<Transfer>, amount: u64) -> Result<()> {
|
||||
let pda = &ctx.accounts.pda;
|
||||
let signer = &ctx.accounts.signer;
|
||||
|
||||
|
@ -52,13 +52,29 @@ pub mod lamports {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Return overflow error in the case of overflow (instead of panicking)
|
||||
pub fn overflow(ctx: Context<Overflow>) -> Result<()> {
|
||||
let pda = &ctx.accounts.pda;
|
||||
|
||||
match pda.add_lamports(u64::MAX) {
|
||||
Err(e) => assert_eq!(e, ProgramError::ArithmeticOverflow.into()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
match pda.sub_lamports(u64::MAX) {
|
||||
Err(e) => assert_eq!(e, ProgramError::ArithmeticOverflow.into()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct TestLamportsTrait<'info> {
|
||||
pub struct Transfer<'info> {
|
||||
#[account(mut)]
|
||||
pub signer: Signer<'info>,
|
||||
|
||||
#[account(
|
||||
init,
|
||||
payer = signer,
|
||||
|
@ -67,9 +83,14 @@ pub struct TestLamportsTrait<'info> {
|
|||
bump
|
||||
)]
|
||||
pub pda: Account<'info, LamportsPda>,
|
||||
|
||||
pub system_program: Program<'info, System>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Overflow<'info> {
|
||||
#[account(seeds = [b"lamports"], bump)]
|
||||
pub pda: Account<'info, LamportsPda>,
|
||||
}
|
||||
|
||||
#[account]
|
||||
pub struct LamportsPda {}
|
||||
|
|
|
@ -8,16 +8,13 @@ describe("lamports", () => {
|
|||
|
||||
const program = anchor.workspace.Lamports as anchor.Program<Lamports>;
|
||||
|
||||
it("Can use the Lamports trait", async () => {
|
||||
const signer = program.provider.publicKey!;
|
||||
const [pda] = anchor.web3.PublicKey.findProgramAddressSync(
|
||||
[Buffer.from("lamports")],
|
||||
program.programId
|
||||
);
|
||||
|
||||
it("Can transfer from/to PDA", async () => {
|
||||
await program.methods
|
||||
.testLamportsTrait(new anchor.BN(anchor.web3.LAMPORTS_PER_SOL))
|
||||
.accounts({ signer, pda })
|
||||
.transfer(new anchor.BN(anchor.web3.LAMPORTS_PER_SOL))
|
||||
.rpc();
|
||||
});
|
||||
|
||||
it("Returns an error on overflow", async () => {
|
||||
await program.methods.overflow().rpc();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -315,6 +315,10 @@ export const LangErrorCode = {
|
|||
// IDL instructions.
|
||||
IdlInstructionStub: 1000,
|
||||
IdlInstructionInvalidProgram: 1001,
|
||||
IdlAccountNotEmpty: 1002,
|
||||
|
||||
// Event instructions.
|
||||
EventInstructionStub: 1500,
|
||||
|
||||
// Constraints.
|
||||
ConstraintMut: 2000,
|
||||
|
@ -338,6 +342,25 @@ export const LangErrorCode = {
|
|||
ConstraintMintDecimals: 2018,
|
||||
ConstraintSpace: 2019,
|
||||
ConstraintAccountIsNone: 2020,
|
||||
ConstraintTokenTokenProgram: 2021,
|
||||
ConstraintMintTokenProgram: 2022,
|
||||
ConstraintAssociatedTokenTokenProgram: 2023,
|
||||
ConstraintMintGroupPointerExtension: 2024,
|
||||
ConstraintMintGroupPointerExtensionAuthority: 2025,
|
||||
ConstraintMintGroupPointerExtensionGroupAddress: 2026,
|
||||
ConstraintMintGroupMemberPointerExtension: 2027,
|
||||
ConstraintMintGroupMemberPointerExtensionAuthority: 2028,
|
||||
ConstraintMintGroupMemberPointerExtensionMemberAddress: 2029,
|
||||
ConstraintMintMetadataPointerExtension: 2030,
|
||||
ConstraintMintMetadataPointerExtensionAuthority: 2031,
|
||||
ConstraintMintMetadataPointerExtensionMetadataAddress: 2032,
|
||||
ConstraintMintCloseAuthorityExtension: 2033,
|
||||
ConstraintMintCloseAuthorityExtensionAuthority: 2034,
|
||||
ConstraintMintPermanentDelegateExtension: 2035,
|
||||
ConstraintMintPermanentDelegateExtensionDelegate: 2036,
|
||||
ConstraintMintTransferHookExtension: 2037,
|
||||
ConstraintMintTransferHookExtensionAuthority: 2038,
|
||||
ConstraintMintTransferHookExtensionProgramId: 2039,
|
||||
|
||||
// Require.
|
||||
RequireViolated: 2500,
|
||||
|
@ -370,6 +393,7 @@ export const LangErrorCode = {
|
|||
|
||||
// Miscellaneous
|
||||
DeclaredProgramIdMismatch: 4100,
|
||||
TryingToInitPayerAsProgramAccount: 4101,
|
||||
|
||||
// Used for APIs that shouldn't be used anymore.
|
||||
Deprecated: 5000,
|
||||
|
@ -403,6 +427,16 @@ export const LangErrorMessage = new Map([
|
|||
LangErrorCode.IdlInstructionInvalidProgram,
|
||||
"The transaction was given an invalid program for the IDL instruction",
|
||||
],
|
||||
[
|
||||
LangErrorCode.IdlAccountNotEmpty,
|
||||
"IDL account must be empty in order to resize, try closing first",
|
||||
],
|
||||
|
||||
// Event instructions.
|
||||
[
|
||||
LangErrorCode.EventInstructionStub,
|
||||
"The program was compiled without `event-cpi` feature",
|
||||
],
|
||||
|
||||
// Constraints.
|
||||
[LangErrorCode.ConstraintMut, "A mut constraint was violated"],
|
||||
|
@ -447,6 +481,82 @@ export const LangErrorMessage = new Map([
|
|||
LangErrorCode.ConstraintAccountIsNone,
|
||||
"A required account for the constraint is None",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintTokenTokenProgram,
|
||||
"A token account token program constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintTokenProgram,
|
||||
"A mint token program constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintAssociatedTokenTokenProgram,
|
||||
"An associated token account token program constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintGroupPointerExtension,
|
||||
"A group pointer extension constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintGroupPointerExtensionAuthority,
|
||||
"A group pointer extension authority constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintGroupPointerExtensionGroupAddress,
|
||||
"A group pointer extension group address constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintGroupMemberPointerExtension,
|
||||
"A group member pointer extension constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintGroupMemberPointerExtensionAuthority,
|
||||
"A group member pointer extension authority constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintGroupMemberPointerExtensionMemberAddress,
|
||||
"A group member pointer extension group address constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintMetadataPointerExtension,
|
||||
"A metadata pointer extension constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintMetadataPointerExtensionAuthority,
|
||||
"A metadata pointer extension authority constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintMetadataPointerExtensionMetadataAddress,
|
||||
"A metadata pointer extension metadata address constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintCloseAuthorityExtension,
|
||||
"A close authority constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintCloseAuthorityExtensionAuthority,
|
||||
"A close authority extension authority constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintPermanentDelegateExtension,
|
||||
"A permanent delegate extension constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintPermanentDelegateExtensionDelegate,
|
||||
"A permanent delegate extension delegate constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintTransferHookExtension,
|
||||
"A transfer hook extension constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintTransferHookExtensionAuthority,
|
||||
"A transfer hook extension authority constraint was violated",
|
||||
],
|
||||
[
|
||||
LangErrorCode.ConstraintMintTransferHookExtensionProgramId,
|
||||
"A transfer hook extension transfer hook program id constraint was violated",
|
||||
],
|
||||
|
||||
// Require.
|
||||
[LangErrorCode.RequireViolated, "A require expression was violated"],
|
||||
|
@ -524,6 +634,10 @@ export const LangErrorMessage = new Map([
|
|||
LangErrorCode.DeclaredProgramIdMismatch,
|
||||
"The declared program id does not match the actual program id",
|
||||
],
|
||||
[
|
||||
LangErrorCode.TryingToInitPayerAsProgramAccount,
|
||||
"You cannot/should not initialize the payer account as a program account",
|
||||
],
|
||||
|
||||
// Deprecated
|
||||
[
|
||||
|
|
Loading…
Reference in New Issue