Static owner and program ID checks (#686)
This commit is contained in:
parent
675c7cd81d
commit
3958533750
|
@ -13,8 +13,14 @@ incremented for features.
|
|||
|
||||
### Features
|
||||
|
||||
* lang: Add new `Account` type to replace `ProgramAccount` and `CpiAccount`, both of which are deprecated ([#686](https://github.com/project-serum/anchor/pull/686)).
|
||||
* lang: Add `Owner` trait, which is automatically implemented by all `#[account]` structs ([#686](https://github.com/project-serum/anchor/pull/686)).
|
||||
* lang: Check that ProgramAccount writable before mut borrow (`anchor-debug` only) ([#681](https://github.com/project-serum/anchor/pull/681)).
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* lang: All programs must now define their program id in source via `declare_id!` ([#686](https://github.com/project-serum/anchor/pull/686)).
|
||||
|
||||
## [0.14.0] - 2021-09-02
|
||||
|
||||
### Features
|
||||
|
|
|
@ -72,8 +72,10 @@ version = "0.14.0"
|
|||
dependencies = [
|
||||
"anchor-syn",
|
||||
"anyhow",
|
||||
"bs58 0.4.0",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"rustversion",
|
||||
"syn 1.0.75",
|
||||
]
|
||||
|
||||
|
@ -222,7 +224,7 @@ name = "anchor-syn"
|
|||
version = "0.14.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bs58",
|
||||
"bs58 0.3.1",
|
||||
"heck",
|
||||
"proc-macro2 1.0.29",
|
||||
"proc-macro2-diagnostics",
|
||||
|
@ -477,6 +479,12 @@ version = "0.3.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb"
|
||||
|
||||
[[package]]
|
||||
name = "bs58"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.7.0"
|
||||
|
@ -2725,7 +2733,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"arrayref",
|
||||
"bincode",
|
||||
"bs58",
|
||||
"bs58 0.3.1",
|
||||
"rand 0.7.3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -2861,7 +2869,7 @@ dependencies = [
|
|||
"Inflector",
|
||||
"base64 0.12.3",
|
||||
"bincode",
|
||||
"bs58",
|
||||
"bs58 0.3.1",
|
||||
"bv",
|
||||
"lazy_static",
|
||||
"serde",
|
||||
|
@ -2914,7 +2922,7 @@ checksum = "779f90ee9f77c831426af58c9732902051314bb8f2607473ffd6089a3b008133"
|
|||
dependencies = [
|
||||
"base64 0.13.0",
|
||||
"bincode",
|
||||
"bs58",
|
||||
"bs58 0.3.1",
|
||||
"clap 2.33.3",
|
||||
"indicatif",
|
||||
"jsonrpc-core",
|
||||
|
@ -3008,7 +3016,7 @@ version = "1.7.11"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21ddfc2b65a555c0e0156c043bce092d473bc4f00daa7ca3c223d97d92d2e807"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"bs58 0.3.1",
|
||||
"bv",
|
||||
"generic-array 0.14.4",
|
||||
"log",
|
||||
|
@ -3102,7 +3110,7 @@ dependencies = [
|
|||
"blake3",
|
||||
"borsh",
|
||||
"borsh-derive 0.9.1",
|
||||
"bs58",
|
||||
"bs58 0.3.1",
|
||||
"bv",
|
||||
"curve25519-dalek 2.1.3",
|
||||
"hex",
|
||||
|
@ -3217,7 +3225,7 @@ checksum = "95179bc7d87c5b61c86f3bbbac4e52a5d909432473593d33546e4f20dc582052"
|
|||
dependencies = [
|
||||
"assert_matches",
|
||||
"bincode",
|
||||
"bs58",
|
||||
"bs58 0.3.1",
|
||||
"bv",
|
||||
"byteorder",
|
||||
"chrono",
|
||||
|
@ -3264,7 +3272,7 @@ version = "1.7.11"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b453dca160617b1676c47e3cfd4361f455dc5bb1c93659ec84b0c5d566b5c039"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"bs58 0.3.1",
|
||||
"proc-macro2 1.0.29",
|
||||
"quote 1.0.9",
|
||||
"rustversion",
|
||||
|
@ -3311,7 +3319,7 @@ dependencies = [
|
|||
"Inflector",
|
||||
"base64 0.12.3",
|
||||
"bincode",
|
||||
"bs58",
|
||||
"bs58 0.3.1",
|
||||
"lazy_static",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
|
|
|
@ -4,7 +4,7 @@ use anyhow::{anyhow, Error, Result};
|
|||
use clap::Clap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::signature::Keypair;
|
||||
use solana_sdk::signature::{Keypair, Signer};
|
||||
use std::collections::BTreeMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::fs::{self, File};
|
||||
|
@ -471,13 +471,29 @@ pub struct Program {
|
|||
}
|
||||
|
||||
impl Program {
|
||||
pub fn anchor_keypair_path(&self) -> PathBuf {
|
||||
std::env::current_dir()
|
||||
pub fn pubkey(&self) -> Result<Pubkey> {
|
||||
self.keypair().map(|kp| kp.pubkey())
|
||||
}
|
||||
|
||||
pub fn keypair(&self) -> Result<Keypair> {
|
||||
let file = self.keypair_file()?;
|
||||
solana_sdk::signature::read_keypair_file(file.path())
|
||||
.map_err(|_| anyhow!("failed to read keypair for program: {}", self.lib_name))
|
||||
}
|
||||
|
||||
// Lazily initializes the keypair file with a new key if it doesn't exist.
|
||||
pub fn keypair_file(&self) -> Result<WithPath<File>> {
|
||||
fs::create_dir_all("target/deploy/")?;
|
||||
let path = std::env::current_dir()
|
||||
.expect("Must have current dir")
|
||||
.join(format!(
|
||||
"target/deploy/anchor-{}-keypair.json",
|
||||
self.lib_name
|
||||
))
|
||||
.join(format!("target/deploy/{}-keypair.json", self.lib_name));
|
||||
if path.exists() {
|
||||
return Ok(WithPath::new(File::open(&path)?, path));
|
||||
}
|
||||
let program_kp = Keypair::generate(&mut rand::rngs::OsRng);
|
||||
let mut file = File::create(&path)?;
|
||||
file.write_all(format!("{:?}", &program_kp.to_bytes()).as_bytes())?;
|
||||
Ok(WithPath::new(file, path))
|
||||
}
|
||||
|
||||
pub fn binary_path(&self) -> PathBuf {
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
use crate::config::{
|
||||
AnchorPackage, Config, ConfigOverride, Manifest, Program, ProgramWorkspace, WithPath,
|
||||
};
|
||||
use crate::config::{AnchorPackage, Config, ConfigOverride, Manifest, ProgramWorkspace, WithPath};
|
||||
use anchor_client::Cluster;
|
||||
use anchor_lang::idl::{IdlAccount, IdlInstruction};
|
||||
use anchor_lang::{AccountDeserialize, AnchorDeserialize, AnchorSerialize};
|
||||
|
@ -154,6 +152,16 @@ pub enum Command {
|
|||
/// The name of the program to publish.
|
||||
program: String,
|
||||
},
|
||||
/// Keypair commands.
|
||||
Keys {
|
||||
#[clap(subcommand)]
|
||||
subcmd: KeysCommand,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clap)]
|
||||
pub enum KeysCommand {
|
||||
List,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clap)]
|
||||
|
@ -283,6 +291,7 @@ pub fn entry(opts: Opts) -> Result<()> {
|
|||
Command::Run { script } => run(&opts.cfg_override, script),
|
||||
Command::Login { token } => login(&opts.cfg_override, token),
|
||||
Command::Publish { program } => publish(&opts.cfg_override, program),
|
||||
Command::Keys { subcmd } => keys(&opts.cfg_override, subcmd),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1374,13 +1383,12 @@ fn genesis_flags(cfg: &WithPath<Config>) -> Result<Vec<String>> {
|
|||
for mut program in cfg.read_all_programs()? {
|
||||
let binary_path = program.binary_path().display().to_string();
|
||||
|
||||
// Use the [programs.cluster] override and fallback to the keypair
|
||||
// files if no override is given.
|
||||
let address = programs
|
||||
.and_then(|m| m.get(&program.lib_name))
|
||||
.map(|deployment| deployment.address.to_string())
|
||||
.unwrap_or_else(|| {
|
||||
let kp = Keypair::generate(&mut OsRng);
|
||||
kp.pubkey().to_string()
|
||||
});
|
||||
.map(|deployment| Ok(deployment.address.to_string()))
|
||||
.unwrap_or_else(|| program.pubkey().map(|p| p.to_string()))?;
|
||||
|
||||
flags.push("--bpf-program".to_string());
|
||||
flags.push(address.clone());
|
||||
|
@ -1507,14 +1515,7 @@ fn start_test_validator(cfg: &Config, flags: Option<Vec<String>>) -> Result<Chil
|
|||
Ok(validator_handle)
|
||||
}
|
||||
|
||||
fn deploy(cfg_override: &ConfigOverride, program_name: Option<String>) -> Result<()> {
|
||||
_deploy(cfg_override, program_name).map(|_| ())
|
||||
}
|
||||
|
||||
fn _deploy(
|
||||
cfg_override: &ConfigOverride,
|
||||
program_str: Option<String>,
|
||||
) -> Result<Vec<(Pubkey, Program)>> {
|
||||
fn deploy(cfg_override: &ConfigOverride, program_str: Option<String>) -> Result<()> {
|
||||
with_workspace(cfg_override, |cfg| {
|
||||
let url = cfg.provider.cluster.url().to_string();
|
||||
let keypair = cfg.provider.wallet.to_string();
|
||||
|
@ -1523,8 +1524,6 @@ fn _deploy(
|
|||
println!("Deploying workspace: {}", url);
|
||||
println!("Upgrade authority: {}", keypair);
|
||||
|
||||
let mut programs = Vec::new();
|
||||
|
||||
for mut program in cfg.read_all_programs()? {
|
||||
if let Some(single_prog_str) = &program_str {
|
||||
let program_name = program.path.file_name().unwrap().to_str().unwrap();
|
||||
|
@ -1540,11 +1539,7 @@ fn _deploy(
|
|||
);
|
||||
println!("Program path: {}...", binary_path);
|
||||
|
||||
// Write the program's keypair filepath. This forces a new deploy
|
||||
// address.
|
||||
let program_kp = Keypair::generate(&mut OsRng);
|
||||
let mut file = File::create(program.anchor_keypair_path())?;
|
||||
file.write_all(format!("{:?}", &program_kp.to_bytes()).as_bytes())?;
|
||||
let file = program.keypair_file()?;
|
||||
|
||||
// Send deploy transactions.
|
||||
let exit = std::process::Command::new("solana")
|
||||
|
@ -1555,7 +1550,7 @@ fn _deploy(
|
|||
.arg("--keypair")
|
||||
.arg(&keypair)
|
||||
.arg("--program-id")
|
||||
.arg(program.anchor_keypair_path().display().to_string())
|
||||
.arg(file.path().display().to_string())
|
||||
.arg(&binary_path)
|
||||
.stdout(Stdio::inherit())
|
||||
.stderr(Stdio::inherit())
|
||||
|
@ -1566,10 +1561,11 @@ fn _deploy(
|
|||
std::process::exit(exit.status.code().unwrap_or(1));
|
||||
}
|
||||
|
||||
let program_pubkey = program.pubkey()?;
|
||||
if let Some(mut idl) = program.idl.as_mut() {
|
||||
// Add program address to the IDL.
|
||||
idl.metadata = Some(serde_json::to_value(IdlTestMetadata {
|
||||
address: program_kp.pubkey().to_string(),
|
||||
address: program_pubkey.to_string(),
|
||||
})?);
|
||||
|
||||
// Persist it.
|
||||
|
@ -1578,13 +1574,11 @@ fn _deploy(
|
|||
.with_extension("json");
|
||||
write_idl(idl, OutFile::File(idl_out))?;
|
||||
}
|
||||
|
||||
programs.push((program_kp.pubkey(), program))
|
||||
}
|
||||
|
||||
println!("Deploy success");
|
||||
|
||||
Ok(programs)
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1619,20 +1613,6 @@ fn upgrade(
|
|||
})
|
||||
}
|
||||
|
||||
// The Solana CLI doesn't redeploy a program if this file exists.
|
||||
// So remove it to make all commands explicit.
|
||||
fn clear_program_keys(cfg_override: &ConfigOverride) -> Result<()> {
|
||||
let config = Config::discover(cfg_override).unwrap_or_default().unwrap();
|
||||
|
||||
for program in config.read_all_programs()? {
|
||||
let anchor_keypair_path = program.anchor_keypair_path();
|
||||
if Path::exists(&anchor_keypair_path) {
|
||||
std::fs::remove_file(anchor_keypair_path).expect("Always remove");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_idl_account(
|
||||
cfg: &Config,
|
||||
keypair_path: &str,
|
||||
|
@ -1902,6 +1882,7 @@ fn shell(cfg_override: &ConfigOverride) -> Result<()> {
|
|||
})
|
||||
.collect::<Vec<_>>();
|
||||
}
|
||||
|
||||
// Finalize program list with all programs with IDLs.
|
||||
match cfg.programs.get(&cfg.provider.cluster) {
|
||||
None => Vec::new(),
|
||||
|
@ -2130,6 +2111,21 @@ fn registry_api_token(_cfg_override: &ConfigOverride) -> Result<String> {
|
|||
Ok(credentials_toml.registry.token)
|
||||
}
|
||||
|
||||
fn keys(cfg_override: &ConfigOverride, cmd: KeysCommand) -> Result<()> {
|
||||
match cmd {
|
||||
KeysCommand::List => keys_list(cfg_override),
|
||||
}
|
||||
}
|
||||
|
||||
fn keys_list(cfg_override: &ConfigOverride) -> Result<()> {
|
||||
let cfg = Config::discover(cfg_override)?.expect("Not in workspace.");
|
||||
for program in cfg.read_all_programs()? {
|
||||
let pubkey = program.pubkey()?;
|
||||
println!("{}: {}", program.lib_name, pubkey.to_string());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// with_workspace ensures the current working directory is always the top level
|
||||
// workspace directory, i.e., where the `Anchor.toml` file is located, before
|
||||
// and after the closure invocation.
|
||||
|
@ -2139,8 +2135,6 @@ fn registry_api_token(_cfg_override: &ConfigOverride) -> Result<String> {
|
|||
fn with_workspace<R>(cfg_override: &ConfigOverride, f: impl FnOnce(&WithPath<Config>) -> R) -> R {
|
||||
set_workspace_dir_or_exit();
|
||||
|
||||
clear_program_keys(cfg_override).unwrap();
|
||||
|
||||
let cfg = Config::discover(cfg_override)
|
||||
.expect("Previously set the workspace dir")
|
||||
.expect("Anchor.toml must always exist");
|
||||
|
@ -2148,7 +2142,6 @@ fn with_workspace<R>(cfg_override: &ConfigOverride, f: impl FnOnce(&WithPath<Con
|
|||
let r = f(&cfg);
|
||||
|
||||
set_workspace_dir_or_exit();
|
||||
clear_program_keys(cfg_override).unwrap();
|
||||
|
||||
r
|
||||
}
|
||||
|
|
|
@ -20,35 +20,36 @@ set -euox pipefail
|
|||
|
||||
main() {
|
||||
#
|
||||
# Bootup validator.
|
||||
#
|
||||
solana-test-validator > test-validator.log &
|
||||
sleep 5
|
||||
|
||||
#
|
||||
# Deploy programs.
|
||||
# Build programs.
|
||||
#
|
||||
pushd ../../tests/composite/
|
||||
anchor build
|
||||
anchor deploy
|
||||
local composite_pid=$(cat target/idl/composite.json | jq -r .metadata.address)
|
||||
local composite_pid="EHthziFziNoac9LBGxEaVN47Y3uUiRoXvqAiR6oes4iU"
|
||||
popd
|
||||
pushd ../../examples/tutorial/basic-2/
|
||||
anchor build
|
||||
anchor deploy
|
||||
local basic_2_pid=$(cat target/idl/basic_2.json | jq -r .metadata.address)
|
||||
local basic_2_pid="Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
popd
|
||||
pushd ../../examples/tutorial/basic-4/
|
||||
anchor build
|
||||
anchor deploy
|
||||
local basic_4_pid=$(cat target/idl/basic_4.json | jq -r .metadata.address)
|
||||
local basic_4_pid="CwrqeMj2U8tFr1Rhkgwc84tpAsqbt9pTt2a4taoTADPr"
|
||||
popd
|
||||
pushd ../../tests/events
|
||||
anchor build
|
||||
anchor deploy
|
||||
local events_pid=$(cat target/idl/events.json | jq -r .metadata.address)
|
||||
local events_pid="2dhGsWUzy5YKUsjZdLHLmkNpUDAXkNa9MYWsPc4Ziqzy"
|
||||
popd
|
||||
|
||||
#
|
||||
# Bootup validator.
|
||||
#
|
||||
solana-test-validator \
|
||||
--bpf-program $composite_pid ../../tests/composite/target/deploy/composite.so \
|
||||
--bpf-program $basic_2_pid ../../examples/tutorial/basic-2/target/deploy/basic_2.so \
|
||||
--bpf-program $basic_4_pid ../../examples/tutorial/basic-4/target/deploy/basic_4.so \
|
||||
--bpf-program $events_pid ../../tests/events/target/deploy/events.so \
|
||||
> test-validator.log &
|
||||
sleep 5
|
||||
|
||||
#
|
||||
# Run Test.
|
||||
#
|
||||
|
|
|
@ -2,5 +2,8 @@
|
|||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
basic_1 = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
|
||||
[scripts]
|
||||
test = "mocha -t 1000000 tests/"
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use anchor_lang::prelude::*;
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
#[program]
|
||||
mod basic_1 {
|
||||
use super::*;
|
||||
|
@ -20,7 +22,7 @@ mod basic_1 {
|
|||
#[derive(Accounts)]
|
||||
pub struct Initialize<'info> {
|
||||
#[account(init, payer = user, space = 8 + 8)]
|
||||
pub my_account: ProgramAccount<'info, MyAccount>,
|
||||
pub my_account: Account<'info, MyAccount>,
|
||||
pub user: AccountInfo<'info>,
|
||||
pub system_program: AccountInfo<'info>,
|
||||
}
|
||||
|
@ -28,7 +30,7 @@ pub struct Initialize<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct Update<'info> {
|
||||
#[account(mut)]
|
||||
pub my_account: ProgramAccount<'info, MyAccount>,
|
||||
pub my_account: Account<'info, MyAccount>,
|
||||
}
|
||||
|
||||
#[account]
|
||||
|
|
|
@ -2,5 +2,8 @@
|
|||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
basic_2 = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
|
||||
[scripts]
|
||||
test = "mocha -t 1000000 tests/"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use anchor_lang::prelude::*;
|
||||
use anchor_lang::solana_program::system_program;
|
||||
|
||||
// Define the program's instruction handlers.
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
#[program]
|
||||
mod basic_2 {
|
||||
|
@ -21,12 +21,10 @@ mod basic_2 {
|
|||
}
|
||||
}
|
||||
|
||||
// Define the validated accounts for each handler.
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Create<'info> {
|
||||
#[account(init, payer = user, space = 8 + 40)]
|
||||
pub counter: ProgramAccount<'info, Counter>,
|
||||
pub counter: Account<'info, Counter>,
|
||||
#[account(signer)]
|
||||
pub user: AccountInfo<'info>,
|
||||
#[account(address = system_program::ID)]
|
||||
|
@ -36,13 +34,11 @@ pub struct Create<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct Increment<'info> {
|
||||
#[account(mut, has_one = authority)]
|
||||
pub counter: ProgramAccount<'info, Counter>,
|
||||
pub counter: Account<'info, Counter>,
|
||||
#[account(signer)]
|
||||
pub authority: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
// Define the program owned accounts.
|
||||
|
||||
#[account]
|
||||
pub struct Counter {
|
||||
pub authority: Pubkey,
|
||||
|
|
|
@ -2,5 +2,9 @@
|
|||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
puppet = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
puppet_master = "HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L"
|
||||
|
||||
[scripts]
|
||||
test = "mocha -t 1000000 tests/"
|
||||
|
|
|
@ -2,13 +2,15 @@
|
|||
use anchor_lang::prelude::*;
|
||||
use puppet::{Puppet, SetData};
|
||||
|
||||
declare_id!("HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L");
|
||||
|
||||
#[program]
|
||||
mod puppet_master {
|
||||
use super::*;
|
||||
pub fn pull_strings(ctx: Context<PullStrings>, data: u64) -> ProgramResult {
|
||||
let cpi_program = ctx.accounts.puppet_program.clone();
|
||||
let cpi_accounts = SetData {
|
||||
puppet: ctx.accounts.puppet.clone().into(),
|
||||
puppet: ctx.accounts.puppet.clone(),
|
||||
};
|
||||
let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);
|
||||
puppet::cpi::set_data(cpi_ctx, data)
|
||||
|
@ -18,7 +20,7 @@ mod puppet_master {
|
|||
#[derive(Accounts)]
|
||||
pub struct PullStrings<'info> {
|
||||
#[account(mut, owner = puppet_program)]
|
||||
pub puppet: CpiAccount<'info, Puppet>,
|
||||
pub puppet: Account<'info, Puppet>,
|
||||
pub puppet_program: AccountInfo<'info>,
|
||||
}
|
||||
// #endregion core
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use anchor_lang::prelude::*;
|
||||
use anchor_lang::solana_program::system_program;
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
#[program]
|
||||
pub mod puppet {
|
||||
use super::*;
|
||||
|
@ -18,7 +20,7 @@ pub mod puppet {
|
|||
#[derive(Accounts)]
|
||||
pub struct Initialize<'info> {
|
||||
#[account(init, payer = user, space = 8 + 8)]
|
||||
pub puppet: ProgramAccount<'info, Puppet>,
|
||||
pub puppet: Account<'info, Puppet>,
|
||||
#[account(signer)]
|
||||
pub user: AccountInfo<'info>,
|
||||
#[account(address = system_program::ID)]
|
||||
|
@ -28,7 +30,7 @@ pub struct Initialize<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct SetData<'info> {
|
||||
#[account(mut)]
|
||||
pub puppet: ProgramAccount<'info, Puppet>,
|
||||
pub puppet: Account<'info, Puppet>,
|
||||
}
|
||||
|
||||
#[account]
|
||||
|
|
|
@ -2,5 +2,8 @@
|
|||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
basic_4 = "CwrqeMj2U8tFr1Rhkgwc84tpAsqbt9pTt2a4taoTADPr"
|
||||
|
||||
[scripts]
|
||||
test = "mocha -t 1000000 tests/"
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// #region code
|
||||
use anchor_lang::prelude::*;
|
||||
|
||||
declare_id!("CwrqeMj2U8tFr1Rhkgwc84tpAsqbt9pTt2a4taoTADPr");
|
||||
|
||||
#[program]
|
||||
pub mod basic_4 {
|
||||
use super::*;
|
||||
|
|
|
@ -19,3 +19,5 @@ quote = "1.0"
|
|||
syn = { version = "1.0.60", features = ["full"] }
|
||||
anyhow = "1.0.32"
|
||||
anchor-syn = { path = "../../syn", version = "0.14.0", features = ["hash"] }
|
||||
rustversion = "1.0.3"
|
||||
bs58 = "0.4.0"
|
|
@ -0,0 +1,296 @@
|
|||
//! Copied from solana/sdk/macro so that Anchor programs don't need to specify
|
||||
//! `solana_program` as an additional crate dependency, but instead can access
|
||||
//! it via `anchor_lang::declare_id`.
|
||||
//!
|
||||
//! Convenience macro to declare a static public key and functions to interact with it
|
||||
//!
|
||||
//! Input: a single literal base58 string representation of a program's id
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro2::{Delimiter, Span, TokenTree};
|
||||
use quote::{quote, ToTokens};
|
||||
use std::convert::TryFrom;
|
||||
use syn::{
|
||||
bracketed,
|
||||
parse::{Parse, ParseStream, Result},
|
||||
punctuated::Punctuated,
|
||||
token::Bracket,
|
||||
Expr, Ident, LitByte, LitStr, Path, Token,
|
||||
};
|
||||
|
||||
fn parse_id(
|
||||
input: ParseStream,
|
||||
pubkey_type: proc_macro2::TokenStream,
|
||||
) -> Result<proc_macro2::TokenStream> {
|
||||
let id = if input.peek(syn::LitStr) {
|
||||
let id_literal: LitStr = input.parse()?;
|
||||
parse_pubkey(&id_literal, &pubkey_type)?
|
||||
} else {
|
||||
let expr: Expr = input.parse()?;
|
||||
quote! { #expr }
|
||||
};
|
||||
|
||||
if !input.is_empty() {
|
||||
let stream: proc_macro2::TokenStream = input.parse()?;
|
||||
return Err(syn::Error::new_spanned(stream, "unexpected token"));
|
||||
}
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
fn id_to_tokens(
|
||||
id: &proc_macro2::TokenStream,
|
||||
pubkey_type: proc_macro2::TokenStream,
|
||||
tokens: &mut proc_macro2::TokenStream,
|
||||
) {
|
||||
tokens.extend(quote! {
|
||||
/// The static program ID
|
||||
pub static ID: #pubkey_type = #id;
|
||||
|
||||
/// Confirms that a given pubkey is equivalent to the program ID
|
||||
pub fn check_id(id: &#pubkey_type) -> bool {
|
||||
id == &ID
|
||||
}
|
||||
|
||||
/// Returns the program ID
|
||||
pub fn id() -> #pubkey_type {
|
||||
ID
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn test_id() {
|
||||
assert!(check_id(&id()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn deprecated_id_to_tokens(
|
||||
id: &proc_macro2::TokenStream,
|
||||
pubkey_type: proc_macro2::TokenStream,
|
||||
tokens: &mut proc_macro2::TokenStream,
|
||||
) {
|
||||
tokens.extend(quote! {
|
||||
/// The static program ID
|
||||
pub static ID: #pubkey_type = #id;
|
||||
|
||||
/// Confirms that a given pubkey is equivalent to the program ID
|
||||
#[deprecated()]
|
||||
pub fn check_id(id: &#pubkey_type) -> bool {
|
||||
id == &ID
|
||||
}
|
||||
|
||||
/// Returns the program ID
|
||||
#[deprecated()]
|
||||
pub fn id() -> #pubkey_type {
|
||||
ID
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn test_id() {
|
||||
#[allow(deprecated)]
|
||||
assert!(check_id(&id()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub struct Id(proc_macro2::TokenStream);
|
||||
|
||||
impl Parse for Id {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
parse_id(
|
||||
input,
|
||||
quote! { anchor_lang::solana_program::pubkey::Pubkey },
|
||||
)
|
||||
.map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Id {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
id_to_tokens(
|
||||
&self.0,
|
||||
quote! { anchor_lang::solana_program::pubkey::Pubkey },
|
||||
tokens,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct IdDeprecated(proc_macro2::TokenStream);
|
||||
|
||||
impl Parse for IdDeprecated {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
parse_id(
|
||||
input,
|
||||
quote! { anchor_lang::solana_program::pubkey::Pubkey },
|
||||
)
|
||||
.map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for IdDeprecated {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
deprecated_id_to_tokens(
|
||||
&self.0,
|
||||
quote! { anchor_lang::solana_program::pubkey::Pubkey },
|
||||
tokens,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct ProgramSdkId(proc_macro2::TokenStream);
|
||||
impl Parse for ProgramSdkId {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
parse_id(
|
||||
input,
|
||||
quote! { anchor_lang::solana_program::pubkey::Pubkey },
|
||||
)
|
||||
.map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for ProgramSdkId {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
id_to_tokens(
|
||||
&self.0,
|
||||
quote! { anchor_lang::solana_program::pubkey::Pubkey },
|
||||
tokens,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct ProgramSdkIdDeprecated(proc_macro2::TokenStream);
|
||||
impl Parse for ProgramSdkIdDeprecated {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
parse_id(
|
||||
input,
|
||||
quote! { anchor_lang::solana_program::pubkey::Pubkey },
|
||||
)
|
||||
.map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for ProgramSdkIdDeprecated {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
deprecated_id_to_tokens(
|
||||
&self.0,
|
||||
quote! { anchor_lang::solana_program::pubkey::Pubkey },
|
||||
tokens,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // `respan` may be compiled out
|
||||
struct RespanInput {
|
||||
to_respan: Path,
|
||||
respan_using: Span,
|
||||
}
|
||||
|
||||
impl Parse for RespanInput {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let to_respan: Path = input.parse()?;
|
||||
let _comma: Token![,] = input.parse()?;
|
||||
let respan_tree: TokenTree = input.parse()?;
|
||||
match respan_tree {
|
||||
TokenTree::Group(g) if g.delimiter() == Delimiter::None => {
|
||||
let ident: Ident = syn::parse2(g.stream())?;
|
||||
Ok(RespanInput {
|
||||
to_respan,
|
||||
respan_using: ident.span(),
|
||||
})
|
||||
}
|
||||
val => Err(syn::Error::new_spanned(
|
||||
val,
|
||||
"expected None-delimited group",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_pubkey(
|
||||
id_literal: &LitStr,
|
||||
pubkey_type: &proc_macro2::TokenStream,
|
||||
) -> Result<proc_macro2::TokenStream> {
|
||||
let id_vec = bs58::decode(id_literal.value())
|
||||
.into_vec()
|
||||
.map_err(|_| syn::Error::new_spanned(&id_literal, "failed to decode base58 string"))?;
|
||||
let id_array = <[u8; 32]>::try_from(<&[u8]>::clone(&&id_vec[..])).map_err(|_| {
|
||||
syn::Error::new_spanned(
|
||||
&id_literal,
|
||||
format!("pubkey array is not 32 bytes long: len={}", id_vec.len()),
|
||||
)
|
||||
})?;
|
||||
let bytes = id_array.iter().map(|b| LitByte::new(*b, Span::call_site()));
|
||||
Ok(quote! {
|
||||
#pubkey_type::new_from_array(
|
||||
[#(#bytes,)*]
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
struct Pubkeys {
|
||||
method: Ident,
|
||||
num: usize,
|
||||
pubkeys: proc_macro2::TokenStream,
|
||||
}
|
||||
impl Parse for Pubkeys {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let pubkey_type = quote! {
|
||||
anchor_lang::solana_program::pubkey::Pubkey
|
||||
};
|
||||
|
||||
let method = input.parse()?;
|
||||
let _comma: Token![,] = input.parse()?;
|
||||
let (num, pubkeys) = if input.peek(syn::LitStr) {
|
||||
let id_literal: LitStr = input.parse()?;
|
||||
(1, parse_pubkey(&id_literal, &pubkey_type)?)
|
||||
} else if input.peek(Bracket) {
|
||||
let pubkey_strings;
|
||||
bracketed!(pubkey_strings in input);
|
||||
let punctuated: Punctuated<LitStr, Token![,]> =
|
||||
Punctuated::parse_terminated(&pubkey_strings)?;
|
||||
let mut pubkeys: Punctuated<proc_macro2::TokenStream, Token![,]> = Punctuated::new();
|
||||
for string in punctuated.iter() {
|
||||
pubkeys.push(parse_pubkey(string, &pubkey_type)?);
|
||||
}
|
||||
(pubkeys.len(), quote! {#pubkeys})
|
||||
} else {
|
||||
let stream: proc_macro2::TokenStream = input.parse()?;
|
||||
return Err(syn::Error::new_spanned(stream, "unexpected token"));
|
||||
};
|
||||
|
||||
Ok(Pubkeys {
|
||||
method,
|
||||
num,
|
||||
pubkeys,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Pubkeys {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
let Pubkeys {
|
||||
method,
|
||||
num,
|
||||
pubkeys,
|
||||
} = self;
|
||||
|
||||
let pubkey_type = quote! {
|
||||
anchor_lang::solana_program::pubkey::Pubkey
|
||||
};
|
||||
if *num == 1 {
|
||||
tokens.extend(quote! {
|
||||
pub fn #method() -> #pubkey_type {
|
||||
#pubkeys
|
||||
}
|
||||
});
|
||||
} else {
|
||||
tokens.extend(quote! {
|
||||
pub fn #method() -> ::std::vec::Vec<#pubkey_type> {
|
||||
vec![#pubkeys]
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@ extern crate proc_macro;
|
|||
use quote::quote;
|
||||
use syn::parse_macro_input;
|
||||
|
||||
mod id;
|
||||
|
||||
/// A data structure representing a Solana account, implementing various traits:
|
||||
///
|
||||
/// - [`AccountSerialize`](./trait.AccountSerialize.html)
|
||||
|
@ -98,6 +100,21 @@ pub fn account(
|
|||
format!("{:?}", discriminator).parse().unwrap()
|
||||
};
|
||||
|
||||
let owner_impl = {
|
||||
if namespace.is_empty() {
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl #impl_gen anchor_lang::Owner for #account_name #type_gen #where_clause {
|
||||
fn owner() -> Pubkey {
|
||||
crate::ID
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
}
|
||||
};
|
||||
|
||||
proc_macro::TokenStream::from({
|
||||
if is_zero_copy {
|
||||
quote! {
|
||||
|
@ -142,6 +159,8 @@ pub fn account(
|
|||
Ok(*account)
|
||||
}
|
||||
}
|
||||
|
||||
#owner_impl
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
|
@ -187,6 +206,8 @@ pub fn account(
|
|||
#discriminator
|
||||
}
|
||||
}
|
||||
|
||||
#owner_impl
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -270,3 +291,11 @@ pub fn zero_copy(
|
|||
#account_strct
|
||||
})
|
||||
}
|
||||
|
||||
/// Defines the program's ID. This should be used at the root of all Anchor
|
||||
/// based programs.
|
||||
#[proc_macro]
|
||||
pub fn declare_id(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let id = parse_macro_input!(input as id::Id);
|
||||
proc_macro::TokenStream::from(quote! {#id})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
use crate::error::ErrorCode;
|
||||
use crate::*;
|
||||
use solana_program::account_info::AccountInfo;
|
||||
use solana_program::entrypoint::ProgramResult;
|
||||
use solana_program::instruction::AccountMeta;
|
||||
use solana_program::program_error::ProgramError;
|
||||
use solana_program::pubkey::Pubkey;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
/// Account container that checks ownership on deserialization.
|
||||
#[derive(Clone)]
|
||||
pub struct Account<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> {
|
||||
account: T,
|
||||
info: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
impl<'a, T: AccountSerialize + AccountDeserialize + Owner + Clone> Account<'a, T> {
|
||||
fn new(info: AccountInfo<'a>, account: T) -> Account<'a, T> {
|
||||
Self { info, account }
|
||||
}
|
||||
|
||||
/// Deserializes the given `info` into a `Account`.
|
||||
#[inline(never)]
|
||||
pub fn try_from(info: &AccountInfo<'a>) -> Result<Account<'a, T>, ProgramError> {
|
||||
if info.owner != &T::owner() {
|
||||
return Err(ErrorCode::AccountNotProgramOwned.into());
|
||||
}
|
||||
let mut data: &[u8] = &info.try_borrow_data()?;
|
||||
Ok(Account::new(info.clone(), T::try_deserialize(&mut data)?))
|
||||
}
|
||||
|
||||
/// Deserializes the given `info` into a `Account` without checking
|
||||
/// the account discriminator. Be careful when using this and avoid it if
|
||||
/// possible.
|
||||
#[inline(never)]
|
||||
pub fn try_from_unchecked(info: &AccountInfo<'a>) -> Result<Account<'a, T>, ProgramError> {
|
||||
if info.owner != &T::owner() {
|
||||
return Err(ErrorCode::AccountNotProgramOwned.into());
|
||||
}
|
||||
let mut data: &[u8] = &info.try_borrow_data()?;
|
||||
Ok(Account::new(
|
||||
info.clone(),
|
||||
T::try_deserialize_unchecked(&mut data)?,
|
||||
))
|
||||
}
|
||||
|
||||
/// Reloads the account from storage. This is useful, for example, when
|
||||
/// observing side effects after CPI.
|
||||
pub fn reload(&mut self) -> ProgramResult {
|
||||
let mut data: &[u8] = &self.info.try_borrow_data()?;
|
||||
self.account = T::try_deserialize(&mut data)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> T {
|
||||
self.account
|
||||
}
|
||||
}
|
||||
|
||||
impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> Accounts<'info>
|
||||
for Account<'info, T>
|
||||
where
|
||||
T: AccountSerialize + AccountDeserialize + Owner + Clone,
|
||||
{
|
||||
#[inline(never)]
|
||||
fn try_accounts(
|
||||
_program_id: &Pubkey,
|
||||
accounts: &mut &[AccountInfo<'info>],
|
||||
_ix_data: &[u8],
|
||||
) -> Result<Self, ProgramError> {
|
||||
if accounts.is_empty() {
|
||||
return Err(ErrorCode::AccountNotEnoughKeys.into());
|
||||
}
|
||||
let account = &accounts[0];
|
||||
*accounts = &accounts[1..];
|
||||
Account::try_from(account)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> AccountsExit<'info>
|
||||
for Account<'info, T>
|
||||
{
|
||||
fn exit(&self, program_id: &Pubkey) -> ProgramResult {
|
||||
// Only persist if the owner is the current program.
|
||||
if &T::owner() == program_id {
|
||||
let info = self.to_account_info();
|
||||
let mut data = info.try_borrow_mut_data()?;
|
||||
let dst: &mut [u8] = &mut data;
|
||||
let mut cursor = std::io::Cursor::new(dst);
|
||||
self.account.try_serialize(&mut cursor)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> AccountsClose<'info>
|
||||
for Account<'info, T>
|
||||
{
|
||||
fn close(&self, sol_destination: AccountInfo<'info>) -> ProgramResult {
|
||||
crate::common::close(self.to_account_info(), sol_destination)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> ToAccountMetas
|
||||
for Account<'info, T>
|
||||
{
|
||||
fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
|
||||
let is_signer = is_signer.unwrap_or(self.info.is_signer);
|
||||
let meta = match self.info.is_writable {
|
||||
false => AccountMeta::new_readonly(*self.info.key, is_signer),
|
||||
true => AccountMeta::new(*self.info.key, is_signer),
|
||||
};
|
||||
vec![meta]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> ToAccountInfos<'info>
|
||||
for Account<'info, T>
|
||||
{
|
||||
fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
|
||||
vec![self.info.clone()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> ToAccountInfo<'info>
|
||||
for Account<'info, T>
|
||||
{
|
||||
fn to_account_info(&self) -> AccountInfo<'info> {
|
||||
self.info.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> AsRef<AccountInfo<'info>>
|
||||
for Account<'info, T>
|
||||
{
|
||||
fn as_ref(&self) -> &AccountInfo<'info> {
|
||||
&self.info
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: AccountSerialize + AccountDeserialize + Owner + Clone> Deref for Account<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&(*self).account
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: AccountSerialize + AccountDeserialize + Owner + Clone> DerefMut for Account<'a, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
#[cfg(feature = "anchor-debug")]
|
||||
if !self.info.is_writable {
|
||||
solana_program::msg!("The given Account is not mutable");
|
||||
panic!();
|
||||
}
|
||||
&mut self.account
|
||||
}
|
||||
}
|
||||
|
||||
impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> Key for Account<'info, T> {
|
||||
fn key(&self) -> Pubkey {
|
||||
*self.info.key
|
||||
}
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
use crate::error::ErrorCode;
|
||||
use crate::{
|
||||
AccountDeserialize, Accounts, AccountsExit, Key, ToAccountInfo, ToAccountInfos, ToAccountMetas,
|
||||
};
|
||||
use crate::*;
|
||||
use solana_program::account_info::AccountInfo;
|
||||
use solana_program::entrypoint::ProgramResult;
|
||||
use solana_program::instruction::AccountMeta;
|
||||
|
@ -119,3 +117,12 @@ impl<'info, T: AccountDeserialize + Clone> Key for CpiAccount<'info, T> {
|
|||
*self.info.key
|
||||
}
|
||||
}
|
||||
|
||||
impl<'info, T> From<Account<'info, T>> for CpiAccount<'info, T>
|
||||
where
|
||||
T: AccountSerialize + AccountDeserialize + Owner + Clone,
|
||||
{
|
||||
fn from(a: Account<'info, T>) -> Self {
|
||||
Self::new(a.to_account_info(), Box::new(a.into_inner()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ use solana_program::program_error::ProgramError;
|
|||
use solana_program::pubkey::Pubkey;
|
||||
use std::io::Write;
|
||||
|
||||
mod account;
|
||||
mod account_info;
|
||||
mod account_meta;
|
||||
mod boxed;
|
||||
|
@ -48,6 +49,7 @@ pub mod state;
|
|||
mod sysvar;
|
||||
mod vec;
|
||||
|
||||
pub use crate::account::Account;
|
||||
pub use crate::context::{Context, CpiContext, CpiStateContext};
|
||||
pub use crate::cpi_account::CpiAccount;
|
||||
pub use crate::cpi_state::CpiState;
|
||||
|
@ -56,7 +58,7 @@ pub use crate::program_account::ProgramAccount;
|
|||
pub use crate::state::ProgramState;
|
||||
pub use crate::sysvar::Sysvar;
|
||||
pub use anchor_attribute_access_control::access_control;
|
||||
pub use anchor_attribute_account::{account, zero_copy};
|
||||
pub use anchor_attribute_account::{account, declare_id, zero_copy};
|
||||
pub use anchor_attribute_error::error;
|
||||
pub use anchor_attribute_event::{emit, event};
|
||||
pub use anchor_attribute_interface::interface;
|
||||
|
@ -199,6 +201,12 @@ pub trait Bump {
|
|||
fn seed(&self) -> u8;
|
||||
}
|
||||
|
||||
/// Defines an address expected to own an account.
|
||||
pub trait Owner {
|
||||
fn owner() -> Pubkey;
|
||||
}
|
||||
|
||||
/// Defines the Pubkey of an account.
|
||||
pub trait Key {
|
||||
fn key(&self) -> Pubkey;
|
||||
}
|
||||
|
@ -213,15 +221,15 @@ impl Key for Pubkey {
|
|||
/// All programs should include it via `anchor_lang::prelude::*;`.
|
||||
pub mod prelude {
|
||||
pub use super::{
|
||||
access_control, account, emit, error, event, interface, program, require, state, zero_copy,
|
||||
AccountDeserialize, AccountSerialize, Accounts, AccountsExit, AnchorDeserialize,
|
||||
AnchorSerialize, Context, CpiAccount, CpiContext, CpiState, CpiStateContext, Key, Loader,
|
||||
ProgramAccount, ProgramState, Sysvar, ToAccountInfo, ToAccountInfos, ToAccountMetas,
|
||||
access_control, account, declare_id, emit, error, event, interface, program, require,
|
||||
state, zero_copy, Account, AccountDeserialize, AccountSerialize, Accounts, AccountsExit,
|
||||
AnchorDeserialize, AnchorSerialize, Context, CpiAccount, CpiContext, CpiState,
|
||||
CpiStateContext, Key, Loader, ProgramAccount, ProgramState, Sysvar, ToAccountInfo,
|
||||
ToAccountInfos, ToAccountMetas,
|
||||
};
|
||||
|
||||
pub use borsh;
|
||||
pub use solana_program::account_info::{next_account_info, AccountInfo};
|
||||
pub use solana_program::declare_id;
|
||||
pub use solana_program::entrypoint::ProgramResult;
|
||||
pub use solana_program::instruction::AccountMeta;
|
||||
pub use solana_program::msg;
|
||||
|
|
|
@ -142,9 +142,10 @@ pub fn generate_constraint_init(f: &Field, c: &ConstraintInitGroup) -> proc_macr
|
|||
|
||||
pub fn generate_constraint_zeroed(f: &Field, _c: &ConstraintZeroed) -> proc_macro2::TokenStream {
|
||||
let field = &f.ident;
|
||||
let (account_ty, account_wrapper_ty, _) = parse_ty(f);
|
||||
let ty_decl = f.ty_decl();
|
||||
let from_account_info = f.from_account_info(None);
|
||||
quote! {
|
||||
let #field: #account_wrapper_ty<#account_ty> = {
|
||||
let #field: #ty_decl = {
|
||||
let mut __data: &[u8] = &#field.try_borrow_data()?;
|
||||
let mut __disc_bytes = [0u8; 8];
|
||||
__disc_bytes.copy_from_slice(&__data[..8]);
|
||||
|
@ -152,10 +153,7 @@ pub fn generate_constraint_zeroed(f: &Field, _c: &ConstraintZeroed) -> proc_macr
|
|||
if __discriminator != 0 {
|
||||
return Err(anchor_lang::__private::ErrorCode::ConstraintZero.into());
|
||||
}
|
||||
#account_wrapper_ty::try_from_unchecked(
|
||||
program_id,
|
||||
&#field,
|
||||
)?
|
||||
#from_account_info
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -198,6 +196,7 @@ pub fn generate_constraint_signer(f: &Field, _c: &ConstraintSigner) -> proc_macr
|
|||
let info = match f.ty {
|
||||
Ty::AccountInfo => quote! { #ident },
|
||||
Ty::ProgramAccount(_) => quote! { #ident.to_account_info() },
|
||||
Ty::Account(_) => quote! { #ident.to_account_info() },
|
||||
Ty::Loader(_) => quote! { #ident.to_account_info() },
|
||||
Ty::CpiAccount(_) => quote! { #ident.to_account_info() },
|
||||
_ => panic!("Invalid syntax: signer cannot be specified."),
|
||||
|
@ -308,7 +307,7 @@ fn generate_constraint_init_group(f: &Field, c: &ConstraintInitGroup) -> proc_ma
|
|||
}
|
||||
}
|
||||
};
|
||||
generate_pda(f, seeds_with_nonce, payer, &c.space, &c.kind)
|
||||
generate_init(f, seeds_with_nonce, payer, &c.space, &c.kind)
|
||||
}
|
||||
|
||||
fn generate_constraint_seeds(f: &Field, c: &ConstraintSeedsGroup) -> proc_macro2::TokenStream {
|
||||
|
@ -366,56 +365,7 @@ fn generate_constraint_seeds(f: &Field, c: &ConstraintSeedsGroup) -> proc_macro2
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_ty(f: &Field) -> (proc_macro2::TokenStream, proc_macro2::TokenStream, bool) {
|
||||
match &f.ty {
|
||||
Ty::ProgramAccount(ty) => {
|
||||
let ident = &ty.account_type_path;
|
||||
(
|
||||
quote! {
|
||||
#ident
|
||||
},
|
||||
quote! {
|
||||
anchor_lang::ProgramAccount
|
||||
},
|
||||
false,
|
||||
)
|
||||
}
|
||||
Ty::Loader(ty) => {
|
||||
let ident = &ty.account_type_path;
|
||||
(
|
||||
quote! {
|
||||
#ident
|
||||
},
|
||||
quote! {
|
||||
anchor_lang::Loader
|
||||
},
|
||||
true,
|
||||
)
|
||||
}
|
||||
Ty::CpiAccount(ty) => {
|
||||
let ident = &ty.account_type_path;
|
||||
(
|
||||
quote! {
|
||||
#ident
|
||||
},
|
||||
quote! {
|
||||
anchor_lang::CpiAccount
|
||||
},
|
||||
false,
|
||||
)
|
||||
}
|
||||
Ty::AccountInfo => (
|
||||
quote! {
|
||||
AccountInfo
|
||||
},
|
||||
quote! {},
|
||||
false,
|
||||
),
|
||||
_ => panic!("Invalid type for initializing a program derived address"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_pda(
|
||||
pub fn generate_init(
|
||||
f: &Field,
|
||||
seeds_with_nonce: proc_macro2::TokenStream,
|
||||
payer: proc_macro2::TokenStream,
|
||||
|
@ -423,30 +373,8 @@ pub fn generate_pda(
|
|||
kind: &InitKind,
|
||||
) -> proc_macro2::TokenStream {
|
||||
let field = &f.ident;
|
||||
let (account_ty, account_wrapper_ty, is_zero_copy) = parse_ty(f);
|
||||
|
||||
let (combined_account_ty, try_from) = match f.ty {
|
||||
Ty::AccountInfo => (
|
||||
quote! {
|
||||
AccountInfo
|
||||
},
|
||||
quote! {
|
||||
#field.to_account_info()
|
||||
},
|
||||
),
|
||||
_ => (
|
||||
quote! {
|
||||
#account_wrapper_ty<#account_ty>
|
||||
},
|
||||
quote! {
|
||||
#account_wrapper_ty::try_from_unchecked(
|
||||
program_id,
|
||||
&#field.to_account_info(),
|
||||
)?
|
||||
},
|
||||
),
|
||||
};
|
||||
|
||||
let ty_decl = f.ty_decl();
|
||||
let from_account_info = f.from_account_info(Some(kind));
|
||||
match kind {
|
||||
InitKind::Token { owner, mint } => {
|
||||
let create_account = generate_create_account(
|
||||
|
@ -456,7 +384,7 @@ pub fn generate_pda(
|
|||
seeds_with_nonce,
|
||||
);
|
||||
quote! {
|
||||
let #field: #combined_account_ty = {
|
||||
let #field: #ty_decl = {
|
||||
// Define payer variable.
|
||||
#payer
|
||||
|
||||
|
@ -473,9 +401,8 @@ pub fn generate_pda(
|
|||
};
|
||||
let cpi_ctx = CpiContext::new(cpi_program, accounts);
|
||||
anchor_spl::token::initialize_account(cpi_ctx)?;
|
||||
anchor_lang::CpiAccount::try_from_unchecked(
|
||||
&#field.to_account_info(),
|
||||
)?
|
||||
let mut pa: #ty_decl = #from_account_info;
|
||||
pa
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -487,7 +414,7 @@ pub fn generate_pda(
|
|||
seeds_with_nonce,
|
||||
);
|
||||
quote! {
|
||||
let #field: #combined_account_ty = {
|
||||
let #field: #ty_decl = {
|
||||
// Define payer variable.
|
||||
#payer
|
||||
|
||||
|
@ -502,9 +429,8 @@ pub fn generate_pda(
|
|||
};
|
||||
let cpi_ctx = CpiContext::new(cpi_program, accounts);
|
||||
anchor_spl::token::initialize_mint(cpi_ctx, #decimals, &#owner.to_account_info().key, None)?;
|
||||
anchor_lang::CpiAccount::try_from_unchecked(
|
||||
&#field.to_account_info(),
|
||||
)?
|
||||
let mut pa: #ty_decl = #from_account_info;
|
||||
pa
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -512,7 +438,9 @@ pub fn generate_pda(
|
|||
let space = match space {
|
||||
// If no explicit space param was given, serialize the type to bytes
|
||||
// and take the length (with +8 for the discriminator.)
|
||||
None => match is_zero_copy {
|
||||
None => {
|
||||
let account_ty = f.account_ty();
|
||||
match matches!(f.ty, Ty::Loader(_)) {
|
||||
false => {
|
||||
quote! {
|
||||
let space = 8 + #account_ty::default().try_to_vec().unwrap().len();
|
||||
|
@ -523,7 +451,8 @@ pub fn generate_pda(
|
|||
let space = 8 + anchor_lang::__private::bytemuck::bytes_of(&#account_ty::default()).len();
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
// Explicit account size given. Use it.
|
||||
Some(s) => quote! {
|
||||
let space = #s;
|
||||
|
@ -547,7 +476,7 @@ pub fn generate_pda(
|
|||
#space
|
||||
#payer
|
||||
#create_account
|
||||
let mut pa: #combined_account_ty = #try_from;
|
||||
let mut pa: #ty_decl = #from_account_info;
|
||||
pa
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::codegen::accounts::{constraints, generics, ParsedGenerics};
|
||||
use crate::{AccountField, AccountsStruct, Field, SysvarTy, Ty};
|
||||
use proc_macro2::TokenStream;
|
||||
use crate::{AccountField, AccountsStruct};
|
||||
use quote::quote;
|
||||
use syn::Expr;
|
||||
|
||||
|
@ -40,7 +39,7 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
|
|||
*accounts = &accounts[1..];
|
||||
}
|
||||
} else {
|
||||
let name = typed_ident(f);
|
||||
let name = f.typed_ident();
|
||||
quote! {
|
||||
#[cfg(feature = "anchor-debug")]
|
||||
::solana_program::log::sol_log(stringify!(#name));
|
||||
|
@ -107,65 +106,6 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
fn typed_ident(field: &Field) -> TokenStream {
|
||||
let name = &field.ident;
|
||||
|
||||
let ty = match &field.ty {
|
||||
Ty::AccountInfo => quote! { AccountInfo },
|
||||
Ty::ProgramState(ty) => {
|
||||
let account = &ty.account_type_path;
|
||||
quote! {
|
||||
ProgramState<#account>
|
||||
}
|
||||
}
|
||||
Ty::CpiState(ty) => {
|
||||
let account = &ty.account_type_path;
|
||||
quote! {
|
||||
CpiState<#account>
|
||||
}
|
||||
}
|
||||
Ty::ProgramAccount(ty) => {
|
||||
let account = &ty.account_type_path;
|
||||
quote! {
|
||||
ProgramAccount<#account>
|
||||
}
|
||||
}
|
||||
Ty::Loader(ty) => {
|
||||
let account = &ty.account_type_path;
|
||||
quote! {
|
||||
Loader<#account>
|
||||
}
|
||||
}
|
||||
Ty::CpiAccount(ty) => {
|
||||
let account = &ty.account_type_path;
|
||||
quote! {
|
||||
CpiAccount<#account>
|
||||
}
|
||||
}
|
||||
Ty::Sysvar(ty) => {
|
||||
let account = match ty {
|
||||
SysvarTy::Clock => quote! {Clock},
|
||||
SysvarTy::Rent => quote! {Rent},
|
||||
SysvarTy::EpochSchedule => quote! {EpochSchedule},
|
||||
SysvarTy::Fees => quote! {Fees},
|
||||
SysvarTy::RecentBlockhashes => quote! {RecentBlockhashes},
|
||||
SysvarTy::SlotHashes => quote! {SlotHashes},
|
||||
SysvarTy::SlotHistory => quote! {SlotHistory},
|
||||
SysvarTy::StakeHistory => quote! {StakeHistory},
|
||||
SysvarTy::Instructions => quote! {Instructions},
|
||||
SysvarTy::Rewards => quote! {Rewards},
|
||||
};
|
||||
quote! {
|
||||
Sysvar<#account>
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
quote! {
|
||||
#name: #ty
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_constraints(accs: &AccountsStruct) -> proc_macro2::TokenStream {
|
||||
let non_init_fields: Vec<&AccountField> =
|
||||
accs.fields.iter().filter(|af| !is_init(af)).collect();
|
||||
|
|
|
@ -36,7 +36,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
|
|||
let data = anchor_lang::InstructionData::data(&ix);
|
||||
let accounts = ctx.to_account_metas(None);
|
||||
anchor_lang::solana_program::instruction::Instruction {
|
||||
program_id: *ctx.program().key,
|
||||
program_id: crate::ID,
|
||||
accounts,
|
||||
data,
|
||||
}
|
||||
|
@ -82,13 +82,12 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
|
|||
data.append(&mut ix_data);
|
||||
let accounts = ctx.to_account_metas(None);
|
||||
anchor_lang::solana_program::instruction::Instruction {
|
||||
program_id: *ctx.program.key,
|
||||
program_id: crate::ID,
|
||||
accounts,
|
||||
data,
|
||||
}
|
||||
};
|
||||
let mut acc_infos = ctx.to_account_infos();
|
||||
acc_infos.push(ctx.program.clone());
|
||||
anchor_lang::solana_program::program::invoke_signed(
|
||||
&ix,
|
||||
&acc_infos,
|
||||
|
|
|
@ -3,6 +3,7 @@ use codegen::program as program_codegen;
|
|||
use parser::accounts as accounts_parser;
|
||||
use parser::program as program_parser;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use quote::ToTokens;
|
||||
use std::ops::Deref;
|
||||
use syn::ext::IdentExt;
|
||||
|
@ -161,6 +162,177 @@ pub struct Field {
|
|||
pub ty: Ty,
|
||||
}
|
||||
|
||||
impl Field {
|
||||
pub fn typed_ident(&self) -> proc_macro2::TokenStream {
|
||||
let name = &self.ident;
|
||||
let ty_decl = self.ty_decl();
|
||||
quote! {
|
||||
#name: #ty_decl
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ty_decl(&self) -> proc_macro2::TokenStream {
|
||||
let account_ty = self.account_ty();
|
||||
let container_ty = self.container_ty();
|
||||
match &self.ty {
|
||||
Ty::AccountInfo => quote! {
|
||||
AccountInfo
|
||||
},
|
||||
Ty::Account(AccountTy { boxed, .. }) => {
|
||||
if *boxed {
|
||||
quote! {
|
||||
Box<#container_ty<#account_ty>>
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#container_ty<#account_ty>
|
||||
}
|
||||
}
|
||||
}
|
||||
Ty::Sysvar(ty) => {
|
||||
let account = match ty {
|
||||
SysvarTy::Clock => quote! {Clock},
|
||||
SysvarTy::Rent => quote! {Rent},
|
||||
SysvarTy::EpochSchedule => quote! {EpochSchedule},
|
||||
SysvarTy::Fees => quote! {Fees},
|
||||
SysvarTy::RecentBlockhashes => quote! {RecentBlockhashes},
|
||||
SysvarTy::SlotHashes => quote! {SlotHashes},
|
||||
SysvarTy::SlotHistory => quote! {SlotHistory},
|
||||
SysvarTy::StakeHistory => quote! {StakeHistory},
|
||||
SysvarTy::Instructions => quote! {Instructions},
|
||||
SysvarTy::Rewards => quote! {Rewards},
|
||||
};
|
||||
quote! {
|
||||
Sysvar<#account>
|
||||
}
|
||||
}
|
||||
_ => quote! {
|
||||
#container_ty<#account_ty>
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove the option once `CpiAccount` is completely removed (not
|
||||
// just deprecated).
|
||||
pub fn from_account_info(&self, kind: Option<&InitKind>) -> proc_macro2::TokenStream {
|
||||
let field = &self.ident;
|
||||
let container_ty = self.container_ty();
|
||||
match &self.ty {
|
||||
Ty::AccountInfo => quote! { #field.to_account_info() },
|
||||
Ty::Account(AccountTy { boxed, .. }) => {
|
||||
if *boxed {
|
||||
quote! {
|
||||
Box::new(#container_ty::try_from_unchecked(
|
||||
&#field,
|
||||
)?)
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#container_ty::try_from_unchecked(
|
||||
&#field,
|
||||
)?
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let owner_addr = match &kind {
|
||||
None => quote! { program_id },
|
||||
Some(InitKind::Program { .. }) => quote! {
|
||||
program_id
|
||||
},
|
||||
_ => quote! {
|
||||
&anchor_spl::token::ID
|
||||
},
|
||||
};
|
||||
quote! {
|
||||
#container_ty::try_from_unchecked(
|
||||
#owner_addr,
|
||||
&#field,
|
||||
)?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn container_ty(&self) -> proc_macro2::TokenStream {
|
||||
match &self.ty {
|
||||
Ty::ProgramAccount(_) => quote! {
|
||||
anchor_lang::ProgramAccount
|
||||
},
|
||||
Ty::Account(_) => quote! {
|
||||
anchor_lang::Account
|
||||
},
|
||||
Ty::Loader(_) => quote! {
|
||||
anchor_lang::Loader
|
||||
},
|
||||
Ty::CpiAccount(_) => quote! {
|
||||
anchor_lang::CpiAccount
|
||||
},
|
||||
Ty::Sysvar(_) => quote! { anchor_lang::Sysvar },
|
||||
Ty::CpiState(_) => quote! { anchor_lang::CpiState },
|
||||
Ty::ProgramState(_) => quote! { anchor_lang::ProgramState },
|
||||
Ty::AccountInfo => quote! {},
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the inner account struct type.
|
||||
pub fn account_ty(&self) -> proc_macro2::TokenStream {
|
||||
match &self.ty {
|
||||
Ty::AccountInfo => quote! {
|
||||
AccountInfo
|
||||
},
|
||||
Ty::ProgramAccount(ty) => {
|
||||
let ident = &ty.account_type_path;
|
||||
quote! {
|
||||
#ident
|
||||
}
|
||||
}
|
||||
Ty::Account(ty) => {
|
||||
let ident = &ty.account_type_path;
|
||||
quote! {
|
||||
#ident
|
||||
}
|
||||
}
|
||||
Ty::Loader(ty) => {
|
||||
let ident = &ty.account_type_path;
|
||||
quote! {
|
||||
#ident
|
||||
}
|
||||
}
|
||||
Ty::CpiAccount(ty) => {
|
||||
let ident = &ty.account_type_path;
|
||||
quote! {
|
||||
#ident
|
||||
}
|
||||
}
|
||||
Ty::ProgramState(ty) => {
|
||||
let account = &ty.account_type_path;
|
||||
quote! {
|
||||
#account
|
||||
}
|
||||
}
|
||||
Ty::CpiState(ty) => {
|
||||
let account = &ty.account_type_path;
|
||||
quote! {
|
||||
#account
|
||||
}
|
||||
}
|
||||
Ty::Sysvar(ty) => match ty {
|
||||
SysvarTy::Clock => quote! {Clock},
|
||||
SysvarTy::Rent => quote! {Rent},
|
||||
SysvarTy::EpochSchedule => quote! {EpochSchedule},
|
||||
SysvarTy::Fees => quote! {Fees},
|
||||
SysvarTy::RecentBlockhashes => quote! {RecentBlockhashes},
|
||||
SysvarTy::SlotHashes => quote! {SlotHashes},
|
||||
SysvarTy::SlotHistory => quote! {SlotHistory},
|
||||
SysvarTy::StakeHistory => quote! {StakeHistory},
|
||||
SysvarTy::Instructions => quote! {Instructions},
|
||||
SysvarTy::Rewards => quote! {Rewards},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CompositeField {
|
||||
pub ident: Ident,
|
||||
|
@ -180,6 +352,7 @@ pub enum Ty {
|
|||
Loader(LoaderTy),
|
||||
CpiAccount(CpiAccountTy),
|
||||
Sysvar(SysvarTy),
|
||||
Account(AccountTy),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
@ -224,6 +397,14 @@ pub struct LoaderTy {
|
|||
pub account_type_path: TypePath,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct AccountTy {
|
||||
// The struct type of the account.
|
||||
pub account_type_path: TypePath,
|
||||
// True if the account has been boxed via `Box<T>`.
|
||||
pub boxed: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
pub name: String,
|
||||
|
|
|
@ -561,11 +561,12 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
|||
|
||||
fn add_close(&mut self, c: Context<ConstraintClose>) -> ParseResult<()> {
|
||||
if !matches!(self.f_ty, Some(Ty::ProgramAccount(_)))
|
||||
&& !matches!(self.f_ty, Some(Ty::Account(_)))
|
||||
&& !matches!(self.f_ty, Some(Ty::Loader(_)))
|
||||
{
|
||||
return Err(ParseError::new(
|
||||
c.span(),
|
||||
"close must be on a ProgramAccount",
|
||||
"close must be on an Account, ProgramAccount, or Loader",
|
||||
));
|
||||
}
|
||||
if self.mutable.is_none() {
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
use crate::{
|
||||
AccountField, AccountsStruct, CompositeField, CpiAccountTy, CpiStateTy, Field, LoaderTy,
|
||||
ProgramAccountTy, ProgramStateTy, SysvarTy, Ty,
|
||||
};
|
||||
use crate::*;
|
||||
use syn::parse::{Error as ParseError, Result as ParseResult};
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::spanned::Spanned;
|
||||
|
@ -76,6 +73,7 @@ fn is_field_primitive(f: &syn::Field) -> ParseResult<bool> {
|
|||
| "AccountInfo"
|
||||
| "CpiState"
|
||||
| "Loader"
|
||||
| "Account"
|
||||
);
|
||||
Ok(r)
|
||||
}
|
||||
|
@ -93,6 +91,7 @@ fn parse_ty(f: &syn::Field) -> ParseResult<Ty> {
|
|||
"Sysvar" => Ty::Sysvar(parse_sysvar(&path)?),
|
||||
"AccountInfo" => Ty::AccountInfo,
|
||||
"Loader" => Ty::Loader(parse_program_account_zero_copy(&path)?),
|
||||
"Account" => Ty::Account(parse_account_ty(&path)?),
|
||||
_ => return Err(ParseError::new(f.ty.span(), "invalid account type given")),
|
||||
};
|
||||
|
||||
|
@ -104,6 +103,12 @@ fn ident_string(f: &syn::Field) -> ParseResult<String> {
|
|||
syn::Type::Path(ty_path) => ty_path.path.clone(),
|
||||
_ => return Err(ParseError::new(f.ty.span(), "invalid type")),
|
||||
};
|
||||
if parser::tts_to_string(&path)
|
||||
.replace(" ", "")
|
||||
.starts_with("Box<Account<")
|
||||
{
|
||||
return Ok("Account".to_string());
|
||||
}
|
||||
// TODO: allow segmented paths.
|
||||
if path.segments.len() != 1 {
|
||||
return Err(ParseError::new(
|
||||
|
@ -151,7 +156,54 @@ fn parse_program_account_zero_copy(path: &syn::Path) -> ParseResult<LoaderTy> {
|
|||
})
|
||||
}
|
||||
|
||||
fn parse_account(path: &syn::Path) -> ParseResult<syn::TypePath> {
|
||||
fn parse_account_ty(path: &syn::Path) -> ParseResult<AccountTy> {
|
||||
let account_type_path = parse_account(path)?;
|
||||
let boxed = parser::tts_to_string(&path)
|
||||
.replace(" ", "")
|
||||
.starts_with("Box<Account<");
|
||||
Ok(AccountTy {
|
||||
account_type_path,
|
||||
boxed,
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: this whole method is a hack. Do something more idiomatic.
|
||||
fn parse_account(mut path: &syn::Path) -> ParseResult<syn::TypePath> {
|
||||
if parser::tts_to_string(path)
|
||||
.replace(" ", "")
|
||||
.starts_with("Box<Account<")
|
||||
{
|
||||
let segments = &path.segments[0];
|
||||
match &segments.arguments {
|
||||
syn::PathArguments::AngleBracketed(args) => {
|
||||
// Expected: <'info, MyType>.
|
||||
if args.args.len() != 1 {
|
||||
return Err(ParseError::new(
|
||||
args.args.span(),
|
||||
"bracket arguments must be the lifetime and type",
|
||||
));
|
||||
}
|
||||
match &args.args[0] {
|
||||
syn::GenericArgument::Type(syn::Type::Path(ty_path)) => {
|
||||
path = &ty_path.path;
|
||||
}
|
||||
_ => {
|
||||
return Err(ParseError::new(
|
||||
args.args[1].span(),
|
||||
"first bracket argument must be a lifetime",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(ParseError::new(
|
||||
segments.arguments.span(),
|
||||
"expected angle brackets with a lifetime and type",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let segments = &path.segments[0];
|
||||
match &segments.arguments {
|
||||
syn::PathArguments::AngleBracketed(args) => {
|
||||
|
|
|
@ -4,6 +4,9 @@ use anchor_lang::prelude::borsh::maybestd::io::Write;
|
|||
use anchor_lang::prelude::*;
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
|
||||
// Needed to declare accounts.
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct GenericsTest<'info, T, U, const N: usize>
|
||||
where
|
||||
|
|
|
@ -5,6 +5,7 @@ use anchor_lang::solana_program::program_error::ProgramError;
|
|||
use anchor_lang::solana_program::program_pack::Pack;
|
||||
use anchor_lang::solana_program::pubkey::Pubkey;
|
||||
use anchor_lang::{Accounts, CpiContext};
|
||||
use std::io::Write;
|
||||
use std::ops::Deref;
|
||||
|
||||
pub use spl_token::ID;
|
||||
|
@ -245,6 +246,19 @@ impl anchor_lang::AccountDeserialize for TokenAccount {
|
|||
}
|
||||
}
|
||||
|
||||
impl anchor_lang::AccountSerialize for TokenAccount {
|
||||
fn try_serialize<W: Write>(&self, _writer: &mut W) -> Result<(), ProgramError> {
|
||||
// no-op
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl anchor_lang::Owner for TokenAccount {
|
||||
fn owner() -> Pubkey {
|
||||
ID
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for TokenAccount {
|
||||
type Target = spl_token::state::Account;
|
||||
|
||||
|
@ -270,6 +284,19 @@ impl anchor_lang::AccountDeserialize for Mint {
|
|||
}
|
||||
}
|
||||
|
||||
impl anchor_lang::AccountSerialize for Mint {
|
||||
fn try_serialize<W: Write>(&self, _writer: &mut W) -> Result<(), ProgramError> {
|
||||
// no-op
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl anchor_lang::Owner for Mint {
|
||||
fn owner() -> Pubkey {
|
||||
ID
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Mint {
|
||||
type Target = spl_token::state::Mint;
|
||||
|
||||
|
|
|
@ -2,5 +2,8 @@
|
|||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
cashiers_check = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
|
||||
[scripts]
|
||||
test = "mocha -t 1000000 tests/"
|
||||
|
|
|
@ -7,6 +7,8 @@ use anchor_lang::prelude::*;
|
|||
use anchor_spl::token::{self, TokenAccount, Transfer};
|
||||
use std::convert::Into;
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
#[program]
|
||||
pub mod cashiers_check {
|
||||
use super::*;
|
||||
|
@ -84,18 +86,18 @@ pub mod cashiers_check {
|
|||
pub struct CreateCheck<'info> {
|
||||
// Check being created.
|
||||
#[account(zero)]
|
||||
check: ProgramAccount<'info, Check>,
|
||||
check: Account<'info, Check>,
|
||||
// Check's token vault.
|
||||
#[account(mut, constraint = &vault.owner == check_signer.key)]
|
||||
vault: CpiAccount<'info, TokenAccount>,
|
||||
vault: Account<'info, TokenAccount>,
|
||||
// Program derived address for the check.
|
||||
check_signer: AccountInfo<'info>,
|
||||
// Token account the check is made from.
|
||||
#[account(mut, has_one = owner)]
|
||||
from: CpiAccount<'info, TokenAccount>,
|
||||
from: Account<'info, TokenAccount>,
|
||||
// Token account the check is made to.
|
||||
#[account(constraint = from.mint == to.mint)]
|
||||
to: CpiAccount<'info, TokenAccount>,
|
||||
to: Account<'info, TokenAccount>,
|
||||
// Owner of the `from` token account.
|
||||
owner: AccountInfo<'info>,
|
||||
token_program: AccountInfo<'info>,
|
||||
|
@ -118,7 +120,7 @@ impl<'info> CreateCheck<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct CashCheck<'info> {
|
||||
#[account(mut, has_one = vault, has_one = to)]
|
||||
check: ProgramAccount<'info, Check>,
|
||||
check: Account<'info, Check>,
|
||||
#[account(mut)]
|
||||
vault: AccountInfo<'info>,
|
||||
#[account(
|
||||
|
@ -127,7 +129,7 @@ pub struct CashCheck<'info> {
|
|||
)]
|
||||
check_signer: AccountInfo<'info>,
|
||||
#[account(mut, has_one = owner)]
|
||||
to: CpiAccount<'info, TokenAccount>,
|
||||
to: Account<'info, TokenAccount>,
|
||||
#[account(signer)]
|
||||
owner: AccountInfo<'info>,
|
||||
token_program: AccountInfo<'info>,
|
||||
|
@ -136,7 +138,7 @@ pub struct CashCheck<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct CancelCheck<'info> {
|
||||
#[account(mut, has_one = vault, has_one = from)]
|
||||
check: ProgramAccount<'info, Check>,
|
||||
check: Account<'info, Check>,
|
||||
#[account(mut)]
|
||||
vault: AccountInfo<'info>,
|
||||
#[account(
|
||||
|
@ -145,7 +147,7 @@ pub struct CancelCheck<'info> {
|
|||
)]
|
||||
check_signer: AccountInfo<'info>,
|
||||
#[account(mut, has_one = owner)]
|
||||
from: CpiAccount<'info, TokenAccount>,
|
||||
from: Account<'info, TokenAccount>,
|
||||
#[account(signer)]
|
||||
owner: AccountInfo<'info>,
|
||||
token_program: AccountInfo<'info>,
|
||||
|
|
|
@ -3,6 +3,7 @@ cluster = "localnet"
|
|||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
cfo = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
registry = { address = "GrAkKfEpTKQuVHG2Y97Y2FF4i7y7Q5AHLK94JBy7Y5yv", idl = "./deps/stake/target/idl/registry.json" }
|
||||
lockup = { address = "6ebQNeTPZ1j7k3TtkCCtEPRvG7GQsucQrZ7sSEDQi9Ks", idl = "./deps/stake/target/idl/lockup.json" }
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ use anchor_spl::{dex, mint};
|
|||
use registry::{Registrar, RewardVendorKind};
|
||||
use std::convert::TryInto;
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
/// CFO is the program representing the Serum chief financial officer. It is
|
||||
/// the program responsible for collecting and distributing fees from the Serum
|
||||
/// DEX.
|
||||
|
@ -303,7 +305,7 @@ pub struct CreateOfficer<'info> {
|
|||
bump = bumps.bump,
|
||||
payer = authority,
|
||||
)]
|
||||
officer: ProgramAccount<'info, Officer>,
|
||||
officer: Box<Account<'info, Officer>>,
|
||||
#[account(
|
||||
init,
|
||||
seeds = [b"vault", officer.key().as_ref()],
|
||||
|
@ -312,7 +314,7 @@ pub struct CreateOfficer<'info> {
|
|||
token::mint = mint,
|
||||
token::authority = officer,
|
||||
)]
|
||||
srm_vault: CpiAccount<'info, TokenAccount>,
|
||||
srm_vault: Box<Account<'info, TokenAccount>>,
|
||||
#[account(
|
||||
init,
|
||||
seeds = [b"stake", officer.key().as_ref()],
|
||||
|
@ -321,7 +323,7 @@ pub struct CreateOfficer<'info> {
|
|||
token::mint = mint,
|
||||
token::authority = officer,
|
||||
)]
|
||||
stake: CpiAccount<'info, TokenAccount>,
|
||||
stake: Box<Account<'info, TokenAccount>>,
|
||||
#[account(
|
||||
init,
|
||||
seeds = [b"treasury", officer.key().as_ref()],
|
||||
|
@ -330,7 +332,7 @@ pub struct CreateOfficer<'info> {
|
|||
token::mint = mint,
|
||||
token::authority = officer,
|
||||
)]
|
||||
treasury: CpiAccount<'info, TokenAccount>,
|
||||
treasury: Box<Account<'info, TokenAccount>>,
|
||||
#[account(signer)]
|
||||
authority: AccountInfo<'info>,
|
||||
#[cfg_attr(
|
||||
|
@ -352,7 +354,7 @@ pub struct CreateOfficer<'info> {
|
|||
#[derive(Accounts)]
|
||||
#[instruction(bump: u8)]
|
||||
pub struct CreateOfficerToken<'info> {
|
||||
officer: ProgramAccount<'info, Officer>,
|
||||
officer: Account<'info, Officer>,
|
||||
#[account(
|
||||
init,
|
||||
seeds = [officer.key().as_ref(), mint.key().as_ref()],
|
||||
|
@ -361,7 +363,7 @@ pub struct CreateOfficerToken<'info> {
|
|||
token::authority = officer,
|
||||
payer = payer,
|
||||
)]
|
||||
token: CpiAccount<'info, TokenAccount>,
|
||||
token: Account<'info, TokenAccount>,
|
||||
#[account(owner = token_program)]
|
||||
mint: AccountInfo<'info>,
|
||||
#[account(mut, signer)]
|
||||
|
@ -376,7 +378,7 @@ pub struct CreateOfficerToken<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct SetDistribution<'info> {
|
||||
#[account(has_one = authority)]
|
||||
officer: ProgramAccount<'info, Officer>,
|
||||
officer: Account<'info, Officer>,
|
||||
#[account(signer)]
|
||||
authority: AccountInfo<'info>,
|
||||
}
|
||||
|
@ -387,14 +389,14 @@ pub struct SweepFees<'info> {
|
|||
seeds = [dex.dex_program.key.as_ref()],
|
||||
bump = officer.bumps.bump,
|
||||
)]
|
||||
officer: ProgramAccount<'info, Officer>,
|
||||
officer: Account<'info, Officer>,
|
||||
#[account(
|
||||
mut,
|
||||
owner = dex.token_program,
|
||||
seeds = [officer.key().as_ref(), mint.key().as_ref()],
|
||||
bump,
|
||||
)]
|
||||
sweep_vault: CpiAccount<'info, TokenAccount>,
|
||||
sweep_vault: Account<'info, TokenAccount>,
|
||||
mint: AccountInfo<'info>,
|
||||
dex: Dex<'info>,
|
||||
}
|
||||
|
@ -418,7 +420,7 @@ pub struct SwapToUsdc<'info> {
|
|||
seeds = [dex_program.key().as_ref()],
|
||||
bump = officer.bumps.bump,
|
||||
)]
|
||||
officer: ProgramAccount<'info, Officer>,
|
||||
officer: Account<'info, Officer>,
|
||||
market: DexMarketAccounts<'info>,
|
||||
#[account(
|
||||
owner = token_program,
|
||||
|
@ -447,7 +449,7 @@ pub struct SwapToSrm<'info> {
|
|||
seeds = [dex_program.key().as_ref()],
|
||||
bump = officer.bumps.bump,
|
||||
)]
|
||||
officer: ProgramAccount<'info, Officer>,
|
||||
officer: Account<'info, Officer>,
|
||||
market: DexMarketAccounts<'info>,
|
||||
#[account(
|
||||
owner = token_program,
|
||||
|
@ -513,14 +515,14 @@ pub struct DexMarketAccounts<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct Distribute<'info> {
|
||||
#[account(has_one = treasury, has_one = stake)]
|
||||
officer: ProgramAccount<'info, Officer>,
|
||||
officer: Account<'info, Officer>,
|
||||
treasury: AccountInfo<'info>,
|
||||
stake: AccountInfo<'info>,
|
||||
#[account(
|
||||
owner = token_program,
|
||||
constraint = srm_vault.mint == mint::SRM,
|
||||
)]
|
||||
srm_vault: CpiAccount<'info, TokenAccount>,
|
||||
srm_vault: Account<'info, TokenAccount>,
|
||||
#[account(address = mint::SRM)]
|
||||
mint: AccountInfo<'info>,
|
||||
#[account(address = spl_token::ID)]
|
||||
|
@ -536,12 +538,12 @@ pub struct DropStakeReward<'info> {
|
|||
constraint = srm.registrar.key == &officer.registrar,
|
||||
constraint = msrm.registrar.key == &officer.msrm_registrar,
|
||||
)]
|
||||
officer: ProgramAccount<'info, Officer>,
|
||||
officer: Box<Account<'info, Officer>>,
|
||||
#[account(
|
||||
seeds = [b"stake", officer.key().as_ref()],
|
||||
bump = officer.bumps.stake,
|
||||
)]
|
||||
stake: CpiAccount<'info, TokenAccount>,
|
||||
stake: Box<Account<'info, TokenAccount>>,
|
||||
#[cfg_attr(
|
||||
not(feature = "test"),
|
||||
account(address = mint::SRM),
|
||||
|
@ -550,7 +552,7 @@ pub struct DropStakeReward<'info> {
|
|||
srm: DropStakeRewardPool<'info>,
|
||||
msrm: DropStakeRewardPool<'info>,
|
||||
#[account(owner = registry_program)]
|
||||
msrm_registrar: CpiAccount<'info, Registrar>,
|
||||
msrm_registrar: Box<Account<'info, Registrar>>,
|
||||
#[account(address = token::ID)]
|
||||
token_program: AccountInfo<'info>,
|
||||
#[account(address = registry::ID)]
|
||||
|
@ -569,7 +571,7 @@ pub struct DropStakeReward<'info> {
|
|||
pub struct DropStakeRewardPool<'info> {
|
||||
registrar: AccountInfo<'info>,
|
||||
reward_event_q: AccountInfo<'info>,
|
||||
pool_mint: CpiAccount<'info, Mint>,
|
||||
pool_mint: Account<'info, Mint>,
|
||||
vendor: AccountInfo<'info>,
|
||||
vendor_vault: AccountInfo<'info>,
|
||||
}
|
||||
|
@ -704,8 +706,9 @@ impl<'info> DropStakeReward<'info> {
|
|||
let program = self.registry_program.clone();
|
||||
let accounts = registry::DropReward {
|
||||
registrar: ProgramAccount::try_from(program.key, &self.srm.registrar).unwrap(),
|
||||
reward_event_q: ProgramAccount::try_from(program.key, &self.srm.reward_event_q).unwrap(),
|
||||
pool_mint: self.srm.pool_mint.clone(),
|
||||
reward_event_q: ProgramAccount::try_from(program.key, &self.srm.reward_event_q)
|
||||
.unwrap(),
|
||||
pool_mint: self.srm.pool_mint.clone().into(),
|
||||
vendor: ProgramAccount::try_from(program.key, &self.srm.vendor).unwrap(),
|
||||
vendor_vault: CpiAccount::try_from(&self.srm.vendor_vault).unwrap(),
|
||||
depositor: self.stake.to_account_info(),
|
||||
|
@ -721,8 +724,9 @@ impl<'info> DropStakeReward<'info> {
|
|||
let program = self.registry_program.clone();
|
||||
let accounts = registry::DropReward {
|
||||
registrar: ProgramAccount::try_from(program.key, &self.msrm.registrar).unwrap(),
|
||||
reward_event_q: ProgramAccount::try_from(program.key, &self.msrm.reward_event_q).unwrap(),
|
||||
pool_mint: self.msrm.pool_mint.clone(),
|
||||
reward_event_q: ProgramAccount::try_from(program.key, &self.msrm.reward_event_q)
|
||||
.unwrap(),
|
||||
pool_mint: self.msrm.pool_mint.clone().into(),
|
||||
vendor: ProgramAccount::try_from(program.key, &self.msrm.vendor).unwrap(),
|
||||
vendor_vault: CpiAccount::try_from(&self.msrm.vendor_vault).unwrap(),
|
||||
depositor: self.stake.to_account_info(),
|
||||
|
|
|
@ -2,5 +2,8 @@
|
|||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
chat = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
|
||||
[scripts]
|
||||
test = "mocha -t 1000000 tests/"
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
use anchor_lang::prelude::*;
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
#[program]
|
||||
pub mod chat {
|
||||
use super::*;
|
||||
|
@ -45,7 +47,7 @@ pub struct CreateUser<'info> {
|
|||
payer = authority,
|
||||
space = 320,
|
||||
)]
|
||||
user: ProgramAccount<'info, User>,
|
||||
user: Account<'info, User>,
|
||||
#[account(signer)]
|
||||
authority: AccountInfo<'info>,
|
||||
system_program: AccountInfo<'info>,
|
||||
|
@ -64,7 +66,7 @@ pub struct SendMessage<'info> {
|
|||
bump = user.bump,
|
||||
has_one = authority,
|
||||
)]
|
||||
user: ProgramAccount<'info, User>,
|
||||
user: Account<'info, User>,
|
||||
#[account(signer)]
|
||||
authority: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
|
|
|
@ -2,5 +2,8 @@
|
|||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
composite = "EHthziFziNoac9LBGxEaVN47Y3uUiRoXvqAiR6oes4iU"
|
||||
|
||||
[scripts]
|
||||
test = "mocha -t 1000000 tests/"
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
use anchor_lang::prelude::*;
|
||||
|
||||
declare_id!("EHthziFziNoac9LBGxEaVN47Y3uUiRoXvqAiR6oes4iU");
|
||||
|
||||
#[program]
|
||||
mod composite {
|
||||
use super::*;
|
||||
|
@ -28,9 +30,9 @@ mod composite {
|
|||
#[derive(Accounts)]
|
||||
pub struct Initialize<'info> {
|
||||
#[account(zero)]
|
||||
pub dummy_a: ProgramAccount<'info, DummyA>,
|
||||
pub dummy_a: Account<'info, DummyA>,
|
||||
#[account(zero)]
|
||||
pub dummy_b: ProgramAccount<'info, DummyB>,
|
||||
pub dummy_b: Account<'info, DummyB>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
|
@ -42,13 +44,13 @@ pub struct CompositeUpdate<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct Foo<'info> {
|
||||
#[account(mut)]
|
||||
pub dummy_a: ProgramAccount<'info, DummyA>,
|
||||
pub dummy_a: Account<'info, DummyA>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Bar<'info> {
|
||||
#[account(mut)]
|
||||
pub dummy_b: ProgramAccount<'info, DummyB>,
|
||||
pub dummy_b: Account<'info, DummyB>,
|
||||
}
|
||||
|
||||
#[account]
|
||||
|
|
|
@ -2,5 +2,8 @@
|
|||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
errors = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
|
||||
[scripts]
|
||||
test = "mocha -t 1000000 tests/"
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
use anchor_lang::prelude::*;
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
#[program]
|
||||
mod errors {
|
||||
use super::*;
|
||||
|
@ -44,7 +46,7 @@ pub struct MutError<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct HasOneError<'info> {
|
||||
#[account(zero, has_one = owner)]
|
||||
my_account: ProgramAccount<'info, HasOneAccount>,
|
||||
my_account: Account<'info, HasOneAccount>,
|
||||
owner: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
|
|
|
@ -2,5 +2,8 @@
|
|||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
escrow = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
|
||||
[scripts]
|
||||
test = "mocha -t 1000000 tests/"
|
||||
|
|
|
@ -19,6 +19,8 @@ use anchor_lang::prelude::*;
|
|||
use anchor_spl::token::{self, SetAuthority, TokenAccount, Transfer};
|
||||
use spl_token::instruction::AuthorityType;
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
#[program]
|
||||
pub mod escrow {
|
||||
use super::*;
|
||||
|
@ -104,10 +106,10 @@ pub struct InitializeEscrow<'info> {
|
|||
mut,
|
||||
constraint = initializer_deposit_token_account.amount >= initializer_amount
|
||||
)]
|
||||
pub initializer_deposit_token_account: CpiAccount<'info, TokenAccount>,
|
||||
pub initializer_receive_token_account: CpiAccount<'info, TokenAccount>,
|
||||
pub initializer_deposit_token_account: Account<'info, TokenAccount>,
|
||||
pub initializer_receive_token_account: Account<'info, TokenAccount>,
|
||||
#[account(zero)]
|
||||
pub escrow_account: ProgramAccount<'info, EscrowAccount>,
|
||||
pub escrow_account: Account<'info, EscrowAccount>,
|
||||
pub token_program: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
|
@ -116,13 +118,13 @@ pub struct Exchange<'info> {
|
|||
#[account(signer)]
|
||||
pub taker: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
pub taker_deposit_token_account: CpiAccount<'info, TokenAccount>,
|
||||
pub taker_deposit_token_account: Account<'info, TokenAccount>,
|
||||
#[account(mut)]
|
||||
pub taker_receive_token_account: CpiAccount<'info, TokenAccount>,
|
||||
pub taker_receive_token_account: Account<'info, TokenAccount>,
|
||||
#[account(mut)]
|
||||
pub pda_deposit_token_account: CpiAccount<'info, TokenAccount>,
|
||||
pub pda_deposit_token_account: Account<'info, TokenAccount>,
|
||||
#[account(mut)]
|
||||
pub initializer_receive_token_account: CpiAccount<'info, TokenAccount>,
|
||||
pub initializer_receive_token_account: Account<'info, TokenAccount>,
|
||||
#[account(mut)]
|
||||
pub initializer_main_account: AccountInfo<'info>,
|
||||
#[account(
|
||||
|
@ -133,7 +135,7 @@ pub struct Exchange<'info> {
|
|||
constraint = escrow_account.initializer_key == *initializer_main_account.key,
|
||||
close = initializer_main_account
|
||||
)]
|
||||
pub escrow_account: ProgramAccount<'info, EscrowAccount>,
|
||||
pub escrow_account: Account<'info, EscrowAccount>,
|
||||
pub pda_account: AccountInfo<'info>,
|
||||
pub token_program: AccountInfo<'info>,
|
||||
}
|
||||
|
@ -142,7 +144,7 @@ pub struct Exchange<'info> {
|
|||
pub struct CancelEscrow<'info> {
|
||||
pub initializer: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
pub pda_deposit_token_account: CpiAccount<'info, TokenAccount>,
|
||||
pub pda_deposit_token_account: Account<'info, TokenAccount>,
|
||||
pub pda_account: AccountInfo<'info>,
|
||||
#[account(
|
||||
mut,
|
||||
|
@ -150,7 +152,7 @@ pub struct CancelEscrow<'info> {
|
|||
constraint = escrow_account.initializer_deposit_token_account == *pda_deposit_token_account.to_account_info().key,
|
||||
close = initializer
|
||||
)]
|
||||
pub escrow_account: ProgramAccount<'info, EscrowAccount>,
|
||||
pub escrow_account: Account<'info, EscrowAccount>,
|
||||
pub token_program: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
|
|
|
@ -2,5 +2,8 @@
|
|||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
events = "2dhGsWUzy5YKUsjZdLHLmkNpUDAXkNa9MYWsPc4Ziqzy"
|
||||
|
||||
[scripts]
|
||||
test = "mocha -t 1000000 tests/"
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
use anchor_lang::prelude::*;
|
||||
|
||||
declare_id!("2dhGsWUzy5YKUsjZdLHLmkNpUDAXkNa9MYWsPc4Ziqzy");
|
||||
|
||||
#[program]
|
||||
pub mod events {
|
||||
use super::*;
|
||||
|
|
|
@ -2,5 +2,8 @@
|
|||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
ido_pool = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
|
||||
[scripts]
|
||||
test = "mocha -t 1000000 tests/"
|
||||
|
|
|
@ -5,6 +5,8 @@ use anchor_lang::prelude::*;
|
|||
use anchor_lang::solana_program::program_option::COption;
|
||||
use anchor_spl::token::{self, Burn, Mint, MintTo, TokenAccount, Transfer};
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
#[program]
|
||||
pub mod ido_pool {
|
||||
use super::*;
|
||||
|
@ -192,23 +194,23 @@ pub mod ido_pool {
|
|||
#[derive(Accounts)]
|
||||
pub struct InitializePool<'info> {
|
||||
#[account(zero)]
|
||||
pub pool_account: ProgramAccount<'info, PoolAccount>,
|
||||
pub pool_account: Box<Account<'info, PoolAccount>>,
|
||||
pub pool_signer: AccountInfo<'info>,
|
||||
#[account(
|
||||
constraint = redeemable_mint.mint_authority == COption::Some(*pool_signer.key),
|
||||
constraint = redeemable_mint.supply == 0
|
||||
)]
|
||||
pub redeemable_mint: CpiAccount<'info, Mint>,
|
||||
pub redeemable_mint: Account<'info, Mint>,
|
||||
#[account(constraint = usdc_mint.decimals == redeemable_mint.decimals)]
|
||||
pub usdc_mint: CpiAccount<'info, Mint>,
|
||||
pub usdc_mint: Account<'info, Mint>,
|
||||
#[account(mut, constraint = pool_watermelon.owner == *pool_signer.key)]
|
||||
pub pool_watermelon: CpiAccount<'info, TokenAccount>,
|
||||
pub pool_watermelon: Account<'info, TokenAccount>,
|
||||
#[account(constraint = pool_usdc.owner == *pool_signer.key)]
|
||||
pub pool_usdc: CpiAccount<'info, TokenAccount>,
|
||||
pub pool_usdc: Account<'info, TokenAccount>,
|
||||
#[account(signer)]
|
||||
pub distribution_authority: AccountInfo<'info>,
|
||||
#[account(mut, constraint = creator_watermelon.owner == *distribution_authority.key)]
|
||||
pub creator_watermelon: CpiAccount<'info, TokenAccount>,
|
||||
pub creator_watermelon: Account<'info, TokenAccount>,
|
||||
#[account(constraint = token_program.key == &token::ID)]
|
||||
pub token_program: AccountInfo<'info>,
|
||||
pub clock: Sysvar<'info, Clock>,
|
||||
|
@ -231,7 +233,7 @@ impl<'info> InitializePool<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct ExchangeUsdcForRedeemable<'info> {
|
||||
#[account(has_one = redeemable_mint, has_one = pool_usdc)]
|
||||
pub pool_account: ProgramAccount<'info, PoolAccount>,
|
||||
pub pool_account: Account<'info, PoolAccount>,
|
||||
#[account(
|
||||
seeds = [pool_account.watermelon_mint.as_ref()],
|
||||
bump = pool_account.nonce,
|
||||
|
@ -241,15 +243,15 @@ pub struct ExchangeUsdcForRedeemable<'info> {
|
|||
mut,
|
||||
constraint = redeemable_mint.mint_authority == COption::Some(*pool_signer.key)
|
||||
)]
|
||||
pub redeemable_mint: CpiAccount<'info, Mint>,
|
||||
pub redeemable_mint: Account<'info, Mint>,
|
||||
#[account(mut, constraint = pool_usdc.owner == *pool_signer.key)]
|
||||
pub pool_usdc: CpiAccount<'info, TokenAccount>,
|
||||
pub pool_usdc: Account<'info, TokenAccount>,
|
||||
#[account(signer)]
|
||||
pub user_authority: AccountInfo<'info>,
|
||||
#[account(mut, constraint = user_usdc.owner == *user_authority.key)]
|
||||
pub user_usdc: CpiAccount<'info, TokenAccount>,
|
||||
pub user_usdc: Account<'info, TokenAccount>,
|
||||
#[account(mut, constraint = user_redeemable.owner == *user_authority.key)]
|
||||
pub user_redeemable: CpiAccount<'info, TokenAccount>,
|
||||
pub user_redeemable: Account<'info, TokenAccount>,
|
||||
#[account(constraint = token_program.key == &token::ID)]
|
||||
pub token_program: AccountInfo<'info>,
|
||||
pub clock: Sysvar<'info, Clock>,
|
||||
|
@ -258,7 +260,7 @@ pub struct ExchangeUsdcForRedeemable<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct ExchangeRedeemableForUsdc<'info> {
|
||||
#[account(has_one = redeemable_mint, has_one = pool_usdc)]
|
||||
pub pool_account: ProgramAccount<'info, PoolAccount>,
|
||||
pub pool_account: Account<'info, PoolAccount>,
|
||||
#[account(
|
||||
seeds = [pool_account.watermelon_mint.as_ref()],
|
||||
bump = pool_account.nonce,
|
||||
|
@ -268,15 +270,15 @@ pub struct ExchangeRedeemableForUsdc<'info> {
|
|||
mut,
|
||||
constraint = redeemable_mint.mint_authority == COption::Some(*pool_signer.key)
|
||||
)]
|
||||
pub redeemable_mint: CpiAccount<'info, Mint>,
|
||||
pub redeemable_mint: Account<'info, Mint>,
|
||||
#[account(mut, constraint = pool_usdc.owner == *pool_signer.key)]
|
||||
pub pool_usdc: CpiAccount<'info, TokenAccount>,
|
||||
pub pool_usdc: Account<'info, TokenAccount>,
|
||||
#[account(signer)]
|
||||
pub user_authority: AccountInfo<'info>,
|
||||
#[account(mut, constraint = user_usdc.owner == *user_authority.key)]
|
||||
pub user_usdc: CpiAccount<'info, TokenAccount>,
|
||||
pub user_usdc: Account<'info, TokenAccount>,
|
||||
#[account(mut, constraint = user_redeemable.owner == *user_authority.key)]
|
||||
pub user_redeemable: CpiAccount<'info, TokenAccount>,
|
||||
pub user_redeemable: Account<'info, TokenAccount>,
|
||||
#[account(constraint = token_program.key == &token::ID)]
|
||||
pub token_program: AccountInfo<'info>,
|
||||
pub clock: Sysvar<'info, Clock>,
|
||||
|
@ -285,7 +287,7 @@ pub struct ExchangeRedeemableForUsdc<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct ExchangeRedeemableForWatermelon<'info> {
|
||||
#[account(has_one = redeemable_mint, has_one = pool_watermelon)]
|
||||
pub pool_account: ProgramAccount<'info, PoolAccount>,
|
||||
pub pool_account: Account<'info, PoolAccount>,
|
||||
#[account(
|
||||
seeds = [pool_account.watermelon_mint.as_ref()],
|
||||
bump = pool_account.nonce,
|
||||
|
@ -295,15 +297,15 @@ pub struct ExchangeRedeemableForWatermelon<'info> {
|
|||
mut,
|
||||
constraint = redeemable_mint.mint_authority == COption::Some(*pool_signer.key)
|
||||
)]
|
||||
pub redeemable_mint: CpiAccount<'info, Mint>,
|
||||
pub redeemable_mint: Account<'info, Mint>,
|
||||
#[account(mut, constraint = pool_watermelon.owner == *pool_signer.key)]
|
||||
pub pool_watermelon: CpiAccount<'info, TokenAccount>,
|
||||
pub pool_watermelon: Account<'info, TokenAccount>,
|
||||
#[account(signer)]
|
||||
pub user_authority: AccountInfo<'info>,
|
||||
#[account(mut, constraint = user_watermelon.owner == *user_authority.key)]
|
||||
pub user_watermelon: CpiAccount<'info, TokenAccount>,
|
||||
pub user_watermelon: Account<'info, TokenAccount>,
|
||||
#[account(mut, constraint = user_redeemable.owner == *user_authority.key)]
|
||||
pub user_redeemable: CpiAccount<'info, TokenAccount>,
|
||||
pub user_redeemable: Account<'info, TokenAccount>,
|
||||
#[account(constraint = token_program.key == &token::ID)]
|
||||
pub token_program: AccountInfo<'info>,
|
||||
pub clock: Sysvar<'info, Clock>,
|
||||
|
@ -312,18 +314,18 @@ pub struct ExchangeRedeemableForWatermelon<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct WithdrawPoolUsdc<'info> {
|
||||
#[account(has_one = pool_usdc, has_one = distribution_authority)]
|
||||
pub pool_account: ProgramAccount<'info, PoolAccount>,
|
||||
pub pool_account: Account<'info, PoolAccount>,
|
||||
#[account(
|
||||
seeds = [pool_account.watermelon_mint.as_ref()],
|
||||
bump = pool_account.nonce,
|
||||
)]
|
||||
pub pool_signer: AccountInfo<'info>,
|
||||
#[account(mut, constraint = pool_usdc.owner == *pool_signer.key)]
|
||||
pub pool_usdc: CpiAccount<'info, TokenAccount>,
|
||||
pub pool_usdc: Account<'info, TokenAccount>,
|
||||
#[account(signer)]
|
||||
pub distribution_authority: AccountInfo<'info>,
|
||||
#[account(mut, constraint = creator_usdc.owner == *distribution_authority.key)]
|
||||
pub creator_usdc: CpiAccount<'info, TokenAccount>,
|
||||
pub creator_usdc: Account<'info, TokenAccount>,
|
||||
#[account(constraint = token_program.key == &token::ID)]
|
||||
pub token_program: AccountInfo<'info>,
|
||||
pub clock: Sysvar<'info, Clock>,
|
||||
|
@ -399,7 +401,7 @@ fn withdraw_only_phase(ctx: &Context<ExchangeRedeemableForUsdc>) -> Result<()> {
|
|||
|
||||
// Asserts the IDO sale period has ended, based on the current timestamp.
|
||||
fn ido_over<'info>(
|
||||
pool_account: &ProgramAccount<'info, PoolAccount>,
|
||||
pool_account: &Account<'info, PoolAccount>,
|
||||
clock: &Sysvar<'info, Clock>,
|
||||
) -> Result<()> {
|
||||
if !(pool_account.end_ido_ts < clock.unix_timestamp) {
|
||||
|
|
|
@ -2,5 +2,9 @@
|
|||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
counter = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
counter_auth = "Aws2XRVHjNqCUbMmaU245ojT2DBJFYX58KVo2YySEeeP"
|
||||
|
||||
[scripts]
|
||||
test = "mocha -t 1000000 tests/"
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
use anchor_lang::prelude::*;
|
||||
use counter::Auth;
|
||||
|
||||
declare_id!("Aws2XRVHjNqCUbMmaU245ojT2DBJFYX58KVo2YySEeeP");
|
||||
|
||||
#[program]
|
||||
pub mod counter_auth {
|
||||
use super::*;
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
use anchor_lang::prelude::*;
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
#[program]
|
||||
pub mod counter {
|
||||
use super::*;
|
||||
|
|
|
@ -2,5 +2,9 @@
|
|||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
lockup = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
registry = "HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L"
|
||||
|
||||
[scripts]
|
||||
test = "mocha -t 1000000 tests/"
|
||||
|
|
|
@ -8,6 +8,8 @@ use anchor_spl::token::{self, TokenAccount, Transfer};
|
|||
|
||||
mod calculator;
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
#[program]
|
||||
pub mod lockup {
|
||||
use super::*;
|
||||
|
@ -208,9 +210,9 @@ pub struct Auth<'info> {
|
|||
pub struct CreateVesting<'info> {
|
||||
// Vesting.
|
||||
#[account(zero)]
|
||||
vesting: ProgramAccount<'info, Vesting>,
|
||||
vesting: Account<'info, Vesting>,
|
||||
#[account(mut)]
|
||||
vault: CpiAccount<'info, TokenAccount>,
|
||||
vault: Account<'info, TokenAccount>,
|
||||
// Depositor.
|
||||
#[account(mut)]
|
||||
depositor: AccountInfo<'info>,
|
||||
|
@ -246,11 +248,11 @@ impl<'info> CreateVesting<'info> {
|
|||
pub struct Withdraw<'info> {
|
||||
// Vesting.
|
||||
#[account(mut, has_one = beneficiary, has_one = vault)]
|
||||
vesting: ProgramAccount<'info, Vesting>,
|
||||
vesting: Account<'info, Vesting>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
vault: CpiAccount<'info, TokenAccount>,
|
||||
vault: Account<'info, TokenAccount>,
|
||||
#[account(
|
||||
seeds = [vesting.to_account_info().key.as_ref()],
|
||||
bump = vesting.nonce,
|
||||
|
@ -258,7 +260,7 @@ pub struct Withdraw<'info> {
|
|||
vesting_signer: AccountInfo<'info>,
|
||||
// Withdraw receiving target..
|
||||
#[account(mut)]
|
||||
token: CpiAccount<'info, TokenAccount>,
|
||||
token: Account<'info, TokenAccount>,
|
||||
// Misc.
|
||||
#[account(constraint = token_program.key == &token::ID)]
|
||||
token_program: AccountInfo<'info>,
|
||||
|
@ -284,9 +286,9 @@ pub struct WhitelistTransfer<'info> {
|
|||
|
||||
// Whitelist interface.
|
||||
#[account(mut, has_one = beneficiary, has_one = vault)]
|
||||
vesting: ProgramAccount<'info, Vesting>,
|
||||
vesting: Account<'info, Vesting>,
|
||||
#[account(mut, constraint = &vault.owner == vesting_signer.key)]
|
||||
vault: CpiAccount<'info, TokenAccount>,
|
||||
vault: Account<'info, TokenAccount>,
|
||||
#[account(
|
||||
seeds = [vesting.to_account_info().key.as_ref()],
|
||||
bump = vesting.nonce,
|
||||
|
@ -301,7 +303,7 @@ pub struct WhitelistTransfer<'info> {
|
|||
|
||||
#[derive(Accounts)]
|
||||
pub struct AvailableForWithdrawal<'info> {
|
||||
vesting: ProgramAccount<'info, Vesting>,
|
||||
vesting: Account<'info, Vesting>,
|
||||
clock: Sysvar<'info, Clock>,
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ use anchor_spl::token::{self, Mint, TokenAccount, Transfer};
|
|||
use lockup::{CreateVesting, RealizeLock, Realizor, Vesting};
|
||||
use std::convert::Into;
|
||||
|
||||
declare_id!("HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L");
|
||||
|
||||
#[program]
|
||||
mod registry {
|
||||
use super::*;
|
||||
|
@ -557,11 +559,11 @@ mod registry {
|
|||
#[derive(Accounts)]
|
||||
pub struct Initialize<'info> {
|
||||
#[account(zero)]
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
registrar: Account<'info, Registrar>,
|
||||
#[account(zero)]
|
||||
reward_event_q: ProgramAccount<'info, RewardQueue>,
|
||||
reward_event_q: Account<'info, RewardQueue>,
|
||||
#[account("pool_mint.decimals == 0")]
|
||||
pool_mint: CpiAccount<'info, Mint>,
|
||||
pool_mint: Account<'info, Mint>,
|
||||
}
|
||||
|
||||
impl<'info> Initialize<'info> {
|
||||
|
@ -585,7 +587,7 @@ impl<'info> Initialize<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct UpdateRegistrar<'info> {
|
||||
#[account(mut, has_one = authority)]
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
registrar: Account<'info, Registrar>,
|
||||
#[account(signer)]
|
||||
authority: AccountInfo<'info>,
|
||||
}
|
||||
|
@ -593,10 +595,10 @@ pub struct UpdateRegistrar<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct CreateMember<'info> {
|
||||
// Stake instance.
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
registrar: Box<Account<'info, Registrar>>,
|
||||
// Member.
|
||||
#[account(zero)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
member: Box<Account<'info, Member>>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
#[account(
|
||||
|
@ -642,17 +644,17 @@ impl<'info> CreateMember<'info> {
|
|||
#[derive(Accounts, Clone)]
|
||||
pub struct BalanceSandboxAccounts<'info> {
|
||||
#[account(mut)]
|
||||
spt: CpiAccount<'info, TokenAccount>,
|
||||
spt: Box<Account<'info, TokenAccount>>,
|
||||
#[account(mut, constraint = vault.owner == spt.owner)]
|
||||
vault: CpiAccount<'info, TokenAccount>,
|
||||
vault: Box<Account<'info, TokenAccount>>,
|
||||
#[account(
|
||||
mut,
|
||||
constraint = vault_stake.owner == spt.owner,
|
||||
constraint = vault_stake.mint == vault.mint
|
||||
)]
|
||||
vault_stake: CpiAccount<'info, TokenAccount>,
|
||||
vault_stake: Box<Account<'info, TokenAccount>>,
|
||||
#[account(mut, constraint = vault_pw.owner == spt.owner, constraint = vault_pw.mint == vault.mint)]
|
||||
vault_pw: CpiAccount<'info, TokenAccount>,
|
||||
vault_pw: Box<Account<'info, TokenAccount>>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
|
@ -672,15 +674,15 @@ pub struct IsRealized<'info> {
|
|||
constraint = &member.balances.spt == member_spt.to_account_info().key,
|
||||
constraint = &member.balances_locked.spt == member_spt_locked.to_account_info().key
|
||||
)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
member_spt: CpiAccount<'info, TokenAccount>,
|
||||
member_spt_locked: CpiAccount<'info, TokenAccount>,
|
||||
member: Account<'info, Member>,
|
||||
member_spt: Account<'info, TokenAccount>,
|
||||
member_spt_locked: Account<'info, TokenAccount>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct UpdateMember<'info> {
|
||||
#[account(mut, has_one = beneficiary)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
member: Account<'info, Member>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
}
|
||||
|
@ -689,11 +691,11 @@ pub struct UpdateMember<'info> {
|
|||
pub struct Deposit<'info> {
|
||||
// Member.
|
||||
#[account(has_one = beneficiary)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
member: Account<'info, Member>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
#[account(mut, constraint = vault.to_account_info().key == &member.balances.vault)]
|
||||
vault: CpiAccount<'info, TokenAccount>,
|
||||
vault: Account<'info, TokenAccount>,
|
||||
// Depositor.
|
||||
#[account(mut)]
|
||||
depositor: AccountInfo<'info>,
|
||||
|
@ -711,7 +713,7 @@ pub struct DepositLocked<'info> {
|
|||
constraint = vesting.to_account_info().owner == ®istry.lockup_program,
|
||||
constraint = vesting.beneficiary == member.beneficiary
|
||||
)]
|
||||
vesting: CpiAccount<'info, Vesting>,
|
||||
vesting: Box<Account<'info, Vesting>>,
|
||||
#[account(mut, constraint = vesting_vault.key == &vesting.vault)]
|
||||
vesting_vault: AccountInfo<'info>,
|
||||
// Note: no need to verify the depositor_authority since the SPL program
|
||||
|
@ -724,7 +726,7 @@ pub struct DepositLocked<'info> {
|
|||
mut,
|
||||
constraint = member_vault.to_account_info().key == &member.balances_locked.vault
|
||||
)]
|
||||
member_vault: CpiAccount<'info, TokenAccount>,
|
||||
member_vault: Box<Account<'info, TokenAccount>>,
|
||||
#[account(
|
||||
seeds = [registrar.to_account_info().key.as_ref(), member.to_account_info().key.as_ref()],
|
||||
bump = member.nonce,
|
||||
|
@ -733,9 +735,9 @@ pub struct DepositLocked<'info> {
|
|||
|
||||
// Program specific.
|
||||
registry: ProgramState<'info, Registry>,
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
registrar: Box<Account<'info, Registrar>>,
|
||||
#[account(has_one = registrar, has_one = beneficiary)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
member: Box<Account<'info, Member>>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
}
|
||||
|
@ -744,14 +746,14 @@ pub struct DepositLocked<'info> {
|
|||
pub struct Stake<'info> {
|
||||
// Global accounts for the staking instance.
|
||||
#[account(has_one = pool_mint, has_one = reward_event_q)]
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
reward_event_q: ProgramAccount<'info, RewardQueue>,
|
||||
registrar: Account<'info, Registrar>,
|
||||
reward_event_q: Account<'info, RewardQueue>,
|
||||
#[account(mut)]
|
||||
pool_mint: CpiAccount<'info, Mint>,
|
||||
pool_mint: Account<'info, Mint>,
|
||||
|
||||
// Member.
|
||||
#[account(mut, has_one = beneficiary, has_one = registrar)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
member: Account<'info, Member>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
#[account(constraint = BalanceSandbox::from(&balances) == member.balances)]
|
||||
|
@ -781,16 +783,16 @@ pub struct Stake<'info> {
|
|||
pub struct StartUnstake<'info> {
|
||||
// Stake instance globals.
|
||||
#[account(has_one = reward_event_q)]
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
reward_event_q: ProgramAccount<'info, RewardQueue>,
|
||||
registrar: Account<'info, Registrar>,
|
||||
reward_event_q: Account<'info, RewardQueue>,
|
||||
#[account(mut)]
|
||||
pool_mint: AccountInfo<'info>,
|
||||
|
||||
// Member.
|
||||
#[account(zero)]
|
||||
pending_withdrawal: ProgramAccount<'info, PendingWithdrawal>,
|
||||
pending_withdrawal: Account<'info, PendingWithdrawal>,
|
||||
#[account(has_one = beneficiary, has_one = registrar)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
member: Account<'info, Member>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
#[account(constraint = BalanceSandbox::from(&balances) == member.balances)]
|
||||
|
@ -813,14 +815,14 @@ pub struct StartUnstake<'info> {
|
|||
|
||||
#[derive(Accounts)]
|
||||
pub struct EndUnstake<'info> {
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
registrar: Account<'info, Registrar>,
|
||||
|
||||
#[account(has_one = registrar, has_one = beneficiary)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
member: Account<'info, Member>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
#[account(mut, has_one = registrar, has_one = member, constraint = !pending_withdrawal.burned)]
|
||||
pending_withdrawal: ProgramAccount<'info, PendingWithdrawal>,
|
||||
pending_withdrawal: Account<'info, PendingWithdrawal>,
|
||||
|
||||
// If we had ordered maps implementing Accounts we could do a constraint like
|
||||
// balances.get(pending_withdrawal.balance_id).vault == vault.key.
|
||||
|
@ -845,14 +847,14 @@ pub struct EndUnstake<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct Withdraw<'info> {
|
||||
// Stake instance.
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
registrar: Account<'info, Registrar>,
|
||||
// Member.
|
||||
#[account(has_one = registrar, has_one = beneficiary)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
member: Account<'info, Member>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
#[account(mut, constraint = vault.to_account_info().key == &member.balances.vault)]
|
||||
vault: CpiAccount<'info, TokenAccount>,
|
||||
vault: Account<'info, TokenAccount>,
|
||||
#[account(
|
||||
seeds = [registrar.to_account_info().key.as_ref(), member.to_account_info().key.as_ref()],
|
||||
bump = member.nonce,
|
||||
|
@ -873,7 +875,7 @@ pub struct WithdrawLocked<'info> {
|
|||
constraint = vesting.to_account_info().owner == ®istry.lockup_program,
|
||||
constraint = vesting.beneficiary == member.beneficiary,
|
||||
)]
|
||||
vesting: CpiAccount<'info, Vesting>,
|
||||
vesting: Box<Account<'info, Vesting>>,
|
||||
#[account(mut, constraint = vesting_vault.key == &vesting.vault)]
|
||||
vesting_vault: AccountInfo<'info>,
|
||||
#[account(signer)]
|
||||
|
@ -884,7 +886,7 @@ pub struct WithdrawLocked<'info> {
|
|||
mut,
|
||||
constraint = member_vault.to_account_info().key == &member.balances_locked.vault
|
||||
)]
|
||||
member_vault: CpiAccount<'info, TokenAccount>,
|
||||
member_vault: Box<Account<'info, TokenAccount>>,
|
||||
#[account(
|
||||
seeds = [registrar.to_account_info().key.as_ref(), member.to_account_info().key.as_ref()],
|
||||
bump = member.nonce,
|
||||
|
@ -893,9 +895,9 @@ pub struct WithdrawLocked<'info> {
|
|||
|
||||
// Program specific.
|
||||
registry: ProgramState<'info, Registry>,
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
registrar: Box<Account<'info, Registrar>>,
|
||||
#[account(has_one = registrar, has_one = beneficiary)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
member: Box<Account<'info, Member>>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
}
|
||||
|
@ -904,15 +906,15 @@ pub struct WithdrawLocked<'info> {
|
|||
pub struct DropReward<'info> {
|
||||
// Staking instance.
|
||||
#[account(has_one = reward_event_q, has_one = pool_mint)]
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
registrar: Account<'info, Registrar>,
|
||||
#[account(mut)]
|
||||
reward_event_q: ProgramAccount<'info, RewardQueue>,
|
||||
pool_mint: CpiAccount<'info, Mint>,
|
||||
reward_event_q: Account<'info, RewardQueue>,
|
||||
pool_mint: Account<'info, Mint>,
|
||||
// Vendor.
|
||||
#[account(zero)]
|
||||
vendor: ProgramAccount<'info, RewardVendor>,
|
||||
vendor: Account<'info, RewardVendor>,
|
||||
#[account(mut)]
|
||||
vendor_vault: CpiAccount<'info, TokenAccount>,
|
||||
vendor_vault: Account<'info, TokenAccount>,
|
||||
// Depositor.
|
||||
#[account(mut)]
|
||||
depositor: AccountInfo<'info>,
|
||||
|
@ -963,10 +965,10 @@ pub struct ClaimRewardLocked<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct ClaimRewardCommon<'info> {
|
||||
// Stake instance.
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
registrar: Account<'info, Registrar>,
|
||||
// Member.
|
||||
#[account(mut, has_one = registrar, has_one = beneficiary)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
member: Account<'info, Member>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
#[account(constraint = BalanceSandbox::from(&balances) == member.balances)]
|
||||
|
@ -975,7 +977,7 @@ pub struct ClaimRewardCommon<'info> {
|
|||
balances_locked: BalanceSandboxAccounts<'info>,
|
||||
// Vendor.
|
||||
#[account(has_one = registrar, has_one = vault)]
|
||||
vendor: ProgramAccount<'info, RewardVendor>,
|
||||
vendor: Account<'info, RewardVendor>,
|
||||
#[account(mut)]
|
||||
vault: AccountInfo<'info>,
|
||||
#[account(
|
||||
|
@ -992,12 +994,12 @@ pub struct ClaimRewardCommon<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct ExpireReward<'info> {
|
||||
// Staking instance globals.
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
registrar: Account<'info, Registrar>,
|
||||
// Vendor.
|
||||
#[account(mut, has_one = registrar, has_one = vault, has_one = expiry_receiver)]
|
||||
vendor: ProgramAccount<'info, RewardVendor>,
|
||||
vendor: Account<'info, RewardVendor>,
|
||||
#[account(mut)]
|
||||
vault: CpiAccount<'info, TokenAccount>,
|
||||
vault: Account<'info, TokenAccount>,
|
||||
#[account(
|
||||
seeds = [registrar.to_account_info().key.as_ref(), vendor.to_account_info().key.as_ref()],
|
||||
bump = vendor.nonce
|
||||
|
@ -1303,8 +1305,8 @@ fn reward_eligible(cmn: &ClaimRewardCommon) -> Result<()> {
|
|||
// Asserts the user calling the `Stake` instruction has no rewards available
|
||||
// in the reward queue.
|
||||
pub fn no_available_rewards<'info>(
|
||||
reward_q: &ProgramAccount<'info, RewardQueue>,
|
||||
member: &ProgramAccount<'info, Member>,
|
||||
reward_q: &Account<'info, RewardQueue>,
|
||||
member: &Account<'info, Member>,
|
||||
balances: &BalanceSandboxAccounts<'info>,
|
||||
balances_locked: &BalanceSandboxAccounts<'info>,
|
||||
) -> Result<()> {
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
misc = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
misc2 = "HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L"
|
||||
|
||||
[[test.genesis]]
|
||||
address = "FtMNMKp9DZHKWUyVAsj3Q5QV8ow4P3fUPP7ZrWEQJzKr"
|
||||
program = "./target/deploy/misc.so"
|
||||
|
|
|
@ -15,7 +15,7 @@ pub struct TestTokenSeedsInit<'info> {
|
|||
mint::decimals = 6,
|
||||
mint::authority = authority,
|
||||
)]
|
||||
pub mint: CpiAccount<'info, Mint>,
|
||||
pub mint: Account<'info, Mint>,
|
||||
#[account(
|
||||
init,
|
||||
seeds = [b"my-token-seed".as_ref()],
|
||||
|
@ -24,7 +24,7 @@ pub struct TestTokenSeedsInit<'info> {
|
|||
token::mint = mint,
|
||||
token::authority = authority,
|
||||
)]
|
||||
pub my_pda: CpiAccount<'info, TokenAccount>,
|
||||
pub my_pda: Account<'info, TokenAccount>,
|
||||
pub authority: AccountInfo<'info>,
|
||||
pub system_program: AccountInfo<'info>,
|
||||
pub rent: Sysvar<'info, Rent>,
|
||||
|
@ -51,7 +51,7 @@ pub struct TestPdaInit<'info> {
|
|||
bump = bump,
|
||||
payer = my_payer,
|
||||
)]
|
||||
pub my_pda: ProgramAccount<'info, DataU16>,
|
||||
pub my_pda: Account<'info, DataU16>,
|
||||
pub my_payer: AccountInfo<'info>,
|
||||
pub foo: AccountInfo<'info>,
|
||||
pub system_program: AccountInfo<'info>,
|
||||
|
@ -91,7 +91,7 @@ pub struct RemainingAccounts {}
|
|||
#[derive(Accounts)]
|
||||
pub struct Initialize<'info> {
|
||||
#[account(zero)]
|
||||
pub data: ProgramAccount<'info, Data>,
|
||||
pub data: Account<'info, Data>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
|
@ -120,20 +120,20 @@ pub struct TestStateCpi<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct TestClose<'info> {
|
||||
#[account(mut, close = sol_dest)]
|
||||
pub data: ProgramAccount<'info, Data>,
|
||||
pub data: Account<'info, Data>,
|
||||
sol_dest: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct TestU16<'info> {
|
||||
#[account(zero)]
|
||||
pub my_account: ProgramAccount<'info, DataU16>,
|
||||
pub my_account: Account<'info, DataU16>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct TestI16<'info> {
|
||||
#[account(zero)]
|
||||
pub data: ProgramAccount<'info, DataI16>,
|
||||
pub data: Account<'info, DataI16>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
|
@ -142,13 +142,13 @@ pub struct TestSimulate {}
|
|||
#[derive(Accounts)]
|
||||
pub struct TestI8<'info> {
|
||||
#[account(zero)]
|
||||
pub data: ProgramAccount<'info, DataI8>,
|
||||
pub data: Account<'info, DataI8>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct TestInit<'info> {
|
||||
#[account(init, payer = payer)]
|
||||
pub data: ProgramAccount<'info, DataI8>,
|
||||
pub data: Account<'info, DataI8>,
|
||||
#[account(signer)]
|
||||
pub payer: AccountInfo<'info>,
|
||||
pub system_program: AccountInfo<'info>,
|
||||
|
@ -166,7 +166,7 @@ pub struct TestInitZeroCopy<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct TestInitMint<'info> {
|
||||
#[account(init, mint::decimals = 6, mint::authority = payer, payer = payer)]
|
||||
pub mint: CpiAccount<'info, Mint>,
|
||||
pub mint: Account<'info, Mint>,
|
||||
#[account(signer)]
|
||||
pub payer: AccountInfo<'info>,
|
||||
pub rent: Sysvar<'info, Rent>,
|
||||
|
@ -177,8 +177,8 @@ pub struct TestInitMint<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct TestInitToken<'info> {
|
||||
#[account(init, token::mint = mint, token::authority = payer, payer = payer)]
|
||||
pub token: CpiAccount<'info, TokenAccount>,
|
||||
pub mint: CpiAccount<'info, Mint>,
|
||||
pub token: Account<'info, TokenAccount>,
|
||||
pub mint: Account<'info, Mint>,
|
||||
#[account(signer)]
|
||||
pub payer: AccountInfo<'info>,
|
||||
pub rent: Sysvar<'info, Rent>,
|
||||
|
|
|
@ -10,6 +10,8 @@ mod account;
|
|||
mod context;
|
||||
mod event;
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
#[program]
|
||||
pub mod misc {
|
||||
use super::*;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use anchor_lang::prelude::*;
|
||||
|
||||
declare_id!("HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L");
|
||||
|
||||
#[program]
|
||||
pub mod misc2 {
|
||||
use super::*;
|
||||
|
|
|
@ -155,17 +155,19 @@ describe("misc", () => {
|
|||
assert.ok(resp.events[2].data.data === 9);
|
||||
});
|
||||
|
||||
let dataI8;
|
||||
|
||||
it("Can use i8 in the idl", async () => {
|
||||
const data = anchor.web3.Keypair.generate();
|
||||
dataI8 = anchor.web3.Keypair.generate();
|
||||
await program.rpc.testI8(-3, {
|
||||
accounts: {
|
||||
data: data.publicKey,
|
||||
data: dataI8.publicKey,
|
||||
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
||||
},
|
||||
instructions: [await program.account.dataI8.createInstruction(data)],
|
||||
signers: [data],
|
||||
instructions: [await program.account.dataI8.createInstruction(dataI8)],
|
||||
signers: [dataI8],
|
||||
});
|
||||
const dataAccount = await program.account.dataI8.fetch(data.publicKey);
|
||||
const dataAccount = await program.account.dataI8.fetch(dataI8.publicKey);
|
||||
assert.ok(dataAccount.data === -3);
|
||||
});
|
||||
|
||||
|
|
|
@ -2,5 +2,8 @@
|
|||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
multisig = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
|
||||
[scripts]
|
||||
test = "mocha -t 1000000 tests/"
|
||||
|
|
|
@ -22,6 +22,8 @@ use anchor_lang::solana_program;
|
|||
use anchor_lang::solana_program::instruction::Instruction;
|
||||
use std::convert::Into;
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
#[program]
|
||||
pub mod multisig {
|
||||
use super::*;
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
[provider]
|
||||
cluster = "localnet"
|
||||
wallet = "~/.config/solana/id.json"
|
||||
|
||||
[programs.localnet]
|
||||
tictactoe = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
|
||||
[scripts]
|
||||
test = "mocha -t 1000000 tests/"
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use anchor_lang::prelude::*;
|
||||
use std::str::FromStr;
|
||||
|
||||
const BOARD_ITEM_FREE: u8 = 0; // Free slot
|
||||
const BOARD_ITEM_X: u8 = 1; // Player X
|
||||
const BOARD_ITEM_O: u8 = 2; // Player O
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
/// Game State
|
||||
/// 0 - Waiting
|
||||
/// 1 - XMove
|
||||
|
@ -55,14 +56,14 @@ pub mod tictactoe {
|
|||
|
||||
#[derive(Accounts)]
|
||||
pub struct Status<'info> {
|
||||
dashboard: ProgramAccount<'info, Dashboard>,
|
||||
game: ProgramAccount<'info, Game>,
|
||||
dashboard: Account<'info, Dashboard>,
|
||||
game: Account<'info, Game>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Initializedashboard<'info> {
|
||||
#[account(init)]
|
||||
dashboard: ProgramAccount<'info, Dashboard>,
|
||||
#[account(zero)]
|
||||
dashboard: Account<'info, Dashboard>,
|
||||
#[account(signer)]
|
||||
authority: AccountInfo<'info>,
|
||||
}
|
||||
|
@ -72,9 +73,9 @@ pub struct Initialize<'info> {
|
|||
#[account(signer)]
|
||||
player_x: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
dashboard: ProgramAccount<'info, Dashboard>,
|
||||
#[account(init)]
|
||||
game: ProgramAccount<'info, Game>,
|
||||
dashboard: Account<'info, Dashboard>,
|
||||
#[account(zero)]
|
||||
game: Account<'info, Game>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
|
@ -82,7 +83,7 @@ pub struct Playerjoin<'info> {
|
|||
#[account(signer)]
|
||||
player_o: AccountInfo<'info>,
|
||||
#[account(mut, constraint = game.game_state != 0 && game.player_x != Pubkey::default())]
|
||||
game: ProgramAccount<'info, Game>,
|
||||
game: Account<'info, Game>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
|
@ -90,7 +91,7 @@ pub struct Playermove<'info> {
|
|||
#[account(signer)]
|
||||
player: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
game: ProgramAccount<'info, Game>,
|
||||
game: Account<'info, Game>,
|
||||
}
|
||||
|
||||
impl<'info> Playermove<'info> {
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
use anchor_lang::prelude::*;
|
||||
|
||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
||||
|
||||
#[program]
|
||||
pub mod zero_copy {
|
||||
use super::*;
|
||||
|
|
Loading…
Reference in New Issue