lang: Add ProgramData account (#1095)
This commit is contained in:
parent
517838e494
commit
3321a3f9c9
|
@ -17,3 +17,5 @@ runs:
|
|||
shell: bash
|
||||
- run: solana-keygen new --no-bip39-passphrase
|
||||
shell: bash
|
||||
- run: solana config set --url localhost
|
||||
shell: bash
|
||||
|
|
|
@ -179,6 +179,48 @@ jobs:
|
|||
- uses: ./.github/actions/setup-solana/
|
||||
- run: cd client/example && ./run-test.sh
|
||||
|
||||
test-bpf-upgradeable-state:
|
||||
needs: setup-anchor-cli
|
||||
name: Test tests/bpf-upgradeable-state
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/setup/
|
||||
- uses: ./.github/actions/setup-ts/
|
||||
- uses: ./.github/actions/setup-solana/
|
||||
|
||||
- uses: actions/cache@v2
|
||||
name: Cache Cargo registry + index
|
||||
id: cache-anchor
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
./target/
|
||||
key: cargo-${{ runner.os }}-anchor-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: anchor-binary
|
||||
path: ~/.cargo/bin/
|
||||
|
||||
- uses: actions/cache@v2
|
||||
name: Cache tests/bpf-upgradeable-state target
|
||||
id: cache-test-target
|
||||
with:
|
||||
path: tests/bpf-upgradeable-state/target
|
||||
key: cargo-${{ runner.os }}-tests/bpf-upgradeable-state-${{ env.ANCHOR_VERSION }}
|
||||
|
||||
- run: solana-test-validator -r --quiet &
|
||||
name: start validator
|
||||
- run: cd tests/bpf-upgradeable-state && yarn
|
||||
- run: cd tests/bpf-upgradeable-state && yarn link @project-serum/anchor
|
||||
- run: cd tests/bpf-upgradeable-state && anchor build
|
||||
- run: cd tests/bpf-upgradeable-state && solana program deploy --program-id program_with_different_programdata.json target/deploy/bpf_upgradeable_state.so
|
||||
- run: cd tests/bpf-upgradeable-state && cp bpf_upgradeable_state-keypair.json target/deploy/bpf_upgradeable_state-keypair.json && anchor deploy && anchor test --skip-deploy --skip-build
|
||||
|
||||
test-programs:
|
||||
needs: setup-anchor-cli
|
||||
name: Test ${{ matrix.node.path }}
|
||||
|
|
|
@ -21,6 +21,7 @@ incremented for features.
|
|||
|
||||
* lang: Add `ErrorCode::AccountNotInitialized` error to separate the situation when the account has the wrong owner from when it does not exist (#[1024](https://github.com/project-serum/anchor/pull/1024))
|
||||
* lang: Called instructions now log their name by default. This can be turned off with the `no-log-ix-name` flag ([#1057](https://github.com/project-serum/anchor/pull/1057))
|
||||
* lang: `ProgramData` and `UpgradableLoaderState` can now be passed into `Account` as generics. see [UpgradeableLoaderState](https://docs.rs/solana-program/latest/solana_program/bpf_loader_upgradeable/enum.UpgradeableLoaderState.html). `UpgradableLoaderState` can also be matched on to get `ProgramData`, but when `ProgramData` is used instead, anchor does the serialization and checking that it is actually program data for you ([#1095](https://github.com/project-serum/anchor/pull/1095))
|
||||
* ts: Add better error msgs in the ts client if something wrong (i.e. not a pubkey or a string) is passed in as an account in an instruction accounts object ([#1098](https://github.com/project-serum/anchor/pull/1098))
|
||||
|
||||
## [0.18.2] - 2021-11-14
|
||||
|
|
|
@ -81,11 +81,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anchor-attribute-constant"
|
||||
version = "0.18.0"
|
||||
version = "0.18.2"
|
||||
dependencies = [
|
||||
"anchor-syn",
|
||||
"proc-macro2 1.0.29",
|
||||
"syn 1.0.75",
|
||||
"proc-macro2 1.0.32",
|
||||
"syn 1.0.81",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -213,6 +213,7 @@ dependencies = [
|
|||
"anchor-attribute-state",
|
||||
"anchor-derive-accounts",
|
||||
"base64 0.13.0",
|
||||
"bincode",
|
||||
"borsh",
|
||||
"bytemuck",
|
||||
"solana-program",
|
||||
|
|
|
@ -38,3 +38,4 @@ borsh = "0.9"
|
|||
bytemuck = "1.4.0"
|
||||
solana-program = "1.8.0"
|
||||
thiserror = "1.0.20"
|
||||
bincode = "1.3.3"
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
use crate::{AccountDeserialize, AccountSerialize, Owner};
|
||||
use solana_program::{
|
||||
bpf_loader_upgradeable::UpgradeableLoaderState, program_error::ProgramError, pubkey::Pubkey,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ProgramData {
|
||||
pub slot: u64,
|
||||
pub upgrade_authority_address: Option<Pubkey>,
|
||||
}
|
||||
|
||||
impl AccountDeserialize for ProgramData {
|
||||
fn try_deserialize(
|
||||
buf: &mut &[u8],
|
||||
) -> Result<Self, solana_program::program_error::ProgramError> {
|
||||
ProgramData::try_deserialize_unchecked(buf)
|
||||
}
|
||||
|
||||
fn try_deserialize_unchecked(
|
||||
buf: &mut &[u8],
|
||||
) -> Result<Self, solana_program::program_error::ProgramError> {
|
||||
let program_state = AccountDeserialize::try_deserialize_unchecked(buf)?;
|
||||
|
||||
match program_state {
|
||||
UpgradeableLoaderState::Uninitialized => {
|
||||
Err(anchor_lang::error::ErrorCode::AccountNotProgramData.into())
|
||||
}
|
||||
UpgradeableLoaderState::Buffer {
|
||||
authority_address: _,
|
||||
} => Err(anchor_lang::error::ErrorCode::AccountNotProgramData.into()),
|
||||
UpgradeableLoaderState::Program {
|
||||
programdata_address: _,
|
||||
} => Err(anchor_lang::error::ErrorCode::AccountNotProgramData.into()),
|
||||
UpgradeableLoaderState::ProgramData {
|
||||
slot,
|
||||
upgrade_authority_address,
|
||||
} => Ok(ProgramData {
|
||||
slot,
|
||||
upgrade_authority_address,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AccountSerialize for ProgramData {
|
||||
fn try_serialize<W: std::io::Write>(
|
||||
&self,
|
||||
_writer: &mut W,
|
||||
) -> Result<(), solana_program::program_error::ProgramError> {
|
||||
// no-op
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Owner for ProgramData {
|
||||
fn owner() -> solana_program::pubkey::Pubkey {
|
||||
anchor_lang::solana_program::bpf_loader_upgradeable::ID
|
||||
}
|
||||
}
|
||||
|
||||
impl Owner for UpgradeableLoaderState {
|
||||
fn owner() -> Pubkey {
|
||||
anchor_lang::solana_program::bpf_loader_upgradeable::ID
|
||||
}
|
||||
}
|
||||
|
||||
impl AccountSerialize for UpgradeableLoaderState {
|
||||
fn try_serialize<W: std::io::Write>(&self, _writer: &mut W) -> Result<(), ProgramError> {
|
||||
// no-op
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl AccountDeserialize for UpgradeableLoaderState {
|
||||
fn try_deserialize(buf: &mut &[u8]) -> Result<Self, ProgramError> {
|
||||
UpgradeableLoaderState::try_deserialize_unchecked(buf)
|
||||
}
|
||||
|
||||
fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result<Self, ProgramError> {
|
||||
bincode::deserialize(buf).map_err(|_| ProgramError::InvalidAccountData)
|
||||
}
|
||||
}
|
|
@ -76,6 +76,8 @@ pub enum ErrorCode {
|
|||
AccountNotSystemOwned,
|
||||
#[msg("The program expected this account to be already initialized")]
|
||||
AccountNotInitialized,
|
||||
#[msg("The given account is not a program data account")]
|
||||
AccountNotProgramData,
|
||||
|
||||
// State.
|
||||
#[msg("The given state account does not have the correct address")]
|
||||
|
|
|
@ -35,6 +35,7 @@ mod account;
|
|||
mod account_info;
|
||||
mod account_meta;
|
||||
mod boxed;
|
||||
mod bpf_upgradeable_state;
|
||||
mod common;
|
||||
mod context;
|
||||
mod cpi_account;
|
||||
|
@ -56,6 +57,7 @@ mod unchecked_account;
|
|||
mod vec;
|
||||
|
||||
pub use crate::account::Account;
|
||||
pub use crate::bpf_upgradeable_state::*;
|
||||
#[doc(hidden)]
|
||||
#[allow(deprecated)]
|
||||
pub use crate::context::CpiStateContext;
|
||||
|
@ -252,9 +254,10 @@ impl Key for Pubkey {
|
|||
pub mod prelude {
|
||||
pub use super::{
|
||||
access_control, account, constant, declare_id, emit, error, event, interface, program,
|
||||
require, state, zero_copy, Account, AccountDeserialize, AccountLoader, AccountSerialize,
|
||||
Accounts, AccountsExit, AnchorDeserialize, AnchorSerialize, Context, CpiContext, Id, Key,
|
||||
Owner, Program, Signer, System, SystemAccount, Sysvar, ToAccountInfo, ToAccountInfos,
|
||||
require, solana_program::bpf_loader_upgradeable::UpgradeableLoaderState, state, zero_copy,
|
||||
Account, AccountDeserialize, AccountLoader, AccountSerialize, Accounts, AccountsExit,
|
||||
AnchorDeserialize, AnchorSerialize, Context, CpiContext, Id, Key, Owner, Program,
|
||||
ProgramData, Signer, System, SystemAccount, Sysvar, ToAccountInfo, ToAccountInfos,
|
||||
ToAccountMetas, UncheckedAccount,
|
||||
};
|
||||
|
||||
|
|
|
@ -486,11 +486,9 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
|
|||
.methods
|
||||
.iter()
|
||||
.map(|ix| {
|
||||
if state.is_zero_copy {
|
||||
// Easy to implement. Just need to write a test.
|
||||
// Feel free to open a PR.
|
||||
panic!("Trait implementations not yet implemented for zero copy state structs. Please file an issue.");
|
||||
}
|
||||
// Easy to implement. Just need to write a test.
|
||||
// Feel free to open a PR.
|
||||
assert!(!state.is_zero_copy, "Trait implementations not yet implemented for zero copy state structs. Please file an issue.");
|
||||
|
||||
let ix_arg_names: Vec<&syn::Ident> =
|
||||
ix.args.iter().map(|arg| &arg.name).collect();
|
||||
|
|
|
@ -184,6 +184,9 @@ impl Field {
|
|||
Ty::Signer => quote! {
|
||||
Signer
|
||||
},
|
||||
Ty::ProgramData => quote! {
|
||||
ProgramData
|
||||
},
|
||||
Ty::SystemAccount => quote! {
|
||||
SystemAccount
|
||||
},
|
||||
|
@ -298,6 +301,7 @@ impl Field {
|
|||
Ty::UncheckedAccount => quote! {},
|
||||
Ty::Signer => quote! {},
|
||||
Ty::SystemAccount => quote! {},
|
||||
Ty::ProgramData => quote! {},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -316,6 +320,9 @@ impl Field {
|
|||
Ty::SystemAccount => quote! {
|
||||
SystemAccount
|
||||
},
|
||||
Ty::ProgramData => quote! {
|
||||
ProgramData
|
||||
},
|
||||
Ty::ProgramAccount(ty) => {
|
||||
let ident = &ty.account_type_path;
|
||||
quote! {
|
||||
|
@ -405,6 +412,7 @@ pub enum Ty {
|
|||
Program(ProgramTy),
|
||||
Signer,
|
||||
SystemAccount,
|
||||
ProgramData,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
|
|
@ -79,6 +79,7 @@ fn is_field_primitive(f: &syn::Field) -> ParseResult<bool> {
|
|||
| "Program"
|
||||
| "Signer"
|
||||
| "SystemAccount"
|
||||
| "ProgramData"
|
||||
);
|
||||
Ok(r)
|
||||
}
|
||||
|
@ -102,6 +103,7 @@ fn parse_ty(f: &syn::Field) -> ParseResult<Ty> {
|
|||
"Program" => Ty::Program(parse_program_ty(&path)?),
|
||||
"Signer" => Ty::Signer,
|
||||
"SystemAccount" => Ty::SystemAccount,
|
||||
"ProgramData" => Ty::ProgramData,
|
||||
_ => return Err(ParseError::new(f.ty.span(), "invalid account type given")),
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
yarn.lock
|
|
@ -0,0 +1,12 @@
|
|||
[programs.localnet]
|
||||
bpf_upgradeable_state = "Cum9tTyj5HwcEiAmhgaS7Bbj4UczCwsucrCkxRECzM4e"
|
||||
|
||||
[registry]
|
||||
url = "https://anchor.projectserum.com"
|
||||
|
||||
[provider]
|
||||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[scripts]
|
||||
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
|
|
@ -0,0 +1,4 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"programs/*"
|
||||
]
|
|
@ -0,0 +1 @@
|
|||
[114,99,192,17,48,208,90,184,231,46,220,91,47,115,132,253,218,163,228,101,8,121,220,138,41,140,176,127,254,91,51,28,176,244,174,182,223,57,57,125,117,201,31,213,9,39,207,212,100,173,88,252,61,235,89,156,53,86,4,90,16,251,191,219]
|
|
@ -0,0 +1,12 @@
|
|||
// Migrations are an early feature. Currently, they're nothing more than this
|
||||
// single deploy script that's invoked from the CLI, injecting a provider
|
||||
// configured from the workspace's Anchor.toml.
|
||||
|
||||
const anchor = require("@project-serum/anchor");
|
||||
|
||||
module.exports = async function (provider) {
|
||||
// Configure client to use the provider.
|
||||
anchor.setProvider(provider);
|
||||
|
||||
// Add your deploy script here.
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"@project-serum/anchor": "^0.18.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^4.3.4",
|
||||
"mocha": "^9.0.3",
|
||||
"ts-mocha": "^8.0.0",
|
||||
"@types/mocha": "^9.0.0",
|
||||
"typescript": "^4.3.5"
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
[86,234,116,86,82,140,116,250,254,32,75,217,35,39,9,238,39,98,242,254,25,216,201,66,1,239,93,12,81,19,34,108,219,67,158,98,245,234,81,126,228,157,205,206,130,5,14,54,1,21,88,246,128,124,240,93,157,49,102,19,253,19,205,178]
|
|
@ -0,0 +1,18 @@
|
|||
[package]
|
||||
name = "bpf-upgradeable-state"
|
||||
version = "0.1.0"
|
||||
description = "Created with Anchor"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "lib"]
|
||||
name = "bpf_upgradeable_state"
|
||||
|
||||
[features]
|
||||
no-entrypoint = []
|
||||
no-idl = []
|
||||
cpi = ["no-entrypoint"]
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
anchor-lang = { path = "../../../../lang" }
|
|
@ -0,0 +1,2 @@
|
|||
[target.bpfel-unknown-unknown.dependencies.std]
|
||||
features = []
|
|
@ -0,0 +1,53 @@
|
|||
use anchor_lang::prelude::*;
|
||||
|
||||
declare_id!("Cum9tTyj5HwcEiAmhgaS7Bbj4UczCwsucrCkxRECzM4e");
|
||||
|
||||
// TODO: Once anchor can deserialize data of programs (=programdata_address) automatically, add another test to this file.
|
||||
// Instead of using UpgradeableLoaderState, it should use Program<'info, MY_PROGRAM>
|
||||
|
||||
#[program]
|
||||
pub mod bpf_upgradeable_state {
|
||||
use super::*;
|
||||
pub fn set_admin_settings(ctx: Context<SetAdminSettings>, admin_data: u64) -> ProgramResult {
|
||||
match *ctx.accounts.program {
|
||||
UpgradeableLoaderState::Program {
|
||||
programdata_address,
|
||||
} => {
|
||||
if programdata_address != ctx.accounts.program_data.key() {
|
||||
return Err(CustomError::InvalidProgramDataAddress.into());
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(CustomError::AccountNotProgram.into());
|
||||
}
|
||||
};
|
||||
ctx.accounts.settings.admin_data = admin_data;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[account]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Settings {
|
||||
admin_data: u64,
|
||||
}
|
||||
|
||||
#[error]
|
||||
pub enum CustomError {
|
||||
InvalidProgramDataAddress,
|
||||
AccountNotProgram,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
#[instruction(admin_data: u64)]
|
||||
pub struct SetAdminSettings<'info> {
|
||||
#[account(init, payer = authority)]
|
||||
pub settings: Account<'info, Settings>,
|
||||
#[account(mut)]
|
||||
pub authority: Signer<'info>,
|
||||
#[account(address = crate::ID)]
|
||||
pub program: Account<'info, UpgradeableLoaderState>,
|
||||
#[account(constraint = program_data.upgrade_authority_address == Some(authority.key()))]
|
||||
pub program_data: Account<'info, ProgramData>,
|
||||
pub system_program: Program<'info, System>,
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
import * as anchor from '@project-serum/anchor';
|
||||
import { 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';
|
||||
import { BpfUpgradeableState } from '../target/types/bpf_upgradeable_state';
|
||||
|
||||
describe('bpf_upgradeable_state', () => {
|
||||
const provider = anchor.Provider.env();
|
||||
// Configure the client to use the local cluster.
|
||||
anchor.setProvider(provider);
|
||||
|
||||
const program = anchor.workspace.BpfUpgradeableState as Program<BpfUpgradeableState>;
|
||||
const programDataAddress = findProgramAddressSync(
|
||||
[program.programId.toBytes()],
|
||||
new anchor.web3.PublicKey("BPFLoaderUpgradeab1e11111111111111111111111")
|
||||
)[0];
|
||||
|
||||
it('Reads ProgramData and sets field', async () => {
|
||||
const settings = anchor.web3.Keypair.generate();
|
||||
const tx = await program.rpc.setAdminSettings(new anchor.BN(500), {
|
||||
accounts: {
|
||||
authority: program.provider.wallet.publicKey,
|
||||
systemProgram: anchor.web3.SystemProgram.programId,
|
||||
programData: programDataAddress,
|
||||
program: program.programId,
|
||||
settings: settings.publicKey
|
||||
},
|
||||
signers: [settings]
|
||||
});
|
||||
assert.equal((await program.account.settings.fetch(settings.publicKey)).adminData, 500);
|
||||
|
||||
console.log("Your transaction signature", tx);
|
||||
});
|
||||
|
||||
it('Validates constraint on ProgramData', async () => {
|
||||
const settings = anchor.web3.Keypair.generate();
|
||||
try {
|
||||
const authority = anchor.web3.Keypair.generate();
|
||||
await provider.connection.confirmTransaction(
|
||||
await provider.connection.requestAirdrop(authority.publicKey, 10000000000),
|
||||
"confirmed"
|
||||
);
|
||||
await program.rpc.setAdminSettings(new anchor.BN(500), {
|
||||
accounts: {
|
||||
authority: authority.publicKey,
|
||||
systemProgram: anchor.web3.SystemProgram.programId,
|
||||
programData: programDataAddress,
|
||||
settings: settings.publicKey,
|
||||
program: program.programId,
|
||||
},
|
||||
signers: [settings, authority]
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 143);
|
||||
assert.equal(err.msg, "A raw constraint was violated");
|
||||
}
|
||||
});
|
||||
|
||||
it('Validates that account is ProgramData', async () => {
|
||||
const settings = anchor.web3.Keypair.generate();
|
||||
try {
|
||||
await program.rpc.setAdminSettings(new anchor.BN(500), {
|
||||
accounts: {
|
||||
authority: program.provider.wallet.publicKey,
|
||||
systemProgram: anchor.web3.SystemProgram.programId,
|
||||
programData: program.programId,
|
||||
settings: settings.publicKey,
|
||||
program: program.programId,
|
||||
},
|
||||
signers: [settings]
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 173);
|
||||
assert.equal(err.msg, "The given account is not a program data account");
|
||||
}
|
||||
});
|
||||
|
||||
it('Validates that account is owned by the upgradeable bpf loader', async () => {
|
||||
const settings = anchor.web3.Keypair.generate();
|
||||
try {
|
||||
await program.rpc.setAdminSettings(new anchor.BN(500), {
|
||||
accounts: {
|
||||
authority: program.provider.wallet.publicKey,
|
||||
systemProgram: anchor.web3.SystemProgram.programId,
|
||||
programData: program.provider.wallet.publicKey,
|
||||
settings: settings.publicKey,
|
||||
program: program.programId,
|
||||
},
|
||||
signers: [settings]
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 167);
|
||||
assert.equal(err.msg, "The given account is not owned by the executing program");
|
||||
}
|
||||
});
|
||||
|
||||
it('Deserializes UpgradableLoaderState and validates that programData is the expected account', async () => {
|
||||
const secondProgramAddress = new PublicKey("Fkv67TwmbakfZw2PoW57wYPbqNexAH6vuxpyT8vmrc3B");
|
||||
const secondProgramProgramDataAddress = findProgramAddressSync(
|
||||
[secondProgramAddress.toBytes()],
|
||||
new anchor.web3.PublicKey("BPFLoaderUpgradeab1e11111111111111111111111")
|
||||
)[0];
|
||||
|
||||
const settings = anchor.web3.Keypair.generate();
|
||||
try {
|
||||
await program.rpc.setAdminSettings(new anchor.BN(500), {
|
||||
accounts: {
|
||||
authority: program.provider.wallet.publicKey,
|
||||
systemProgram: anchor.web3.SystemProgram.programId,
|
||||
programData: secondProgramProgramDataAddress,
|
||||
settings: settings.publicKey,
|
||||
program: program.programId,
|
||||
},
|
||||
signers: [settings]
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
assert.equal(err.code, 300);
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"types": ["mocha", "chai"],
|
||||
"typeRoots": ["./node_modules/@types"],
|
||||
"lib": ["es2015"],
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
|
@ -50,10 +50,10 @@
|
|||
snake-case "^3.0.4"
|
||||
toml "^3.0.0"
|
||||
|
||||
"@project-serum/anchor@^0.18.0":
|
||||
version "0.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.18.0.tgz#867144282e59482230f797f73ee9f5634f846061"
|
||||
integrity sha512-WTm+UB93MoxyCbjnHIibv/uUEoO/5gL4GEtE/aMioLF8Z4i0vCMPnvAN0xpk9VBu3t7ld2DcCE/L+6Z7dwU++w==
|
||||
"@project-serum/anchor@^0.18.2":
|
||||
version "0.18.2"
|
||||
resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.18.2.tgz#0f13b5c2046446b7c24cf28763eec90febb28485"
|
||||
integrity sha512-uyjiN/3Ipp+4hrZRm/hG18HzGLZyvP790LXrCsGO3IWxSl28YRhiGEpKnZycfMW94R7nxdUoE3wY67V+ZHSQBQ==
|
||||
dependencies:
|
||||
"@project-serum/borsh" "^0.2.2"
|
||||
"@solana/web3.js" "^1.17.0"
|
||||
|
|
|
@ -90,6 +90,7 @@ const LangErrorCode = {
|
|||
AccountNotSigner: 170,
|
||||
AccountNotSystemOwned: 171,
|
||||
AccountNotInitialized: 172,
|
||||
AccountNotProgramData: 173,
|
||||
|
||||
// State.
|
||||
StateInvalidAddress: 180,
|
||||
|
@ -180,6 +181,10 @@ const LangErrorMessage = new Map([
|
|||
LangErrorCode.AccountNotInitialized,
|
||||
"The program expected this account to be already initialized",
|
||||
],
|
||||
[
|
||||
LangErrorCode.AccountNotProgramData,
|
||||
"The given account is not a program data account",
|
||||
],
|
||||
|
||||
// State.
|
||||
[
|
||||
|
|
Loading…
Reference in New Issue