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