lang: Return overflow error from `Lamports` trait operations (#2907)
This commit is contained in:
parent
95c4959287
commit
257b560109
|
@ -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)).
|
- 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: 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, 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
|
### Fixes
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ extern crate self as anchor_lang;
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use solana_program::account_info::AccountInfo;
|
use solana_program::account_info::AccountInfo;
|
||||||
use solana_program::instruction::AccountMeta;
|
use solana_program::instruction::AccountMeta;
|
||||||
|
use solana_program::program_error::ProgramError;
|
||||||
use solana_program::pubkey::Pubkey;
|
use solana_program::pubkey::Pubkey;
|
||||||
use std::{collections::BTreeSet, fmt::Debug, io::Write};
|
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.
|
/// See [`Lamports::sub_lamports`] for subtracting lamports.
|
||||||
fn add_lamports(&self, amount: u64) -> Result<&Self> {
|
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)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +219,10 @@ pub trait Lamports<'info>: AsRef<AccountInfo<'info>> {
|
||||||
///
|
///
|
||||||
/// See [`Lamports::add_lamports`] for adding lamports.
|
/// See [`Lamports::add_lamports`] for adding lamports.
|
||||||
fn sub_lamports(&self, amount: u64) -> Result<&Self> {
|
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)
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ declare_id!("Lamports11111111111111111111111111111111111");
|
||||||
pub mod lamports {
|
pub mod lamports {
|
||||||
use super::*;
|
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 pda = &ctx.accounts.pda;
|
||||||
let signer = &ctx.accounts.signer;
|
let signer = &ctx.accounts.signer;
|
||||||
|
|
||||||
|
@ -52,13 +52,29 @@ pub mod lamports {
|
||||||
|
|
||||||
Ok(())
|
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)]
|
#[derive(Accounts)]
|
||||||
pub struct TestLamportsTrait<'info> {
|
pub struct Transfer<'info> {
|
||||||
#[account(mut)]
|
#[account(mut)]
|
||||||
pub signer: Signer<'info>,
|
pub signer: Signer<'info>,
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
init,
|
init,
|
||||||
payer = signer,
|
payer = signer,
|
||||||
|
@ -67,9 +83,14 @@ pub struct TestLamportsTrait<'info> {
|
||||||
bump
|
bump
|
||||||
)]
|
)]
|
||||||
pub pda: Account<'info, LamportsPda>,
|
pub pda: Account<'info, LamportsPda>,
|
||||||
|
|
||||||
pub system_program: Program<'info, System>,
|
pub system_program: Program<'info, System>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Accounts)]
|
||||||
|
pub struct Overflow<'info> {
|
||||||
|
#[account(seeds = [b"lamports"], bump)]
|
||||||
|
pub pda: Account<'info, LamportsPda>,
|
||||||
|
}
|
||||||
|
|
||||||
#[account]
|
#[account]
|
||||||
pub struct LamportsPda {}
|
pub struct LamportsPda {}
|
||||||
|
|
|
@ -8,16 +8,13 @@ describe("lamports", () => {
|
||||||
|
|
||||||
const program = anchor.workspace.Lamports as anchor.Program<Lamports>;
|
const program = anchor.workspace.Lamports as anchor.Program<Lamports>;
|
||||||
|
|
||||||
it("Can use the Lamports trait", async () => {
|
it("Can transfer from/to PDA", async () => {
|
||||||
const signer = program.provider.publicKey!;
|
|
||||||
const [pda] = anchor.web3.PublicKey.findProgramAddressSync(
|
|
||||||
[Buffer.from("lamports")],
|
|
||||||
program.programId
|
|
||||||
);
|
|
||||||
|
|
||||||
await program.methods
|
await program.methods
|
||||||
.testLamportsTrait(new anchor.BN(anchor.web3.LAMPORTS_PER_SOL))
|
.transfer(new anchor.BN(anchor.web3.LAMPORTS_PER_SOL))
|
||||||
.accounts({ signer, pda })
|
|
||||||
.rpc();
|
.rpc();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Returns an error on overflow", async () => {
|
||||||
|
await program.methods.overflow().rpc();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue