lang: add additional `require_x` comparison macros (#1622)

This commit is contained in:
Matthew Callens 2022-03-16 14:45:09 -04:00 committed by GitHub
parent 3face237fb
commit b376fd4615
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 456 additions and 15 deletions

View File

@ -15,12 +15,13 @@ incremented for features.
* cli: Add `anchor clean` command that's the same as `cargo clean` but preserves keypairs inside `target/deploy` ([#1470](https://github.com/project-serum/anchor/issues/1470)).
* cli: Running `anchor init` now initializes a new git repository for the workspace. This can be disabled with the `--no-git` flag ([#1605](https://github.com/project-serum/anchor/pull/1605)).
* cli: Add support for `anchor idl fetch` to work outside anchor workspace ([#1509](https://github.com/project-serum/anchor/pull/1509)).
* cli: [[test.validator.clone]] also clones the program data account of programs owned by the bpf upgradeable loader ([#1481](https://github.com/project-serum/anchor/issues/1481)).
* lang: Add new `AccountSysvarMismatch` error code and test cases for sysvars ([#1535](https://github.com/project-serum/anchor/pull/1535)).
* lang: Replace `std::io::Cursor` with a custom `Write` impl that uses the Solana mem syscalls ([#1589](https://github.com/project-serum/anchor/pull/1589)).
* lang: Add `require_neq`, `require_keys_neq`, `require_gt`, and `require_gte` comparison macros ([#1622](https://github.com/project-serum/anchor/pull/1622)).
* spl: Add support for revoke instruction ([#1493](https://github.com/project-serum/anchor/pull/1493)).
* cli: Add support for `anchor idl fetch` to work outside anchor workspace ([#1509](https://github.com/project-serum/anchor/pull/1509)).
* ts: Add provider parameter to `Spl.token` factory method ([#1597](https://github.com/project-serum/anchor/pull/1597)).
* cli: [[test.validator.clone]] also clones the program data account of programs owned by the bpf upgradeable loader ([#1481](https://github.com/project-serum/anchor/issues/1481)).
### Fixes

View File

@ -116,6 +116,18 @@ pub enum ErrorCode {
/// 2502 - A require_keys_eq expression was violated
#[msg("A require_keys_eq expression was violated")]
RequireKeysEqViolated,
/// 2503 - A require_neq expression was violated
#[msg("A require_neq expression was violated")]
RequireNeqViolated,
/// 2504 - A require_keys_neq expression was violated
#[msg("A require_keys_neq expression was violated")]
RequireKeysNeqViolated,
/// 2505 - A require_gt expression was violated
#[msg("A require_gt expression was violated")]
RequireGtViolated,
/// 2506 - A require_gte expression was violated
#[msg("A require_gte expression was violated")]
RequireGteViolated,
// Accounts.
/// 3000 - The account discriminator was already set on this account

View File

@ -239,9 +239,9 @@ pub mod prelude {
accounts::signer::Signer, accounts::system_account::SystemAccount,
accounts::sysvar::Sysvar, accounts::unchecked_account::UncheckedAccount, constant,
context::Context, context::CpiContext, declare_id, emit, err, error, event, interface,
program, require, require_eq, require_keys_eq,
solana_program::bpf_loader_upgradeable::UpgradeableLoaderState, source, state, zero_copy,
AccountDeserialize, AccountSerialize, Accounts, AccountsExit, AnchorDeserialize,
program, require, require_eq, require_gt, require_gte, require_keys_eq, require_keys_neq,
require_neq, solana_program::bpf_loader_upgradeable::UpgradeableLoaderState, source, state,
zero_copy, AccountDeserialize, AccountSerialize, Accounts, AccountsExit, AnchorDeserialize,
AnchorSerialize, Id, Key, Owner, ProgramData, Result, System, ToAccountInfo,
ToAccountInfos, ToAccountMetas,
};
@ -397,6 +397,36 @@ macro_rules! require_eq {
};
}
/// Ensures two NON-PUBKEY values are not equal.
///
/// Use [require_keys_neq](crate::prelude::require_keys_neq)
/// to compare two pubkeys.
///
/// Can be used with or without a custom error code.
///
/// # Example
/// ```rust,ignore
/// pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
/// require_neq!(ctx.accounts.data.data, 0);
/// ctx.accounts.data.data = data;
/// Ok(());
/// }
/// ```
#[macro_export]
macro_rules! require_neq {
($value1: expr, $value2: expr, $error_code: expr $(,)?) => {
if $value1 == $value2 {
return Err(error!($error_code).with_values(($value1, $value2)));
}
};
($value1: expr, $value2: expr $(,)?) => {
if $value1 == $value2 {
return Err(error!(anchor_lang::error::ErrorCode::RequireNeqViolated)
.with_values(($value1, $value2)));
}
};
}
/// Ensures two pubkeys values are equal.
///
/// Use [require_eq](crate::prelude::require_eq)
@ -427,6 +457,96 @@ macro_rules! require_keys_eq {
};
}
/// Ensures two pubkeys are not equal.
///
/// Use [require_neq](crate::prelude::require_neq)
/// to compare two non-pubkey values.
///
/// Can be used with or without a custom error code.
///
/// # Example
/// ```rust,ignore
/// pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
/// require_keys_neq!(ctx.accounts.data.authority.key(), ctx.accounts.other.key());
/// ctx.accounts.data.data = data;
/// Ok(())
/// }
/// ```
#[macro_export]
macro_rules! require_keys_neq {
($value1: expr, $value2: expr, $error_code: expr $(,)?) => {
if $value1 == $value2 {
return Err(error!($error_code).with_pubkeys(($value1, $value2)));
}
};
($value1: expr, $value2: expr $(,)?) => {
if $value1 == $value2 {
return Err(
error!(anchor_lang::error::ErrorCode::RequireKeysNeqViolated)
.with_pubkeys(($value1, $value2)),
);
}
};
}
/// Ensures the first NON-PUBKEY value is greater than the second
/// NON-PUBKEY value.
///
/// To include an equality check, use [require_gte](crate::require_gte).
///
/// Can be used with or without a custom error code.
///
/// # Example
/// ```rust,ignore
/// pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
/// require_gt!(ctx.accounts.data.data, 0);
/// ctx.accounts.data.data = data;
/// Ok(());
/// }
/// ```
#[macro_export]
macro_rules! require_gt {
($value1: expr, $value2: expr, $error_code: expr $(,)?) => {
if $value1 <= $value2 {
return Err(error!($error_code).with_values(($value1, $value2)));
}
};
($value1: expr, $value2: expr $(,)?) => {
if $value1 <= $value2 {
return Err(error!(anchor_lang::error::ErrorCode::RequireGtViolated)
.with_values(($value1, $value2)));
}
};
}
/// Ensures the first NON-PUBKEY value is greater than or equal
/// to the second NON-PUBKEY value.
///
/// Can be used with or without a custom error code.
///
/// # Example
/// ```rust,ignore
/// pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
/// require_gte!(ctx.accounts.data.data, 1);
/// ctx.accounts.data.data = data;
/// Ok(());
/// }
/// ```
#[macro_export]
macro_rules! require_gte {
($value1: expr, $value2: expr, $error_code: expr $(,)?) => {
if $value1 < $value2 {
return Err(error!($error_code).with_values(($value1, $value2)));
}
};
($value1: expr, $value2: expr $(,)?) => {
if $value1 < $value2 {
return Err(error!(anchor_lang::error::ErrorCode::RequireGteViolated)
.with_values(($value1, $value2)));
}
};
}
/// Returns with the given error.
/// Use this with a custom error type.
///

View File

@ -9,3 +9,4 @@ errors = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
test = "yarn run mocha -t 1000000 tests/"
[features]
seeds = false

View File

@ -74,8 +74,22 @@ mod errors {
Ok(())
}
pub fn require_neq(_ctx: Context<RequireNeq>) -> Result<()> {
require_neq!(500, 500, MyError::ValueMatch);
Ok(())
}
pub fn require_neq_default_error(_ctx: Context<RequireNeq>) -> Result<()> {
require_neq!(500, 500);
Ok(())
}
pub fn require_keys_eq(ctx: Context<RequireKeysEq>) -> Result<()> {
require_keys_eq!(ctx.accounts.some_account.key(), *ctx.program_id, MyError::ValueMismatch);
require_keys_eq!(
ctx.accounts.some_account.key(),
*ctx.program_id,
MyError::ValueMismatch
);
Ok(())
}
@ -83,6 +97,40 @@ mod errors {
require_keys_eq!(ctx.accounts.some_account.key(), *ctx.program_id);
Ok(())
}
pub fn require_keys_neq(ctx: Context<RequireKeysNeq>) -> Result<()> {
require_keys_neq!(
ctx.accounts.some_account.key(),
*ctx.program_id,
MyError::ValueMatch
);
Ok(())
}
pub fn require_keys_neq_default_error(ctx: Context<RequireKeysNeq>) -> Result<()> {
require_keys_neq!(ctx.accounts.some_account.key(), *ctx.program_id);
Ok(())
}
pub fn require_gt(_ctx: Context<RequireGt>) -> Result<()> {
require_gt!(5, 10, MyError::ValueLessOrEqual);
Ok(())
}
pub fn require_gt_default_error(_ctx: Context<RequireGt>) -> Result<()> {
require_gt!(10, 10);
Ok(())
}
pub fn require_gte(_ctx: Context<RequireGt>) -> Result<()> {
require_gte!(5, 10, MyError::ValueLess);
Ok(())
}
pub fn require_gte_default_error(_ctx: Context<RequireGt>) -> Result<()> {
require_gte!(5, 10);
Ok(())
}
}
#[derive(Accounts)]
@ -133,9 +181,23 @@ pub struct AccountOwnedByWrongProgramError<'info> {
#[derive(Accounts)]
pub struct RequireEq {}
#[derive(Accounts)]
pub struct RequireNeq {}
#[derive(Accounts)]
pub struct RequireGt {}
#[derive(Accounts)]
pub struct RequireGte {}
#[derive(Accounts)]
pub struct RequireKeysEq<'info> {
pub some_account: UncheckedAccount<'info>
pub some_account: UncheckedAccount<'info>,
}
#[derive(Accounts)]
pub struct RequireKeysNeq<'info> {
pub some_account: UncheckedAccount<'info>,
}
#[error_code]
@ -146,4 +208,7 @@ pub enum MyError {
HelloNext,
HelloCustom,
ValueMismatch,
ValueMatch,
ValueLess,
ValueLessOrEqual,
}

View File

@ -333,6 +333,40 @@ describe("errors", () => {
]);
});
it("Emits a ValueMatch error via require_neq", async () => {
await withLogTest(async () => {
try {
const tx = await program.rpc.requireNeq();
assert.fail(
"Unexpected success in creating a transaction that should have failed with `ValueMatch` error"
);
} catch (err) {
assert.equal(err.code, 6127);
}
}, [
"Program log: AnchorError thrown in programs/errors/src/lib.rs:78. Error Code: ValueMatch. Error Number: 6127. Error Message: ValueMatch.",
"Program log: Left: 500",
"Program log: Right: 500",
]);
});
it("Emits a RequireNeqViolated error via require_neq", async () => {
await withLogTest(async () => {
try {
const tx = await program.rpc.requireNeqDefaultError();
assert.fail(
"Unexpected success in creating a transaction that should have failed with `RequireNeqViolated` error"
);
} catch (err) {
assert.equal(err.code, 2503);
}
}, [
"Program log: AnchorError thrown in programs/errors/src/lib.rs:83. Error Code: RequireNeqViolated. Error Number: 2503. Error Message: A require_neq expression was violated.",
"Program log: Left: 500",
"Program log: Right: 500",
]);
});
it("Emits a ValueMismatch error via require_keys_eq", async () => {
const someAccount = anchor.web3.Keypair.generate().publicKey;
await withLogTest(async () => {
@ -349,7 +383,7 @@ describe("errors", () => {
assert.equal(err.code, 6126);
}
}, [
"Program log: AnchorError thrown in programs/errors/src/lib.rs:78. Error Code: ValueMismatch. Error Number: 6126. Error Message: ValueMismatch.",
"Program log: AnchorError thrown in programs/errors/src/lib.rs:88. Error Code: ValueMismatch. Error Number: 6126. Error Message: ValueMismatch.",
"Program log: Left:",
`Program log: ${someAccount}`,
"Program log: Right:",
@ -373,11 +407,127 @@ describe("errors", () => {
assert.equal(err.code, 2502);
}
}, [
"Program log: AnchorError thrown in programs/errors/src/lib.rs:83. Error Code: RequireKeysEqViolated. Error Number: 2502. Error Message: A require_keys_eq expression was violated.",
"Program log: AnchorError thrown in programs/errors/src/lib.rs:97. Error Code: RequireKeysEqViolated. Error Number: 2502. Error Message: A require_keys_eq expression was violated.",
"Program log: Left:",
`Program log: ${someAccount}`,
"Program log: Right:",
`Program log: ${program.programId}`,
]);
});
it("Emits a ValueMatch error via require_keys_neq", async () => {
const someAccount = program.programId;
await withLogTest(async () => {
try {
const tx = await program.rpc.requireKeysNeq({
accounts: {
someAccount,
},
});
assert.fail(
"Unexpected success in creating a transaction that should have failed with `ValueMatch` error"
);
} catch (err) {
assert.equal(err.code, 6127);
}
}, [
"Program log: AnchorError thrown in programs/errors/src/lib.rs:102. Error Code: ValueMatch. Error Number: 6127. Error Message: ValueMatch.",
"Program log: Left:",
`Program log: ${someAccount}`,
"Program log: Right:",
`Program log: ${program.programId}`,
]);
});
it("Emits a RequireKeysNeqViolated error via require_keys_neq", async () => {
const someAccount = program.programId;
await withLogTest(async () => {
try {
const tx = await program.rpc.requireKeysNeqDefaultError({
accounts: {
someAccount,
},
});
assert.fail(
"Unexpected success in creating a transaction that should have failed with `RequireKeysNeqViolated` error"
);
} catch (err) {
assert.equal(err.code, 2504);
}
}, [
"Program log: AnchorError thrown in programs/errors/src/lib.rs:111. Error Code: RequireKeysNeqViolated. Error Number: 2504. Error Message: A require_keys_neq expression was violated.",
"Program log: Left:",
`Program log: ${someAccount}`,
"Program log: Right:",
`Program log: ${program.programId}`,
]);
});
it("Emits a ValueLessOrEqual error via require_gt", async () => {
await withLogTest(async () => {
try {
const tx = await program.rpc.requireGt();
assert.fail(
"Unexpected success in creating a transaction that should have failed with `ValueLessOrEqual` error"
);
} catch (err) {
assert.equal(err.code, 6129);
}
}, [
"Program log: AnchorError thrown in programs/errors/src/lib.rs:116. Error Code: ValueLessOrEqual. Error Number: 6129. Error Message: ValueLessOrEqual.",
"Program log: Left: 5",
"Program log: Right: 10",
]);
});
it("Emits a RequireGtViolated error via require_gt", async () => {
await withLogTest(async () => {
try {
const tx = await program.rpc.requireGtDefaultError();
assert.fail(
"Unexpected success in creating a transaction that should have failed with `RequireGtViolated` error"
);
} catch (err) {
assert.equal(err.code, 2505);
}
}, [
"Program log: AnchorError thrown in programs/errors/src/lib.rs:121. Error Code: RequireGtViolated. Error Number: 2505. Error Message: A require_gt expression was violated.",
"Program log: Left: 10",
"Program log: Right: 10",
]);
});
it("Emits a ValueLess error via require_gte", async () => {
await withLogTest(async () => {
try {
const tx = await program.rpc.requireGte();
assert.fail(
"Unexpected success in creating a transaction that should have failed with `ValueLess` error"
);
} catch (err) {
assert.equal(err.code, 6128);
}
}, [
"Program log: AnchorError thrown in programs/errors/src/lib.rs:126. Error Code: ValueLess. Error Number: 6128. Error Message: ValueLess.",
"Program log: Left: 5",
"Program log: Right: 10",
]);
});
it("Emits a RequireGteViolated error via require_gte", async () => {
await withLogTest(async () => {
try {
const tx = await program.rpc.requireGteDefaultError();
assert.fail(
"Unexpected success in creating a transaction that should have failed with `RequireGteViolated` error"
);
} catch (err) {
assert.equal(err.code, 2506);
}
}, [
"Program log: AnchorError thrown in programs/errors/src/lib.rs:131. Error Code: RequireGteViolated. Error Number: 2506. Error Message: A require_gte expression was violated.",
"Program log: Left: 5",
"Program log: Right: 10",
]);
});
});

View File

@ -50,12 +50,12 @@
snake-case "^3.0.4"
toml "^3.0.0"
"@project-serum/anchor@^0.21.0":
version "0.21.0"
resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.21.0.tgz#ad5fb33744991ec1900cdb2fd22707c908b12b5f"
integrity sha512-flRuW/F+iC8mitNokx82LOXyND7Dyk6n5UUPJpQv/+NfySFrNFlzuQZaBZJ4CG5g9s8HS/uaaIz1nVkDR8V/QA==
"@project-serum/anchor@^0.22.1":
version "0.22.1"
resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.22.1.tgz#698a9620f94691de0a12bbc650a5c8380e2f0e8a"
integrity sha512-5pHeyvQhzLahIQ8aZymmDMZJAJFklN0joZdI+YIqFkK2uU/mlKr6rBLQjxysf/j1mLLiNG00tdyLfUtTAdQz7w==
dependencies:
"@project-serum/borsh" "^0.2.4"
"@project-serum/borsh" "^0.2.5"
"@solana/web3.js" "^1.17.0"
base64-js "^1.5.1"
bn.js "^5.1.2"
@ -79,7 +79,7 @@
bn.js "^5.1.2"
buffer-layout "^1.2.0"
"@project-serum/borsh@^0.2.4":
"@project-serum/borsh@^0.2.5":
version "0.2.5"
resolved "https://registry.yarnpkg.com/@project-serum/borsh/-/borsh-0.2.5.tgz#6059287aa624ecebbfc0edd35e4c28ff987d8663"
integrity sha512-UmeUkUoKdQ7rhx6Leve1SssMR/Ghv8qrEiyywyxSWg7ooV7StdpPBhciiy5eB3T0qU1BXvdRNC8TdrkxK7WC5Q==
@ -421,6 +421,21 @@ chokidar@3.5.2:
optionalDependencies:
fsevents "~2.3.2"
chokidar@3.5.3:
version "3.5.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
dependencies:
anymatch "~3.1.2"
braces "~3.0.2"
glob-parent "~5.1.2"
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
readdirp "~3.6.0"
optionalDependencies:
fsevents "~2.3.2"
circular-json@^0.5.9:
version "0.5.9"
resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d"
@ -483,6 +498,13 @@ debug@4.3.2:
dependencies:
ms "2.1.2"
debug@4.3.3:
version "4.3.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
dependencies:
ms "2.1.2"
decamelize@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837"
@ -639,6 +661,18 @@ glob@7.1.7:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
growl@1.10.5:
version "1.10.5"
resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e"
@ -847,6 +881,13 @@ minimatch@3.0.4, minimatch@^3.0.4:
dependencies:
brace-expansion "^1.1.7"
minimatch@4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4"
integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==
dependencies:
brace-expansion "^1.1.7"
minimist@^1.2.0, minimist@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
@ -889,6 +930,36 @@ mocha@^9.1.3:
yargs-parser "20.2.4"
yargs-unparser "2.0.0"
mocha@^9.2.2:
version "9.2.2"
resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9"
integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==
dependencies:
"@ungap/promise-all-settled" "1.1.2"
ansi-colors "4.1.1"
browser-stdout "1.3.1"
chokidar "3.5.3"
debug "4.3.3"
diff "5.0.0"
escape-string-regexp "4.0.0"
find-up "5.0.0"
glob "7.2.0"
growl "1.10.5"
he "1.2.0"
js-yaml "4.1.0"
log-symbols "4.1.0"
minimatch "4.2.1"
ms "2.1.3"
nanoid "3.3.1"
serialize-javascript "6.0.0"
strip-json-comments "3.1.1"
supports-color "8.1.1"
which "2.0.2"
workerpool "6.2.0"
yargs "16.2.0"
yargs-parser "20.2.4"
yargs-unparser "2.0.0"
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
@ -904,6 +975,11 @@ nanoid@3.1.25:
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152"
integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==
nanoid@3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35"
integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==
no-case@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
@ -1255,6 +1331,11 @@ workerpool@6.1.5:
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.5.tgz#0f7cf076b6215fd7e1da903ff6f22ddd1886b581"
integrity sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==
workerpool@6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b"
integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"

View File

@ -99,6 +99,10 @@ const LangErrorCode = {
RequireViolated: 2500,
RequireEqViolated: 2501,
RequireKeysEqViolated: 2502,
RequireNeqViolated: 2503,
RequireKeysNeqViolated: 2504,
RequireGtViolated: 2505,
RequireGteViolated: 2506,
// Accounts.
AccountDiscriminatorAlreadySet: 3000,
@ -197,6 +201,13 @@ const LangErrorMessage = new Map([
LangErrorCode.RequireKeysEqViolated,
"A require_keys_eq expression was violated",
],
[LangErrorCode.RequireNeqViolated, "A require_neq expression was violated"],
[
LangErrorCode.RequireKeysNeqViolated,
"A require_keys_neq expression was violated",
],
[LangErrorCode.RequireGtViolated, "A require_gt expression was violated"],
[LangErrorCode.RequireGteViolated, "A require_gte expression was violated"],
// Accounts.
[