Add account creation to node setup tutorial (#78)
This commit is contained in:
parent
b202b8f8ee
commit
a51d6e8d65
|
@ -3123,6 +3123,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 3.0.0-beta.2",
|
||||
"serde_json",
|
||||
"serum-context",
|
||||
"serum-registry-rewards-client",
|
||||
"solana-client-gen",
|
||||
|
|
|
@ -27,6 +27,9 @@ pub struct Context {
|
|||
pub lockup_pid: Pubkey,
|
||||
pub dex_pid: Pubkey,
|
||||
pub faucet_pid: Option<Pubkey>,
|
||||
pub registrar: Pubkey,
|
||||
pub safe: Pubkey,
|
||||
pub rewards_instance: Pubkey,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
|
@ -66,6 +69,7 @@ struct Config {
|
|||
pub network: Network,
|
||||
pub mints: Mints,
|
||||
pub programs: Programs,
|
||||
pub accounts: Option<Accounts>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
|
@ -89,6 +93,13 @@ struct Programs {
|
|||
pub faucet_pid: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
struct Accounts {
|
||||
pub registrar: String,
|
||||
pub safe: String,
|
||||
pub rewards_instance: String,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
fn from(path: &str) -> Result<Self> {
|
||||
let rdr = fs::File::open(path)?;
|
||||
|
@ -126,6 +137,18 @@ impl TryFrom<Config> for Context {
|
|||
meta_entity_pid: cfg.programs.meta_entity_pid.parse()?,
|
||||
dex_pid: cfg.programs.dex_pid.parse()?,
|
||||
faucet_pid,
|
||||
registrar: cfg
|
||||
.accounts
|
||||
.as_ref()
|
||||
.map_or(Ok(Default::default()), |a| a.registrar.parse::<Pubkey>())?,
|
||||
safe: cfg
|
||||
.accounts
|
||||
.as_ref()
|
||||
.map_or(Ok(Default::default()), |a| a.safe.parse())?,
|
||||
rewards_instance: cfg
|
||||
.accounts
|
||||
.as_ref()
|
||||
.map_or(Ok(Default::default()), |a| a.rewards_instance.parse())?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -210,9 +210,6 @@ pub enum Command {
|
|||
|
||||
#[derive(Debug, Clap, Clone)]
|
||||
pub struct RewardsContext {
|
||||
/// Account controlling the rewards vault for crankers.
|
||||
#[clap(long = "rewards.instance")]
|
||||
pub instance: Pubkey,
|
||||
/// Token account rewards are sent to when cranking.
|
||||
#[clap(long = "rewards.receiver")]
|
||||
pub receiver: Pubkey,
|
||||
|
@ -220,6 +217,8 @@ pub struct RewardsContext {
|
|||
#[clap(long = "rewards.registry-entity")]
|
||||
pub registry_entity: Pubkey,
|
||||
#[clap(skip)]
|
||||
pub instance: Pubkey,
|
||||
#[clap(skip)]
|
||||
pub url: String,
|
||||
#[clap(skip)]
|
||||
pub program_id: Pubkey,
|
||||
|
@ -337,6 +336,7 @@ pub fn start(ctx: Option<Context>, opts: Opts) -> Result<()> {
|
|||
let ctx = ctx.expect("context must exist when consuming rewards");
|
||||
r_ctx.url = opts.cluster.url().to_string();
|
||||
r_ctx.program_id = ctx.rewards_pid;
|
||||
r_ctx.instance = ctx.rewards_instance;
|
||||
init_logger(log_directory);
|
||||
|
||||
// Unused by the DEX. Nevertheless required to be passed in.
|
||||
|
|
|
@ -9,17 +9,13 @@ when their node has at least 1 MSRM staked. These "cranking rewards"
|
|||
are effectively transaction fees earned for operating the DEX.
|
||||
|
||||
For an introduction to the DEX and the idea of cranking, see
|
||||
[A technical introduction to the Serum DEX](https://docs.google.com/document/d/1isGJES4jzQutI0GtQGuqtrBUqeHxl_xJNXdtOv4SdII/edit).
|
||||
[A technical introduction to the Serum DEX](https://docs.google.com/document/d/1isGJES4jzQutI0GtQGuqtrBUqeHxl_xJNXdtOv4SdII/edit). For an introduction to staking, see [Serum Staking](./staking.md).
|
||||
|
||||
The way cranking rewards work is simple, instead of sending transactions directly to the DEX,
|
||||
a cranker sends transactions to a cranking rewards vendor, which is an on-chain
|
||||
Solana program that proxies all requests to the DEX, recording the amount of events
|
||||
cranked, and then sends a reward to the cranker's wallet as a function of the number
|
||||
of events processed and the reward vendor's fee rate.
|
||||
|
||||
(Note that, although similar in spirit, the cranking rewards vendor is an entirely different
|
||||
program and account from the **Registry**'s reward vendors. Only node leaders are eligible
|
||||
to crank.)
|
||||
of events processed and the reward vendor's fee rate. This proxy program can be found [here](../registry/rewards/program).
|
||||
|
||||
If the rewards vendor's vault becomes empty or if the node leader's Entity stake
|
||||
balance ever transitions to **inactive**, then the vendor will refuse to pay
|
||||
|
@ -39,7 +35,6 @@ sudo apt-get install -y pkg-config build-essential python3-pip jq
|
|||
|
||||
## Install the CLI
|
||||
|
||||
The CLI is a work in progress, so there's not yet a proper installer.
|
||||
For now, we can use Cargo.
|
||||
|
||||
```bash
|
||||
|
@ -50,30 +45,7 @@ To verify the installation worked, run `serum -h`.
|
|||
|
||||
## Setup your CLI Config
|
||||
|
||||
Add your YAML config for Mainnet Beta at `~/.config/serum/cli/config.yaml`.
|
||||
|
||||
For Mainnet Beta
|
||||
|
||||
```yaml
|
||||
---
|
||||
network:
|
||||
cluster: mainnet
|
||||
|
||||
mints:
|
||||
srm: SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt
|
||||
msrm: MSRMcoVyrFxnSgo5uXwone5SKcGhT1KEJMFEkMEWf9L
|
||||
|
||||
programs:
|
||||
rewards_pid: 8xYo1X6uw7SBngXgPzib8jghWb8BhiiVxv5yV799Tw3G
|
||||
registry_pid: Gw1XNGbSnx7PJcHTTuxxhWfkjjPmq29Qkv1hWbVFnrDp
|
||||
meta_entity_pid: 9etE5ZjHZTrZ2wQfyfTSp5WBxjpvaakNJa5fSVToZn17
|
||||
lockup_pid: 6GSn1woRF541HaiEWqNofYn8quzJuRBPi1nwoho8zNnh
|
||||
dex_pid: EUqojwWA2rd19FZrzeBncJsm38Jm1hEhE3zsmX3bRc2o
|
||||
```
|
||||
|
||||
When operating over multiple networks, you can specify your config file with the
|
||||
`serum --config <path>` option. For example, one might want to test
|
||||
against Devnet with the following config
|
||||
Add your YAML config for Devnet at `~/.config/serum/cli/config.yaml`.
|
||||
|
||||
```yaml
|
||||
---
|
||||
|
@ -81,35 +53,83 @@ network:
|
|||
cluster: devnet
|
||||
|
||||
mints:
|
||||
srm: 5ya5rnzm5MkvCXhLDCJqAUzT16A37ks2DekkfoNnwNMn
|
||||
msrm: 3fHm9sEBS3CukUX366mwzn3YwEc5zWNzR4JcGK6EVQad
|
||||
srm: Bap9SwT53SjGPeKq4LAC6i86fCzEzUGGHsYfRiCFSGyF
|
||||
msrm: CmtL8e86367ZLiAuJELx4WqmDz7dRnD1oyaiq4TQDdEU
|
||||
|
||||
programs:
|
||||
rewards_pid: EXzpf5GBfUQkwLeLEJXLmVKxGpxyMQWxpudYxogW4ad8
|
||||
registry_pid: 3ofaHrxu7RdqH8m1wXfVrsTqgwctmx2NsHPv6m7oh1dy
|
||||
meta_entity_pid: 8v8hwdeyBhmV4y235F9XQ7g5Vz2EYvJTkGqTfrh3Hz5f
|
||||
lockup_pid: Az4dD6YeA4akzz4Qx3RuQqaCtLEaDiBT8u7mDL24sbAu
|
||||
dex_pid: DiDDva9iDSXTtJ4CeWXbKdDvQ3M6g5G87PZGUGvxi3eV
|
||||
rewards_pid: 7sXyzeu6GJqkXZz8VhjdsXvDg1xR1PEkXbbDaxMc186C
|
||||
registry_pid: CKKz2WYvneiLb2mzouWc4iPpKisuXs5XKYn7ZUrRjkeK
|
||||
meta_entity_pid: BsVgsh8mqi3qn8eKRiye1a4eF8Qwqot8p2n3ZMNdL2UY
|
||||
lockup_pid: 8wreDpv5nuY1gee1X4wkqtRkzoGypVYzWBrMmzipAJKN
|
||||
dex_pid: 9MVDeYQnJmN2Dt7H44Z8cob4bET2ysdNu2uFJcatDJno
|
||||
|
||||
accounts:
|
||||
registrar: 7Tzf4D4BU1tzwitXbHeUf7bwMNSSVQXfzPsgnbM5RY7d
|
||||
safe: CxiGCt8kVm5BuzmWycJdZwXsYt52iLB8Huty5r1xRvRZ
|
||||
rewards_instance: 32qFc9QWX4wBU6EFZ9FzyxGthSHNwCUKaN7APn3GAH2X
|
||||
```
|
||||
|
||||
## Cranking a market
|
||||
If not specified, the `wallet` key will be searched for in the standard location:
|
||||
`~/.config/solana/id.json` and used as the **payer** for all transactions initiated
|
||||
by the CLI.
|
||||
|
||||
## Create an Entity
|
||||
|
||||
An **Entity** is the on-chain Solana account representing a node and
|
||||
it's collective **Member** accounts.
|
||||
|
||||
To create an **Entity** with the **Registrar**, run
|
||||
|
||||
```bash
|
||||
serum registry create-entity --name <string> --about <string>
|
||||
```
|
||||
|
||||
Entering your node's `name` and `about` info, which can be displayed in UIs. Note that, by default,
|
||||
the wallet creating the entity will be tagged as the node leader, which is the address eligible for
|
||||
earning crank rewards.
|
||||
|
||||
## Create a Member
|
||||
|
||||
After creating a node entity, use your new **Entity** address to create a member account, which will
|
||||
allow you to stake.
|
||||
|
||||
```bash
|
||||
serum registry create-member --entity <address>
|
||||
```
|
||||
|
||||
## Activate your Node
|
||||
|
||||
Once created, one must "activate" a node by staking MSRM before being able to earn rewards. Any **Member**
|
||||
associated with the **Entity** can stake this MSRM.
|
||||
|
||||
For now, it's recommended to do this through the UI at https://project-serum.github.io/serum-ts/stake-ui,
|
||||
where you can
|
||||
|
||||
* Select a network.
|
||||
* Connect your wallet.
|
||||
* Deposit 1 MSRM into your **Member** account via the **Deposit** button. If you're on Devnet,
|
||||
[airdrop](https://www.spl-token-ui.com/#/token-faucets) yourself tokens. The faucet address can be found in the **Environment** tab of the UI.
|
||||
* Stake the newly deposited 1 MSRM via the **Stake** tab into the **Mega Stake Pool**.
|
||||
|
||||
You should see that your Entity is now in the `Active` state making it eligible for rewards.
|
||||
|
||||
## Cranking a Market
|
||||
|
||||
Finally you can run your crank. Pick a market and run
|
||||
|
||||
```bash
|
||||
serum crank consume-event-rewards \
|
||||
--market <address> \
|
||||
--log-directory <path> \
|
||||
--rewards.receiver <address> \
|
||||
--rewards.registry-entity <address> \
|
||||
--rewards.instance <address>
|
||||
serum crank consume-event-rewards \
|
||||
--market <address> \
|
||||
--log-directory <path> \
|
||||
--rewards.receiver <address> \
|
||||
--rewards.registry-entity <address>
|
||||
```
|
||||
|
||||
If the given `--rewards.registry-entity` is properly staked, and if the given
|
||||
`--rewards.instance` is funded, then you should see your token account
|
||||
If the given `--rewards.registry-entity` is properly staked, and if the configured
|
||||
rewards `instance` is funded, then you should see your SPL token account
|
||||
`--rewards.receiver` start to receive rewards with each event consumed.
|
||||
|
||||
## Finding a market to crank
|
||||
## Finding a Market to Crank
|
||||
|
||||
You can crank any market of your choosing. To find all market addresses one can use the `getProgramAccounts`
|
||||
API exposed by the Solana JSON RPC. In python,
|
||||
|
@ -133,3 +153,31 @@ def find_market_addresses(program_id: str):
|
|||
}).json()
|
||||
return [info['pubkey'] for info in resp['result']]
|
||||
```
|
||||
|
||||
## Switching to Mainnet Beta
|
||||
|
||||
When operating over multiple networks, you can specify your config file with the
|
||||
`serum --config <path>` option. For example, when switching to Mainnet Beta,
|
||||
one can use the following config.
|
||||
|
||||
```yaml
|
||||
---
|
||||
network:
|
||||
cluster: mainnet
|
||||
|
||||
mints:
|
||||
srm: SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt
|
||||
msrm: MSRMcoVyrFxnSgo5uXwone5SKcGhT1KEJMFEkMEWf9L
|
||||
|
||||
programs:
|
||||
rewards_pid: 4bcHoAgLP9NBje1oVo9WKRDYkvSxcqtJeTSXMRFX5AdZ
|
||||
registry_pid: 6J7ZoSxtKJUjVLpGRcBrEtvE2T3YVf9mfKUaicndzpCc
|
||||
meta_entity_pid: 68gpi9be8NNVTDViQxSYtbM1788uebczX2Vz7obSnQRz
|
||||
lockup_pid: 4nvqpaMz7H12VgHSABjEDFmH62MoWP3BxfMG3BAFQiBo
|
||||
dex_pid: EUqojwWA2rd19FZrzeBncJsm38Jm1hEhE3zsmX3bRc2o
|
||||
|
||||
accounts:
|
||||
registrar: 8ZS85GGfa92JH6vrmpy8fgQQEBLWwYUwWmpBhcA94fDH
|
||||
safe: Dp5zzdTLnYNq9E6H81YQu1ucNLK3FzH3Ah3KedydiNgE
|
||||
rewards_instance: BX1aNRFES78bz9G8GJWmrYSkRVWcV5wdnvSWfXJhTEkE
|
||||
```
|
||||
|
|
|
@ -30,9 +30,6 @@ pub enum Command {
|
|||
},
|
||||
/// Creates a node entity, setting the active wallet as leader.
|
||||
CreateEntity {
|
||||
/// Registrar account address.
|
||||
#[clap(short, long)]
|
||||
registrar: Pubkey,
|
||||
#[clap(short, long)]
|
||||
name: String,
|
||||
#[clap(short, long)]
|
||||
|
@ -40,6 +37,11 @@ pub enum Command {
|
|||
#[clap(short, long)]
|
||||
image_url: Option<String>,
|
||||
},
|
||||
/// Creates a member account with the given entity.
|
||||
CreateMember {
|
||||
#[clap(short, long)]
|
||||
entity: Pubkey,
|
||||
},
|
||||
/// Updates an entity. Active wallet must be the node leader.
|
||||
UpdateEntity {
|
||||
#[clap(short, long)]
|
||||
|
@ -59,8 +61,6 @@ pub enum Command {
|
|||
token: Pubkey,
|
||||
#[clap(long)]
|
||||
vendor: Pubkey,
|
||||
#[clap(short, long)]
|
||||
registrar: Pubkey,
|
||||
},
|
||||
/// Sends all unclaimed funds from an expired locked reward vendor to a given
|
||||
/// account.
|
||||
|
@ -70,8 +70,6 @@ pub enum Command {
|
|||
token: Pubkey,
|
||||
#[clap(long)]
|
||||
vendor: Pubkey,
|
||||
#[clap(short, long)]
|
||||
registrar: Pubkey,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -126,41 +124,33 @@ pub fn run(ctx: Context, cmd: Command) -> Result<()> {
|
|||
stake_rate_mega,
|
||||
),
|
||||
Command::CreateEntity {
|
||||
registrar,
|
||||
name,
|
||||
about,
|
||||
image_url,
|
||||
} => create_entity_cmd(&ctx, registry_pid, registrar, name, about, image_url),
|
||||
} => create_entity_cmd(&ctx, registry_pid, ctx.registrar, name, about, image_url),
|
||||
Command::CreateMember { entity } => create_member_cmd(&ctx, entity),
|
||||
Command::UpdateEntity {
|
||||
name,
|
||||
about,
|
||||
image_url,
|
||||
entity,
|
||||
} => update_entity_cmd(&ctx, name, about, image_url, entity),
|
||||
Command::ExpireUnlockedReward {
|
||||
token,
|
||||
vendor,
|
||||
registrar,
|
||||
} => {
|
||||
Command::ExpireUnlockedReward { token, vendor } => {
|
||||
let client = ctx.connect::<Client>(registry_pid)?;
|
||||
let resp = client.expire_unlocked_reward(ExpireUnlockedRewardRequest {
|
||||
token,
|
||||
vendor,
|
||||
registrar,
|
||||
registrar: ctx.registrar,
|
||||
})?;
|
||||
println!("Transaction executed: {:?}", resp.tx);
|
||||
Ok(())
|
||||
}
|
||||
Command::ExpireLockedReward {
|
||||
token,
|
||||
vendor,
|
||||
registrar,
|
||||
} => {
|
||||
Command::ExpireLockedReward { token, vendor } => {
|
||||
let client = ctx.connect::<Client>(registry_pid)?;
|
||||
let resp = client.expire_locked_reward(ExpireLockedRewardRequest {
|
||||
token,
|
||||
vendor,
|
||||
registrar,
|
||||
registrar: ctx.registrar,
|
||||
})?;
|
||||
println!("Transaction executed: {:?}", resp.tx);
|
||||
Ok(())
|
||||
|
@ -195,6 +185,26 @@ fn create_entity_cmd(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn create_member_cmd(ctx: &Context, entity: Pubkey) -> Result<()> {
|
||||
let beneficiary = ctx.wallet()?;
|
||||
let client = ctx.connect::<Client>(ctx.registry_pid)?;
|
||||
// Vesting vault authority.
|
||||
let (delegate, _nonce) = Pubkey::find_program_address(
|
||||
&[ctx.safe.as_ref(), beneficiary.pubkey().as_ref()],
|
||||
&ctx.lockup_pid,
|
||||
);
|
||||
let CreateMemberResponse { member, .. } = client.create_member(CreateMemberRequest {
|
||||
entity,
|
||||
beneficiary: &beneficiary,
|
||||
delegate,
|
||||
registrar: ctx.registrar,
|
||||
})?;
|
||||
|
||||
println!("Member created: {}", member.to_string());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_entity_cmd(
|
||||
ctx: &Context,
|
||||
name: Option<String>,
|
||||
|
|
|
@ -11,3 +11,4 @@ serum-context = { path = "../../../context" }
|
|||
solana-client-gen = { path = "../../../solana-client-gen" }
|
||||
anyhow = "1.0.32"
|
||||
serum-registry-rewards-client = { path = "../client" }
|
||||
serde_json = "1.0.59"
|
|
@ -106,7 +106,10 @@ fn gov_cmd(ctx: &Context, cmd: GovCommand) -> Result<()> {
|
|||
fee_rate,
|
||||
authority: wallet.pubkey(),
|
||||
})?;
|
||||
println!("Rewards instance created: {:?}", resp.instance);
|
||||
println!(
|
||||
"{}",
|
||||
serde_json::json!({"instance": resp.instance.to_string()})
|
||||
);
|
||||
}
|
||||
GovCommand::SetAuthority {
|
||||
new_authority,
|
||||
|
|
|
@ -9,7 +9,6 @@ lazy_static::lazy_static! {
|
|||
.expect("Registrar has a fixed size");
|
||||
}
|
||||
|
||||
/// Registry defines the account representing an instance of the program.
|
||||
#[derive(Clone, Debug, Default, PartialEq, BorshSerialize, BorshDeserialize, BorshSchema)]
|
||||
pub struct Registrar {
|
||||
/// Set by the program on initialization.
|
||||
|
|
|
@ -61,6 +61,10 @@ STAKE_RATE=10000000
|
|||
#
|
||||
STAKE_RATE_MEGA=1
|
||||
#
|
||||
# Unit of srm to pay crankers.
|
||||
#
|
||||
CRANK_FEE_RATE=1
|
||||
#
|
||||
# Must be built with the `dev` feature on.
|
||||
#
|
||||
serum=$(pwd)/target/debug/serum
|
||||
|
@ -158,7 +162,7 @@ EOM
|
|||
# Now intialize all the accounts.
|
||||
#
|
||||
echo "Initializing registrar..."
|
||||
local rInit=$($serum --config $CONFIG_FILE \
|
||||
local r_init=$($serum --config $CONFIG_FILE \
|
||||
registry init \
|
||||
--deactivation-timelock $DEACTIVATION_TIMELOCK \
|
||||
--withdrawal-timelock $WITHDRAWAL_TIMELOCK \
|
||||
|
@ -166,29 +170,15 @@ EOM
|
|||
--stake-rate $STAKE_RATE \
|
||||
--stake-rate-mega $STAKE_RATE_MEGA)
|
||||
|
||||
local registrar=$(echo $rInit | jq .registrar -r)
|
||||
local registrar_nonce=$(echo $rInit | jq .nonce -r)
|
||||
local reward_q=$(echo $rInit | jq .rewardEventQueue -r)
|
||||
local registrar=$(echo $r_init | jq .registrar -r)
|
||||
local registrar_nonce=$(echo $r_init | jq .nonce -r)
|
||||
local reward_q=$(echo $r_init | jq .rewardEventQueue -r)
|
||||
|
||||
echo "Initializing lockup..."
|
||||
local lInit=$($serum --config $CONFIG_FILE \
|
||||
local l_init=$($serum --config $CONFIG_FILE \
|
||||
lockup initialize)
|
||||
|
||||
local safe=$(echo $lInit | jq .safe -r)
|
||||
|
||||
#
|
||||
# Initialize a node entity. Hack until we separate joining entities
|
||||
# from creating member accounts.
|
||||
#
|
||||
echo "Creating the default node entity..."
|
||||
local createEntity=$($serum --config $CONFIG_FILE \
|
||||
registry create-entity \
|
||||
--registrar $registrar \
|
||||
--about "This the default entity all new members join." \
|
||||
--image-url " " \
|
||||
--name "Default" )
|
||||
|
||||
local entity=$(echo $createEntity | jq .entity -r)
|
||||
local safe=$(echo $l_init | jq .safe -r)
|
||||
|
||||
#
|
||||
# Add the registry to the lockup program whitelist.
|
||||
|
@ -202,6 +192,38 @@ EOM
|
|||
--nonce $registrar_nonce \
|
||||
--program-id $registry_pid
|
||||
|
||||
#
|
||||
# Create a crank rewards instance.
|
||||
#
|
||||
local crank_rewards=$($serum --config $CONFIG_FILE rewards gov init \
|
||||
--registrar $registrar \
|
||||
--reward-mint $srm_mint \
|
||||
--fee-rate $CRANK_FEE_RATE)
|
||||
local rewards_instance=$(echo $crank_rewards | jq .instance -r)
|
||||
|
||||
#
|
||||
# Append to the previously generated config file.
|
||||
#
|
||||
cat << EOM >> $CONFIG_FILE
|
||||
accounts:
|
||||
registrar: $registrar
|
||||
safe: $safe
|
||||
rewards_instance: $rewards_instance
|
||||
EOM
|
||||
|
||||
|
||||
#
|
||||
# Initialize the default node entity.
|
||||
#
|
||||
echo "Creating the default node entity..."
|
||||
local create_entity=$($serum --config $CONFIG_FILE \
|
||||
registry create-entity \
|
||||
--about "This the default entity all new members join." \
|
||||
--image-url " " \
|
||||
--name "Default" )
|
||||
|
||||
local entity=$(echo $create_entity | jq .entity -r)
|
||||
|
||||
#
|
||||
# Log the generated TypeScript.
|
||||
#
|
||||
|
|
Loading…
Reference in New Issue