ts: add error log parsing to ts client (#1640)
This commit is contained in:
parent
45a5d20a79
commit
9afdb17ac2
|
@ -23,6 +23,7 @@ incremented for features.
|
|||
* lang: Handle arrays with const as size in instruction data ([#1623](https://github.com/project-serum/anchor/issues/1623).
|
||||
* spl: Add support for revoke instruction ([#1493](https://github.com/project-serum/anchor/pull/1493)).
|
||||
* ts: Add provider parameter to `Spl.token` factory method ([#1597](https://github.com/project-serum/anchor/pull/1597)).
|
||||
* ts: Add `AnchorError` with program stack and also a program stack for non-`AnchorError` errors ([#1640](https://github.com/project-serum/anchor/pull/1640)). `AnchorError` is not returned for `processed` tx that have `skipPreflight` set to `true` (it falls back to `ProgramError` or the raw solana library error).
|
||||
|
||||
### Fixes
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as anchor from "@project-serum/anchor";
|
||||
import { Program } from "@project-serum/anchor";
|
||||
import { AnchorError, Program } from "@project-serum/anchor";
|
||||
import { findProgramAddressSync } from "@project-serum/anchor/dist/cjs/utils/pubkey";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import assert from "assert";
|
||||
|
@ -78,9 +78,11 @@ describe("bpf_upgradeable_state", () => {
|
|||
signers: [settings, authority],
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2003);
|
||||
assert.equal(err.msg, "A raw constraint was violated");
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2003);
|
||||
assert.equal(err.error.errorMessage, "A raw constraint was violated");
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -98,9 +100,14 @@ describe("bpf_upgradeable_state", () => {
|
|||
signers: [settings],
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 3013);
|
||||
assert.equal(err.msg, "The given account is not a program data account");
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 3013);
|
||||
assert.equal(
|
||||
err.error.errorMessage,
|
||||
"The given account is not a program data account"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -118,10 +125,12 @@ describe("bpf_upgradeable_state", () => {
|
|||
signers: [settings],
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 3007);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 3007);
|
||||
assert.equal(
|
||||
err.msg,
|
||||
err.error.errorMessage,
|
||||
"The given account is owned by a different program than expected"
|
||||
);
|
||||
}
|
||||
|
@ -149,8 +158,10 @@ describe("bpf_upgradeable_state", () => {
|
|||
signers: [settings],
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 6000);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 6000);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -176,8 +187,10 @@ describe("bpf_upgradeable_state", () => {
|
|||
signers: [settings],
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2003);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2003);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,4 +6,4 @@ wallet = "~/.config/solana/id.json"
|
|||
declare_id = "FJcF5c8HncdfAgjPjTH49GAEypkJCG2ZADh2xhduNi5B"
|
||||
|
||||
[scripts]
|
||||
test = "yarn run mocha -t 1000000 tests/"
|
||||
test = "yarn run ts-mocha -t 1000000 tests/*.ts"
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
const anchor = require("@project-serum/anchor");
|
||||
const splToken = require("@solana/spl-token");
|
||||
const assert = require("assert");
|
||||
|
||||
describe("declare_id", () => {
|
||||
anchor.setProvider(anchor.Provider.local());
|
||||
const program = anchor.workspace.DeclareId;
|
||||
|
||||
it("throws error!", async () => {
|
||||
try {
|
||||
await program.rpc.initialize();
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 4100);
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,22 @@
|
|||
import * as anchor from "@project-serum/anchor";
|
||||
import { AnchorError, Program } from "@project-serum/anchor";
|
||||
import splToken from "@solana/spl-token";
|
||||
import { DeclareId } from "../target/types/declare_id";
|
||||
|
||||
import { assert } from "chai";
|
||||
|
||||
describe("declare_id", () => {
|
||||
anchor.setProvider(anchor.Provider.local());
|
||||
const program = anchor.workspace.DeclareId as Program<DeclareId>;
|
||||
|
||||
it("throws error!", async () => {
|
||||
try {
|
||||
await program.rpc.initialize();
|
||||
assert.ok(false);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 4100);
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"types": ["mocha", "chai", "node"],
|
||||
"typeRoots": ["./node_modules/@types"],
|
||||
"lib": ["es2015"],
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ wallet = "~/.config/solana/id.json"
|
|||
errors = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
|
||||
[scripts]
|
||||
test = "yarn run mocha -t 1000000 tests/"
|
||||
test = "yarn run ts-mocha -t 1000000 tests/*.ts"
|
||||
|
||||
[features]
|
||||
seeds = false
|
||||
|
|
|
@ -1,13 +1,26 @@
|
|||
const assert = require("assert");
|
||||
const anchor = require("@project-serum/anchor");
|
||||
const { Account, Transaction, TransactionInstruction } = anchor.web3;
|
||||
const { TOKEN_PROGRAM_ID, Token } = require("@solana/spl-token");
|
||||
const { Keypair } = require("@solana/web3.js");
|
||||
import * as anchor from "@project-serum/anchor";
|
||||
import {
|
||||
Program,
|
||||
BN,
|
||||
IdlAccounts,
|
||||
AnchorError,
|
||||
ProgramError,
|
||||
} from "@project-serum/anchor";
|
||||
import {
|
||||
PublicKey,
|
||||
Keypair,
|
||||
SystemProgram,
|
||||
Transaction,
|
||||
TransactionInstruction,
|
||||
} from "@solana/web3.js";
|
||||
import { TOKEN_PROGRAM_ID, Token } from "@solana/spl-token";
|
||||
import { assert, expect } from "chai";
|
||||
import { Errors } from "../target/types/errors";
|
||||
|
||||
// sleep to allow logs to come in
|
||||
const sleep = (ms) =>
|
||||
new Promise((resolve) => {
|
||||
setTimeout(() => resolve(), ms);
|
||||
setTimeout(() => resolve(0), ms);
|
||||
});
|
||||
|
||||
const withLogTest = async (callback, expectedLogs) => {
|
||||
|
@ -45,7 +58,6 @@ const withLogTest = async (callback, expectedLogs) => {
|
|||
anchor.getProvider().connection.removeOnLogsListener(listener);
|
||||
throw err;
|
||||
}
|
||||
await sleep(3000);
|
||||
anchor.getProvider().connection.removeOnLogsListener(listener);
|
||||
assert.ok(logTestOk);
|
||||
};
|
||||
|
@ -54,21 +66,33 @@ describe("errors", () => {
|
|||
// Configure the client to use the local cluster.
|
||||
const localProvider = anchor.Provider.local();
|
||||
localProvider.opts.skipPreflight = true;
|
||||
// processed failed tx do not result in AnchorErrors in the client
|
||||
// because we cannot get logs for them (only through overkill `onLogs`)
|
||||
localProvider.opts.commitment = "confirmed";
|
||||
anchor.setProvider(localProvider);
|
||||
|
||||
const program = anchor.workspace.Errors;
|
||||
const program = anchor.workspace.Errors as Program<Errors>;
|
||||
|
||||
it("Emits a Hello error", async () => {
|
||||
await withLogTest(async () => {
|
||||
try {
|
||||
const tx = await program.rpc.hello();
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
const errMsg =
|
||||
"This is an error message clients will automatically display";
|
||||
assert.equal(err.toString(), errMsg);
|
||||
assert.equal(err.msg, errMsg);
|
||||
assert.equal(err.code, 6000);
|
||||
const fullErrMsg =
|
||||
"AnchorError thrown in programs/errors/src/lib.rs:13. Error Code: Hello. Error Number: 6000. Error Message: This is an error message clients will automatically display.";
|
||||
assert.equal(err.toString(), fullErrMsg);
|
||||
assert.equal(err.error.errorMessage, errMsg);
|
||||
assert.equal(err.error.errorCode.number, 6000);
|
||||
assert.equal(err.program.toString(), program.programId.toString());
|
||||
expect(err.error.origin).to.deep.equal({
|
||||
file: "programs/errors/src/lib.rs",
|
||||
line: 13,
|
||||
});
|
||||
}
|
||||
}, [
|
||||
"Program log: AnchorError thrown in programs/errors/src/lib.rs:13. Error Code: Hello. Error Number: 6000. Error Message: This is an error message clients will automatically display.",
|
||||
|
@ -79,12 +103,14 @@ describe("errors", () => {
|
|||
try {
|
||||
const tx = await program.rpc.testRequire();
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
const errMsg =
|
||||
"This is an error message clients will automatically display";
|
||||
assert.equal(err.toString(), errMsg);
|
||||
assert.equal(err.msg, errMsg);
|
||||
assert.equal(err.code, 6000);
|
||||
assert.equal(err.error.errorMessage, errMsg);
|
||||
assert.equal(err.error.errorCode.number, 6000);
|
||||
assert.equal(err.error.errorCode.code, "Hello");
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -92,12 +118,13 @@ describe("errors", () => {
|
|||
try {
|
||||
const tx = await program.rpc.testErr();
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
const errMsg =
|
||||
"This is an error message clients will automatically display";
|
||||
assert.equal(err.toString(), errMsg);
|
||||
assert.equal(err.msg, errMsg);
|
||||
assert.equal(err.code, 6000);
|
||||
assert.equal(err.error.errorMessage, errMsg);
|
||||
assert.equal(err.error.errorCode.number, 6000);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -107,7 +134,10 @@ describe("errors", () => {
|
|||
const tx = await program.rpc.testProgramError();
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
// No-op (withLogTest expects the callback to catch the initial tx error)
|
||||
expect(err.programErrorStack.map((pk) => pk.toString())).to.deep.equal([
|
||||
program.programId.toString(),
|
||||
]);
|
||||
expect(err.program.toString()).to.equal(program.programId.toString());
|
||||
}
|
||||
}, [
|
||||
"Program log: ProgramError occurred. Error Code: InvalidAccountData. Error Number: 17179869184. Error Message: An account's data contents was invalid.",
|
||||
|
@ -120,7 +150,9 @@ describe("errors", () => {
|
|||
const tx = await program.rpc.testProgramErrorWithSource();
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
// No-op (withLogTest expects the callback to catch the initial tx error)
|
||||
expect(err.programErrorStack.map((pk) => pk.toString())).to.deep.equal([
|
||||
program.programId.toString(),
|
||||
]);
|
||||
}
|
||||
}, [
|
||||
"Program log: ProgramError thrown in programs/errors/src/lib.rs:38. Error Code: InvalidAccountData. Error Number: 17179869184. Error Message: An account's data contents was invalid.",
|
||||
|
@ -131,11 +163,11 @@ describe("errors", () => {
|
|||
try {
|
||||
const tx = await program.rpc.helloNoMsg();
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
const errMsg = "HelloNoMsg";
|
||||
assert.equal(err.toString(), errMsg);
|
||||
assert.equal(err.msg, errMsg);
|
||||
assert.equal(err.code, 6000 + 123);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorMessage, "HelloNoMsg");
|
||||
assert.equal(err.error.errorCode.number, 6123);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -143,11 +175,11 @@ describe("errors", () => {
|
|||
try {
|
||||
const tx = await program.rpc.helloNext();
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
const errMsg = "HelloNext";
|
||||
assert.equal(err.toString(), errMsg);
|
||||
assert.equal(err.msg, errMsg);
|
||||
assert.equal(err.code, 6000 + 124);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorMessage, "HelloNext");
|
||||
assert.equal(err.error.errorCode.number, 6124);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -160,11 +192,12 @@ describe("errors", () => {
|
|||
},
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
const errMsg = "A mut constraint was violated";
|
||||
assert.equal(err.toString(), errMsg);
|
||||
assert.equal(err.msg, errMsg);
|
||||
assert.equal(err.code, 2000);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorMessage, "A mut constraint was violated");
|
||||
assert.equal(err.error.errorCode.number, 2000);
|
||||
assert.equal(err.error.origin, "my_account");
|
||||
}
|
||||
}, [
|
||||
"Program log: AnchorError caused by account: my_account. Error Code: ConstraintMut. Error Number: 2000. Error Message: A mut constraint was violated.",
|
||||
|
@ -187,11 +220,23 @@ describe("errors", () => {
|
|||
signers: [account],
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
const errMsg = "A has_one constraint was violated";
|
||||
assert.equal(err.toString(), errMsg);
|
||||
assert.equal(err.msg, errMsg);
|
||||
assert.equal(err.code, 2001);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(
|
||||
err.error.errorMessage,
|
||||
"A has one constraint was violated"
|
||||
);
|
||||
assert.equal(err.error.errorCode.number, 2001);
|
||||
assert.equal(err.error.errorCode.code, "ConstraintHasOne");
|
||||
assert.equal(err.error.origin, "my_account");
|
||||
assert.equal(err.program.toString(), program.programId.toString());
|
||||
expect(
|
||||
err.error.comparedValues.map((pk) => pk.toString())
|
||||
).to.deep.equal([
|
||||
"11111111111111111111111111111111",
|
||||
"SysvarRent111111111111111111111111111111111",
|
||||
]);
|
||||
}
|
||||
}, [
|
||||
"Program log: AnchorError caused by account: my_account. Error Code: ConstraintHasOne. Error Number: 2001. Error Message: A has one constraint was violated.",
|
||||
|
@ -228,7 +273,6 @@ describe("errors", () => {
|
|||
await program.provider.send(tx);
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
await sleep(3000);
|
||||
anchor.getProvider().connection.removeOnLogsListener(listener);
|
||||
const errMsg = `Error: Raw transaction ${signature} failed ({"err":{"InstructionError":[0,{"Custom":3010}]}})`;
|
||||
assert.equal(err.toString(), errMsg);
|
||||
|
@ -245,11 +289,12 @@ describe("errors", () => {
|
|||
},
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
const errMsg = "HelloCustom";
|
||||
assert.equal(err.toString(), errMsg);
|
||||
assert.equal(err.msg, errMsg);
|
||||
assert.equal(err.code, 6000 + 125);
|
||||
assert.equal(err.error.errorMessage, errMsg);
|
||||
assert.equal(err.error.errorCode.number, 6125);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -264,10 +309,12 @@ describe("errors", () => {
|
|||
assert.fail(
|
||||
"Unexpected success in creating a transaction that should have fail with `AccountNotInitialized` error"
|
||||
);
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
const errMsg =
|
||||
"The program expected this account to be already initialized";
|
||||
assert.equal(err.toString(), errMsg);
|
||||
assert.equal(err.error.errorMessage, errMsg);
|
||||
}
|
||||
}, [
|
||||
"Program log: AnchorError caused by account: not_initialized_account. Error Code: AccountNotInitialized. Error Number: 3012. Error Message: The program expected this account to be already initialized.",
|
||||
|
@ -294,10 +341,12 @@ describe("errors", () => {
|
|||
assert.fail(
|
||||
"Unexpected success in creating a transaction that should have failed with `AccountOwnedByWrongProgram` error"
|
||||
);
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
const errMsg =
|
||||
"The given account is owned by a different program than expected";
|
||||
assert.equal(err.toString(), errMsg);
|
||||
assert.equal(err.error.errorMessage, errMsg);
|
||||
}
|
||||
}, [
|
||||
"Program log: AnchorError caused by account: wrong_account. Error Code: AccountOwnedByWrongProgram. Error Number: 3007. Error Message: The given account is owned by a different program than expected.",
|
||||
|
@ -315,8 +364,11 @@ describe("errors", () => {
|
|||
assert.fail(
|
||||
"Unexpected success in creating a transaction that should have failed with `ValueMismatch` error"
|
||||
);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 6126);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 6126);
|
||||
expect(err.error.comparedValues).to.deep.equal(["5241", "124124124"]);
|
||||
}
|
||||
}, [
|
||||
"Program log: AnchorError thrown in programs/errors/src/lib.rs:68. Error Code: ValueMismatch. Error Number: 6126. Error Message: ValueMismatch.",
|
||||
|
@ -332,8 +384,10 @@ describe("errors", () => {
|
|||
assert.fail(
|
||||
"Unexpected success in creating a transaction that should have failed with `ValueMismatch` error"
|
||||
);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2501);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2501);
|
||||
}
|
||||
}, [
|
||||
"Program log: AnchorError thrown in programs/errors/src/lib.rs:73. Error Code: RequireEqViolated. Error Number: 2501. Error Message: A require_eq expression was violated.",
|
||||
|
@ -349,8 +403,10 @@ describe("errors", () => {
|
|||
assert.fail(
|
||||
"Unexpected success in creating a transaction that should have failed with `ValueMatch` error"
|
||||
);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 6127);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 6127);
|
||||
}
|
||||
}, [
|
||||
"Program log: AnchorError thrown in programs/errors/src/lib.rs:78. Error Code: ValueMatch. Error Number: 6127. Error Message: ValueMatch.",
|
||||
|
@ -366,8 +422,10 @@ describe("errors", () => {
|
|||
assert.fail(
|
||||
"Unexpected success in creating a transaction that should have failed with `RequireNeqViolated` error"
|
||||
);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2503);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 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.",
|
||||
|
@ -388,8 +446,10 @@ describe("errors", () => {
|
|||
assert.fail(
|
||||
"Unexpected success in creating a transaction that should have failed with `ValueMismatch` error"
|
||||
);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 6126);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 6126);
|
||||
}
|
||||
}, [
|
||||
"Program log: AnchorError thrown in programs/errors/src/lib.rs:88. Error Code: ValueMismatch. Error Number: 6126. Error Message: ValueMismatch.",
|
||||
|
@ -412,8 +472,10 @@ describe("errors", () => {
|
|||
assert.fail(
|
||||
"Unexpected success in creating a transaction that should have failed with `ValueMismatch` error"
|
||||
);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2502);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2502);
|
||||
}
|
||||
}, [
|
||||
"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.",
|
||||
|
@ -436,8 +498,10 @@ describe("errors", () => {
|
|||
assert.fail(
|
||||
"Unexpected success in creating a transaction that should have failed with `ValueMatch` error"
|
||||
);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 6127);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 6127);
|
||||
}
|
||||
}, [
|
||||
"Program log: AnchorError thrown in programs/errors/src/lib.rs:102. Error Code: ValueMatch. Error Number: 6127. Error Message: ValueMatch.",
|
||||
|
@ -460,8 +524,10 @@ describe("errors", () => {
|
|||
assert.fail(
|
||||
"Unexpected success in creating a transaction that should have failed with `RequireKeysNeqViolated` error"
|
||||
);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2504);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 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.",
|
||||
|
@ -479,8 +545,10 @@ describe("errors", () => {
|
|||
assert.fail(
|
||||
"Unexpected success in creating a transaction that should have failed with `ValueLessOrEqual` error"
|
||||
);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 6129);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 6129);
|
||||
}
|
||||
}, [
|
||||
"Program log: AnchorError thrown in programs/errors/src/lib.rs:116. Error Code: ValueLessOrEqual. Error Number: 6129. Error Message: ValueLessOrEqual.",
|
||||
|
@ -496,8 +564,10 @@ describe("errors", () => {
|
|||
assert.fail(
|
||||
"Unexpected success in creating a transaction that should have failed with `RequireGtViolated` error"
|
||||
);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2505);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 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.",
|
||||
|
@ -513,8 +583,10 @@ describe("errors", () => {
|
|||
assert.fail(
|
||||
"Unexpected success in creating a transaction that should have failed with `ValueLess` error"
|
||||
);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 6128);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 6128);
|
||||
}
|
||||
}, [
|
||||
"Program log: AnchorError thrown in programs/errors/src/lib.rs:126. Error Code: ValueLess. Error Number: 6128. Error Message: ValueLess.",
|
||||
|
@ -530,8 +602,10 @@ describe("errors", () => {
|
|||
assert.fail(
|
||||
"Unexpected success in creating a transaction that should have failed with `RequireGteViolated` error"
|
||||
);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2506);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 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.",
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"types": ["mocha", "chai", "node"],
|
||||
"typeRoots": ["./node_modules/@types"],
|
||||
"lib": ["es2015"],
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@ const anchor = require("@project-serum/anchor");
|
|||
const serumCmn = require("@project-serum/common");
|
||||
const { TOKEN_PROGRAM_ID } = require("@solana/spl-token");
|
||||
const utils = require("./utils");
|
||||
const chai = require("chai");
|
||||
const expect = chai.expect;
|
||||
|
||||
anchor.utils.features.set("anchor-deprecated-state");
|
||||
|
||||
|
@ -118,8 +120,8 @@ describe("Lockup and Registry", () => {
|
|||
await lockup.state.rpc.whitelistAdd(e, { accounts });
|
||||
},
|
||||
(err) => {
|
||||
assert.equal(err.code, 6008);
|
||||
assert.equal(err.msg, "Whitelist is full");
|
||||
assert.equal(err.error.errorCode.number, 6008);
|
||||
assert.equal(err.error.errorMessage, "Whitelist is full");
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
@ -216,8 +218,11 @@ describe("Lockup and Registry", () => {
|
|||
});
|
||||
},
|
||||
(err) => {
|
||||
assert.equal(err.code, 6007);
|
||||
assert.equal(err.msg, "Insufficient withdrawal balance.");
|
||||
assert.equal(err.error.errorCode.number, 6007);
|
||||
assert.equal(
|
||||
err.error.errorMessage,
|
||||
"Insufficient withdrawal balance."
|
||||
);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
@ -773,8 +778,24 @@ describe("Lockup and Registry", () => {
|
|||
(err) => {
|
||||
// Solana doesn't propagate errors across CPI. So we receive the registry's error code,
|
||||
// not the lockup's.
|
||||
const errorCode = "custom program error: 0x1784";
|
||||
assert.ok(err.toString().split(errorCode).length === 2);
|
||||
assert.equal(err.error.errorCode.number, 6020);
|
||||
assert.equal(err.error.errorCode.code, "UnrealizedReward");
|
||||
assert.equal(
|
||||
err.error.errorMessage,
|
||||
"Locked rewards cannot be realized until one unstaked all tokens."
|
||||
);
|
||||
expect(err.error.origin).to.deep.equal({
|
||||
file: "programs/registry/src/lib.rs",
|
||||
line: 63,
|
||||
});
|
||||
assert.equal(
|
||||
err.program.toString(),
|
||||
"HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L"
|
||||
);
|
||||
expect(err.programErrorStack.map((pk) => pk.toString())).to.deep.equal([
|
||||
"Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS",
|
||||
"HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L",
|
||||
]);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
@ -855,8 +876,11 @@ describe("Lockup and Registry", () => {
|
|||
await tryEndUnstake();
|
||||
},
|
||||
(err) => {
|
||||
assert.equal(err.code, 6009);
|
||||
assert.equal(err.msg, "The unstake timelock has not yet expired.");
|
||||
assert.equal(err.error.errorCode.number, 6009);
|
||||
assert.equal(
|
||||
err.error.errorMessage,
|
||||
"The unstake timelock has not yet expired."
|
||||
);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
|
|
@ -14,4 +14,4 @@ program = "./target/deploy/misc.so"
|
|||
exclude = ["programs/shared"]
|
||||
|
||||
[scripts]
|
||||
test = "yarn run mocha -t 1000000 tests/"
|
||||
test = "yarn run ts-mocha -t 1000000 tests/*.ts"
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
const anchor = require("@project-serum/anchor");
|
||||
const assert = require("assert");
|
||||
const {
|
||||
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||
import * as anchor from "@project-serum/anchor";
|
||||
import { Program, BN, IdlAccounts, AnchorError } from "@project-serum/anchor";
|
||||
import {
|
||||
PublicKey,
|
||||
Keypair,
|
||||
SystemProgram,
|
||||
SYSVAR_RENT_PUBKEY,
|
||||
} from "@solana/web3.js";
|
||||
import {
|
||||
TOKEN_PROGRAM_ID,
|
||||
Token,
|
||||
} = require("@solana/spl-token");
|
||||
const miscIdl = require("../target/idl/misc.json");
|
||||
const {
|
||||
SystemProgram,
|
||||
Keypair,
|
||||
PublicKey,
|
||||
SYSVAR_RENT_PUBKEY,
|
||||
} = require("@solana/web3.js");
|
||||
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||
} from "@solana/spl-token";
|
||||
import { Misc } from "../target/types/misc";
|
||||
const utf8 = anchor.utils.bytes.utf8;
|
||||
const assert = require("assert");
|
||||
const miscIdl = require("../target/idl/misc.json");
|
||||
|
||||
describe("misc", () => {
|
||||
// Configure the client to use the local cluster.
|
||||
|
@ -231,9 +233,8 @@ describe("misc", () => {
|
|||
assert.ok(false);
|
||||
} catch (err) {
|
||||
const errMsg = "A close constraint was violated";
|
||||
assert.equal(err.toString(), errMsg);
|
||||
assert.equal(err.msg, errMsg);
|
||||
assert.equal(err.code, 2011);
|
||||
assert.equal(err.error.errorMessage, errMsg);
|
||||
assert.equal(err.error.errorCode.number, 2011);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -702,7 +703,7 @@ describe("misc", () => {
|
|||
});
|
||||
},
|
||||
(err) => {
|
||||
assert.equal(err.code, 2009);
|
||||
assert.equal(err.error.errorCode.number, 2009);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
@ -737,7 +738,7 @@ describe("misc", () => {
|
|||
});
|
||||
},
|
||||
(err) => {
|
||||
assert.equal(err.code, 2015);
|
||||
assert.equal(err.error.errorCode.number, 2015);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
@ -872,7 +873,7 @@ describe("misc", () => {
|
|||
},
|
||||
}),
|
||||
(err) => {
|
||||
assert.equal(err.code, 2006);
|
||||
assert.equal(err.error.errorCode.number, 2006);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
@ -990,8 +991,10 @@ describe("misc", () => {
|
|||
},
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2004);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2004);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1027,8 +1030,10 @@ describe("misc", () => {
|
|||
},
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2006);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2006);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1054,8 +1059,10 @@ describe("misc", () => {
|
|||
signers: [newAcc],
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2019);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2019);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1086,8 +1093,10 @@ describe("misc", () => {
|
|||
signers: [mint],
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2016);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2016);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1118,8 +1127,10 @@ describe("misc", () => {
|
|||
signers: [mint],
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2017);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2017);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1150,8 +1161,10 @@ describe("misc", () => {
|
|||
signers: [mint],
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2018);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2018);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1195,8 +1208,10 @@ describe("misc", () => {
|
|||
signers: [token],
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2015);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2015);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1252,8 +1267,10 @@ describe("misc", () => {
|
|||
signers: [token],
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2014);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2014);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1303,8 +1320,10 @@ describe("misc", () => {
|
|||
},
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2015);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2015);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1366,8 +1385,10 @@ describe("misc", () => {
|
|||
},
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2014);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2014);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1430,8 +1451,10 @@ describe("misc", () => {
|
|||
},
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 3014);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 3014);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1456,8 +1479,10 @@ describe("misc", () => {
|
|||
signers: [data],
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2005);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2005);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1582,9 +1607,14 @@ describe("misc", () => {
|
|||
},
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(2005, err.code);
|
||||
assert.equal("A rent exempt constraint was violated", err.msg);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2005);
|
||||
assert.equal(
|
||||
"A rent exemption constraint was violated",
|
||||
err.error.errorMessage
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1611,8 +1641,10 @@ describe("misc", () => {
|
|||
},
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2006);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2006);
|
||||
}
|
||||
|
||||
// matching bump seed for wrong address but derived from wrong program
|
||||
|
@ -1624,8 +1656,10 @@ describe("misc", () => {
|
|||
},
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2006);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2006);
|
||||
}
|
||||
|
||||
// correct inputs should lead to successful tx
|
||||
|
@ -1661,8 +1695,10 @@ describe("misc", () => {
|
|||
},
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2006);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2006);
|
||||
}
|
||||
|
||||
// same seeds but derived from wrong program
|
||||
|
@ -1674,8 +1710,10 @@ describe("misc", () => {
|
|||
},
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 2006);
|
||||
} catch (_err) {
|
||||
assert.ok(_err instanceof AnchorError);
|
||||
const err: AnchorError = _err;
|
||||
assert.equal(err.error.errorCode.number, 2006);
|
||||
}
|
||||
|
||||
// correct inputs should lead to successful tx
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"types": ["mocha", "chai"],
|
||||
"typeRoots": ["./node_modules/@types"],
|
||||
"lib": ["es2015"],
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
|
@ -42,6 +42,8 @@
|
|||
"devDependencies": {
|
||||
"@types/node": "^14.14.37",
|
||||
"chai": "^4.3.4",
|
||||
"@types/chai": "^4.3.0",
|
||||
"@types/mocha": "^9.1.0",
|
||||
"mocha": "^9.1.3",
|
||||
"ts-mocha": "^8.0.0",
|
||||
"typescript": "^4.4.4",
|
||||
|
|
|
@ -52,9 +52,8 @@ describe("system_accounts", () => {
|
|||
assert.ok(false);
|
||||
} catch (err) {
|
||||
const errMsg = "The given account is not owned by the system program";
|
||||
assert.equal(err.toString(), errMsg);
|
||||
assert.equal(err.msg, errMsg);
|
||||
assert.equal(err.code, 3011);
|
||||
assert.equal(err.error.errorMessage, errMsg);
|
||||
assert.equal(err.error.errorCode.number, 3011);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@ describe("sysvars", () => {
|
|||
console.log("Your transaction signature", tx);
|
||||
});
|
||||
|
||||
it("Fails when the wrote pubkeys are provided", async () => {
|
||||
it("Fails when the wrong pubkeys are provided", async () => {
|
||||
try {
|
||||
await program.methods
|
||||
.sysvars()
|
||||
|
@ -31,9 +31,8 @@ describe("sysvars", () => {
|
|||
assert.ok(false);
|
||||
} catch (err) {
|
||||
const errMsg = "The given public key does not match the required sysvar";
|
||||
assert.strictEqual(err.toString(), errMsg);
|
||||
assert.strictEqual(err.msg, errMsg);
|
||||
assert.strictEqual(err.code, 3015);
|
||||
assert.strictEqual(err.error.errorMessage, errMsg);
|
||||
assert.strictEqual(err.error.errorCode.number, 3015);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -153,6 +153,11 @@
|
|||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/chai@^4.3.0":
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.0.tgz#23509ebc1fa32f1b4d50d6a66c4032d5b8eaabdc"
|
||||
integrity sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==
|
||||
|
||||
"@types/connect@^3.4.33":
|
||||
version "3.4.35"
|
||||
resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1"
|
||||
|
@ -179,6 +184,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.176.tgz#641150fc1cda36fbfa329de603bbb175d7ee20c0"
|
||||
integrity sha512-xZmuPTa3rlZoIbtDUyJKZQimJV3bxCmzMIO2c9Pz9afyDro6kr7R79GwcB6mRhuoPmV2p1Vb66WOJH7F886WKQ==
|
||||
|
||||
"@types/mocha@^9.1.0":
|
||||
version "9.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.0.tgz#baf17ab2cca3fcce2d322ebc30454bff487efad5"
|
||||
integrity sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==
|
||||
|
||||
"@types/node@*":
|
||||
version "16.11.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.7.tgz#36820945061326978c42a01e56b61cd223dfdc42"
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@project-serum/borsh": "^0.2.5",
|
||||
"@solana/web3.js": "^1.17.0",
|
||||
"@solana/web3.js": "^1.36.0",
|
||||
"base64-js": "^1.5.1",
|
||||
"bn.js": "^5.1.2",
|
||||
"bs58": "^4.0.1",
|
||||
|
@ -59,7 +59,7 @@
|
|||
"@types/bn.js": "^4.11.6",
|
||||
"@types/bs58": "^4.0.1",
|
||||
"@types/crypto-hash": "^1.1.2",
|
||||
"@types/jest": "^27.0.3",
|
||||
"@types/jest": "^27.4.1",
|
||||
"@types/pako": "^1.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^4.6.0",
|
||||
"@typescript-eslint/parser": "^4.6.0",
|
||||
|
|
|
@ -2,7 +2,6 @@ import BN from "bn.js";
|
|||
import * as BufferLayout from "buffer-layout";
|
||||
import { Layout } from "buffer-layout";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import * as utils from "../../utils";
|
||||
|
||||
export function uint64(property?: string): Layout<u64 | null> {
|
||||
return new WrappedLayout(
|
||||
|
@ -88,7 +87,7 @@ export class COptionLayout<T> extends Layout<T | null> {
|
|||
} else if (discriminator === 1) {
|
||||
return this.layout.decode(b, offset + 4);
|
||||
}
|
||||
throw new Error("Invalid coption " + this.property);
|
||||
throw new Error("Invalid coption " + this.layout.property);
|
||||
}
|
||||
|
||||
getSpan(b: Buffer, offset = 0): number {
|
||||
|
|
265
ts/src/error.ts
265
ts/src/error.ts
|
@ -1,3 +1,6 @@
|
|||
import { PublicKey } from "@solana/web3.js";
|
||||
import * as features from "./utils/features.js";
|
||||
|
||||
export class IdlError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
|
@ -5,10 +8,212 @@ export class IdlError extends Error {
|
|||
}
|
||||
}
|
||||
|
||||
interface ErrorCode {
|
||||
code: string;
|
||||
number: number;
|
||||
}
|
||||
|
||||
interface FileLine {
|
||||
file: string;
|
||||
line: number;
|
||||
}
|
||||
|
||||
type Origin = string | FileLine;
|
||||
type ComparedAccountNames = [string, string];
|
||||
type ComparedPublicKeys = [PublicKey, PublicKey];
|
||||
type ComparedValues = ComparedAccountNames | ComparedPublicKeys;
|
||||
|
||||
export class ProgramErrorStack {
|
||||
constructor(readonly stack: PublicKey[]) {}
|
||||
|
||||
public static parse(logs: string[]) {
|
||||
const programKeyRegex = /^Program (\w*) invoke/;
|
||||
const successRegex = /^Program \w* success/;
|
||||
|
||||
const programStack: PublicKey[] = [];
|
||||
for (let i = 0; i < logs.length; i++) {
|
||||
if (successRegex.exec(logs[i])) {
|
||||
programStack.pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
const programKey = programKeyRegex.exec(logs[i])?.[1];
|
||||
if (!programKey) {
|
||||
continue;
|
||||
}
|
||||
programStack.push(new PublicKey(programKey));
|
||||
}
|
||||
return new ProgramErrorStack(programStack);
|
||||
}
|
||||
}
|
||||
|
||||
export class AnchorError extends Error {
|
||||
readonly error: {
|
||||
errorCode: ErrorCode;
|
||||
errorMessage: string;
|
||||
comparedValues?: ComparedValues;
|
||||
origin?: Origin;
|
||||
};
|
||||
private readonly _programErrorStack: ProgramErrorStack;
|
||||
|
||||
constructor(
|
||||
errorCode: ErrorCode,
|
||||
errorMessage: string,
|
||||
readonly errorLogs: string[],
|
||||
readonly logs: string[],
|
||||
origin?: Origin,
|
||||
comparedValues?: ComparedValues
|
||||
) {
|
||||
super(errorLogs.join("\n").replace("Program log: ", ""));
|
||||
this.error = { errorCode, errorMessage, comparedValues, origin };
|
||||
this._programErrorStack = ProgramErrorStack.parse(logs);
|
||||
}
|
||||
|
||||
public static parse(logs: string[]) {
|
||||
if (!logs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const anchorErrorLogIndex = logs.findIndex((log) =>
|
||||
log.startsWith("Program log: AnchorError")
|
||||
);
|
||||
if (anchorErrorLogIndex === -1) {
|
||||
return null;
|
||||
}
|
||||
const anchorErrorLog = logs[anchorErrorLogIndex];
|
||||
const errorLogs = [anchorErrorLog];
|
||||
let comparedValues: ComparedValues | undefined;
|
||||
if (anchorErrorLogIndex + 1 < logs.length) {
|
||||
// This catches the comparedValues where the following is logged
|
||||
// <AnchorError>
|
||||
// Left:
|
||||
// <Pubkey>
|
||||
// Right:
|
||||
// <Pubkey>
|
||||
if (logs[anchorErrorLogIndex + 1] === "Program log: Left:") {
|
||||
const pubkeyRegex = /^Program log: (.*)$/;
|
||||
const leftPubkey = pubkeyRegex.exec(logs[anchorErrorLogIndex + 2])![1];
|
||||
const rightPubkey = pubkeyRegex.exec(logs[anchorErrorLogIndex + 4])![1];
|
||||
comparedValues = [
|
||||
new PublicKey(leftPubkey),
|
||||
new PublicKey(rightPubkey),
|
||||
];
|
||||
errorLogs.push(
|
||||
...logs.slice(anchorErrorLogIndex + 1, anchorErrorLogIndex + 5)
|
||||
);
|
||||
}
|
||||
// This catches the comparedValues where the following is logged
|
||||
// <AnchorError>
|
||||
// Left: <value>
|
||||
// Right: <value>
|
||||
else if (logs[anchorErrorLogIndex + 1].startsWith("Program log: Left:")) {
|
||||
const valueRegex = /^Program log: (Left|Right): (.*)$/;
|
||||
const leftValue = valueRegex.exec(logs[anchorErrorLogIndex + 1])![2];
|
||||
const rightValue = valueRegex.exec(logs[anchorErrorLogIndex + 2])![2];
|
||||
errorLogs.push(
|
||||
...logs.slice(anchorErrorLogIndex + 1, anchorErrorLogIndex + 3)
|
||||
);
|
||||
comparedValues = [leftValue, rightValue];
|
||||
}
|
||||
}
|
||||
const regexNoInfo = /^Program log: AnchorError occurred\. Error Code: (.*)\. Error Number: (\d*)\. Error Message: (.*)\./;
|
||||
const noInfoAnchorErrorLog = regexNoInfo.exec(anchorErrorLog);
|
||||
const regexFileLine = /^Program log: AnchorError thrown in (.*):(\d*)\. Error Code: (.*)\. Error Number: (\d*)\. Error Message: (.*)\./;
|
||||
const fileLineAnchorErrorLog = regexFileLine.exec(anchorErrorLog);
|
||||
const regexAccountName = /^Program log: AnchorError caused by account: (.*)\. Error Code: (.*)\. Error Number: (\d*)\. Error Message: (.*)\./;
|
||||
const accountNameAnchorErrorLog = regexAccountName.exec(anchorErrorLog);
|
||||
if (noInfoAnchorErrorLog) {
|
||||
const [
|
||||
errorCodeString,
|
||||
errorNumber,
|
||||
errorMessage,
|
||||
] = noInfoAnchorErrorLog.slice(1, 4);
|
||||
const errorCode = {
|
||||
code: errorCodeString,
|
||||
number: parseInt(errorNumber),
|
||||
};
|
||||
return new AnchorError(
|
||||
errorCode,
|
||||
errorMessage,
|
||||
errorLogs,
|
||||
logs,
|
||||
undefined,
|
||||
comparedValues
|
||||
);
|
||||
} else if (fileLineAnchorErrorLog) {
|
||||
const [
|
||||
file,
|
||||
line,
|
||||
errorCodeString,
|
||||
errorNumber,
|
||||
errorMessage,
|
||||
] = fileLineAnchorErrorLog.slice(1, 6);
|
||||
const errorCode = {
|
||||
code: errorCodeString,
|
||||
number: parseInt(errorNumber),
|
||||
};
|
||||
const fileLine = { file, line: parseInt(line) };
|
||||
return new AnchorError(
|
||||
errorCode,
|
||||
errorMessage,
|
||||
errorLogs,
|
||||
logs,
|
||||
fileLine,
|
||||
comparedValues
|
||||
);
|
||||
} else if (accountNameAnchorErrorLog) {
|
||||
const [
|
||||
accountName,
|
||||
errorCodeString,
|
||||
errorNumber,
|
||||
errorMessage,
|
||||
] = accountNameAnchorErrorLog.slice(1, 5);
|
||||
const origin = accountName;
|
||||
const errorCode = {
|
||||
code: errorCodeString,
|
||||
number: parseInt(errorNumber),
|
||||
};
|
||||
return new AnchorError(
|
||||
errorCode,
|
||||
errorMessage,
|
||||
errorLogs,
|
||||
logs,
|
||||
origin,
|
||||
comparedValues
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
get program(): PublicKey {
|
||||
return this._programErrorStack.stack[
|
||||
this._programErrorStack.stack.length - 1
|
||||
];
|
||||
}
|
||||
|
||||
get programErrorStack(): PublicKey[] {
|
||||
return this._programErrorStack.stack;
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
return this.message;
|
||||
}
|
||||
}
|
||||
|
||||
// An error from a user defined program.
|
||||
export class ProgramError extends Error {
|
||||
constructor(readonly code: number, readonly msg: string, ...params: any[]) {
|
||||
super(...params);
|
||||
private readonly _programErrorStack?: ProgramErrorStack;
|
||||
|
||||
constructor(
|
||||
readonly code: number,
|
||||
readonly msg: string,
|
||||
readonly logs?: string[]
|
||||
) {
|
||||
super();
|
||||
if (logs) {
|
||||
this._programErrorStack = ProgramErrorStack.parse(logs);
|
||||
}
|
||||
}
|
||||
|
||||
public static parse(
|
||||
|
@ -44,24 +249,71 @@ export class ProgramError extends Error {
|
|||
// Parse user error.
|
||||
let errorMsg = idlErrors.get(errorCode);
|
||||
if (errorMsg !== undefined) {
|
||||
return new ProgramError(errorCode, errorMsg, errorCode + ": " + errorMsg);
|
||||
return new ProgramError(errorCode, errorMsg, err.logs);
|
||||
}
|
||||
|
||||
// Parse framework internal error.
|
||||
errorMsg = LangErrorMessage.get(errorCode);
|
||||
if (errorMsg !== undefined) {
|
||||
return new ProgramError(errorCode, errorMsg, errorCode + ": " + errorMsg);
|
||||
return new ProgramError(errorCode, errorMsg, err.logs);
|
||||
}
|
||||
|
||||
// Unable to parse the error. Just return the untranslated error.
|
||||
return null;
|
||||
}
|
||||
|
||||
get program(): PublicKey | undefined {
|
||||
return this._programErrorStack?.stack[
|
||||
this._programErrorStack.stack.length - 1
|
||||
];
|
||||
}
|
||||
|
||||
get programErrorStack(): PublicKey[] | undefined {
|
||||
return this._programErrorStack?.stack;
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
return this.msg;
|
||||
}
|
||||
}
|
||||
|
||||
export function translateError(err: any, idlErrors: Map<number, string>) {
|
||||
if (features.isSet("debug-logs")) {
|
||||
console.log("Translating error:", err);
|
||||
}
|
||||
|
||||
const anchorError = AnchorError.parse(err.logs);
|
||||
if (anchorError) {
|
||||
return anchorError;
|
||||
}
|
||||
|
||||
const programError = ProgramError.parse(err, idlErrors);
|
||||
if (programError) {
|
||||
return programError;
|
||||
}
|
||||
if (err.logs) {
|
||||
const handler = {
|
||||
get: function (target, prop) {
|
||||
if (prop === "programErrorStack") {
|
||||
return target.programErrorStack.stack;
|
||||
} else if (prop === "program") {
|
||||
return target.programErrorStack.stack[
|
||||
err.programErrorStack.stack.length - 1
|
||||
];
|
||||
} else {
|
||||
// this is the normal way to return all other props
|
||||
// without modifying them.
|
||||
// @ts-expect-error
|
||||
return Reflect.get(...arguments);
|
||||
}
|
||||
},
|
||||
};
|
||||
err.programErrorStack = ProgramErrorStack.parse(err.logs);
|
||||
return new Proxy(err, handler);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
const LangErrorCode = {
|
||||
// Instructions.
|
||||
InstructionMissing: 100,
|
||||
|
@ -166,7 +418,10 @@ const LangErrorMessage = new Map([
|
|||
[LangErrorCode.ConstraintSigner, "A signer constraint was violated"],
|
||||
[LangErrorCode.ConstraintRaw, "A raw constraint was violated"],
|
||||
[LangErrorCode.ConstraintOwner, "An owner constraint was violated"],
|
||||
[LangErrorCode.ConstraintRentExempt, "A rent exempt constraint was violated"],
|
||||
[
|
||||
LangErrorCode.ConstraintRentExempt,
|
||||
"A rent exemption constraint was violated",
|
||||
],
|
||||
[LangErrorCode.ConstraintSeeds, "A seeds constraint was violated"],
|
||||
[LangErrorCode.ConstraintExecutable, "An executable constraint was violated"],
|
||||
[LangErrorCode.ConstraintState, "A state constraint was violated"],
|
||||
|
|
|
@ -3,8 +3,7 @@ import Provider from "../../provider.js";
|
|||
import { Idl } from "../../idl.js";
|
||||
import { splitArgsAndCtx } from "../context.js";
|
||||
import { TransactionFn } from "./transaction.js";
|
||||
import { ProgramError } from "../../error.js";
|
||||
import * as features from "../../utils/features.js";
|
||||
import { translateError } from "../../error.js";
|
||||
import {
|
||||
AllInstructions,
|
||||
InstructionContextFn,
|
||||
|
@ -22,18 +21,9 @@ export default class RpcFactory {
|
|||
const tx = txFn(...args);
|
||||
const [, ctx] = splitArgsAndCtx(idlIx, [...args]);
|
||||
try {
|
||||
const txSig = await provider.send(tx, ctx.signers, ctx.options);
|
||||
return txSig;
|
||||
return await provider.send(tx, ctx.signers, ctx.options);
|
||||
} catch (err) {
|
||||
if (features.isSet("debug-logs")) {
|
||||
console.log("Translating error:", err);
|
||||
}
|
||||
|
||||
let translatedErr = ProgramError.parse(err, idlErrors);
|
||||
if (translatedErr === null) {
|
||||
throw err;
|
||||
}
|
||||
throw translatedErr;
|
||||
throw translateError(err, idlErrors);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -9,8 +9,7 @@ import { TransactionFn } from "./transaction.js";
|
|||
import { EventParser, Event } from "../event.js";
|
||||
import { Coder } from "../../coder/index.js";
|
||||
import { Idl, IdlEvent } from "../../idl.js";
|
||||
import { ProgramError } from "../../error.js";
|
||||
import * as features from "../../utils/features.js";
|
||||
import { translateError } from "../../error.js";
|
||||
import {
|
||||
AllInstructions,
|
||||
IdlTypes,
|
||||
|
@ -37,15 +36,7 @@ export default class SimulateFactory {
|
|||
try {
|
||||
resp = await provider!.simulate(tx, ctx.signers, ctx.options);
|
||||
} catch (err) {
|
||||
if (features.isSet("debug-logs")) {
|
||||
console.log("Translating error:", err);
|
||||
}
|
||||
|
||||
let translatedErr = ProgramError.parse(err, idlErrors);
|
||||
if (translatedErr === null) {
|
||||
throw err;
|
||||
}
|
||||
throw translatedErr;
|
||||
throw translateError(err, idlErrors);
|
||||
}
|
||||
if (resp === undefined) {
|
||||
throw new Error("Unable to simulate transaction");
|
||||
|
|
|
@ -5,11 +5,12 @@ import {
|
|||
Transaction,
|
||||
TransactionSignature,
|
||||
ConfirmOptions,
|
||||
sendAndConfirmRawTransaction,
|
||||
RpcResponseAndContext,
|
||||
SimulatedTransactionResponse,
|
||||
Commitment,
|
||||
SendTransactionError,
|
||||
} from "@solana/web3.js";
|
||||
import { bs58 } from "./utils/bytes/index.js";
|
||||
import { isBrowser } from "./utils/common.js";
|
||||
|
||||
/**
|
||||
|
@ -115,13 +116,30 @@ export default class Provider {
|
|||
|
||||
const rawTx = tx.serialize();
|
||||
|
||||
const txId = await sendAndConfirmRawTransaction(
|
||||
this.connection,
|
||||
rawTx,
|
||||
opts
|
||||
);
|
||||
|
||||
return txId;
|
||||
try {
|
||||
return await sendAndConfirmRawTransaction(this.connection, rawTx, opts);
|
||||
} catch (err) {
|
||||
// thrown if the underlying 'confirmTransaction' encounters a failed tx
|
||||
// the 'confirmTransaction' error does not return logs so we make another rpc call to get them
|
||||
if (err instanceof ConfirmError) {
|
||||
// choose the shortest available commitment for 'getTransaction'
|
||||
// (the json RPC does not support any shorter than "confirmed" for 'getTransaction')
|
||||
// because that will see the tx sent with `sendAndConfirmRawTransaction` no matter which
|
||||
// commitment `sendAndConfirmRawTransaction` used
|
||||
const failedTx = await this.connection.getTransaction(
|
||||
bs58.encode(tx.signature!),
|
||||
{ commitment: "confirmed" }
|
||||
);
|
||||
if (!failedTx) {
|
||||
throw err;
|
||||
} else {
|
||||
const logs = failedTx.meta?.logMessages;
|
||||
throw !logs ? err : new SendTransactionError(err.message, logs);
|
||||
}
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -253,6 +271,45 @@ async function simulateTransaction(
|
|||
return res.result;
|
||||
}
|
||||
|
||||
// Copy of Connection.sendAndConfirmRawTransaction that throws
|
||||
// a better error if 'confirmTransaction` returns an error status
|
||||
async function sendAndConfirmRawTransaction(
|
||||
connection: Connection,
|
||||
rawTransaction: Buffer,
|
||||
options?: ConfirmOptions
|
||||
): Promise<TransactionSignature> {
|
||||
const sendOptions = options && {
|
||||
skipPreflight: options.skipPreflight,
|
||||
preflightCommitment: options.preflightCommitment || options.commitment,
|
||||
};
|
||||
|
||||
const signature = await connection.sendRawTransaction(
|
||||
rawTransaction,
|
||||
sendOptions
|
||||
);
|
||||
|
||||
const status = (
|
||||
await connection.confirmTransaction(
|
||||
signature,
|
||||
options && options.commitment
|
||||
)
|
||||
).value;
|
||||
|
||||
if (status.err) {
|
||||
throw new ConfirmError(
|
||||
`Raw transaction ${signature} failed (${JSON.stringify(status)})`
|
||||
);
|
||||
}
|
||||
|
||||
return signature;
|
||||
}
|
||||
|
||||
class ConfirmError extends Error {
|
||||
constructor(message?: string) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default provider on the client.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,332 @@
|
|||
import { ProgramErrorStack, AnchorError } from "../src/error";
|
||||
|
||||
describe("ProgramErrorStack", () => {
|
||||
test("basic", () => {
|
||||
const logs = [
|
||||
"Program ERRM6YCMsccM22TEaPuu35KVU4iCY3GLCz4qMsKLYReE invoke [1]",
|
||||
"Program ERRM6YCMsccM22TEaPuu35KVU4iCY3GLCz4qMsKLYReE consumed 3797 of 200000 compute units",
|
||||
"Program ERRM6YCMsccM22TEaPuu35KVU4iCY3GLCz4qMsKLYReE failed: custom program error: 0x29",
|
||||
];
|
||||
|
||||
expect(
|
||||
ProgramErrorStack.parse(logs).stack.map((publicKey) =>
|
||||
publicKey.toString()
|
||||
)
|
||||
).toEqual(["ERRM6YCMsccM22TEaPuu35KVU4iCY3GLCz4qMsKLYReE"]);
|
||||
});
|
||||
|
||||
it("basic multiple ix", () => {
|
||||
const logs = [
|
||||
"Program 9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin invoke [1]",
|
||||
"Program 9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin consumed 4308 of 200000 compute units",
|
||||
"Program 9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin success",
|
||||
"Program ERRM6YCMsccM22TEaPuu35KVU4iCY3GLCz4qMsKLYReE invoke [1]",
|
||||
"Program ERRM6YCMsccM22TEaPuu35KVU4iCY3GLCz4qMsKLYReE consumed 3797 of 200000 compute units",
|
||||
"Program ERRM6YCMsccM22TEaPuu35KVU4iCY3GLCz4qMsKLYReE failed: custom program error: 0x29",
|
||||
];
|
||||
|
||||
expect(
|
||||
ProgramErrorStack.parse(logs).stack.map((publicKey) =>
|
||||
publicKey.toString()
|
||||
)
|
||||
).toEqual(["ERRM6YCMsccM22TEaPuu35KVU4iCY3GLCz4qMsKLYReE"]);
|
||||
});
|
||||
|
||||
it("failed inner ix", () => {
|
||||
const logs = [
|
||||
"Program Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS invoke [1]",
|
||||
"Program log: Instruction: Create",
|
||||
"Program ERRM6YCMsccM22TEaPuu35KVU4iCY3GLCz4qMsKLYReE invoke [2]",
|
||||
"Program log: AnchorError thrown in programs/switchboard_v2/src/actions/aggregator_save_result_action.rs:235. Error Code: OracleMismatchError. Error Number: 6021. Error Message: An unexpected oracle account was provided for the transaction..",
|
||||
"Program Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS consumed 12619 of 1400000 compute units",
|
||||
"Program Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS failed: Program failed to complete",
|
||||
];
|
||||
|
||||
expect(
|
||||
ProgramErrorStack.parse(logs).stack.map((publicKey) =>
|
||||
publicKey.toString()
|
||||
)
|
||||
).toEqual([
|
||||
"Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS",
|
||||
"ERRM6YCMsccM22TEaPuu35KVU4iCY3GLCz4qMsKLYReE",
|
||||
]);
|
||||
});
|
||||
|
||||
it("ignore successful inner ix", () => {
|
||||
const logs = [
|
||||
"Program Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS invoke [1]",
|
||||
"Program log: Instruction: Create",
|
||||
"Program 11111111111111111111111111111111 invoke [2]",
|
||||
"Program 11111111111111111111111111111111 success",
|
||||
"Program log: panicked at programs/floats/src/lib.rs:17:9",
|
||||
"Program Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS consumed 12619 of 1400000 compute units",
|
||||
"Program failed to complete: BPF program panicked",
|
||||
"Program Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS failed: Program failed to complete",
|
||||
];
|
||||
expect(
|
||||
ProgramErrorStack.parse(logs).stack.map((publicKey) =>
|
||||
publicKey.toString()
|
||||
)
|
||||
).toEqual(["Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"]);
|
||||
});
|
||||
|
||||
it("ignore successful inner ix but don't ignore failing inner ix", () => {
|
||||
const logs = [
|
||||
"Program Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS invoke [1]",
|
||||
"Program log: Instruction: Create",
|
||||
"Program 11111111111111111111111111111111 invoke [2]",
|
||||
"Program 11111111111111111111111111111111 success",
|
||||
"Program ERRM6YCMsccM22TEaPuu35KVU4iCY3GLCz4qMsKLYReE invoke [2]",
|
||||
"Program log: panicked at programs/floats/src/lib.rs:17:9",
|
||||
"Program Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS consumed 12619 of 1400000 compute units",
|
||||
"Program failed to complete: BPF program panicked",
|
||||
"Program Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS failed: Program failed to complete",
|
||||
];
|
||||
expect(
|
||||
ProgramErrorStack.parse(logs).stack.map((publicKey) =>
|
||||
publicKey.toString()
|
||||
)
|
||||
).toEqual([
|
||||
"Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS",
|
||||
"ERRM6YCMsccM22TEaPuu35KVU4iCY3GLCz4qMsKLYReE",
|
||||
]);
|
||||
});
|
||||
|
||||
it("ignore successful inner ix but don't ignore failing inner ix - big nested", () => {
|
||||
const logs = [
|
||||
"Program Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS invoke [1]",
|
||||
"Program log: Instruction: Create",
|
||||
"Program 11111111111111111111111111111111 invoke [2]",
|
||||
"Program 11111111111111111111111111111111 success",
|
||||
"Program 1119iqpxV28XnisGGQVMHsABdWZAx9PjtwegepRhGm5 invoke [2]",
|
||||
"Program 1119iqpxV28XnisGGQVMHsABdWZAx9PjtwegepRhGm5 consumed 4308 of 200000 compute units",
|
||||
"Program 1119iqpxV28XnisGGQVMHsABdWZAx9PjtwegepRhGm5 success",
|
||||
"Program 222fsxyjMZSSpT9gpucChbiFmjZC2GtaZmKsBkh66KMZ invoke [2]",
|
||||
"Program 333fE7qebyWBjcaCJcVmkzwrheA1Ka9bjGChuhVD9iQr invoke [3]",
|
||||
"Program 444D5MLf9UbeJBiuFw5WzVG3bMejweunZHPboWm2oTsh invoke [4]",
|
||||
"Program 444D5MLf9UbeJBiuFw5WzVG3bMejweunZHPboWm2oTsh consumed 14343 of 200000 compute units",
|
||||
"Program 444D5MLf9UbeJBiuFw5WzVG3bMejweunZHPboWm2oTsh success",
|
||||
"Program 555CBVR14jAYjK8jRE5kurBACiSNYXkffciRSG2R3krX invoke [4]",
|
||||
"Program 555CBVR14jAYjK8jRE5kurBACiSNYXkffciRSG2R3krX consumed 163337 of 200000 compute units",
|
||||
"Program 555CBVR14jAYjK8jRE5kurBACiSNYXkffciRSG2R3krX success",
|
||||
"Program 666UBGVHWNP7qNqUdnYz86owJ8oErztVvgeF5Dd5v8cR invoke [4]",
|
||||
"Program 666UBGVHWNP7qNqUdnYz86owJ8oErztVvgeF5Dd5v8cR success",
|
||||
"Program 333fE7qebyWBjcaCJcVmkzwrheA1Ka9bjGChuhVD9iQr success",
|
||||
"Program 222fsxyjMZSSpT9gpucChbiFmjZC2GtaZmKsBkh66KMZ success",
|
||||
"Program 777UGK3pU4ygVWwnn7MDnetec1nSVg4Xi53DFSHu9D6A invoke [2]",
|
||||
"Program 888E49S65VpyDmydi6juT7tsSwNyD3ZEVkV8te1rL3iH invoke [3]",
|
||||
"Program 999X95icuyGzfYoeP6SPMb8aMn6ahfCpAt9VPddSNPPi invoke [4]",
|
||||
"Program 999X95icuyGzfYoeP6SPMb8aMn6ahfCpAt9VPddSNPPi success",
|
||||
"Program ERRM6YCMsccM22TEaPuu35KVU4iCY3GLCz4qMsKLYReE invoke [4]",
|
||||
"Program log: panicked at programs/floats/src/lib.rs:17:9",
|
||||
"Program Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS consumed 12619 of 1400000 compute units",
|
||||
"Program failed to complete: BPF program panicked",
|
||||
"Program Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS failed: Program failed to complete",
|
||||
];
|
||||
|
||||
expect(
|
||||
ProgramErrorStack.parse(logs).stack.map((publicKey) =>
|
||||
publicKey.toString()
|
||||
)
|
||||
).toEqual([
|
||||
"Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS",
|
||||
"777UGK3pU4ygVWwnn7MDnetec1nSVg4Xi53DFSHu9D6A",
|
||||
"888E49S65VpyDmydi6juT7tsSwNyD3ZEVkV8te1rL3iH",
|
||||
"ERRM6YCMsccM22TEaPuu35KVU4iCY3GLCz4qMsKLYReE",
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("AnchorError", () => {
|
||||
it("FileLine AnchorError with Pubkeys", () => {
|
||||
const logs = [
|
||||
"Program SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f invoke [1]",
|
||||
"Program log: Instruction: AggregatorSaveResult",
|
||||
"Program log: AnchorError thrown in programs/switchboard_v2/src/actions/aggregator_save_result_action.rs:235. Error Code: OracleMismatchError. Error Number: 6021. Error Message: An unexpected oracle account was provided for the transaction..",
|
||||
"Program log: Left:",
|
||||
"Program log: Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS",
|
||||
"Program log: Right:",
|
||||
"Program log: SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f",
|
||||
"Program SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f consumed 28928 of 200000 compute units",
|
||||
"Program SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f failed: custom program error: 0x1785",
|
||||
];
|
||||
|
||||
const anchorError = AnchorError.parse(logs)!;
|
||||
expect(anchorError.program.toString()).toEqual(
|
||||
"SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"
|
||||
);
|
||||
expect(anchorError.error.errorCode).toEqual({
|
||||
code: "OracleMismatchError",
|
||||
number: 6021,
|
||||
});
|
||||
expect(anchorError.error.errorMessage).toEqual(
|
||||
"An unexpected oracle account was provided for the transaction."
|
||||
);
|
||||
expect(anchorError.error.origin).toEqual({
|
||||
file:
|
||||
"programs/switchboard_v2/src/actions/aggregator_save_result_action.rs",
|
||||
line: 235,
|
||||
});
|
||||
expect(
|
||||
anchorError.error.comparedValues!.map((pk) => pk.toString())
|
||||
).toEqual([
|
||||
"Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS",
|
||||
"SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f",
|
||||
]);
|
||||
expect(
|
||||
anchorError.programErrorStack!.map((publicKey) => publicKey.toString())
|
||||
).toEqual(["SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"]);
|
||||
expect(anchorError.errorLogs).toEqual([
|
||||
"Program log: AnchorError thrown in programs/switchboard_v2/src/actions/aggregator_save_result_action.rs:235. Error Code: OracleMismatchError. Error Number: 6021. Error Message: An unexpected oracle account was provided for the transaction..",
|
||||
"Program log: Left:",
|
||||
"Program log: Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS",
|
||||
"Program log: Right:",
|
||||
"Program log: SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f",
|
||||
]);
|
||||
});
|
||||
|
||||
it("FileLine AnchorError with Values", () => {
|
||||
const logs = [
|
||||
"Program SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f invoke [1]",
|
||||
"Program log: Instruction: AggregatorSaveResult",
|
||||
"Program log: AnchorError thrown in programs/switchboard_v2/src/actions/aggregator_save_result_action.rs:235. Error Code: OracleMismatchError. Error Number: 6021. Error Message: An unexpected oracle account was provided for the transaction..",
|
||||
"Program log: Left: 1337",
|
||||
"Program log: Right: 4220",
|
||||
"Program SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f consumed 28928 of 200000 compute units",
|
||||
"Program SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f failed: custom program error: 0x1785",
|
||||
];
|
||||
|
||||
const anchorError = AnchorError.parse(logs)!;
|
||||
expect(anchorError.program.toString()).toEqual(
|
||||
"SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"
|
||||
);
|
||||
expect(anchorError.error.errorCode).toEqual({
|
||||
code: "OracleMismatchError",
|
||||
number: 6021,
|
||||
});
|
||||
expect(anchorError.error.errorMessage).toEqual(
|
||||
"An unexpected oracle account was provided for the transaction."
|
||||
);
|
||||
expect(anchorError.error.origin).toEqual({
|
||||
file:
|
||||
"programs/switchboard_v2/src/actions/aggregator_save_result_action.rs",
|
||||
line: 235,
|
||||
});
|
||||
expect(anchorError.error.comparedValues!).toEqual(["1337", "4220"]);
|
||||
expect(
|
||||
anchorError.programErrorStack!.map((publicKey) => publicKey.toString())
|
||||
).toEqual(["SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"]);
|
||||
expect(anchorError.errorLogs).toEqual([
|
||||
"Program log: AnchorError thrown in programs/switchboard_v2/src/actions/aggregator_save_result_action.rs:235. Error Code: OracleMismatchError. Error Number: 6021. Error Message: An unexpected oracle account was provided for the transaction..",
|
||||
"Program log: Left: 1337",
|
||||
"Program log: Right: 4220",
|
||||
]);
|
||||
});
|
||||
|
||||
it("AccountName AnchorError with Pubkeys", () => {
|
||||
const logs = [
|
||||
"Program SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f invoke [1]",
|
||||
"Program log: Instruction: AggregatorSaveResult",
|
||||
"Program log: AnchorError caused by account: some_account. Error Code: OracleMismatchError. Error Number: 6021. Error Message: An unexpected oracle account was provided for the transaction..",
|
||||
"Program log: Left:",
|
||||
"Program log: Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS",
|
||||
"Program log: Right:",
|
||||
"Program log: SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f",
|
||||
"Program SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f consumed 28928 of 200000 compute units",
|
||||
"Program SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f failed: custom program error: 0x1785",
|
||||
];
|
||||
|
||||
const anchorError = AnchorError.parse(logs)!;
|
||||
expect(anchorError.program.toString()).toEqual(
|
||||
"SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"
|
||||
);
|
||||
expect(anchorError.error.errorCode).toEqual({
|
||||
code: "OracleMismatchError",
|
||||
number: 6021,
|
||||
});
|
||||
expect(anchorError.error.errorMessage).toEqual(
|
||||
"An unexpected oracle account was provided for the transaction."
|
||||
);
|
||||
expect(anchorError.error.origin).toEqual("some_account");
|
||||
expect(
|
||||
anchorError.error.comparedValues!.map((pk) => pk.toString())
|
||||
).toEqual([
|
||||
"Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS",
|
||||
"SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f",
|
||||
]);
|
||||
expect(
|
||||
anchorError.programErrorStack!.map((publicKey) => publicKey.toString())
|
||||
).toEqual(["SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"]);
|
||||
expect(anchorError.errorLogs).toEqual([
|
||||
"Program log: AnchorError caused by account: some_account. Error Code: OracleMismatchError. Error Number: 6021. Error Message: An unexpected oracle account was provided for the transaction..",
|
||||
"Program log: Left:",
|
||||
"Program log: Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS",
|
||||
"Program log: Right:",
|
||||
"Program log: SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f",
|
||||
]);
|
||||
});
|
||||
|
||||
it("AccountName AnchorError with Values", () => {
|
||||
const logs = [
|
||||
"Program SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f invoke [1]",
|
||||
"Program log: Instruction: AggregatorSaveResult",
|
||||
"Program log: AnchorError caused by account: some_account. Error Code: OracleMismatchError. Error Number: 6021. Error Message: An unexpected oracle account was provided for the transaction..",
|
||||
"Program log: Left: 1337",
|
||||
"Program log: Right: 4220",
|
||||
"Program SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f consumed 28928 of 200000 compute units",
|
||||
"Program SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f failed: custom program error: 0x1785",
|
||||
];
|
||||
|
||||
const anchorError = AnchorError.parse(logs)!;
|
||||
expect(anchorError.program.toString()).toEqual(
|
||||
"SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"
|
||||
);
|
||||
expect(anchorError.error.errorCode).toEqual({
|
||||
code: "OracleMismatchError",
|
||||
number: 6021,
|
||||
});
|
||||
expect(anchorError.error.errorMessage).toEqual(
|
||||
"An unexpected oracle account was provided for the transaction."
|
||||
);
|
||||
expect(anchorError.error.origin).toEqual("some_account");
|
||||
expect(anchorError.error.comparedValues!).toEqual(["1337", "4220"]);
|
||||
expect(
|
||||
anchorError.programErrorStack!.map((publicKey) => publicKey.toString())
|
||||
).toEqual(["SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"]);
|
||||
expect(anchorError.errorLogs).toEqual([
|
||||
"Program log: AnchorError caused by account: some_account. Error Code: OracleMismatchError. Error Number: 6021. Error Message: An unexpected oracle account was provided for the transaction..",
|
||||
"Program log: Left: 1337",
|
||||
"Program log: Right: 4220",
|
||||
]);
|
||||
});
|
||||
|
||||
it("Empty AnchorError", () => {
|
||||
const logs = [
|
||||
"Program SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f invoke [1]",
|
||||
"Program log: Instruction: AggregatorSaveResult",
|
||||
"Program log: AnchorError occurred. Error Code: OracleMismatchError. Error Number: 6021. Error Message: An unexpected oracle account was provided for the transaction..",
|
||||
"Program SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f consumed 28928 of 200000 compute units",
|
||||
"Program SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f failed: custom program error: 0x1785",
|
||||
];
|
||||
|
||||
const anchorError = AnchorError.parse(logs)!;
|
||||
expect(anchorError.program.toString()).toEqual(
|
||||
"SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"
|
||||
);
|
||||
expect(anchorError.error.errorCode).toEqual({
|
||||
code: "OracleMismatchError",
|
||||
number: 6021,
|
||||
});
|
||||
expect(anchorError.error.errorMessage).toEqual(
|
||||
"An unexpected oracle account was provided for the transaction."
|
||||
);
|
||||
expect(anchorError.error.origin).toBeUndefined();
|
||||
expect(anchorError.error.comparedValues).toBeUndefined();
|
||||
expect(
|
||||
anchorError.programErrorStack!.map((publicKey) => publicKey.toString())
|
||||
).toEqual(["SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"]);
|
||||
expect(anchorError.errorLogs).toEqual([
|
||||
"Program log: AnchorError occurred. Error Code: OracleMismatchError. Error Number: 6021. Error Message: An unexpected oracle account was provided for the transaction..",
|
||||
]);
|
||||
});
|
||||
});
|
109
ts/yarn.lock
109
ts/yarn.lock
|
@ -649,6 +649,27 @@
|
|||
minimatch "^3.0.4"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@ethersproject/bytes@^5.6.0":
|
||||
version "5.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.6.0.tgz#81652f2a0e04533575befadce555213c11d8aa20"
|
||||
integrity sha512-3hJPlYemb9V4VLfJF5BfN0+55vltPZSHU3QKUyP9M3Y2TcajbiRrz65UG+xVHOzBereB1b9mn7r12o177xgN7w==
|
||||
dependencies:
|
||||
"@ethersproject/logger" "^5.6.0"
|
||||
|
||||
"@ethersproject/logger@^5.6.0":
|
||||
version "5.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.6.0.tgz#d7db1bfcc22fd2e4ab574cba0bb6ad779a9a3e7a"
|
||||
integrity sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg==
|
||||
|
||||
"@ethersproject/sha2@^5.5.0":
|
||||
version "5.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.6.0.tgz#364c4c11cc753bda36f31f001628706ebadb64d9"
|
||||
integrity sha512-1tNWCPFLu1n3JM9t4/kytz35DkuF9MxqkGGEHNauEbaARdm2fafnOyw1s0tIQDPKF/7bkP1u3dbrmjpn5CelyA==
|
||||
dependencies:
|
||||
"@ethersproject/bytes" "^5.6.0"
|
||||
"@ethersproject/logger" "^5.6.0"
|
||||
hash.js "1.1.7"
|
||||
|
||||
"@istanbuljs/load-nyc-config@^1.0.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz"
|
||||
|
@ -927,21 +948,28 @@
|
|||
dependencies:
|
||||
"@sinonjs/commons" "^1.7.0"
|
||||
|
||||
"@solana/web3.js@^1.17.0":
|
||||
version "1.17.0"
|
||||
resolved "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.17.0.tgz"
|
||||
integrity sha512-PBOHY260CudciLwBgwt1U8upwCS1Jq0BbS6EVyX0tz6Tj14Dp4i87dQNyntentNiGQQ+yWBIk4vJEm+PMCSd/A==
|
||||
"@solana/buffer-layout@^3.0.0":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-3.0.0.tgz#b9353caeb9a1589cb77a1b145bcb1a9a93114326"
|
||||
integrity sha512-MVdgAKKL39tEs0l8je0hKaXLQFb7Rdfb0Xg2LjFZd8Lfdazkg6xiS98uAZrEKvaoF3i4M95ei9RydkGIDMeo3w==
|
||||
dependencies:
|
||||
buffer "~6.0.3"
|
||||
|
||||
"@solana/web3.js@^1.36.0":
|
||||
version "1.36.0"
|
||||
resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.36.0.tgz#79d7d5217b49b80139f4de68953adc5b9a9a264f"
|
||||
integrity sha512-RNT1451iRR7TyW7EJKMCrH/0OXawIe4zVm0DWQASwXlR/u1jmW6FrmH0lujIh7cGTlfOVbH+2ZU9AVUPLBFzwA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
"@ethersproject/sha2" "^5.5.0"
|
||||
"@solana/buffer-layout" "^3.0.0"
|
||||
bn.js "^5.0.0"
|
||||
borsh "^0.4.0"
|
||||
bs58 "^4.0.1"
|
||||
buffer "6.0.1"
|
||||
buffer-layout "^1.2.0"
|
||||
crypto-hash "^1.2.2"
|
||||
cross-fetch "^3.1.4"
|
||||
jayson "^3.4.4"
|
||||
js-sha3 "^0.8.0"
|
||||
node-fetch "^2.6.1"
|
||||
rpc-websockets "^7.4.2"
|
||||
secp256k1 "^4.0.2"
|
||||
superstruct "^0.14.2"
|
||||
|
@ -1069,12 +1097,12 @@
|
|||
dependencies:
|
||||
"@types/istanbul-lib-report" "*"
|
||||
|
||||
"@types/jest@^27.0.3":
|
||||
version "27.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.0.3.tgz#0cf9dfe9009e467f70a342f0f94ead19842a783a"
|
||||
integrity sha512-cmmwv9t7gBYt7hNKH5Spu7Kuu/DotGa+Ff+JGRKZ4db5eh8PnKS4LuebJ3YLUoyOyIHraTGyULn23YtEAm0VSg==
|
||||
"@types/jest@^27.4.1":
|
||||
version "27.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.4.1.tgz#185cbe2926eaaf9662d340cc02e548ce9e11ab6d"
|
||||
integrity sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw==
|
||||
dependencies:
|
||||
jest-diff "^27.0.0"
|
||||
jest-matcher-utils "^27.0.0"
|
||||
pretty-format "^27.0.0"
|
||||
|
||||
"@types/json-schema@^7.0.3":
|
||||
|
@ -1568,6 +1596,14 @@ buffer@6.0.1:
|
|||
base64-js "^1.3.1"
|
||||
ieee754 "^1.2.1"
|
||||
|
||||
buffer@~6.0.3:
|
||||
version "6.0.3"
|
||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
|
||||
integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
|
||||
dependencies:
|
||||
base64-js "^1.3.1"
|
||||
ieee754 "^1.2.1"
|
||||
|
||||
bufferutil@^4.0.1:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.3.tgz"
|
||||
|
@ -1836,7 +1872,7 @@ create-require@^1.1.0:
|
|||
resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz"
|
||||
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||
|
||||
cross-fetch@^3.1.5:
|
||||
cross-fetch@^3.1.4, cross-fetch@^3.1.5:
|
||||
version "3.1.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f"
|
||||
integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==
|
||||
|
@ -1852,7 +1888,7 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
|||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
crypto-hash@*, crypto-hash@^1.2.2, crypto-hash@^1.3.0:
|
||||
crypto-hash@*, crypto-hash@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.npmjs.org/crypto-hash/-/crypto-hash-1.3.0.tgz"
|
||||
integrity sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==
|
||||
|
@ -1964,6 +2000,11 @@ diff-sequences@^27.0.6:
|
|||
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.0.6.tgz#3305cb2e55a033924054695cc66019fd7f8e5723"
|
||||
integrity sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==
|
||||
|
||||
diff-sequences@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327"
|
||||
integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==
|
||||
|
||||
diff@^4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz"
|
||||
|
@ -2569,7 +2610,7 @@ has@^1.0.3:
|
|||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
|
||||
hash.js@^1.0.0, hash.js@^1.0.3:
|
||||
hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3:
|
||||
version "1.1.7"
|
||||
resolved "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz"
|
||||
integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==
|
||||
|
@ -2976,7 +3017,7 @@ jest-config@27.3.1, jest-config@^27.3.1:
|
|||
micromatch "^4.0.4"
|
||||
pretty-format "^27.3.1"
|
||||
|
||||
jest-diff@^27.0.0, jest-diff@^27.3.1:
|
||||
jest-diff@^27.3.1:
|
||||
version "27.3.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.3.1.tgz#d2775fea15411f5f5aeda2a5e02c2f36440f6d55"
|
||||
integrity sha512-PCeuAH4AWUo2O5+ksW4pL9v5xJAcIKPUPfIhZBcG1RKv/0+dvaWTQK1Nrau8d67dp65fOqbeMdoil+6PedyEPQ==
|
||||
|
@ -2986,6 +3027,16 @@ jest-diff@^27.0.0, jest-diff@^27.3.1:
|
|||
jest-get-type "^27.3.1"
|
||||
pretty-format "^27.3.1"
|
||||
|
||||
jest-diff@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def"
|
||||
integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==
|
||||
dependencies:
|
||||
chalk "^4.0.0"
|
||||
diff-sequences "^27.5.1"
|
||||
jest-get-type "^27.5.1"
|
||||
pretty-format "^27.5.1"
|
||||
|
||||
jest-docblock@^27.0.6:
|
||||
version "27.0.6"
|
||||
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.0.6.tgz#cc78266acf7fe693ca462cbbda0ea4e639e4e5f3"
|
||||
|
@ -3034,6 +3085,11 @@ jest-get-type@^27.3.1:
|
|||
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.3.1.tgz#a8a2b0a12b50169773099eee60a0e6dd11423eff"
|
||||
integrity sha512-+Ilqi8hgHSAdhlQ3s12CAVNd8H96ZkQBfYoXmArzZnOfAtVAJEiPDBirjByEblvG/4LPJmkL+nBqPO3A1YJAEg==
|
||||
|
||||
jest-get-type@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1"
|
||||
integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==
|
||||
|
||||
jest-haste-map@^27.3.1:
|
||||
version "27.3.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.3.1.tgz#7656fbd64bf48bda904e759fc9d93e2c807353ee"
|
||||
|
@ -3086,6 +3142,16 @@ jest-leak-detector@^27.3.1:
|
|||
jest-get-type "^27.3.1"
|
||||
pretty-format "^27.3.1"
|
||||
|
||||
jest-matcher-utils@^27.0.0:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab"
|
||||
integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==
|
||||
dependencies:
|
||||
chalk "^4.0.0"
|
||||
jest-diff "^27.5.1"
|
||||
jest-get-type "^27.5.1"
|
||||
pretty-format "^27.5.1"
|
||||
|
||||
jest-matcher-utils@^27.3.1:
|
||||
version "27.3.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.3.1.tgz#257ad61e54a6d4044e080d85dbdc4a08811e9c1c"
|
||||
|
@ -3746,7 +3812,7 @@ node-addon-api@^2.0.0:
|
|||
resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz"
|
||||
integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==
|
||||
|
||||
node-fetch@2.6.7, node-fetch@^2.6.1:
|
||||
node-fetch@2.6.7:
|
||||
version "2.6.7"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
|
||||
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
|
||||
|
@ -4006,6 +4072,15 @@ pretty-format@^27.0.0, pretty-format@^27.3.1:
|
|||
ansi-styles "^5.0.0"
|
||||
react-is "^17.0.1"
|
||||
|
||||
pretty-format@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e"
|
||||
integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
ansi-styles "^5.0.0"
|
||||
react-is "^17.0.1"
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz"
|
||||
|
|
Loading…
Reference in New Issue