Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
11 changes: 9 additions & 2 deletions lang/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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)
}

Expand All @@ -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)
}
}
Expand Down
29 changes: 25 additions & 4 deletions tests/misc/programs/lamports/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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,
Expand All @@ -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 {}
15 changes: 6 additions & 9 deletions tests/misc/tests/lamports/lamports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
});