cli, context: Add spl token faucet to init-mint command (#63)

This commit is contained in:
Armani Ferrante 2020-12-15 16:12:51 -08:00 committed by GitHub
parent 7261556aba
commit 6de9192766
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 202 additions and 27 deletions

2
Cargo.lock generated
View File

@ -3085,7 +3085,9 @@ dependencies = [
"serum-registry-cli", "serum-registry-cli",
"serum-registry-rewards-cli", "serum-registry-rewards-cli",
"serum_dex", "serum_dex",
"solana-client",
"solana-sdk", "solana-sdk",
"spl-token 2.0.6",
] ]
[[package]] [[package]]

View File

@ -12,13 +12,15 @@ TEST_PAYER_FILEPATH="$(HOME)/.config/solana/id.json"
# #
# The solana cluster to test against. Defaults to local. # The solana cluster to test against. Defaults to local.
# #
ifndef TEST_CLUSTER
TEST_CLUSTER=l TEST_CLUSTER=l
#TEST_CLUSTER=devnet endif
# #
# The url of TEST_CLUSTER. # The url of TEST_CLUSTER.
# #
ifndef TEST_CLUSTER_URL
TEST_CLUSTER_URL="http://localhost:8899" TEST_CLUSTER_URL="http://localhost:8899"
#TEST_CLUSTER_URL="https://devnet.solana.com" endif
# #
# One can optionally set this along with the test-program command # One can optionally set this along with the test-program command
# to avoid redeploying everytime tests are run. # to avoid redeploying everytime tests are run.

View File

@ -9,7 +9,7 @@ name = "serum"
path = "src/main.rs" path = "src/main.rs"
[features] [features]
dev = ["serum-common", "serum-common-tests", "serum_dex", "solana-sdk", "serde_json", "serum-registry"] dev = ["serum-common", "serum-common-tests", "serum_dex", "solana-sdk", "serde_json", "serum-registry", "spl-token", "solana-client"]
default = [] default = []
@ -29,3 +29,5 @@ serum_dex = { path = "../dex", default-features = false, features = ["client"],
solana-sdk = { version = "1.3.14", optional = true } solana-sdk = { version = "1.3.14", optional = true }
serde_json = { version = "1.0.59", optional = true } serde_json = { version = "1.0.59", optional = true }
serum-registry = { path = "../registry", optional = true } serum-registry = { path = "../registry", optional = true }
spl-token = { version = "2.0.6", optional = true }
solana-client = { version = "1.4.4", optional = true }

81
cli/src/dev/faucet.rs Normal file
View File

@ -0,0 +1,81 @@
use anyhow::{anyhow, Result};
use serum_common::client::rpc;
use serum_context::Context;
use solana_client::rpc_config::RpcSendTransactionConfig;
use solana_sdk::commitment_config::CommitmentConfig;
use solana_sdk::instruction::{AccountMeta, Instruction};
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::Signer;
use solana_sdk::sysvar;
use solana_sdk::transaction::Transaction;
const FAUCET_SIZE: usize = 77;
// `admin` must be the current mint authority.
//
// Faucet program here:
//
// https://github.com/paul-schaaf/spl-token-faucet/blob/main/src/program/src/instruction.rs.
pub fn create(ctx: &Context, mint: Pubkey, amount: u64, admin: Pubkey) -> Result<Pubkey> {
let faucet_pid = ctx.faucet_pid.ok_or(anyhow!("faucet not provided"))?;
let faucet = rpc::create_account_rent_exempt(
&ctx.rpc_client(),
&ctx.wallet()?,
FAUCET_SIZE,
&faucet_pid,
)?
.pubkey();
let ixs = {
let (faucet_pda, _nonce) =
Pubkey::find_program_address(&["faucet".to_string().as_bytes()], &faucet_pid);
let set_auth_ix = spl_token::instruction::set_authority(
&spl_token::ID,
&mint,
Some(&faucet_pda),
spl_token::instruction::AuthorityType::MintTokens,
&admin,
&[],
)?;
let create_faucet_ix = {
let accounts = vec![
AccountMeta::new_readonly(mint, false),
AccountMeta::new(faucet, false),
AccountMeta::new(sysvar::rent::ID, false),
AccountMeta::new_readonly(admin, false),
];
let mut data = vec![0];
data.extend_from_slice(&amount.to_le_bytes());
Instruction {
program_id: faucet_pid,
data,
accounts,
}
};
[set_auth_ix, create_faucet_ix]
};
let _tx = {
let client = ctx.rpc_client();
let payer = ctx.wallet()?;
let (recent_hash, _fee_calc) = client.get_recent_blockhash()?;
let tx =
Transaction::new_signed_with_payer(&ixs, Some(&payer.pubkey()), &[&payer], recent_hash);
let sig = client.send_and_confirm_transaction_with_spinner_and_config(
&tx,
CommitmentConfig::single(),
RpcSendTransactionConfig {
skip_preflight: true,
..RpcSendTransactionConfig::default()
},
)?;
sig
};
Ok(faucet)
}

View File

@ -13,11 +13,16 @@ use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::Signer; use solana_sdk::signature::Signer;
use std::num::NonZeroU64; use std::num::NonZeroU64;
mod faucet;
#[derive(Debug, Clap)] #[derive(Debug, Clap)]
pub enum Command { pub enum Command {
/// Creates 1) SRM mint, 2) MSRM mint 3) SRM funded token account, and /// Creates 1) SRM mint, 2) MSRM mint 3) SRM funded token account, and
/// 4) MSRM funded token account, all owned by the configured wallet. /// 4) MSRM funded token account, all owned by the configured wallet.
InitMint, InitMint {
#[clap(short, long)]
faucet: bool,
},
AllocateAccount { AllocateAccount {
#[clap(short, long)] #[clap(short, long)]
program_id: Pubkey, program_id: Pubkey,
@ -34,7 +39,7 @@ pub enum Command {
pub fn run(ctx: Context, cmd: Command) -> Result<()> { pub fn run(ctx: Context, cmd: Command) -> Result<()> {
match cmd { match cmd {
Command::InitMint => init_mint(&ctx), Command::InitMint { faucet } => init_mint(&ctx, faucet),
Command::AllocateAccount { program_id, size } => allocate_account(&ctx, program_id, size), Command::AllocateAccount { program_id, size } => allocate_account(&ctx, program_id, size),
Command::GenerateOrders { Command::GenerateOrders {
coin_wallet, coin_wallet,
@ -43,7 +48,7 @@ pub fn run(ctx: Context, cmd: Command) -> Result<()> {
} }
} }
fn init_mint(ctx: &Context) -> Result<()> { fn init_mint(ctx: &Context, faucet: bool) -> Result<()> {
// Doesn't matter. // Doesn't matter.
let program_id = Pubkey::new_from_array([0; 32]).to_string(); let program_id = Pubkey::new_from_array([0; 32]).to_string();
let payer_filepath = &ctx.wallet_path.to_string(); let payer_filepath = &ctx.wallet_path.to_string();
@ -51,13 +56,22 @@ fn init_mint(ctx: &Context) -> Result<()> {
std::env::set_var(serum_common_tests::TEST_PROGRAM_ID, program_id); std::env::set_var(serum_common_tests::TEST_PROGRAM_ID, program_id);
std::env::set_var(serum_common_tests::TEST_PAYER_FILEPATH, payer_filepath); std::env::set_var(serum_common_tests::TEST_PAYER_FILEPATH, payer_filepath);
std::env::set_var(serum_common_tests::TEST_CLUSTER, cluster); std::env::set_var(serum_common_tests::TEST_CLUSTER, cluster);
let (_client, g) = serum_common_tests::genesis::<Client>(); let (client, g) = serum_common_tests::genesis::<Client>();
let (srm_faucet, msrm_faucet) = match faucet {
false => (None, None),
true => {
let srm_faucet =
faucet::create(ctx, g.srm_mint, 1_000_000_000_000, client.payer().pubkey())?;
let msrm_faucet =
faucet::create(ctx, g.msrm_mint, 1_000_000_000_000, client.payer().pubkey())?;
(Some(srm_faucet), Some(msrm_faucet))
}
};
println!( println!(
"{}", "{}",
serde_json::json!({ serde_json::json!({
"wallet": g.wallet.to_string(), "wallet": g.wallet.to_string(),
"mintAuthority": g.mint_authority.to_string(),
"srmMint": g.srm_mint.to_string(), "srmMint": g.srm_mint.to_string(),
"msrmMint": g.msrm_mint.to_string(), "msrmMint": g.msrm_mint.to_string(),
"god": g.god.to_string(), "god": g.god.to_string(),
@ -65,6 +79,14 @@ fn init_mint(ctx: &Context) -> Result<()> {
"godBalanceBefore": g.god_balance_before, "godBalanceBefore": g.god_balance_before,
"godMsrmBalanceBefore": g.god_msrm_balance_before, "godMsrmBalanceBefore": g.god_msrm_balance_before,
"godOwner": g.god_owner.to_string(), "godOwner": g.god_owner.to_string(),
"srmFaucet": match srm_faucet {
None => "null".to_string(),
Some(f) => f.to_string(),
},
"msrmFaucet": match msrm_faucet {
None => "null".to_string(),
Some(f) => f.to_string(),
}
}) })
); );

View File

@ -32,7 +32,7 @@ impl FromStr for Cluster {
"l" | "localnet" => Ok(Cluster::Localnet), "l" | "localnet" => Ok(Cluster::Localnet),
"g" | "debug" => Ok(Cluster::Debug), "g" | "debug" => Ok(Cluster::Debug),
_ => Err(anyhow::Error::msg( _ => Err(anyhow::Error::msg(
"Cluster must be one of [testnet, mainnet, devnet] or be an http or https url\n", "Cluster must be one of [localnet, testnet, mainnet, devnet] or be an http or https url\n",
)), )),
} }
} }

View File

@ -26,6 +26,7 @@ pub struct Context {
pub meta_entity_pid: Pubkey, pub meta_entity_pid: Pubkey,
pub lockup_pid: Pubkey, pub lockup_pid: Pubkey,
pub dex_pid: Pubkey, pub dex_pid: Pubkey,
pub faucet_pid: Option<Pubkey>,
} }
impl Context { impl Context {
@ -85,6 +86,7 @@ struct Programs {
pub meta_entity_pid: String, pub meta_entity_pid: String,
pub lockup_pid: String, pub lockup_pid: String,
pub dex_pid: String, pub dex_pid: String,
pub faucet_pid: Option<String>,
} }
impl Config { impl Config {
@ -98,11 +100,20 @@ impl Config {
impl TryFrom<Config> for Context { impl TryFrom<Config> for Context {
type Error = anyhow::Error; type Error = anyhow::Error;
fn try_from(cfg: Config) -> std::result::Result<Self, anyhow::Error> { fn try_from(cfg: Config) -> std::result::Result<Self, anyhow::Error> {
Ok(Self { let cluster = cfg
cluster: cfg
.network .network
.cluster .cluster
.map_or(Ok(Default::default()), |c| c.parse())?, .map_or(Ok(Default::default()), |c| c.parse())?;
let faucet_pid = cfg
.programs
.faucet_pid
.or_else(|| match &cluster {
Cluster::Devnet => Some("4bXpkKSV8swHSnwqtzuboGPaPDeEgAn4Vt8GfarV5rZt".to_string()),
_ => None,
})
.map(|f| f.parse().unwrap());
Ok(Self {
cluster,
wallet_path: cfg wallet_path: cfg
.wallet_path .wallet_path
.map_or(Default::default(), |p| WalletPath(p)), .map_or(Default::default(), |p| WalletPath(p)),
@ -114,6 +125,7 @@ impl TryFrom<Config> for Context {
lockup_pid: cfg.programs.lockup_pid.parse()?, lockup_pid: cfg.programs.lockup_pid.parse()?,
meta_entity_pid: cfg.programs.meta_entity_pid.parse()?, meta_entity_pid: cfg.programs.meta_entity_pid.parse()?,
dex_pid: cfg.programs.dex_pid.parse()?, dex_pid: cfg.programs.dex_pid.parse()?,
faucet_pid,
}) })
} }
} }

View File

@ -6,10 +6,39 @@
# Does deployment + initialization of all programs and accounts needed to run # Does deployment + initialization of all programs and accounts needed to run
# the staking + lockup application. # the staking + lockup application.
# #
# Usage:
#
# ./scripts/deploy-staking.sh <localnet | devnet | mainnet>
#
################################################################################ ################################################################################
CLUSTER=l set -euox pipefail
#CLUSTER=devnet
CLUSTER=$1
if [ "$CLUSTER" = "devnet" ]; then
echo "Deploying to Devnet..."
FAUCET_FLAG="--faucet"
CONFIG_FILE=~/.config/serum/cli/devnet.yaml
CLUSTER_URL="https://devnet.solana.com"
elif [ "$CLUSTER" = "mainnet" ]; then
echo "Deploying to Mainnet..."
FAUCET_FLAG=""
CONFIG_FILE=~/.config/serum/cli/mainnet.yaml
CLUSTER_URL="https://api.mainnet-beta.solana.com"
elif [ "$CLUSTER" = "localnet" ]; then
echo "Deploying to Localnet..."
FAUCET_FLAG=""
CONFIG_FILE=~/.config/serum/cli/localnet.yaml
CLUSTER_URL="http://localhost:8899"
else
echo "Invalid cluster"
exit 1
fi
#
# Seconds.
#
DEACTIVATION_TIMELOCK=60 DEACTIVATION_TIMELOCK=60
WITHDRAWAL_TIMELOCK=60 WITHDRAWAL_TIMELOCK=60
# #
@ -24,8 +53,9 @@ STAKE_RATE=1000000
# 1 MSRM (0 decimals) to stake. # 1 MSRM (0 decimals) to stake.
# #
STAKE_RATE_MEGA=1 STAKE_RATE_MEGA=1
#
CONFIG_FILE=~/.config/serum/cli/dev.yaml # Must be built with the `dev` feature on.
#
serum=$(pwd)/target/debug/serum serum=$(pwd)/target/debug/serum
main() { main() {
@ -40,6 +70,7 @@ main() {
# #
# Build all programs. # Build all programs.
# #
echo "Building all programs..."
make -s -C lockup build make -s -C lockup build
make -s -C registry build make -s -C registry build
make -s -C registry/meta-entity build make -s -C registry/meta-entity build
@ -49,34 +80,51 @@ main() {
# #
# Deploy all the programs. # Deploy all the programs.
# #
local pids=$(make -s -C registry deploy-all) echo "Deploying all programs..."
local rewards_pids=$(make -s -C registry/rewards deploy-all) local pids=$(TEST_CLUSTER="$CLUSTER" TEST_CLUSTER_URL="$CLUSTER_URL" make -s -C registry deploy-all)
local rewards_pids=$(TEST_CLUSTER="$CLUSTER" TEST_CLUSTER_URL="$CLUSTER_URL" make -s -C registry/rewards deploy-all)
local registry_pid=$(echo $pids | jq .registryProgramId -r) local registry_pid=$(echo $pids | jq .registryProgramId -r)
local lockup_pid=$(echo $pids | jq .lockupProgramId -r) local lockup_pid=$(echo $pids | jq .lockupProgramId -r)
local meta_entity_pid=$(echo $pids | jq .metaEntityProgramId -r) local meta_entity_pid=$(echo $pids | jq .metaEntityProgramId -r)
local dex_pid=$(echo $rewards_pids | jq .dexProgramId -r)
local rewards_pid=$(echo $rewards_pids | jq .rewardsProgramId -r) local rewards_pid=$(echo $rewards_pids | jq .rewardsProgramId -r)
local dex_pid=$(echo $rewards_pids | jq .dexProgramId -r)
# #
# Generate genesis state. # Generate genesis state. Use dummy accounts, if needed.
# #
local genesis=$($serum dev init-mint) local srm_mint="SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt"
local msrm_mint="MSRMcoVyrFxnSgo5uXwone5SKcGhT1KEJMFEkMEWf9L"
local god="FhmUh2PEpTzUwBWPt4qgDBeqfmb2ES3T64CkT1ZiktSS" # Dummy.
local god_msrm="FhmUh2PEpTzUwBWPt4qgDBeqfmb2ES3T64CkT1ZiktSS" # Dummy.
local srm_faucet="None"
local msrm_faucet="None"
if [ "$CLUSTER" != "mainnet" ]; then
echo "Genesis initialization..."
genesis=$($serum --config $CONFIG_FILE dev init-mint $FAUCET_FLAG)
local srm_mint=$(echo $genesis | jq .srmMint -r) srm_mint=$(echo $genesis | jq .srmMint -r)
local msrm_mint=$(echo $genesis | jq .msrmMint -r) msrm_mint=$(echo $genesis | jq .msrmMint -r)
local god=$(echo $genesis | jq .god -r) god=$(echo $genesis | jq .god -r)
local god_msrm=$(echo $genesis | jq .godMsrm -r) god_msrm=$(echo $genesis | jq .godMsrm -r)
srm_faucet=$(echo $genesis | jq .srmFaucet -r)
msrm_faucet=$(echo $genesis | jq .msrmFaucet -r)
fi
# #
# Write out the CLI configuration file. # Write out the CLI configuration file.
# #
echo "Writing config $CONFIG_FILE..."
mkdir -p $(dirname $CONFIG_FILE) mkdir -p $(dirname $CONFIG_FILE)
cat << EOM > $CONFIG_FILE cat << EOM > $CONFIG_FILE
--- ---
network: network:
cluster: $CLUSTER cluster: $CLUSTER
#
# SRM Faucet: $srm_faucet
# MSRM Faucet: $msrm_faucet
#
mints: mints:
srm: $srm_mint srm: $srm_mint
msrm: $msrm_mint msrm: $msrm_mint
@ -87,11 +135,13 @@ programs:
meta_entity_pid: $meta_entity_pid meta_entity_pid: $meta_entity_pid
lockup_pid: $lockup_pid lockup_pid: $lockup_pid
dex_pid: $dex_pid dex_pid: $dex_pid
EOM EOM
# #
# Now intialize all the accounts. # Now intialize all the accounts.
# #
echo "Initializing registrar..."
local rInit=$($serum --config $CONFIG_FILE \ local rInit=$($serum --config $CONFIG_FILE \
registry init \ registry init \
--deactivation-timelock $DEACTIVATION_TIMELOCK \ --deactivation-timelock $DEACTIVATION_TIMELOCK \
@ -104,6 +154,7 @@ EOM
local registrar_nonce=$(echo $rInit | jq .nonce -r) local registrar_nonce=$(echo $rInit | jq .nonce -r)
local reward_q=$(echo $rInit | jq .rewardEventQueue -r) local reward_q=$(echo $rInit | jq .rewardEventQueue -r)
echo "Initializing lockup..."
local lInit=$($serum --config $CONFIG_FILE \ local lInit=$($serum --config $CONFIG_FILE \
lockup initialize) lockup initialize)
@ -113,6 +164,7 @@ EOM
# Initialize a node entity. Hack until we separate joining entities # Initialize a node entity. Hack until we separate joining entities
# from creating member accounts. # from creating member accounts.
# #
echo "Creating the default node entity..."
local createEntity=$($serum --config $CONFIG_FILE \ local createEntity=$($serum --config $CONFIG_FILE \
registry create-entity \ registry create-entity \
--registrar $registrar \ --registrar $registrar \
@ -125,6 +177,7 @@ EOM
# #
# Add the registry to the lockup program whitelist. # Add the registry to the lockup program whitelist.
# #
echo "Adding registry to the lockup whitelist..."
$serum --config $CONFIG_FILE \ $serum --config $CONFIG_FILE \
lockup gov \ lockup gov \
--safe $safe \ --safe $safe \
@ -136,6 +189,7 @@ EOM
# #
# Log the generated TypeScript. # Log the generated TypeScript.
# #
set +e
read -r -d '' VAR << EOM read -r -d '' VAR << EOM
{ {
srm: new PublicKey('${srm_mint}'), srm: new PublicKey('${srm_mint}'),