split wallet staking commands (#6168)
* split wallet staking commands * elide real home * unit->UNIT for usage * unit->UNIT, don't try to run SUBCOMMANDS: ;) * more fixup * fixups * actually check * shellcheck * preserve #6158 after rebase * fixup * test * too hard * remove test
This commit is contained in:
34
book/build-cli-usage.sh
Executable file
34
book/build-cli-usage.sh
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
usage=$(cargo -q run -p solana-cli -- -C ~/.foo --help | sed 's|'"$HOME"'|~|g')
|
||||||
|
|
||||||
|
out=${1:-src/api-reference/cli.md}
|
||||||
|
|
||||||
|
cat src/api-reference/.cli.md > "$out"
|
||||||
|
|
||||||
|
section() {
|
||||||
|
declare mark=${2:-"###"}
|
||||||
|
declare section=$1
|
||||||
|
read -r name rest <<<"$section"
|
||||||
|
|
||||||
|
printf '%s %s
|
||||||
|
' "$mark" "$name"
|
||||||
|
printf '```text
|
||||||
|
%s
|
||||||
|
```
|
||||||
|
|
||||||
|
' "$section"
|
||||||
|
}
|
||||||
|
|
||||||
|
section "$usage" >> "$out"
|
||||||
|
|
||||||
|
in_subcommands=0
|
||||||
|
while read -r subcommand rest; do
|
||||||
|
[[ $subcommand == "SUBCOMMANDS:" ]] && in_subcommands=1 && continue
|
||||||
|
if ((in_subcommands)); then
|
||||||
|
section "$(cargo -q run -p solana-cli -- help "$subcommand" | sed 's|'"$HOME"'|~|g')" "####" >> "$out"
|
||||||
|
fi
|
||||||
|
done <<<"$usage">>"$out"
|
177
book/src/api-reference/.cli.md
Normal file
177
book/src/api-reference/.cli.md
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
# solana CLI
|
||||||
|
|
||||||
|
The [solana-cli crate](https://crates.io/crates/solana-cli) provides a command-line interface tool for Solana
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Get Pubkey
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Command
|
||||||
|
$ solana address
|
||||||
|
|
||||||
|
// Return
|
||||||
|
<PUBKEY>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Airdrop SOL/Lamports
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Command
|
||||||
|
$ solana airdrop 2
|
||||||
|
|
||||||
|
// Return
|
||||||
|
"2.00000000 SOL"
|
||||||
|
|
||||||
|
// Command
|
||||||
|
$ solana airdrop 123 --lamports
|
||||||
|
|
||||||
|
// Return
|
||||||
|
"123 lamports"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Balance
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Command
|
||||||
|
$ solana balance
|
||||||
|
|
||||||
|
// Return
|
||||||
|
"3.00050001 SOL"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Confirm Transaction
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Command
|
||||||
|
$ solana confirm <TX_SIGNATURE>
|
||||||
|
|
||||||
|
// Return
|
||||||
|
"Confirmed" / "Not found" / "Transaction failed with error <ERR>"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deploy program
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Command
|
||||||
|
$ solana deploy <PATH>
|
||||||
|
|
||||||
|
// Return
|
||||||
|
<PROGRAM_ID>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Unconditional Immediate Transfer
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Command
|
||||||
|
$ solana pay <PUBKEY> 123
|
||||||
|
|
||||||
|
// Return
|
||||||
|
<TX_SIGNATURE>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Post-Dated Transfer
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Command
|
||||||
|
$ solana pay <PUBKEY> 123 \
|
||||||
|
--after 2018-12-24T23:59:00 --require-timestamp-from <PUBKEY>
|
||||||
|
|
||||||
|
// Return
|
||||||
|
{signature: <TX_SIGNATURE>, processId: <PROCESS_ID>}
|
||||||
|
```
|
||||||
|
|
||||||
|
_`require-timestamp-from` is optional. If not provided, the transaction will expect a timestamp signed by this wallet's private key_
|
||||||
|
|
||||||
|
### Authorized Transfer
|
||||||
|
|
||||||
|
A third party must send a signature to unlock the lamports.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Command
|
||||||
|
$ solana pay <PUBKEY> 123 \
|
||||||
|
--require-signature-from <PUBKEY>
|
||||||
|
|
||||||
|
// Return
|
||||||
|
{signature: <TX_SIGNATURE>, processId: <PROCESS_ID>}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Post-Dated and Authorized Transfer
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Command
|
||||||
|
$ solana pay <PUBKEY> 123 \
|
||||||
|
--after 2018-12-24T23:59 --require-timestamp-from <PUBKEY> \
|
||||||
|
--require-signature-from <PUBKEY>
|
||||||
|
|
||||||
|
// Return
|
||||||
|
{signature: <TX_SIGNATURE>, processId: <PROCESS_ID>}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Multiple Witnesses
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Command
|
||||||
|
$ solana pay <PUBKEY> 123 \
|
||||||
|
--require-signature-from <PUBKEY> \
|
||||||
|
--require-signature-from <PUBKEY>
|
||||||
|
|
||||||
|
// Return
|
||||||
|
{signature: <TX_SIGNATURE>, processId: <PROCESS_ID>}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cancelable Transfer
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Command
|
||||||
|
$ solana pay <PUBKEY> 123 \
|
||||||
|
--require-signature-from <PUBKEY> \
|
||||||
|
--cancelable
|
||||||
|
|
||||||
|
// Return
|
||||||
|
{signature: <TX_SIGNATURE>, processId: <PROCESS_ID>}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cancel Transfer
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Command
|
||||||
|
$ solana cancel <PROCESS_ID>
|
||||||
|
|
||||||
|
// Return
|
||||||
|
<TX_SIGNATURE>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Send Signature
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Command
|
||||||
|
$ solana send-signature <PUBKEY> <PROCESS_ID>
|
||||||
|
|
||||||
|
// Return
|
||||||
|
<TX_SIGNATURE>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Indicate Elapsed Time
|
||||||
|
|
||||||
|
Use the current system time:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Command
|
||||||
|
$ solana send-timestamp <PUBKEY> <PROCESS_ID>
|
||||||
|
|
||||||
|
// Return
|
||||||
|
<TX_SIGNATURE>
|
||||||
|
```
|
||||||
|
|
||||||
|
Or specify some other arbitrary timestamp:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Command
|
||||||
|
$ solana send-timestamp <PUBKEY> <PROCESS_ID> --date 2018-12-24T23:59:00
|
||||||
|
|
||||||
|
// Return
|
||||||
|
<TX_SIGNATURE>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
@ -175,12 +175,13 @@ $ solana send-timestamp <PUBKEY> <PROCESS_ID> --date 2018-12-24T23:59:00
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
### solana-cli
|
||||||
```text
|
```text
|
||||||
solana 0.12.0
|
solana-cli 0.20.0
|
||||||
|
Blockchain, Rebuilt for Scale
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
solana [FLAGS] [OPTIONS] [SUBCOMMAND]
|
solana [OPTIONS] <SUBCOMMAND>
|
||||||
|
|
||||||
FLAGS:
|
FLAGS:
|
||||||
-h, --help Prints help information
|
-h, --help Prints help information
|
||||||
@ -194,13 +195,13 @@ OPTIONS:
|
|||||||
SUBCOMMANDS:
|
SUBCOMMANDS:
|
||||||
address Get your public key
|
address Get your public key
|
||||||
airdrop Request lamports
|
airdrop Request lamports
|
||||||
authorize-voter Authorize a new vote signing keypair for the given vote account
|
|
||||||
balance Get your balance
|
balance Get your balance
|
||||||
cancel Cancel a transfer
|
cancel Cancel a transfer
|
||||||
claim-storage-reward Redeem storage reward credits
|
claim-storage-reward Redeem storage reward credits
|
||||||
cluster-version Get the version of the cluster entrypoint
|
cluster-version Get the version of the cluster entrypoint
|
||||||
confirm Confirm transaction by signature
|
confirm Confirm transaction by signature
|
||||||
create-replicator-storage-account Create a replicator storage account
|
create-replicator-storage-account Create a replicator storage account
|
||||||
|
create-stake-account Create a stake account
|
||||||
create-storage-mining-pool-account Create mining pool account
|
create-storage-mining-pool-account Create mining pool account
|
||||||
create-validator-storage-account Create a validator storage account
|
create-validator-storage-account Create a validator storage account
|
||||||
create-vote-account Create a vote account
|
create-vote-account Create a vote account
|
||||||
@ -222,12 +223,18 @@ SUBCOMMANDS:
|
|||||||
show-stake-account Show the contents of a stake account
|
show-stake-account Show the contents of a stake account
|
||||||
show-storage-account Show the contents of a storage account
|
show-storage-account Show the contents of a storage account
|
||||||
show-vote-account Show the contents of a vote account
|
show-vote-account Show the contents of a vote account
|
||||||
|
stake-authorize-staker Authorize a new stake signing keypair for the given stake account
|
||||||
|
stake-authorize-withdrawer Authorize a new withdraw signing keypair for the given stake account
|
||||||
|
uptime Show the uptime of a validator, based on epoch voting history
|
||||||
validator-info Publish/get Validator info on Solana
|
validator-info Publish/get Validator info on Solana
|
||||||
|
vote-authorize-voter Authorize a new vote signing keypair for the given vote account
|
||||||
|
vote-authorize-withdrawer Authorize a new withdraw signing keypair for the given vote account
|
||||||
withdraw-stake Withdraw the unstaked lamports from the stake account
|
withdraw-stake Withdraw the unstaked lamports from the stake account
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-address
|
||||||
```text
|
```text
|
||||||
solana-address
|
solana-address
|
||||||
Get your public key
|
Get your public key
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -243,19 +250,20 @@ OPTIONS:
|
|||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-airdrop
|
||||||
```text
|
```text
|
||||||
solana-airdrop
|
solana-airdrop
|
||||||
Request a batch of lamports
|
Request lamports
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
solana airdrop [OPTIONS] <AMOUNT> [unit]
|
solana airdrop [OPTIONS] <AMOUNT> [UNIT]
|
||||||
|
|
||||||
FLAGS:
|
FLAGS:
|
||||||
-h, --help Prints help information
|
-h, --help Prints help information
|
||||||
-V, --version Prints version information
|
-V, --version Prints version information
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
-C, --config <PATH> Configuration file to use [default: /Users/tyeraeulberg/.config/solana/wallet/config.yml]
|
-C, --config <PATH> Configuration file to use [default: ~/.config/solana/wallet/config.yml]
|
||||||
--drone-host <HOST> Drone host to use [default: the --url host]
|
--drone-host <HOST> Drone host to use [default: the --url host]
|
||||||
--drone-port <PORT> Drone port to use [default: 9900]
|
--drone-port <PORT> Drone port to use [default: 9900]
|
||||||
-u, --url <URL> JSON RPC URL for the solana cluster
|
-u, --url <URL> JSON RPC URL for the solana cluster
|
||||||
@ -263,33 +271,12 @@ OPTIONS:
|
|||||||
|
|
||||||
ARGS:
|
ARGS:
|
||||||
<AMOUNT> The airdrop amount to request (default unit SOL)
|
<AMOUNT> The airdrop amount to request (default unit SOL)
|
||||||
<unit> Specify unit to use for request and balance display [possible values: SOL, lamports]
|
<UNIT> Specify unit to use for request and balance display [possible values: SOL, lamports]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-balance
|
||||||
```text
|
```text
|
||||||
solana-authorize-voter
|
solana-balance
|
||||||
Authorize a new vote signing keypair for the given vote account
|
|
||||||
|
|
||||||
USAGE:
|
|
||||||
solana authorize-voter [OPTIONS] <VOTE ACCOUNT PUBKEY> <CURRENT VOTER KEYPAIR FILE> <NEW VOTER PUBKEY>
|
|
||||||
|
|
||||||
FLAGS:
|
|
||||||
-h, --help Prints help information
|
|
||||||
-V, --version Prints version information
|
|
||||||
|
|
||||||
OPTIONS:
|
|
||||||
-C, --config <PATH> Configuration file to use [default: ~/.config/solana/wallet/config.yml]
|
|
||||||
-u, --url <URL> JSON RPC URL for the solana cluster
|
|
||||||
-k, --keypair <PATH> /path/to/id.json
|
|
||||||
|
|
||||||
ARGS:
|
|
||||||
<VOTE ACCOUNT PUBKEY> Vote account in which to set the authorized voter
|
|
||||||
<CURRENT VOTER KEYPAIR FILE> Keypair file for the currently authorized vote signer
|
|
||||||
<NEW VOTER PUBKEY> New vote signer to authorize
|
|
||||||
```
|
|
||||||
|
|
||||||
```text
|
|
||||||
solana-balance
|
|
||||||
Get your balance
|
Get your balance
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -309,8 +296,9 @@ ARGS:
|
|||||||
<PUBKEY> The public key of the balance to check
|
<PUBKEY> The public key of the balance to check
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-cancel
|
||||||
```text
|
```text
|
||||||
solana-cancel
|
solana-cancel
|
||||||
Cancel a transfer
|
Cancel a transfer
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -329,8 +317,9 @@ ARGS:
|
|||||||
<PROCESS ID> The process id of the transfer to cancel
|
<PROCESS ID> The process id of the transfer to cancel
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-claim-storage-reward
|
||||||
```text
|
```text
|
||||||
solana-claim-storage-reward
|
solana-claim-storage-reward
|
||||||
Redeem storage reward credits
|
Redeem storage reward credits
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -350,8 +339,9 @@ ARGS:
|
|||||||
<STORAGE ACCOUNT PUBKEY> Storage account address to redeem credits for
|
<STORAGE ACCOUNT PUBKEY> Storage account address to redeem credits for
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-cluster-version
|
||||||
```text
|
```text
|
||||||
solana-cluster-version
|
solana-cluster-version
|
||||||
Get the version of the cluster entrypoint
|
Get the version of the cluster entrypoint
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -367,8 +357,9 @@ OPTIONS:
|
|||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-confirm
|
||||||
```text
|
```text
|
||||||
solana-confirm
|
solana-confirm
|
||||||
Confirm transaction by signature
|
Confirm transaction by signature
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -387,8 +378,9 @@ ARGS:
|
|||||||
<SIGNATURE> The transaction signature to confirm
|
<SIGNATURE> The transaction signature to confirm
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-create-replicator-storage-account
|
||||||
```text
|
```text
|
||||||
solana-create-replicator-storage-account
|
solana-create-replicator-storage-account
|
||||||
Create a replicator storage account
|
Create a replicator storage account
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -404,34 +396,64 @@ OPTIONS:
|
|||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
|
||||||
ARGS:
|
ARGS:
|
||||||
<STORAGE ACCOUNT OWNER PUBKEY>
|
<STORAGE ACCOUNT OWNER PUBKEY>
|
||||||
<STORAGE ACCOUNT PUBKEY>
|
<STORAGE ACCOUNT PUBKEY>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-create-stake-account
|
||||||
```text
|
```text
|
||||||
solana-create-storage-mining-pool-account
|
solana-create-stake-account
|
||||||
Create mining pool account
|
Create a stake account
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
solana create-storage-mining-pool-account [OPTIONS] <STORAGE ACCOUNT PUBKEY> <AMOUNT> [unit]
|
solana create-stake-account [OPTIONS] <STAKE ACCOUNT> <AMOUNT> [UNIT]
|
||||||
|
|
||||||
FLAGS:
|
FLAGS:
|
||||||
-h, --help Prints help information
|
-h, --help Prints help information
|
||||||
-V, --version Prints version information
|
-V, --version Prints version information
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
-C, --config <PATH> Configuration file to use [default: /Users/tyeraeulberg/.config/solana/wallet/config.yml]
|
--authorized-staker <PUBKEY> Public key of authorized staker (defaults to wallet)
|
||||||
|
--authorized-withdrawer <PUBKEY> Public key of the authorized withdrawer (defaults to wallet)
|
||||||
|
-C, --config <PATH> Configuration file to use [default:
|
||||||
|
~/.config/solana/wallet/config.yml]
|
||||||
|
--custodian <PUBKEY> Identity of the custodian (can withdraw before lockup expires)
|
||||||
|
-u, --url <URL> JSON RPC URL for the solana cluster
|
||||||
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
--lockup <SLOT> The slot height at which this account will be available for withdrawal
|
||||||
|
|
||||||
|
ARGS:
|
||||||
|
<STAKE ACCOUNT> Address of the stake account to fund (pubkey or keypair)
|
||||||
|
<AMOUNT> The amount of send to the vote account (default unit SOL)
|
||||||
|
<UNIT> Specify unit to use for request [possible values: SOL, lamports]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### solana-create-storage-mining-pool-account
|
||||||
|
```text
|
||||||
|
solana-create-storage-mining-pool-account
|
||||||
|
Create mining pool account
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
solana create-storage-mining-pool-account [OPTIONS] <STORAGE ACCOUNT PUBKEY> <AMOUNT> [UNIT]
|
||||||
|
|
||||||
|
FLAGS:
|
||||||
|
-h, --help Prints help information
|
||||||
|
-V, --version Prints version information
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
-C, --config <PATH> Configuration file to use [default: ~/.config/solana/wallet/config.yml]
|
||||||
-u, --url <URL> JSON RPC URL for the solana cluster
|
-u, --url <URL> JSON RPC URL for the solana cluster
|
||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
|
||||||
ARGS:
|
ARGS:
|
||||||
<STORAGE ACCOUNT PUBKEY> Storage mining pool account address to fund
|
<STORAGE ACCOUNT PUBKEY> Storage mining pool account address to fund
|
||||||
<AMOUNT> The amount to assign to the storage mining pool account (default unit SOL)
|
<AMOUNT> The amount to assign to the storage mining pool account (default unit SOL)
|
||||||
<unit> Specify unit to use for request [possible values: SOL, lamports]
|
<UNIT> Specify unit to use for request [possible values: SOL, lamports]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-create-validator-storage-account
|
||||||
```text
|
```text
|
||||||
solana-create-validator-storage-account
|
solana-create-validator-storage-account
|
||||||
Create a validator storage account
|
Create a validator storage account
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -447,39 +469,45 @@ OPTIONS:
|
|||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
|
||||||
ARGS:
|
ARGS:
|
||||||
<STORAGE ACCOUNT OWNER PUBKEY>
|
<STORAGE ACCOUNT OWNER PUBKEY>
|
||||||
<STORAGE ACCOUNT PUBKEY>
|
<STORAGE ACCOUNT PUBKEY>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-create-vote-account
|
||||||
```text
|
```text
|
||||||
solana-create-vote-account
|
solana-create-vote-account
|
||||||
Create a vote account
|
Create a vote account
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
solana create-vote-account [OPTIONS] <VOTE ACCOUNT PUBKEY> <VALIDATOR PUBKEY> <LAMPORTS>
|
solana create-vote-account [OPTIONS] <VOTE ACCOUNT PUBKEY> <VALIDATOR PUBKEY> <AMOUNT> [UNIT]
|
||||||
|
|
||||||
FLAGS:
|
FLAGS:
|
||||||
-h, --help Prints help information
|
-h, --help Prints help information
|
||||||
-V, --version Prints version information
|
-V, --version Prints version information
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
--commission <NUM> The commission taken on reward redemption (0-255), default: 0
|
--authorized-voter <PUBKEY> Public key of the authorized voter (defaults to vote account)
|
||||||
-C, --config <PATH> Configuration file to use [default: ~/.config/solana/wallet/config.yml]
|
--authorized-withdrawer <PUBKEY> Public key of the authorized withdrawer (defaults to wallet)
|
||||||
-u, --url <URL> JSON RPC URL for the solana cluster
|
--commission <NUM> The commission taken on reward redemption (0-255), default: 0
|
||||||
-k, --keypair <PATH> /path/to/id.json
|
-C, --config <PATH> Configuration file to use [default:
|
||||||
|
~/.config/solana/wallet/config.yml]
|
||||||
|
-u, --url <URL> JSON RPC URL for the solana cluster
|
||||||
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
|
||||||
ARGS:
|
ARGS:
|
||||||
<VOTE ACCOUNT PUBKEY> Vote account address to fund
|
<VOTE ACCOUNT PUBKEY> Vote account address to fund
|
||||||
<VALIDATOR PUBKEY> Validator that will vote with this account
|
<VALIDATOR PUBKEY> Validator that will vote with this account
|
||||||
<LAMPORTS> The amount of lamports to send to the vote account
|
<AMOUNT> The amount of send to the vote account (default unit SOL)
|
||||||
|
<UNIT> Specify unit to use for request [possible values: SOL, lamports]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-deactivate-stake
|
||||||
```text
|
```text
|
||||||
solana-deactivate-stake
|
solana-deactivate-stake
|
||||||
Deactivate the delegated stake from the stake account
|
Deactivate the delegated stake from the stake account
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
solana deactivate-stake [OPTIONS] <STAKE ACCOUNT KEYPAIR FILE> <PUBKEY>
|
solana deactivate-stake [OPTIONS] <STAKE ACCOUNT> <VOTE ACCOUNT>
|
||||||
|
|
||||||
FLAGS:
|
FLAGS:
|
||||||
-h, --help Prints help information
|
-h, --help Prints help information
|
||||||
@ -491,35 +519,35 @@ OPTIONS:
|
|||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
|
||||||
ARGS:
|
ARGS:
|
||||||
<STAKE ACCOUNT KEYPAIR FILE> Keypair file for the stake account, for signing the delegate transaction.
|
<STAKE ACCOUNT> Stake account to be deactivated.
|
||||||
<PUBKEY> The vote account to which the stake is currently delegated
|
<VOTE ACCOUNT> The vote account to which the stake is currently delegated
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-delegate-stake
|
||||||
```text
|
```text
|
||||||
solana-delegate-stake
|
solana-delegate-stake
|
||||||
Delegate stake to a vote account
|
Delegate stake to a vote account
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
solana delegate-stake [OPTIONS] <STAKE ACCOUNT KEYPAIR FILE> <VOTE ACCOUNT PUBKEY> <AMOUNT> [unit]
|
solana delegate-stake [OPTIONS] <STAKE ACCOUNT> <VOTE ACCOUNT>
|
||||||
|
|
||||||
FLAGS:
|
FLAGS:
|
||||||
-h, --help Prints help information
|
-h, --help Prints help information
|
||||||
-V, --version Prints version information
|
-V, --version Prints version information
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
-C, --config <PATH> Configuration file to use [default: /Users/tyeraeulberg/.config/solana/wallet/config.yml]
|
-C, --config <PATH> Configuration file to use [default: ~/.config/solana/wallet/config.yml]
|
||||||
-u, --url <URL> JSON RPC URL for the solana cluster
|
-u, --url <URL> JSON RPC URL for the solana cluster
|
||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
|
||||||
ARGS:
|
ARGS:
|
||||||
<STAKE ACCOUNT KEYPAIR FILE> Keypair file for the new stake account
|
<STAKE ACCOUNT> Stake account to delegate
|
||||||
<VOTE ACCOUNT PUBKEY> The vote account to which the stake will be delegated
|
<VOTE ACCOUNT> The vote account to which the stake will be delegated
|
||||||
<AMOUNT> The amount to delegate (default unit SOL)
|
|
||||||
<unit> Specify unit to use for request [possible values: SOL, lamports]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-deploy
|
||||||
```text
|
```text
|
||||||
solana-deploy
|
solana-deploy
|
||||||
Deploy a program
|
Deploy a program
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -538,8 +566,9 @@ ARGS:
|
|||||||
<PATH TO PROGRAM> /path/to/program.o
|
<PATH TO PROGRAM> /path/to/program.o
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-fees
|
||||||
```text
|
```text
|
||||||
solana-fees
|
solana-fees
|
||||||
Display current cluster fees
|
Display current cluster fees
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -555,8 +584,9 @@ OPTIONS:
|
|||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-get
|
||||||
```text
|
```text
|
||||||
solana-get
|
solana-get
|
||||||
Get wallet config settings
|
Get wallet config settings
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -575,8 +605,9 @@ ARGS:
|
|||||||
<CONFIG_FIELD> Return a specific config setting [possible values: url, keypair]
|
<CONFIG_FIELD> Return a specific config setting [possible values: url, keypair]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-get-slot
|
||||||
```text
|
```text
|
||||||
solana-get-slot
|
solana-get-slot
|
||||||
Get current slot
|
Get current slot
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -592,8 +623,9 @@ OPTIONS:
|
|||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-get-transaction-count
|
||||||
```text
|
```text
|
||||||
solana-get-transaction-count
|
solana-get-transaction-count
|
||||||
Get current transaction count
|
Get current transaction count
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -609,21 +641,34 @@ OPTIONS:
|
|||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-help
|
||||||
```text
|
```text
|
||||||
solana-pay
|
solana-help
|
||||||
|
Prints this message or the help of the given subcommand(s)
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
solana help [subcommand]...
|
||||||
|
|
||||||
|
ARGS:
|
||||||
|
<subcommand>... The subcommand whose help message to display
|
||||||
|
```
|
||||||
|
|
||||||
|
#### solana-pay
|
||||||
|
```text
|
||||||
|
solana-pay
|
||||||
Send a payment
|
Send a payment
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
solana pay [FLAGS] [OPTIONS] <PUBKEY> <AMOUNT> [--] [unit]
|
solana pay [FLAGS] [OPTIONS] <PUBKEY> <AMOUNT> [--] [UNIT]
|
||||||
|
|
||||||
FLAGS:
|
FLAGS:
|
||||||
--cancelable
|
--cancelable
|
||||||
-h, --help Prints help information
|
-h, --help Prints help information
|
||||||
-V, --version Prints version information
|
-V, --version Prints version information
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
-C, --config <PATH> Configuration file to use [default:
|
-C, --config <PATH> Configuration file to use [default:
|
||||||
/Users/tyeraeulberg/.config/solana/wallet/config.yml]
|
~/.config/solana/wallet/config.yml]
|
||||||
-u, --url <URL> JSON RPC URL for the solana cluster
|
-u, --url <URL> JSON RPC URL for the solana cluster
|
||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
--after <DATETIME> A timestamp after which transaction will execute
|
--after <DATETIME> A timestamp after which transaction will execute
|
||||||
@ -631,13 +676,14 @@ OPTIONS:
|
|||||||
--require-signature-from <PUBKEY>... Any third party signatures required to unlock the lamports
|
--require-signature-from <PUBKEY>... Any third party signatures required to unlock the lamports
|
||||||
|
|
||||||
ARGS:
|
ARGS:
|
||||||
<PUBKEY> The public key of recipient
|
<PUBKEY> The pubkey of recipient
|
||||||
<AMOUNT> The amount to send (default unit SOL)
|
<AMOUNT> The amount to send (default unit SOL)
|
||||||
<unit> Specify unit to use for request [possible values: SOL, lamports]
|
<UNIT> Specify unit to use for request [possible values: SOL, lamports]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-ping
|
||||||
```text
|
```text
|
||||||
solana-ping
|
solana-ping
|
||||||
Submit transactions sequentially
|
Submit transactions sequentially
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -648,8 +694,7 @@ FLAGS:
|
|||||||
-V, --version Prints version information
|
-V, --version Prints version information
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
-C, --config <PATH> Configuration file to use [default:
|
-C, --config <PATH> Configuration file to use [default: ~/.config/solana/wallet/config.yml]
|
||||||
~/.config/solana/wallet/config.yml]
|
|
||||||
-c, --count <NUMBER> Stop after submitting count transactions
|
-c, --count <NUMBER> Stop after submitting count transactions
|
||||||
-i, --interval <SECONDS> Wait interval seconds between submitting the next transaction [default: 2]
|
-i, --interval <SECONDS> Wait interval seconds between submitting the next transaction [default: 2]
|
||||||
-u, --url <URL> JSON RPC URL for the solana cluster
|
-u, --url <URL> JSON RPC URL for the solana cluster
|
||||||
@ -657,12 +702,13 @@ OPTIONS:
|
|||||||
-t, --timeout <SECONDS> Wait up to timeout seconds for transaction confirmation [default: 10]
|
-t, --timeout <SECONDS> Wait up to timeout seconds for transaction confirmation [default: 10]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-redeem-vote-credits
|
||||||
```text
|
```text
|
||||||
solana-redeem-vote-credits
|
solana-redeem-vote-credits
|
||||||
Redeem credits in the stake account
|
Redeem credits in the stake account
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
solana redeem-vote-credits [OPTIONS] <STAKING ACCOUNT PUBKEY> <VOTE ACCOUNT PUBKEY>
|
solana redeem-vote-credits [OPTIONS] <STAKE ACCOUNT> <VOTE ACCOUNT>
|
||||||
|
|
||||||
FLAGS:
|
FLAGS:
|
||||||
-h, --help Prints help information
|
-h, --help Prints help information
|
||||||
@ -674,12 +720,13 @@ OPTIONS:
|
|||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
|
||||||
ARGS:
|
ARGS:
|
||||||
<STAKING ACCOUNT PUBKEY> Staking account address to redeem credits for
|
<STAKE ACCOUNT> Address of the stake account in which to redeem credits
|
||||||
<VOTE ACCOUNT PUBKEY> The vote account to which the stake was previously delegated.
|
<VOTE ACCOUNT> The vote account to which the stake is currently delegated.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-send-signature
|
||||||
```text
|
```text
|
||||||
solana-send-signature
|
solana-send-signature
|
||||||
Send a signature to authorize a transfer
|
Send a signature to authorize a transfer
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -695,12 +742,13 @@ OPTIONS:
|
|||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
|
||||||
ARGS:
|
ARGS:
|
||||||
<PUBKEY> The public key of recipient
|
<PUBKEY> The pubkey of recipient
|
||||||
<PROCESS ID> The process id of the transfer to authorize
|
<PROCESS ID> The process id of the transfer to authorize
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-send-timestamp
|
||||||
```text
|
```text
|
||||||
solana-send-timestamp
|
solana-send-timestamp
|
||||||
Send a timestamp to unlock a transfer
|
Send a timestamp to unlock a transfer
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -717,12 +765,13 @@ OPTIONS:
|
|||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
|
||||||
ARGS:
|
ARGS:
|
||||||
<PUBKEY> The public key of recipient
|
<PUBKEY> The pubkey of recipient
|
||||||
<PROCESS ID> The process id of the transfer to unlock
|
<PROCESS ID> The process id of the transfer to unlock
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-set
|
||||||
```text
|
```text
|
||||||
solana-set
|
solana-set
|
||||||
Set a wallet config setting
|
Set a wallet config setting
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -738,8 +787,9 @@ OPTIONS:
|
|||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-show-account
|
||||||
```text
|
```text
|
||||||
solana-show-account
|
solana-show-account
|
||||||
Show the contents of an account
|
Show the contents of an account
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -757,19 +807,21 @@ OPTIONS:
|
|||||||
-o, --output <FILE> Write the account data to this file
|
-o, --output <FILE> Write the account data to this file
|
||||||
|
|
||||||
ARGS:
|
ARGS:
|
||||||
<ACCOUNT PUBKEY> Account public key
|
<ACCOUNT PUBKEY> Account pubkey
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-show-stake-account
|
||||||
```text
|
```text
|
||||||
solana-show-stake-account
|
solana-show-stake-account
|
||||||
Show the contents of a stake account
|
Show the contents of a stake account
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
solana show-stake-account [OPTIONS] <STAKE ACCOUNT PUBKEY>
|
solana show-stake-account [FLAGS] [OPTIONS] <STAKE ACCOUNT>
|
||||||
|
|
||||||
FLAGS:
|
FLAGS:
|
||||||
-h, --help Prints help information
|
-h, --help Prints help information
|
||||||
-V, --version Prints version information
|
--lamports Display balance in lamports instead of SOL
|
||||||
|
-V, --version Prints version information
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
-C, --config <PATH> Configuration file to use [default: ~/.config/solana/wallet/config.yml]
|
-C, --config <PATH> Configuration file to use [default: ~/.config/solana/wallet/config.yml]
|
||||||
@ -777,11 +829,12 @@ OPTIONS:
|
|||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
|
||||||
ARGS:
|
ARGS:
|
||||||
<STAKE ACCOUNT PUBKEY> Stake account public key
|
<STAKE ACCOUNT> Address of the stake account to display
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-show-storage-account
|
||||||
```text
|
```text
|
||||||
solana-show-storage-account
|
solana-show-storage-account
|
||||||
Show the contents of a storage account
|
Show the contents of a storage account
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -797,15 +850,38 @@ OPTIONS:
|
|||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
|
||||||
ARGS:
|
ARGS:
|
||||||
<STORAGE ACCOUNT PUBKEY> Storage account public key
|
<STORAGE ACCOUNT PUBKEY> Storage account pubkey
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-show-vote-account
|
||||||
```text
|
```text
|
||||||
solana-show-vote-account
|
solana-show-vote-account
|
||||||
Show the contents of a vote account
|
Show the contents of a vote account
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
solana show-vote-account [OPTIONS] <VOTE ACCOUNT PUBKEY>
|
solana show-vote-account [FLAGS] [OPTIONS] <VOTE ACCOUNT PUBKEY>
|
||||||
|
|
||||||
|
FLAGS:
|
||||||
|
-h, --help Prints help information
|
||||||
|
--lamports Display balance in lamports instead of SOL
|
||||||
|
-V, --version Prints version information
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
-C, --config <PATH> Configuration file to use [default: ~/.config/solana/wallet/config.yml]
|
||||||
|
-u, --url <URL> JSON RPC URL for the solana cluster
|
||||||
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
|
||||||
|
ARGS:
|
||||||
|
<VOTE ACCOUNT PUBKEY> Vote account pubkey
|
||||||
|
```
|
||||||
|
|
||||||
|
#### solana-stake-authorize-staker
|
||||||
|
```text
|
||||||
|
solana-stake-authorize-staker
|
||||||
|
Authorize a new stake signing keypair for the given stake account
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
solana stake-authorize-staker [OPTIONS] <STAKE ACCOUNT> <AUTHORIZE PUBKEY>
|
||||||
|
|
||||||
FLAGS:
|
FLAGS:
|
||||||
-h, --help Prints help information
|
-h, --help Prints help information
|
||||||
@ -817,11 +893,58 @@ OPTIONS:
|
|||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
|
||||||
ARGS:
|
ARGS:
|
||||||
<VOTE ACCOUNT PUBKEY> Vote account public key
|
<STAKE ACCOUNT> Stake account in which to set the authorized staker
|
||||||
|
<AUTHORIZE PUBKEY> New authorized staker
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-stake-authorize-withdrawer
|
||||||
```text
|
```text
|
||||||
solana-validator-info
|
solana-stake-authorize-withdrawer
|
||||||
|
Authorize a new withdraw signing keypair for the given stake account
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
solana stake-authorize-withdrawer [OPTIONS] <STAKE ACCOUNT> <AUTHORIZE PUBKEY>
|
||||||
|
|
||||||
|
FLAGS:
|
||||||
|
-h, --help Prints help information
|
||||||
|
-V, --version Prints version information
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
-C, --config <PATH> Configuration file to use [default: ~/.config/solana/wallet/config.yml]
|
||||||
|
-u, --url <URL> JSON RPC URL for the solana cluster
|
||||||
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
|
||||||
|
ARGS:
|
||||||
|
<STAKE ACCOUNT> Stake account in which to set the authorized withdrawer
|
||||||
|
<AUTHORIZE PUBKEY> New authorized withdrawer
|
||||||
|
```
|
||||||
|
|
||||||
|
#### solana-uptime
|
||||||
|
```text
|
||||||
|
solana-uptime
|
||||||
|
Show the uptime of a validator, based on epoch voting history
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
solana uptime [FLAGS] [OPTIONS] <VOTE ACCOUNT PUBKEY>
|
||||||
|
|
||||||
|
FLAGS:
|
||||||
|
--aggregate Aggregate uptime data across span
|
||||||
|
-h, --help Prints help information
|
||||||
|
-V, --version Prints version information
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
-C, --config <PATH> Configuration file to use [default: ~/.config/solana/wallet/config.yml]
|
||||||
|
-u, --url <URL> JSON RPC URL for the solana cluster
|
||||||
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
--span <NUM OF EPOCHS> Number of recent epochs to examine
|
||||||
|
|
||||||
|
ARGS:
|
||||||
|
<VOTE ACCOUNT PUBKEY> Vote account pubkey
|
||||||
|
```
|
||||||
|
|
||||||
|
#### solana-validator-info
|
||||||
|
```text
|
||||||
|
solana-validator-info
|
||||||
Publish/get Validator info on Solana
|
Publish/get Validator info on Solana
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
@ -842,26 +965,71 @@ SUBCOMMANDS:
|
|||||||
publish Publish Validator info on Solana
|
publish Publish Validator info on Solana
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### solana-vote-authorize-voter
|
||||||
```text
|
```text
|
||||||
solana-withdraw-stake
|
solana-vote-authorize-voter
|
||||||
Withdraw the unstaked lamports from the stake account
|
Authorize a new vote signing keypair for the given vote account
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
solana withdraw-stake [OPTIONS] <STAKE ACCOUNT KEYPAIR FILE> <DESTINATION PUBKEY> <AMOUNT> [unit]
|
solana vote-authorize-voter [OPTIONS] <VOTE ACCOUNT PUBKEY> <NEW VOTER PUBKEY>
|
||||||
|
|
||||||
FLAGS:
|
FLAGS:
|
||||||
-h, --help Prints help information
|
-h, --help Prints help information
|
||||||
-V, --version Prints version information
|
-V, --version Prints version information
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
-C, --config <PATH> Configuration file to use [default: /Users/tyeraeulberg/.config/solana/wallet/config.yml]
|
-C, --config <PATH> Configuration file to use [default: ~/.config/solana/wallet/config.yml]
|
||||||
-u, --url <URL> JSON RPC URL for the solana cluster
|
-u, --url <URL> JSON RPC URL for the solana cluster
|
||||||
-k, --keypair <PATH> /path/to/id.json
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
|
||||||
ARGS:
|
ARGS:
|
||||||
<STAKE ACCOUNT KEYPAIR FILE> Keypair file for the stake account, for signing the withdraw transaction.
|
<VOTE ACCOUNT PUBKEY> Vote account in which to set the authorized voter
|
||||||
<DESTINATION PUBKEY> The account where the lamports should be transfered
|
<NEW VOTER PUBKEY> New vote signer to authorize
|
||||||
<AMOUNT> The amount to withdraw from the stake account (default unit SOL)
|
```
|
||||||
<unit> Specify unit to use for request [possible values: SOL, lamports]
|
|
||||||
|
#### solana-vote-authorize-withdrawer
|
||||||
|
```text
|
||||||
|
solana-vote-authorize-withdrawer
|
||||||
|
Authorize a new withdraw signing keypair for the given vote account
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
solana vote-authorize-withdrawer [OPTIONS] <VOTE ACCOUNT PUBKEY> <NEW WITHDRAWER PUBKEY>
|
||||||
|
|
||||||
|
FLAGS:
|
||||||
|
-h, --help Prints help information
|
||||||
|
-V, --version Prints version information
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
-C, --config <PATH> Configuration file to use [default: ~/.config/solana/wallet/config.yml]
|
||||||
|
-u, --url <URL> JSON RPC URL for the solana cluster
|
||||||
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
|
||||||
|
ARGS:
|
||||||
|
<VOTE ACCOUNT PUBKEY> Vote account in which to set the authorized withdrawer
|
||||||
|
<NEW WITHDRAWER PUBKEY> New withdrawer to authorize
|
||||||
|
```
|
||||||
|
|
||||||
|
#### solana-withdraw-stake
|
||||||
|
```text
|
||||||
|
solana-withdraw-stake
|
||||||
|
Withdraw the unstaked lamports from the stake account
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
solana withdraw-stake [OPTIONS] <STAKE ACCOUNT> <DESTINATION ACCOUNT> <AMOUNT> [UNIT]
|
||||||
|
|
||||||
|
FLAGS:
|
||||||
|
-h, --help Prints help information
|
||||||
|
-V, --version Prints version information
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
-C, --config <PATH> Configuration file to use [default: ~/.config/solana/wallet/config.yml]
|
||||||
|
-u, --url <URL> JSON RPC URL for the solana cluster
|
||||||
|
-k, --keypair <PATH> /path/to/id.json
|
||||||
|
|
||||||
|
ARGS:
|
||||||
|
<STAKE ACCOUNT> Stake account from which to withdraw
|
||||||
|
<DESTINATION ACCOUNT> The account to which the lamports should be transfered
|
||||||
|
<AMOUNT> The amount to withdraw from the stake account (default unit SOL)
|
||||||
|
<UNIT> Specify unit to use for request [possible values: SOL, lamports]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -10,15 +10,22 @@ First create a stake account keypair with `solana-keygen`:
|
|||||||
$ solana-keygen new -o ~/validator-config/stake-keypair.json
|
$ solana-keygen new -o ~/validator-config/stake-keypair.json
|
||||||
```
|
```
|
||||||
|
|
||||||
and use the cli's `delegate-stake` command to stake your validator with 42 lamports:
|
and use the cli's `create-stake-account` and `delegate-stake` commands to stake your validator with 42 lamports:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ solana delegate-stake ~/validator-config/stake-keypair.json ~/validator-vote-keypair.json 42 lamports
|
$ solana create-stake-account ~/validator-config/stake-keypair.json 42 lamports
|
||||||
|
$ solana delegate-stake ~/validator-config/stake-keypair.json ~/validator-vote-keypair.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that stakes need to warm up, and warmup increments are applied at Epoch boundaries, so it can take an hour or more for the change to fully take effect.
|
Note that stakes need to warm up, and warmup increments are applied at Epoch boundaries, so it can take an hour or more for the change to fully take effect.
|
||||||
|
|
||||||
Assuming your node is voting, now you're up and running and generating validator rewards. You'll want to periodically redeem/claim your rewards:
|
Stakes can be re-delegated to another node at any time with the same command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ solana delegate-stake ~/validator-config/stake-keypair.json ~/some-other-validator-vote-keypair.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Assuming the node is voting, now you're up and running and generating validator rewards. You'll want to periodically redeem/claim your rewards:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ solana redeem-vote-credits ~/validator-config/stake-keypair.json ~/validator-vote-keypair.json
|
$ solana redeem-vote-credits ~/validator-config/stake-keypair.json ~/validator-vote-keypair.json
|
||||||
@ -37,4 +44,3 @@ The stake will cool down, deactivate over time. While cooling down, your stake w
|
|||||||
Note that a stake account may only be used once, so after deactivation, use the cli's `withdraw-stake` command to recover the previously staked lamports.
|
Note that a stake account may only be used once, so after deactivation, use the cli's `withdraw-stake` command to recover the previously staked lamports.
|
||||||
|
|
||||||
Be sure and redeem your credits before withdrawing all your lamports. Once the account is fully withdrawn, the account is destroyed.
|
Be sure and redeem your credits before withdrawing all your lamports. Once the account is fully withdrawn, the account is destroyed.
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::sol_to_lamports;
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
@ -43,6 +44,14 @@ pub fn pubkey_of(matches: &ArgMatches<'_>, name: &str) -> Option<Pubkey> {
|
|||||||
value_of(matches, name).or_else(|| keypair_of(matches, name).map(|keypair| keypair.pubkey()))
|
value_of(matches, name).or_else(|| keypair_of(matches, name).map(|keypair| keypair.pubkey()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn amount_of(matches: &ArgMatches<'_>, name: &str, unit: &str) -> Option<u64> {
|
||||||
|
if matches.value_of(unit) == Some("lamports") {
|
||||||
|
value_of(matches, name)
|
||||||
|
} else {
|
||||||
|
value_of(matches, name).map(sol_to_lamports)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -5,6 +5,7 @@ pub mod config;
|
|||||||
pub mod display;
|
pub mod display;
|
||||||
pub mod input_parsers;
|
pub mod input_parsers;
|
||||||
pub mod input_validators;
|
pub mod input_validators;
|
||||||
|
pub mod stake;
|
||||||
pub mod validator_info;
|
pub mod validator_info;
|
||||||
pub mod vote;
|
pub mod vote;
|
||||||
pub mod wallet;
|
pub mod wallet;
|
||||||
|
742
cli/src/stake.rs
Normal file
742
cli/src/stake.rs
Normal file
@ -0,0 +1,742 @@
|
|||||||
|
use crate::{
|
||||||
|
input_parsers::*,
|
||||||
|
input_validators::*,
|
||||||
|
wallet::{
|
||||||
|
build_balance_message, check_account_for_fee, check_unique_pubkeys,
|
||||||
|
log_instruction_custom_error, ProcessResult, WalletCommand, WalletConfig, WalletError,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||||
|
use solana_client::rpc_client::RpcClient;
|
||||||
|
use solana_sdk::{
|
||||||
|
account_utils::State, pubkey::Pubkey, signature::KeypairUtil, system_instruction::SystemError,
|
||||||
|
transaction::Transaction,
|
||||||
|
};
|
||||||
|
use solana_stake_api::{
|
||||||
|
stake_instruction::{self, StakeError},
|
||||||
|
stake_state::{Authorized, Lockup, StakeAuthorize, StakeState},
|
||||||
|
};
|
||||||
|
use solana_vote_api::vote_state::VoteState;
|
||||||
|
|
||||||
|
pub trait StakeSubCommands {
|
||||||
|
fn stake_subcommands(self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StakeSubCommands for App<'_, '_> {
|
||||||
|
fn stake_subcommands(self) -> Self {
|
||||||
|
self.subcommand(
|
||||||
|
SubCommand::with_name("create-stake-account")
|
||||||
|
.about("Create a stake account")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("stake_account_pubkey")
|
||||||
|
.index(1)
|
||||||
|
.value_name("STAKE ACCOUNT")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_pubkey_or_keypair)
|
||||||
|
.help("Address of the stake account to fund (pubkey or keypair)")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("amount")
|
||||||
|
.index(2)
|
||||||
|
.value_name("AMOUNT")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.help("The amount of send to the vote account (default unit SOL)")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("unit")
|
||||||
|
.index(3)
|
||||||
|
.value_name("UNIT")
|
||||||
|
.takes_value(true)
|
||||||
|
.possible_values(&["SOL", "lamports"])
|
||||||
|
.help("Specify unit to use for request")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("custodian")
|
||||||
|
.long("custodian")
|
||||||
|
.value_name("PUBKEY")
|
||||||
|
.takes_value(true)
|
||||||
|
.validator(is_pubkey_or_keypair)
|
||||||
|
.help("Identity of the custodian (can withdraw before lockup expires)")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("lockup")
|
||||||
|
.long("lockup")
|
||||||
|
.value_name("SLOT")
|
||||||
|
.takes_value(true)
|
||||||
|
.help("The slot height at which this account will be available for withdrawal")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("authorized_staker")
|
||||||
|
.long("authorized-staker")
|
||||||
|
.value_name("PUBKEY")
|
||||||
|
.takes_value(true)
|
||||||
|
.validator(is_pubkey_or_keypair)
|
||||||
|
.help("Public key of authorized staker (defaults to wallet)")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("authorized_withdrawer")
|
||||||
|
.long("authorized-withdrawer")
|
||||||
|
.value_name("PUBKEY")
|
||||||
|
.takes_value(true)
|
||||||
|
.validator(is_pubkey_or_keypair)
|
||||||
|
.help("Public key of the authorized withdrawer (defaults to wallet)")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("delegate-stake")
|
||||||
|
.about("Delegate stake to a vote account")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("force")
|
||||||
|
.long("force")
|
||||||
|
.takes_value(false)
|
||||||
|
.hidden(true) // Don't document this argument to discourage its use
|
||||||
|
.help("Override vote account sanity checks (use carefully!)")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("stake_account_pubkey")
|
||||||
|
.index(1)
|
||||||
|
.value_name("STAKE ACCOUNT")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_pubkey_or_keypair)
|
||||||
|
.help("Stake account to delegate")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("vote_account_pubkey")
|
||||||
|
.index(2)
|
||||||
|
.value_name("VOTE ACCOUNT")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_pubkey_or_keypair)
|
||||||
|
.help("The vote account to which the stake will be delegated")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("stake-authorize-staker")
|
||||||
|
.about("Authorize a new stake signing keypair for the given stake account")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("stake_account_pubkey")
|
||||||
|
.index(1)
|
||||||
|
.value_name("STAKE ACCOUNT")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_pubkey_or_keypair)
|
||||||
|
.help("Stake account in which to set the authorized staker")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("authorized_pubkey")
|
||||||
|
.index(2)
|
||||||
|
.value_name("AUTHORIZE PUBKEY")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_pubkey_or_keypair)
|
||||||
|
.help("New authorized staker")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("stake-authorize-withdrawer")
|
||||||
|
.about("Authorize a new withdraw signing keypair for the given stake account")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("stake_account_pubkey")
|
||||||
|
.index(1)
|
||||||
|
.value_name("STAKE ACCOUNT")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_pubkey_or_keypair)
|
||||||
|
.help("Stake account in which to set the authorized withdrawer")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("authorized_pubkey")
|
||||||
|
.index(2)
|
||||||
|
.value_name("AUTHORIZE PUBKEY")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_pubkey_or_keypair)
|
||||||
|
.help("New authorized withdrawer")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("deactivate-stake")
|
||||||
|
.about("Deactivate the delegated stake from the stake account")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("stake_account_pubkey")
|
||||||
|
.index(1)
|
||||||
|
.value_name("STAKE ACCOUNT")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.help("Stake account to be deactivated.")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("vote_account_pubkey")
|
||||||
|
.index(2)
|
||||||
|
.value_name("VOTE ACCOUNT")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_pubkey_or_keypair)
|
||||||
|
.help("The vote account to which the stake is currently delegated")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("withdraw-stake")
|
||||||
|
.about("Withdraw the unstaked lamports from the stake account")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("stake_account_pubkey")
|
||||||
|
.index(1)
|
||||||
|
.value_name("STAKE ACCOUNT")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_pubkey_or_keypair)
|
||||||
|
.help("Stake account from which to withdraw")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("destination_account_pubkey")
|
||||||
|
.index(2)
|
||||||
|
.value_name("DESTINATION ACCOUNT")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_pubkey_or_keypair)
|
||||||
|
.help("The account to which the lamports should be transfered")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("amount")
|
||||||
|
.index(3)
|
||||||
|
.value_name("AMOUNT")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.help("The amount to withdraw from the stake account (default unit SOL)")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("unit")
|
||||||
|
.index(4)
|
||||||
|
.value_name("UNIT")
|
||||||
|
.takes_value(true)
|
||||||
|
.possible_values(&["SOL", "lamports"])
|
||||||
|
.help("Specify unit to use for request")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("redeem-vote-credits")
|
||||||
|
.about("Redeem credits in the stake account")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("stake_account_pubkey")
|
||||||
|
.index(1)
|
||||||
|
.value_name("STAKE ACCOUNT")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_pubkey_or_keypair)
|
||||||
|
.help("Address of the stake account in which to redeem credits")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("vote_account_pubkey")
|
||||||
|
.index(2)
|
||||||
|
.value_name("VOTE ACCOUNT")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_pubkey_or_keypair)
|
||||||
|
.help("The vote account to which the stake is currently delegated.")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("show-stake-account")
|
||||||
|
.about("Show the contents of a stake account")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("stake_account_pubkey")
|
||||||
|
.index(1)
|
||||||
|
.value_name("STAKE ACCOUNT")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_pubkey_or_keypair)
|
||||||
|
.help("Address of the stake account to display")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("lamports")
|
||||||
|
.long("lamports")
|
||||||
|
.takes_value(false)
|
||||||
|
.help("Display balance in lamports instead of SOL")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_stake_create_account(
|
||||||
|
pubkey: &Pubkey,
|
||||||
|
matches: &ArgMatches<'_>,
|
||||||
|
) -> Result<WalletCommand, WalletError> {
|
||||||
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
||||||
|
let slot = value_of(&matches, "lockup").unwrap_or(0);
|
||||||
|
let custodian = pubkey_of(matches, "custodian").unwrap_or_default();
|
||||||
|
let staker = pubkey_of(matches, "authorized_staker").unwrap_or(*pubkey); // defaults to config
|
||||||
|
let withdrawer = pubkey_of(matches, "authorized_withdrawer").unwrap_or(*pubkey); // defaults to config
|
||||||
|
let lamports = amount_of(matches, "amount", "unit").expect("Invalid amount");
|
||||||
|
|
||||||
|
Ok(WalletCommand::CreateStakeAccount(
|
||||||
|
stake_account_pubkey,
|
||||||
|
Authorized { staker, withdrawer },
|
||||||
|
Lockup { custodian, slot },
|
||||||
|
lamports,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_stake_delegate_stake(matches: &ArgMatches<'_>) -> Result<WalletCommand, WalletError> {
|
||||||
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
||||||
|
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
||||||
|
let force = matches.is_present("force");
|
||||||
|
|
||||||
|
Ok(WalletCommand::DelegateStake(
|
||||||
|
stake_account_pubkey,
|
||||||
|
vote_account_pubkey,
|
||||||
|
force,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_stake_authorize(
|
||||||
|
matches: &ArgMatches<'_>,
|
||||||
|
stake_authorize: StakeAuthorize,
|
||||||
|
) -> Result<WalletCommand, WalletError> {
|
||||||
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
||||||
|
let authorized_pubkey = pubkey_of(matches, "authorized_pubkey").unwrap();
|
||||||
|
|
||||||
|
Ok(WalletCommand::StakeAuthorize(
|
||||||
|
stake_account_pubkey,
|
||||||
|
authorized_pubkey,
|
||||||
|
stake_authorize,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_redeem_vote_credits(matches: &ArgMatches<'_>) -> Result<WalletCommand, WalletError> {
|
||||||
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
||||||
|
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
||||||
|
Ok(WalletCommand::RedeemVoteCredits(
|
||||||
|
stake_account_pubkey,
|
||||||
|
vote_account_pubkey,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_stake_deactivate_stake(
|
||||||
|
matches: &ArgMatches<'_>,
|
||||||
|
) -> Result<WalletCommand, WalletError> {
|
||||||
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
||||||
|
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
||||||
|
Ok(WalletCommand::DeactivateStake(
|
||||||
|
stake_account_pubkey,
|
||||||
|
vote_account_pubkey,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_stake_withdraw_stake(matches: &ArgMatches<'_>) -> Result<WalletCommand, WalletError> {
|
||||||
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
||||||
|
let destination_account_pubkey = pubkey_of(matches, "destination_account_pubkey").unwrap();
|
||||||
|
let lamports = amount_of(matches, "amount", "unit").expect("Invalid amount");
|
||||||
|
|
||||||
|
Ok(WalletCommand::WithdrawStake(
|
||||||
|
stake_account_pubkey,
|
||||||
|
destination_account_pubkey,
|
||||||
|
lamports,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_show_stake_account(matches: &ArgMatches<'_>) -> Result<WalletCommand, WalletError> {
|
||||||
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
||||||
|
let use_lamports_unit = matches.is_present("lamports");
|
||||||
|
Ok(WalletCommand::ShowStakeAccount {
|
||||||
|
pubkey: stake_account_pubkey,
|
||||||
|
use_lamports_unit,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_create_stake_account(
|
||||||
|
rpc_client: &RpcClient,
|
||||||
|
config: &WalletConfig,
|
||||||
|
stake_account_pubkey: &Pubkey,
|
||||||
|
authorized: &Authorized,
|
||||||
|
lockup: &Lockup,
|
||||||
|
lamports: u64,
|
||||||
|
) -> ProcessResult {
|
||||||
|
check_unique_pubkeys(
|
||||||
|
(&config.keypair.pubkey(), "wallet keypair".to_string()),
|
||||||
|
(stake_account_pubkey, "stake_account_pubkey".to_string()),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if rpc_client.get_account(&stake_account_pubkey).is_ok() {
|
||||||
|
return Err(WalletError::BadParameter(format!(
|
||||||
|
"Unable to create stake account. Stake account already exists: {}",
|
||||||
|
stake_account_pubkey
|
||||||
|
))
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let ixs = stake_instruction::create_stake_account_with_lockup(
|
||||||
|
&config.keypair.pubkey(),
|
||||||
|
stake_account_pubkey,
|
||||||
|
authorized,
|
||||||
|
lockup,
|
||||||
|
lamports,
|
||||||
|
);
|
||||||
|
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||||
|
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
|
||||||
|
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
|
||||||
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
|
||||||
|
log_instruction_custom_error::<SystemError>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_stake_authorize(
|
||||||
|
rpc_client: &RpcClient,
|
||||||
|
config: &WalletConfig,
|
||||||
|
stake_account_pubkey: &Pubkey,
|
||||||
|
authorized_pubkey: &Pubkey,
|
||||||
|
stake_authorize: StakeAuthorize,
|
||||||
|
) -> ProcessResult {
|
||||||
|
check_unique_pubkeys(
|
||||||
|
(stake_account_pubkey, "stake_account_pubkey".to_string()),
|
||||||
|
(authorized_pubkey, "new_authorized_pubkey".to_string()),
|
||||||
|
)?;
|
||||||
|
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||||
|
let ixs = vec![stake_instruction::authorize(
|
||||||
|
stake_account_pubkey, // stake account to update
|
||||||
|
&config.keypair.pubkey(), // currently authorized
|
||||||
|
authorized_pubkey, // new stake signer
|
||||||
|
stake_authorize, // stake or withdraw
|
||||||
|
)];
|
||||||
|
|
||||||
|
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
|
||||||
|
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
|
||||||
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
|
||||||
|
log_instruction_custom_error::<StakeError>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_deactivate_stake_account(
|
||||||
|
rpc_client: &RpcClient,
|
||||||
|
config: &WalletConfig,
|
||||||
|
stake_account_pubkey: &Pubkey,
|
||||||
|
vote_account_pubkey: &Pubkey,
|
||||||
|
) -> ProcessResult {
|
||||||
|
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||||
|
let ixs = vec![stake_instruction::deactivate_stake(
|
||||||
|
stake_account_pubkey,
|
||||||
|
&config.keypair.pubkey(),
|
||||||
|
vote_account_pubkey,
|
||||||
|
)];
|
||||||
|
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
|
||||||
|
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
|
||||||
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
|
||||||
|
log_instruction_custom_error::<StakeError>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_withdraw_stake(
|
||||||
|
rpc_client: &RpcClient,
|
||||||
|
config: &WalletConfig,
|
||||||
|
stake_account_pubkey: &Pubkey,
|
||||||
|
destination_account_pubkey: &Pubkey,
|
||||||
|
lamports: u64,
|
||||||
|
) -> ProcessResult {
|
||||||
|
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||||
|
|
||||||
|
let ixs = vec![stake_instruction::withdraw(
|
||||||
|
stake_account_pubkey,
|
||||||
|
&config.keypair.pubkey(),
|
||||||
|
destination_account_pubkey,
|
||||||
|
lamports,
|
||||||
|
)];
|
||||||
|
|
||||||
|
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
|
||||||
|
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
|
||||||
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
|
||||||
|
log_instruction_custom_error::<StakeError>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_redeem_vote_credits(
|
||||||
|
rpc_client: &RpcClient,
|
||||||
|
config: &WalletConfig,
|
||||||
|
stake_account_pubkey: &Pubkey,
|
||||||
|
vote_account_pubkey: &Pubkey,
|
||||||
|
) -> ProcessResult {
|
||||||
|
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||||
|
let ixs = vec![stake_instruction::redeem_vote_credits(
|
||||||
|
stake_account_pubkey,
|
||||||
|
vote_account_pubkey,
|
||||||
|
)];
|
||||||
|
let mut tx = Transaction::new_signed_with_payer(
|
||||||
|
ixs,
|
||||||
|
Some(&config.keypair.pubkey()),
|
||||||
|
&[&config.keypair],
|
||||||
|
recent_blockhash,
|
||||||
|
);
|
||||||
|
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
|
||||||
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
|
||||||
|
log_instruction_custom_error::<StakeError>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_show_stake_account(
|
||||||
|
rpc_client: &RpcClient,
|
||||||
|
_config: &WalletConfig,
|
||||||
|
stake_account_pubkey: &Pubkey,
|
||||||
|
use_lamports_unit: bool,
|
||||||
|
) -> ProcessResult {
|
||||||
|
let stake_account = rpc_client.get_account(stake_account_pubkey)?;
|
||||||
|
if stake_account.owner != solana_stake_api::id() {
|
||||||
|
Err(WalletError::RpcRequestError(
|
||||||
|
format!("{:?} is not a stake account", stake_account_pubkey).to_string(),
|
||||||
|
))?;
|
||||||
|
}
|
||||||
|
fn show_authorized(authorized: &Authorized) {
|
||||||
|
println!("authorized staker: {}", authorized.staker);
|
||||||
|
println!("authorized withdrawer: {}", authorized.staker);
|
||||||
|
}
|
||||||
|
fn show_lockup(lockup: &Lockup) {
|
||||||
|
println!("lockup slot: {}", lockup.slot);
|
||||||
|
println!("lockup custodian: {}", lockup.custodian);
|
||||||
|
}
|
||||||
|
match stake_account.state() {
|
||||||
|
Ok(StakeState::Stake(authorized, lockup, stake)) => {
|
||||||
|
println!(
|
||||||
|
"total stake: {}",
|
||||||
|
build_balance_message(stake_account.lamports, use_lamports_unit)
|
||||||
|
);
|
||||||
|
println!("credits observed: {}", stake.credits_observed);
|
||||||
|
println!(
|
||||||
|
"delegated stake: {}",
|
||||||
|
build_balance_message(stake.stake, use_lamports_unit)
|
||||||
|
);
|
||||||
|
if stake.voter_pubkey != Pubkey::default() {
|
||||||
|
println!("delegated voter pubkey: {}", stake.voter_pubkey);
|
||||||
|
}
|
||||||
|
println!(
|
||||||
|
"stake activates starting from epoch: {}",
|
||||||
|
stake.activation_epoch
|
||||||
|
);
|
||||||
|
if stake.deactivation_epoch < std::u64::MAX {
|
||||||
|
println!(
|
||||||
|
"stake deactivates starting from epoch: {}",
|
||||||
|
stake.deactivation_epoch
|
||||||
|
);
|
||||||
|
}
|
||||||
|
show_authorized(&authorized);
|
||||||
|
show_lockup(&lockup);
|
||||||
|
Ok("".to_string())
|
||||||
|
}
|
||||||
|
Ok(StakeState::RewardsPool) => Ok("Stake account is a rewards pool".to_string()),
|
||||||
|
Ok(StakeState::Uninitialized) => Ok("Stake account is uninitialized".to_string()),
|
||||||
|
Ok(StakeState::Initialized(authorized, lockup)) => {
|
||||||
|
println!("Stake account is undelegated");
|
||||||
|
show_authorized(&authorized);
|
||||||
|
show_lockup(&lockup);
|
||||||
|
Ok("".to_string())
|
||||||
|
}
|
||||||
|
Err(err) => Err(WalletError::RpcRequestError(format!(
|
||||||
|
"Account data could not be deserialized to stake state: {:?}",
|
||||||
|
err
|
||||||
|
)))?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_delegate_stake(
|
||||||
|
rpc_client: &RpcClient,
|
||||||
|
config: &WalletConfig,
|
||||||
|
stake_account_pubkey: &Pubkey,
|
||||||
|
vote_account_pubkey: &Pubkey,
|
||||||
|
force: bool,
|
||||||
|
) -> ProcessResult {
|
||||||
|
check_unique_pubkeys(
|
||||||
|
(&config.keypair.pubkey(), "wallet keypair".to_string()),
|
||||||
|
(stake_account_pubkey, "stake_account_pubkey".to_string()),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Sanity check the vote account to ensure it is attached to a validator that has recently
|
||||||
|
// voted at the tip of the ledger
|
||||||
|
let vote_account_data = rpc_client
|
||||||
|
.get_account_data(vote_account_pubkey)
|
||||||
|
.map_err(|_| {
|
||||||
|
WalletError::RpcRequestError(format!("Vote account not found: {}", vote_account_pubkey))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let vote_state = VoteState::deserialize(&vote_account_data).map_err(|_| {
|
||||||
|
WalletError::RpcRequestError(
|
||||||
|
"Account data could not be deserialized to vote state".to_string(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let sanity_check_result = match vote_state.root_slot {
|
||||||
|
None => Err(WalletError::BadParameter(
|
||||||
|
"Unable to delegate. Vote account has no root slot".to_string(),
|
||||||
|
)),
|
||||||
|
Some(root_slot) => {
|
||||||
|
let slot = rpc_client.get_slot()?;
|
||||||
|
if root_slot + solana_sdk::clock::DEFAULT_SLOTS_PER_TURN < slot {
|
||||||
|
Err(WalletError::BadParameter(
|
||||||
|
format!(
|
||||||
|
"Unable to delegate. Vote account root slot ({}) is too old, the current slot is {}", root_slot, slot
|
||||||
|
)
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if sanity_check_result.is_err() {
|
||||||
|
if !force {
|
||||||
|
sanity_check_result?;
|
||||||
|
} else {
|
||||||
|
println!("--force supplied, ignoring: {:?}", sanity_check_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||||
|
|
||||||
|
let ixs = vec![stake_instruction::delegate_stake(
|
||||||
|
stake_account_pubkey,
|
||||||
|
&config.keypair.pubkey(),
|
||||||
|
vote_account_pubkey,
|
||||||
|
)];
|
||||||
|
|
||||||
|
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
|
||||||
|
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
|
||||||
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
|
||||||
|
log_instruction_custom_error::<StakeError>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::wallet::{app, parse_command};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_command() {
|
||||||
|
let test_commands = app("test", "desc", "version");
|
||||||
|
let pubkey = Pubkey::new_rand();
|
||||||
|
let pubkey_string = format!("{}", pubkey);
|
||||||
|
|
||||||
|
// // Test AuthorizeStaker Subcommand
|
||||||
|
// let out_dir = std::env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_string());
|
||||||
|
// let keypair = Keypair::new();
|
||||||
|
// let keypair_file = format!("{}/tmp/keypair_file-{}", out_dir, keypair.pubkey());
|
||||||
|
// let _ = write_keypair(&keypair, &keypair_file).unwrap();
|
||||||
|
//
|
||||||
|
// let test_authorize_staker = test_commands.clone().get_matches_from(vec![
|
||||||
|
// "test",
|
||||||
|
// "stake-authorize-staker",
|
||||||
|
// &pubkey_string,
|
||||||
|
// &keypair_file,
|
||||||
|
// &pubkey_string,
|
||||||
|
// ]);
|
||||||
|
// assert_eq!(
|
||||||
|
// parse_command(&pubkey, &test_authorize_staker).unwrap(),
|
||||||
|
// WalletCommand::StakeAuthorize(pubkey, keypair, pubkey, StakeAuthorize::Staker)
|
||||||
|
// );
|
||||||
|
// fs::remove_file(&keypair_file).unwrap();
|
||||||
|
|
||||||
|
// Test CreateVoteAccount SubCommand
|
||||||
|
let custodian = Pubkey::new_rand();
|
||||||
|
let custodian_string = format!("{}", custodian);
|
||||||
|
let authorized = Pubkey::new_rand();
|
||||||
|
let authorized_string = format!("{}", authorized);
|
||||||
|
let test_create_stake_account = test_commands.clone().get_matches_from(vec![
|
||||||
|
"test",
|
||||||
|
"create-stake-account",
|
||||||
|
&pubkey_string,
|
||||||
|
"50",
|
||||||
|
"--authorized-staker",
|
||||||
|
&authorized_string,
|
||||||
|
"--authorized-withdrawer",
|
||||||
|
&authorized_string,
|
||||||
|
"--custodian",
|
||||||
|
&custodian_string,
|
||||||
|
"--lockup",
|
||||||
|
"43",
|
||||||
|
"lamports",
|
||||||
|
]);
|
||||||
|
assert_eq!(
|
||||||
|
parse_command(&pubkey, &test_create_stake_account).unwrap(),
|
||||||
|
WalletCommand::CreateStakeAccount(
|
||||||
|
pubkey,
|
||||||
|
Authorized {
|
||||||
|
staker: authorized,
|
||||||
|
withdrawer: authorized,
|
||||||
|
},
|
||||||
|
Lockup {
|
||||||
|
slot: 43,
|
||||||
|
custodian,
|
||||||
|
},
|
||||||
|
50
|
||||||
|
)
|
||||||
|
);
|
||||||
|
let test_create_stake_account2 = test_commands.clone().get_matches_from(vec![
|
||||||
|
"test",
|
||||||
|
"create-stake-account",
|
||||||
|
&pubkey_string,
|
||||||
|
"50",
|
||||||
|
"lamports",
|
||||||
|
]);
|
||||||
|
assert_eq!(
|
||||||
|
parse_command(&pubkey, &test_create_stake_account2).unwrap(),
|
||||||
|
WalletCommand::CreateStakeAccount(
|
||||||
|
pubkey,
|
||||||
|
Authorized {
|
||||||
|
staker: pubkey,
|
||||||
|
withdrawer: pubkey,
|
||||||
|
},
|
||||||
|
Lockup {
|
||||||
|
slot: 0,
|
||||||
|
custodian: Pubkey::default(),
|
||||||
|
},
|
||||||
|
50
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test DelegateStake Subcommand
|
||||||
|
let stake_pubkey = Pubkey::new_rand();
|
||||||
|
let stake_pubkey_string = stake_pubkey.to_string();
|
||||||
|
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
|
||||||
|
"test",
|
||||||
|
"delegate-stake",
|
||||||
|
&stake_pubkey_string,
|
||||||
|
&pubkey_string,
|
||||||
|
]);
|
||||||
|
assert_eq!(
|
||||||
|
parse_command(&pubkey, &test_delegate_stake).unwrap(),
|
||||||
|
WalletCommand::DelegateStake(stake_pubkey, pubkey, false,)
|
||||||
|
);
|
||||||
|
|
||||||
|
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
|
||||||
|
"test",
|
||||||
|
"delegate-stake",
|
||||||
|
"--force",
|
||||||
|
&stake_pubkey_string,
|
||||||
|
&pubkey_string,
|
||||||
|
]);
|
||||||
|
assert_eq!(
|
||||||
|
parse_command(&pubkey, &test_delegate_stake).unwrap(),
|
||||||
|
WalletCommand::DelegateStake(stake_pubkey, pubkey, true)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test WithdrawStake Subcommand
|
||||||
|
let test_withdraw_stake = test_commands.clone().get_matches_from(vec![
|
||||||
|
"test",
|
||||||
|
"withdraw-stake",
|
||||||
|
&stake_pubkey_string,
|
||||||
|
&pubkey_string,
|
||||||
|
"42",
|
||||||
|
"lamports",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
parse_command(&pubkey, &test_withdraw_stake).unwrap(),
|
||||||
|
WalletCommand::WithdrawStake(stake_pubkey, pubkey, 42)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test DeactivateStake Subcommand
|
||||||
|
let test_deactivate_stake = test_commands.clone().get_matches_from(vec![
|
||||||
|
"test",
|
||||||
|
"deactivate-stake",
|
||||||
|
&stake_pubkey_string,
|
||||||
|
&pubkey_string,
|
||||||
|
]);
|
||||||
|
assert_eq!(
|
||||||
|
parse_command(&pubkey, &test_deactivate_stake).unwrap(),
|
||||||
|
WalletCommand::DeactivateStake(stake_pubkey, pubkey)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// TODO: Add process tests
|
||||||
|
}
|
@ -1,16 +1,14 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
input_parsers::*,
|
input_parsers::*,
|
||||||
wallet::{
|
wallet::{
|
||||||
check_account_for_fee, check_unique_pubkeys, log_instruction_custom_error, ProcessResult,
|
build_balance_message, check_account_for_fee, check_unique_pubkeys,
|
||||||
WalletCommand, WalletConfig, WalletError,
|
log_instruction_custom_error, ProcessResult, WalletCommand, WalletConfig, WalletError,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use clap::{value_t_or_exit, ArgMatches};
|
use clap::{value_t_or_exit, ArgMatches};
|
||||||
use solana_client::rpc_client::RpcClient;
|
use solana_client::rpc_client::RpcClient;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey, signature::KeypairUtil, system_instruction::SystemError,
|
||||||
signature::{Keypair, KeypairUtil},
|
|
||||||
system_instruction::SystemError,
|
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_vote_api::{
|
use solana_vote_api::{
|
||||||
@ -18,19 +16,17 @@ use solana_vote_api::{
|
|||||||
vote_state::{VoteAuthorize, VoteInit, VoteState},
|
vote_state::{VoteAuthorize, VoteInit, VoteState},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parse_vote_create_account(matches: &ArgMatches<'_>) -> Result<WalletCommand, WalletError> {
|
pub fn parse_vote_create_account(
|
||||||
|
pubkey: &Pubkey,
|
||||||
|
matches: &ArgMatches<'_>,
|
||||||
|
) -> Result<WalletCommand, WalletError> {
|
||||||
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
||||||
let node_pubkey = pubkey_of(matches, "node_pubkey").unwrap();
|
let node_pubkey = pubkey_of(matches, "node_pubkey").unwrap();
|
||||||
let commission = value_of(&matches, "commission").unwrap_or(0);
|
let commission = value_of(&matches, "commission").unwrap_or(0);
|
||||||
let authorized_voter = pubkey_of(matches, "authorized_voter").unwrap_or(vote_account_pubkey);
|
let authorized_voter = pubkey_of(matches, "authorized_voter").unwrap_or(vote_account_pubkey);
|
||||||
let authorized_withdrawer =
|
let authorized_withdrawer = pubkey_of(matches, "authorized_withdrawer").unwrap_or(*pubkey);
|
||||||
pubkey_of(matches, "authorized_withdrawer").unwrap_or(vote_account_pubkey);
|
|
||||||
|
|
||||||
let lamports = crate::wallet::parse_amount_lamports(
|
let lamports = amount_of(matches, "amount", "unit").expect("Invalid amount");
|
||||||
matches.value_of("amount").unwrap(),
|
|
||||||
matches.value_of("unit"),
|
|
||||||
)
|
|
||||||
.map_err(|err| WalletError::BadParameter(format!("Invalid amount: {:?}", err)))?;
|
|
||||||
|
|
||||||
Ok(WalletCommand::CreateVoteAccount(
|
Ok(WalletCommand::CreateVoteAccount(
|
||||||
vote_account_pubkey,
|
vote_account_pubkey,
|
||||||
@ -49,12 +45,10 @@ pub fn parse_vote_authorize(
|
|||||||
vote_authorize: VoteAuthorize,
|
vote_authorize: VoteAuthorize,
|
||||||
) -> Result<WalletCommand, WalletError> {
|
) -> Result<WalletCommand, WalletError> {
|
||||||
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
||||||
let authorized_keypair = keypair_of(matches, "authorized_keypair_file").unwrap();
|
|
||||||
let new_authorized_pubkey = pubkey_of(matches, "new_authorized_pubkey").unwrap();
|
let new_authorized_pubkey = pubkey_of(matches, "new_authorized_pubkey").unwrap();
|
||||||
|
|
||||||
Ok(WalletCommand::VoteAuthorize(
|
Ok(WalletCommand::VoteAuthorize(
|
||||||
vote_account_pubkey,
|
vote_account_pubkey,
|
||||||
authorized_keypair,
|
|
||||||
new_authorized_pubkey,
|
new_authorized_pubkey,
|
||||||
vote_authorize,
|
vote_authorize,
|
||||||
))
|
))
|
||||||
@ -103,7 +97,6 @@ pub fn process_vote_authorize(
|
|||||||
rpc_client: &RpcClient,
|
rpc_client: &RpcClient,
|
||||||
config: &WalletConfig,
|
config: &WalletConfig,
|
||||||
vote_account_pubkey: &Pubkey,
|
vote_account_pubkey: &Pubkey,
|
||||||
authorized_keypair: &Keypair,
|
|
||||||
new_authorized_pubkey: &Pubkey,
|
new_authorized_pubkey: &Pubkey,
|
||||||
vote_authorize: VoteAuthorize,
|
vote_authorize: VoteAuthorize,
|
||||||
) -> ProcessResult {
|
) -> ProcessResult {
|
||||||
@ -113,21 +106,15 @@ pub fn process_vote_authorize(
|
|||||||
)?;
|
)?;
|
||||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||||
let ixs = vec![vote_instruction::authorize(
|
let ixs = vec![vote_instruction::authorize(
|
||||||
vote_account_pubkey, // vote account to update
|
vote_account_pubkey, // vote account to update
|
||||||
&authorized_keypair.pubkey(), // current authorized voter (often the vote account itself)
|
&config.keypair.pubkey(), // current authorized voter
|
||||||
new_authorized_pubkey, // new vote signer
|
new_authorized_pubkey, // new vote signer/withdrawer
|
||||||
vote_authorize, // vote or withdraw
|
vote_authorize, // vote or withdraw
|
||||||
)];
|
)];
|
||||||
|
|
||||||
let mut tx = Transaction::new_signed_with_payer(
|
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, recent_blockhash);
|
||||||
ixs,
|
|
||||||
Some(&config.keypair.pubkey()),
|
|
||||||
&[&config.keypair, &authorized_keypair],
|
|
||||||
recent_blockhash,
|
|
||||||
);
|
|
||||||
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
|
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
|
||||||
let result =
|
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
|
||||||
rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair, &authorized_keypair]);
|
|
||||||
log_instruction_custom_error::<VoteError>(result)
|
log_instruction_custom_error::<VoteError>(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +155,7 @@ pub fn process_show_vote_account(
|
|||||||
|
|
||||||
println!(
|
println!(
|
||||||
"account balance: {}",
|
"account balance: {}",
|
||||||
crate::wallet::build_balance_message(vote_account.lamports, use_lamports_unit)
|
build_balance_message(vote_account.lamports, use_lamports_unit)
|
||||||
);
|
);
|
||||||
println!("node id: {}", vote_state.node_pubkey);
|
println!("node id: {}", vote_state.node_pubkey);
|
||||||
println!("authorized voter: {}", vote_state.authorized_voter);
|
println!("authorized voter: {}", vote_state.authorized_voter);
|
||||||
@ -290,33 +277,23 @@ pub fn process_uptime(
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::wallet::{app, parse_command};
|
use crate::wallet::{app, parse_command};
|
||||||
use solana_sdk::signature::write_keypair;
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_command() {
|
fn test_parse_command() {
|
||||||
let test_commands = app("test", "desc", "version");
|
let test_commands = app("test", "desc", "version");
|
||||||
let pubkey = Pubkey::new_rand();
|
let pubkey = Pubkey::new_rand();
|
||||||
let pubkey_string = format!("{}", pubkey);
|
let pubkey_string = pubkey.to_string();
|
||||||
|
|
||||||
// Test AuthorizeVoter Subcommand
|
|
||||||
let out_dir = std::env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_string());
|
|
||||||
let keypair = Keypair::new();
|
|
||||||
let keypair_file = format!("{}/tmp/keypair_file-{}", out_dir, keypair.pubkey());
|
|
||||||
let _ = write_keypair(&keypair, &keypair_file).unwrap();
|
|
||||||
|
|
||||||
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
||||||
"test",
|
"test",
|
||||||
"vote-authorize-voter",
|
"vote-authorize-voter",
|
||||||
&pubkey_string,
|
&pubkey_string,
|
||||||
&keypair_file,
|
|
||||||
&pubkey_string,
|
&pubkey_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_authorize_voter).unwrap(),
|
parse_command(&pubkey, &test_authorize_voter).unwrap(),
|
||||||
WalletCommand::VoteAuthorize(pubkey, keypair, pubkey, VoteAuthorize::Voter)
|
WalletCommand::VoteAuthorize(pubkey, pubkey, VoteAuthorize::Voter)
|
||||||
);
|
);
|
||||||
fs::remove_file(&keypair_file).unwrap();
|
|
||||||
|
|
||||||
// Test CreateVoteAccount SubCommand
|
// Test CreateVoteAccount SubCommand
|
||||||
let node_pubkey = Pubkey::new_rand();
|
let node_pubkey = Pubkey::new_rand();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
display::println_name_value, input_parsers::*, input_validators::*, lamports_to_sol,
|
display::println_name_value, input_parsers::*, input_validators::*, lamports_to_sol, stake::*,
|
||||||
sol_to_lamports, validator_info::*, vote::*,
|
validator_info::*, vote::*,
|
||||||
};
|
};
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use clap::{value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
|
use clap::{value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
|
||||||
@ -29,12 +29,9 @@ use solana_sdk::{
|
|||||||
system_transaction,
|
system_transaction,
|
||||||
transaction::{Transaction, TransactionError},
|
transaction::{Transaction, TransactionError},
|
||||||
};
|
};
|
||||||
use solana_stake_api::{
|
use solana_stake_api::stake_state::{Authorized, Lockup, StakeAuthorize};
|
||||||
stake_instruction::{self, StakeError},
|
|
||||||
stake_state::{Authorized, Lockup},
|
|
||||||
};
|
|
||||||
use solana_storage_api::storage_instruction;
|
use solana_storage_api::storage_instruction;
|
||||||
use solana_vote_api::vote_state::{VoteAuthorize, VoteInit, VoteState};
|
use solana_vote_api::vote_state::{VoteAuthorize, VoteInit};
|
||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
fs::File,
|
fs::File,
|
||||||
@ -67,7 +64,7 @@ pub enum WalletCommand {
|
|||||||
},
|
},
|
||||||
Cancel(Pubkey),
|
Cancel(Pubkey),
|
||||||
Confirm(Signature),
|
Confirm(Signature),
|
||||||
VoteAuthorize(Pubkey, Keypair, Pubkey, VoteAuthorize),
|
VoteAuthorize(Pubkey, Pubkey, VoteAuthorize),
|
||||||
CreateVoteAccount(Pubkey, VoteInit, u64),
|
CreateVoteAccount(Pubkey, VoteInit, u64),
|
||||||
ShowAccount {
|
ShowAccount {
|
||||||
pubkey: Pubkey,
|
pubkey: Pubkey,
|
||||||
@ -83,9 +80,11 @@ pub enum WalletCommand {
|
|||||||
aggregate: bool,
|
aggregate: bool,
|
||||||
span: Option<u64>,
|
span: Option<u64>,
|
||||||
},
|
},
|
||||||
DelegateStake(Keypair, Pubkey, u64, Authorized, bool),
|
CreateStakeAccount(Pubkey, Authorized, Lockup, u64),
|
||||||
WithdrawStake(Keypair, Pubkey, u64),
|
StakeAuthorize(Pubkey, Pubkey, StakeAuthorize),
|
||||||
DeactivateStake(Keypair, Pubkey),
|
DelegateStake(Pubkey, Pubkey, bool),
|
||||||
|
WithdrawStake(Pubkey, Pubkey, u64),
|
||||||
|
DeactivateStake(Pubkey, Pubkey),
|
||||||
RedeemVoteCredits(Pubkey, Pubkey),
|
RedeemVoteCredits(Pubkey, Pubkey),
|
||||||
ShowStakeAccount {
|
ShowStakeAccount {
|
||||||
pubkey: Pubkey,
|
pubkey: Pubkey,
|
||||||
@ -202,10 +201,7 @@ pub fn parse_command(
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let lamports = parse_amount_lamports(
|
let lamports = amount_of(airdrop_matches, "amount", "unit").expect("Invalid amount");
|
||||||
airdrop_matches.value_of("amount").unwrap(),
|
|
||||||
airdrop_matches.value_of("unit"),
|
|
||||||
)?;
|
|
||||||
let use_lamports_unit = airdrop_matches.value_of("unit").is_some()
|
let use_lamports_unit = airdrop_matches.value_of("unit").is_some()
|
||||||
&& airdrop_matches.value_of("unit").unwrap() == "lamports";
|
&& airdrop_matches.value_of("unit").unwrap() == "lamports";
|
||||||
Ok(WalletCommand::Airdrop {
|
Ok(WalletCommand::Airdrop {
|
||||||
@ -246,7 +242,7 @@ pub fn parse_command(
|
|||||||
use_lamports_unit,
|
use_lamports_unit,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
("create-vote-account", Some(matches)) => parse_vote_create_account(matches),
|
("create-vote-account", Some(matches)) => parse_vote_create_account(pubkey, matches),
|
||||||
("vote-authorize-voter", Some(matches)) => {
|
("vote-authorize-voter", Some(matches)) => {
|
||||||
parse_vote_authorize(matches, VoteAuthorize::Voter)
|
parse_vote_authorize(matches, VoteAuthorize::Voter)
|
||||||
}
|
}
|
||||||
@ -255,61 +251,18 @@ pub fn parse_command(
|
|||||||
}
|
}
|
||||||
("show-vote-account", Some(matches)) => parse_vote_get_account_command(matches),
|
("show-vote-account", Some(matches)) => parse_vote_get_account_command(matches),
|
||||||
("uptime", Some(matches)) => parse_vote_uptime_command(matches),
|
("uptime", Some(matches)) => parse_vote_uptime_command(matches),
|
||||||
("delegate-stake", Some(matches)) => {
|
("create-stake-account", Some(matches)) => parse_stake_create_account(pubkey, matches),
|
||||||
let stake_account_keypair = keypair_of(matches, "stake_account_keypair_file").unwrap();
|
("delegate-stake", Some(matches)) => parse_stake_delegate_stake(matches),
|
||||||
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
("withdraw-stake", Some(matches)) => parse_stake_withdraw_stake(matches),
|
||||||
let lamports = parse_amount_lamports(
|
("deactivate-stake", Some(matches)) => parse_stake_deactivate_stake(matches),
|
||||||
matches.value_of("amount").unwrap(),
|
("stake-authorize-staker", Some(matches)) => {
|
||||||
matches.value_of("unit"),
|
parse_stake_authorize(matches, StakeAuthorize::Staker)
|
||||||
)?;
|
|
||||||
let authorized = Authorized::auto(&stake_account_keypair.pubkey());
|
|
||||||
let force = matches.is_present("force");
|
|
||||||
Ok(WalletCommand::DelegateStake(
|
|
||||||
stake_account_keypair,
|
|
||||||
vote_account_pubkey,
|
|
||||||
lamports,
|
|
||||||
authorized,
|
|
||||||
force,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
("withdraw-stake", Some(matches)) => {
|
("stake-authorize-withdrawer", Some(matches)) => {
|
||||||
let stake_account_keypair = keypair_of(matches, "stake_account_keypair_file").unwrap();
|
parse_stake_authorize(matches, StakeAuthorize::Withdrawer)
|
||||||
let destination_account_pubkey =
|
|
||||||
pubkey_of(matches, "destination_account_pubkey").unwrap();
|
|
||||||
let lamports = parse_amount_lamports(
|
|
||||||
matches.value_of("amount").unwrap(),
|
|
||||||
matches.value_of("unit"),
|
|
||||||
)?;
|
|
||||||
Ok(WalletCommand::WithdrawStake(
|
|
||||||
stake_account_keypair,
|
|
||||||
destination_account_pubkey,
|
|
||||||
lamports,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
("deactivate-stake", Some(matches)) => {
|
|
||||||
let stake_account_keypair = keypair_of(matches, "stake_account_keypair_file").unwrap();
|
|
||||||
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
|
||||||
Ok(WalletCommand::DeactivateStake(
|
|
||||||
stake_account_keypair,
|
|
||||||
vote_account_pubkey,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
("redeem-vote-credits", Some(matches)) => {
|
|
||||||
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
|
||||||
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
|
||||||
Ok(WalletCommand::RedeemVoteCredits(
|
|
||||||
stake_account_pubkey,
|
|
||||||
vote_account_pubkey,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
("show-stake-account", Some(matches)) => {
|
|
||||||
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
|
||||||
let use_lamports_unit = matches.is_present("lamports");
|
|
||||||
Ok(WalletCommand::ShowStakeAccount {
|
|
||||||
pubkey: stake_account_pubkey,
|
|
||||||
use_lamports_unit,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
("redeem-vote-credits", Some(matches)) => parse_redeem_vote_credits(matches),
|
||||||
|
("show-stake-account", Some(matches)) => parse_show_stake_account(matches),
|
||||||
("create-replicator-storage-account", Some(matches)) => {
|
("create-replicator-storage-account", Some(matches)) => {
|
||||||
let account_owner = pubkey_of(matches, "storage_account_owner").unwrap();
|
let account_owner = pubkey_of(matches, "storage_account_owner").unwrap();
|
||||||
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
|
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
|
||||||
@ -349,10 +302,7 @@ pub fn parse_command(
|
|||||||
("get-epoch-info", Some(_matches)) => Ok(WalletCommand::GetEpochInfo),
|
("get-epoch-info", Some(_matches)) => Ok(WalletCommand::GetEpochInfo),
|
||||||
("get-transaction-count", Some(_matches)) => Ok(WalletCommand::GetTransactionCount),
|
("get-transaction-count", Some(_matches)) => Ok(WalletCommand::GetTransactionCount),
|
||||||
("pay", Some(pay_matches)) => {
|
("pay", Some(pay_matches)) => {
|
||||||
let lamports = parse_amount_lamports(
|
let lamports = amount_of(pay_matches, "amount", "unit").expect("Invalid amount");
|
||||||
pay_matches.value_of("amount").unwrap(),
|
|
||||||
pay_matches.value_of("unit"),
|
|
||||||
)?;
|
|
||||||
let to = value_of(&pay_matches, "to").unwrap_or(*pubkey);
|
let to = value_of(&pay_matches, "to").unwrap_or(*pubkey);
|
||||||
let timestamp = if pay_matches.is_present("timestamp") {
|
let timestamp = if pay_matches.is_present("timestamp") {
|
||||||
// Parse input for serde_json
|
// Parse input for serde_json
|
||||||
@ -589,231 +539,6 @@ fn process_show_account(
|
|||||||
Ok("".to_string())
|
Ok("".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_deactivate_stake_account(
|
|
||||||
rpc_client: &RpcClient,
|
|
||||||
config: &WalletConfig,
|
|
||||||
stake_account_keypair: &Keypair,
|
|
||||||
vote_account_pubkey: &Pubkey,
|
|
||||||
) -> ProcessResult {
|
|
||||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
|
||||||
let ixs =
|
|
||||||
stake_instruction::deactivate_stake(&stake_account_keypair.pubkey(), vote_account_pubkey);
|
|
||||||
let mut tx = Transaction::new_signed_with_payer(
|
|
||||||
vec![ixs],
|
|
||||||
Some(&config.keypair.pubkey()),
|
|
||||||
&[&config.keypair, &stake_account_keypair],
|
|
||||||
recent_blockhash,
|
|
||||||
);
|
|
||||||
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
|
|
||||||
let result = rpc_client
|
|
||||||
.send_and_confirm_transaction(&mut tx, &[&config.keypair, &stake_account_keypair]);
|
|
||||||
log_instruction_custom_error::<StakeError>(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_delegate_stake(
|
|
||||||
rpc_client: &RpcClient,
|
|
||||||
config: &WalletConfig,
|
|
||||||
stake_account_keypair: &Keypair,
|
|
||||||
vote_account_pubkey: &Pubkey,
|
|
||||||
lamports: u64,
|
|
||||||
authorized: &Authorized,
|
|
||||||
force: bool,
|
|
||||||
) -> ProcessResult {
|
|
||||||
check_unique_pubkeys(
|
|
||||||
(&config.keypair.pubkey(), "wallet keypair".to_string()),
|
|
||||||
(
|
|
||||||
&stake_account_keypair.pubkey(),
|
|
||||||
"stake_account_keypair".to_string(),
|
|
||||||
),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if rpc_client
|
|
||||||
.get_account(&stake_account_keypair.pubkey())
|
|
||||||
.is_ok()
|
|
||||||
{
|
|
||||||
return Err(WalletError::BadParameter(format!(
|
|
||||||
"Unable to delegate. Stake account already exists: {}",
|
|
||||||
stake_account_keypair.pubkey()
|
|
||||||
))
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
|
||||||
|
|
||||||
let ixs = stake_instruction::create_stake_account_and_delegate_stake(
|
|
||||||
&config.keypair.pubkey(),
|
|
||||||
&stake_account_keypair.pubkey(),
|
|
||||||
vote_account_pubkey,
|
|
||||||
lamports,
|
|
||||||
authorized,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Sanity check the vote account to ensure it is attached to a validator that has recently
|
|
||||||
// voted at the tip of the ledger
|
|
||||||
let vote_account_data = rpc_client
|
|
||||||
.get_account_data(vote_account_pubkey)
|
|
||||||
.map_err(|_| {
|
|
||||||
WalletError::RpcRequestError(format!("Vote account not found: {}", vote_account_pubkey))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let vote_state = VoteState::deserialize(&vote_account_data).map_err(|_| {
|
|
||||||
WalletError::RpcRequestError(
|
|
||||||
"Account data could not be deserialized to vote state".to_string(),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let sanity_check_result = match vote_state.root_slot {
|
|
||||||
None => Err(WalletError::BadParameter(
|
|
||||||
"Unable to delegate. Vote account has no root slot".to_string(),
|
|
||||||
)),
|
|
||||||
Some(root_slot) => {
|
|
||||||
let slot = rpc_client.get_slot()?;
|
|
||||||
if root_slot + solana_sdk::clock::DEFAULT_SLOTS_PER_TURN < slot {
|
|
||||||
Err(WalletError::BadParameter(
|
|
||||||
format!(
|
|
||||||
"Unable to delegate. Vote account root slot ({}) is too old, the current slot is {}", root_slot, slot
|
|
||||||
)
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if sanity_check_result.is_err() {
|
|
||||||
if !force {
|
|
||||||
sanity_check_result?;
|
|
||||||
} else {
|
|
||||||
println!("--force supplied, ignoring: {:?}", sanity_check_result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut tx = Transaction::new_signed_with_payer(
|
|
||||||
ixs,
|
|
||||||
Some(&config.keypair.pubkey()),
|
|
||||||
&[&config.keypair, &stake_account_keypair],
|
|
||||||
recent_blockhash,
|
|
||||||
);
|
|
||||||
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
|
|
||||||
|
|
||||||
let result = rpc_client
|
|
||||||
.send_and_confirm_transaction(&mut tx, &[&config.keypair, &stake_account_keypair]);
|
|
||||||
log_instruction_custom_error::<StakeError>(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_withdraw_stake(
|
|
||||||
rpc_client: &RpcClient,
|
|
||||||
config: &WalletConfig,
|
|
||||||
stake_account_keypair: &Keypair,
|
|
||||||
destination_account_pubkey: &Pubkey,
|
|
||||||
lamports: u64,
|
|
||||||
) -> ProcessResult {
|
|
||||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
|
||||||
let ixs = vec![stake_instruction::withdraw(
|
|
||||||
&stake_account_keypair.pubkey(),
|
|
||||||
destination_account_pubkey,
|
|
||||||
lamports,
|
|
||||||
)];
|
|
||||||
|
|
||||||
let mut tx = Transaction::new_signed_with_payer(
|
|
||||||
ixs,
|
|
||||||
Some(&config.keypair.pubkey()),
|
|
||||||
&[&config.keypair, &stake_account_keypair],
|
|
||||||
recent_blockhash,
|
|
||||||
);
|
|
||||||
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
|
|
||||||
|
|
||||||
let result = rpc_client
|
|
||||||
.send_and_confirm_transaction(&mut tx, &[&config.keypair, &stake_account_keypair]);
|
|
||||||
log_instruction_custom_error::<StakeError>(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_redeem_vote_credits(
|
|
||||||
rpc_client: &RpcClient,
|
|
||||||
config: &WalletConfig,
|
|
||||||
stake_account_pubkey: &Pubkey,
|
|
||||||
vote_account_pubkey: &Pubkey,
|
|
||||||
) -> ProcessResult {
|
|
||||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
|
||||||
let ixs = vec![stake_instruction::redeem_vote_credits(
|
|
||||||
stake_account_pubkey,
|
|
||||||
vote_account_pubkey,
|
|
||||||
)];
|
|
||||||
let mut tx = Transaction::new_signed_with_payer(
|
|
||||||
ixs,
|
|
||||||
Some(&config.keypair.pubkey()),
|
|
||||||
&[&config.keypair],
|
|
||||||
recent_blockhash,
|
|
||||||
);
|
|
||||||
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
|
|
||||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
|
|
||||||
log_instruction_custom_error::<StakeError>(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_show_stake_account(
|
|
||||||
rpc_client: &RpcClient,
|
|
||||||
_config: &WalletConfig,
|
|
||||||
stake_account_pubkey: &Pubkey,
|
|
||||||
use_lamports_unit: bool,
|
|
||||||
) -> ProcessResult {
|
|
||||||
use solana_stake_api::stake_state::StakeState;
|
|
||||||
let stake_account = rpc_client.get_account(stake_account_pubkey)?;
|
|
||||||
if stake_account.owner != solana_stake_api::id() {
|
|
||||||
Err(WalletError::RpcRequestError(
|
|
||||||
format!("{:?} is not a stake account", stake_account_pubkey).to_string(),
|
|
||||||
))?;
|
|
||||||
}
|
|
||||||
fn show_authorized(authorized: &Authorized) {
|
|
||||||
println!("authorized staker: {}", authorized.staker);
|
|
||||||
println!("authorized withdrawer: {}", authorized.staker);
|
|
||||||
}
|
|
||||||
fn show_lockup(lockup: &Lockup) {
|
|
||||||
println!("lockup slot: {}", lockup.slot);
|
|
||||||
println!("lockup custodian: {}", lockup.custodian);
|
|
||||||
}
|
|
||||||
match stake_account.state() {
|
|
||||||
Ok(StakeState::Stake(authorized, lockup, stake)) => {
|
|
||||||
println!(
|
|
||||||
"total stake: {}",
|
|
||||||
build_balance_message(stake_account.lamports, use_lamports_unit)
|
|
||||||
);
|
|
||||||
println!("credits observed: {}", stake.credits_observed);
|
|
||||||
println!(
|
|
||||||
"delegated stake: {}",
|
|
||||||
build_balance_message(stake.stake, use_lamports_unit)
|
|
||||||
);
|
|
||||||
if stake.voter_pubkey != Pubkey::default() {
|
|
||||||
println!("delegated voter pubkey: {}", stake.voter_pubkey);
|
|
||||||
}
|
|
||||||
println!(
|
|
||||||
"stake activates starting from epoch: {}",
|
|
||||||
stake.activation_epoch
|
|
||||||
);
|
|
||||||
if stake.deactivation_epoch < std::u64::MAX {
|
|
||||||
println!(
|
|
||||||
"stake deactivates starting from epoch: {}",
|
|
||||||
stake.deactivation_epoch
|
|
||||||
);
|
|
||||||
}
|
|
||||||
show_authorized(&authorized);
|
|
||||||
show_lockup(&lockup);
|
|
||||||
Ok("".to_string())
|
|
||||||
}
|
|
||||||
Ok(StakeState::RewardsPool) => Ok("Stake account is a rewards pool".to_string()),
|
|
||||||
Ok(StakeState::Uninitialized) => Ok("Stake account is uninitialized".to_string()),
|
|
||||||
Ok(StakeState::Initialized(authorized, lockup)) => {
|
|
||||||
println!("Stake account is undelegated");
|
|
||||||
show_authorized(&authorized);
|
|
||||||
show_lockup(&lockup);
|
|
||||||
Ok("".to_string())
|
|
||||||
}
|
|
||||||
Err(err) => Err(WalletError::RpcRequestError(format!(
|
|
||||||
"Account data could not be deserialized to stake state: {:?}",
|
|
||||||
err
|
|
||||||
)))?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_create_replicator_storage_account(
|
fn process_create_replicator_storage_account(
|
||||||
rpc_client: &RpcClient,
|
rpc_client: &RpcClient,
|
||||||
config: &WalletConfig,
|
config: &WalletConfig,
|
||||||
@ -1374,14 +1099,12 @@ pub fn process_command(config: &WalletConfig) -> ProcessResult {
|
|||||||
|
|
||||||
WalletCommand::VoteAuthorize(
|
WalletCommand::VoteAuthorize(
|
||||||
vote_account_pubkey,
|
vote_account_pubkey,
|
||||||
authorized_keypair,
|
|
||||||
new_authorized_pubkey,
|
new_authorized_pubkey,
|
||||||
vote_authorize,
|
vote_authorize,
|
||||||
) => process_vote_authorize(
|
) => process_vote_authorize(
|
||||||
&rpc_client,
|
&rpc_client,
|
||||||
config,
|
config,
|
||||||
&vote_account_pubkey,
|
&vote_account_pubkey,
|
||||||
&authorized_keypair,
|
|
||||||
&new_authorized_pubkey,
|
&new_authorized_pubkey,
|
||||||
*vote_authorize,
|
*vote_authorize,
|
||||||
),
|
),
|
||||||
@ -1414,40 +1137,56 @@ pub fn process_command(config: &WalletConfig) -> ProcessResult {
|
|||||||
span,
|
span,
|
||||||
} => process_uptime(&rpc_client, config, &vote_account_pubkey, *aggregate, *span),
|
} => process_uptime(&rpc_client, config, &vote_account_pubkey, *aggregate, *span),
|
||||||
|
|
||||||
WalletCommand::DelegateStake(
|
// Create stake account
|
||||||
stake_account_keypair,
|
WalletCommand::CreateStakeAccount(stake_account_pubkey, authorized, lockup, lamports) => {
|
||||||
vote_account_pubkey,
|
process_create_stake_account(
|
||||||
lamports,
|
&rpc_client,
|
||||||
authorized,
|
config,
|
||||||
force,
|
&stake_account_pubkey,
|
||||||
) => process_delegate_stake(
|
&authorized,
|
||||||
|
lockup,
|
||||||
|
*lamports,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
WalletCommand::DelegateStake(stake_account_pubkey, vote_account_pubkey, force) => {
|
||||||
|
process_delegate_stake(
|
||||||
|
&rpc_client,
|
||||||
|
config,
|
||||||
|
&stake_account_pubkey,
|
||||||
|
&vote_account_pubkey,
|
||||||
|
*force,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
WalletCommand::StakeAuthorize(
|
||||||
|
stake_account_pubkey,
|
||||||
|
new_authorized_pubkey,
|
||||||
|
stake_authorize,
|
||||||
|
) => process_stake_authorize(
|
||||||
&rpc_client,
|
&rpc_client,
|
||||||
config,
|
config,
|
||||||
&stake_account_keypair,
|
&stake_account_pubkey,
|
||||||
&vote_account_pubkey,
|
&new_authorized_pubkey,
|
||||||
*lamports,
|
*stake_authorize,
|
||||||
&authorized,
|
|
||||||
*force,
|
|
||||||
),
|
),
|
||||||
|
|
||||||
WalletCommand::WithdrawStake(
|
WalletCommand::WithdrawStake(
|
||||||
stake_account_keypair,
|
stake_account_pubkey,
|
||||||
destination_account_pubkey,
|
destination_account_pubkey,
|
||||||
lamports,
|
lamports,
|
||||||
) => process_withdraw_stake(
|
) => process_withdraw_stake(
|
||||||
&rpc_client,
|
&rpc_client,
|
||||||
config,
|
config,
|
||||||
&stake_account_keypair,
|
&stake_account_pubkey,
|
||||||
&destination_account_pubkey,
|
&destination_account_pubkey,
|
||||||
*lamports,
|
*lamports,
|
||||||
),
|
),
|
||||||
|
|
||||||
// Deactivate stake account
|
// Deactivate stake account
|
||||||
WalletCommand::DeactivateStake(stake_account_keypair, vote_account_pubkey) => {
|
WalletCommand::DeactivateStake(stake_account_pubkey, vote_account_pubkey) => {
|
||||||
process_deactivate_stake_account(
|
process_deactivate_stake_account(
|
||||||
&rpc_client,
|
&rpc_client,
|
||||||
config,
|
config,
|
||||||
&stake_account_keypair,
|
&stake_account_pubkey,
|
||||||
&vote_account_pubkey,
|
&vote_account_pubkey,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1657,17 +1396,6 @@ pub(crate) fn build_balance_message(lamports: u64, use_lamports_unit: bool) -> S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_amount_lamports(
|
|
||||||
amount: &str,
|
|
||||||
use_lamports_unit: Option<&str>,
|
|
||||||
) -> Result<u64, Box<dyn error::Error>> {
|
|
||||||
if use_lamports_unit.is_some() && use_lamports_unit.unwrap() == "lamports" {
|
|
||||||
Ok(amount.parse()?)
|
|
||||||
} else {
|
|
||||||
Ok(sol_to_lamports(amount.parse()?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, 'v> {
|
pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, 'v> {
|
||||||
App::new(name)
|
App::new(name)
|
||||||
.about(about)
|
.about(about)
|
||||||
@ -1704,6 +1432,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("unit")
|
Arg::with_name("unit")
|
||||||
.index(2)
|
.index(2)
|
||||||
|
.value_name("UNIT")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.possible_values(&["SOL", "lamports"])
|
.possible_values(&["SOL", "lamports"])
|
||||||
.help("Specify unit to use for request and balance display"),
|
.help("Specify unit to use for request and balance display"),
|
||||||
@ -1764,18 +1493,9 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||||||
.validator(is_pubkey_or_keypair)
|
.validator(is_pubkey_or_keypair)
|
||||||
.help("Vote account in which to set the authorized voter"),
|
.help("Vote account in which to set the authorized voter"),
|
||||||
)
|
)
|
||||||
.arg(
|
|
||||||
Arg::with_name("authorized_keypair_file")
|
|
||||||
.index(2)
|
|
||||||
.value_name("CURRENT VOTER KEYPAIR FILE")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.validator(is_keypair)
|
|
||||||
.help("Keypair file for the currently authorized vote signer"),
|
|
||||||
)
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("new_authorized_pubkey")
|
Arg::with_name("new_authorized_pubkey")
|
||||||
.index(3)
|
.index(2)
|
||||||
.value_name("NEW VOTER PUBKEY")
|
.value_name("NEW VOTER PUBKEY")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.required(true)
|
.required(true)
|
||||||
@ -1795,18 +1515,9 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||||||
.validator(is_pubkey_or_keypair)
|
.validator(is_pubkey_or_keypair)
|
||||||
.help("Vote account in which to set the authorized withdrawer"),
|
.help("Vote account in which to set the authorized withdrawer"),
|
||||||
)
|
)
|
||||||
.arg(
|
|
||||||
Arg::with_name("authorized_keypair_file")
|
|
||||||
.index(2)
|
|
||||||
.value_name("CURRENT WITHDRAWER KEYPAIR FILE")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.validator(is_keypair)
|
|
||||||
.help("Keypair file for the currently authorized withdrawer"),
|
|
||||||
)
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("new_authorized_pubkey")
|
Arg::with_name("new_authorized_pubkey")
|
||||||
.index(3)
|
.index(2)
|
||||||
.value_name("NEW WITHDRAWER PUBKEY")
|
.value_name("NEW WITHDRAWER PUBKEY")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.required(true)
|
.required(true)
|
||||||
@ -1846,6 +1557,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("unit")
|
Arg::with_name("unit")
|
||||||
.index(4)
|
.index(4)
|
||||||
|
.value_name("UNIT")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.possible_values(&["SOL", "lamports"])
|
.possible_values(&["SOL", "lamports"])
|
||||||
.help("Specify unit to use for request"),
|
.help("Specify unit to use for request"),
|
||||||
@ -1863,7 +1575,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||||||
.value_name("PUBKEY")
|
.value_name("PUBKEY")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.validator(is_pubkey_or_keypair)
|
.validator(is_pubkey_or_keypair)
|
||||||
.help("Public key of the authorized voter (defaults to vote account pubkey)"),
|
.help("Public key of the authorized voter (defaults to vote account)"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("authorized_withdrawer")
|
Arg::with_name("authorized_withdrawer")
|
||||||
@ -1871,10 +1583,8 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||||||
.value_name("PUBKEY")
|
.value_name("PUBKEY")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.validator(is_pubkey_or_keypair)
|
.validator(is_pubkey_or_keypair)
|
||||||
.help("Public key of the authorized withdrawer (defaults to vote account pubkey)"),
|
.help("Public key of the authorized withdrawer (defaults to wallet)"),
|
||||||
)
|
),
|
||||||
|
|
||||||
,
|
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("show-account")
|
SubCommand::with_name("show-account")
|
||||||
@ -1947,149 +1657,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||||||
.help("Aggregate uptime data across span")
|
.help("Aggregate uptime data across span")
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.stake_subcommands()
|
||||||
SubCommand::with_name("delegate-stake")
|
|
||||||
.about("Delegate stake to a vote account")
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("force")
|
|
||||||
.long("force")
|
|
||||||
.takes_value(false)
|
|
||||||
.hidden(true) // Don't document this argument to discourage its use
|
|
||||||
.help("Override vote account sanity checks (use carefully!)"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("stake_account_keypair_file")
|
|
||||||
.index(1)
|
|
||||||
.value_name("STAKE ACCOUNT KEYPAIR FILE")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.validator(is_keypair)
|
|
||||||
.help("Keypair file for the new stake account"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("vote_account_pubkey")
|
|
||||||
.index(2)
|
|
||||||
.value_name("VOTE ACCOUNT PUBKEY")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.validator(is_pubkey_or_keypair)
|
|
||||||
.help("The vote account to which the stake will be delegated"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("amount")
|
|
||||||
.index(3)
|
|
||||||
.value_name("AMOUNT")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.help("The amount to delegate (default unit SOL)"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("unit")
|
|
||||||
.index(4)
|
|
||||||
.takes_value(true)
|
|
||||||
.possible_values(&["SOL", "lamports"])
|
|
||||||
.help("Specify unit to use for request"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
SubCommand::with_name("deactivate-stake")
|
|
||||||
.about("Deactivate the delegated stake from the stake account")
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("stake_account_keypair_file")
|
|
||||||
.index(1)
|
|
||||||
.value_name("STAKE ACCOUNT KEYPAIR FILE")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.help("Keypair file for the stake account, for signing the delegate transaction."),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("vote_account_pubkey")
|
|
||||||
.index(2)
|
|
||||||
.value_name("PUBKEY")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.validator(is_pubkey_or_keypair)
|
|
||||||
.help("The vote account to which the stake is currently delegated"),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
SubCommand::with_name("withdraw-stake")
|
|
||||||
.about("Withdraw the unstaked lamports from the stake account")
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("stake_account_keypair_file")
|
|
||||||
.index(1)
|
|
||||||
.value_name("STAKE ACCOUNT KEYPAIR FILE")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.validator(is_keypair)
|
|
||||||
.help("Keypair file for the stake account, for signing the withdraw transaction."),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("destination_account_pubkey")
|
|
||||||
.index(2)
|
|
||||||
.value_name("DESTINATION PUBKEY")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.validator(is_pubkey_or_keypair)
|
|
||||||
.help("The account where the lamports should be transfered"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("amount")
|
|
||||||
.index(3)
|
|
||||||
.value_name("AMOUNT")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.help("The amount to withdraw from the stake account (default unit SOL)"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("unit")
|
|
||||||
.index(4)
|
|
||||||
.takes_value(true)
|
|
||||||
.possible_values(&["SOL", "lamports"])
|
|
||||||
.help("Specify unit to use for request"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
SubCommand::with_name("redeem-vote-credits")
|
|
||||||
.about("Redeem credits in the stake account")
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("stake_account_pubkey")
|
|
||||||
.index(1)
|
|
||||||
.value_name("STAKING ACCOUNT PUBKEY")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.validator(is_pubkey_or_keypair)
|
|
||||||
.help("Staking account address to redeem credits for"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("vote_account_pubkey")
|
|
||||||
.index(2)
|
|
||||||
.value_name("VOTE ACCOUNT PUBKEY")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.validator(is_pubkey_or_keypair)
|
|
||||||
.help("The vote account to which the stake was previously delegated."),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
SubCommand::with_name("show-stake-account")
|
|
||||||
.about("Show the contents of a stake account")
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("stake_account_pubkey")
|
|
||||||
.index(1)
|
|
||||||
.value_name("STAKE ACCOUNT PUBKEY")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.validator(is_pubkey_or_keypair)
|
|
||||||
.help("Stake account pubkey"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("lamports")
|
|
||||||
.long("lamports")
|
|
||||||
.takes_value(false)
|
|
||||||
.help("Display balance in lamports instead of SOL"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("create-storage-mining-pool-account")
|
SubCommand::with_name("create-storage-mining-pool-account")
|
||||||
.about("Create mining pool account")
|
.about("Create mining pool account")
|
||||||
@ -2113,6 +1681,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("unit")
|
Arg::with_name("unit")
|
||||||
.index(3)
|
.index(3)
|
||||||
|
.value_name("UNIT")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.possible_values(&["SOL", "lamports"])
|
.possible_values(&["SOL", "lamports"])
|
||||||
.help("Specify unit to use for request"),
|
.help("Specify unit to use for request"),
|
||||||
@ -2243,6 +1812,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("unit")
|
Arg::with_name("unit")
|
||||||
.index(3)
|
.index(3)
|
||||||
|
.value_name("UNIT")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.possible_values(&["SOL", "lamports"])
|
.possible_values(&["SOL", "lamports"])
|
||||||
.help("Specify unit to use for request"),
|
.help("Specify unit to use for request"),
|
||||||
@ -2447,6 +2017,29 @@ mod tests {
|
|||||||
};
|
};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn make_tmp_path(name: &str) -> String {
|
||||||
|
let out_dir = std::env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_string());
|
||||||
|
let keypair = Keypair::new();
|
||||||
|
|
||||||
|
let path = format!("{}/tmp/{}-{}", out_dir, name, keypair.pubkey());
|
||||||
|
|
||||||
|
// whack any possible collision
|
||||||
|
let _ignored = std::fs::remove_dir_all(&path);
|
||||||
|
// whack any possible collision
|
||||||
|
let _ignored = std::fs::remove_file(&path);
|
||||||
|
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_bad_amount() {
|
||||||
|
let test_commands = app("test", "desc", "version");
|
||||||
|
let test_bad_airdrop = test_commands.get_matches_from(vec!["test", "airdrop", "notint"]);
|
||||||
|
let pubkey = Pubkey::new_rand();
|
||||||
|
let _ignored = parse_command(&pubkey, &test_bad_airdrop).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_wallet_parse_command() {
|
fn test_wallet_parse_command() {
|
||||||
let test_commands = app("test", "desc", "version");
|
let test_commands = app("test", "desc", "version");
|
||||||
@ -2472,10 +2065,6 @@ mod tests {
|
|||||||
use_lamports_unit: true,
|
use_lamports_unit: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
let test_bad_airdrop = test_commands
|
|
||||||
.clone()
|
|
||||||
.get_matches_from(vec!["test", "airdrop", "notint"]);
|
|
||||||
assert!(parse_command(&pubkey, &test_bad_airdrop).is_err());
|
|
||||||
|
|
||||||
// Test Balance Subcommand, incl pubkey and keypair-file inputs
|
// Test Balance Subcommand, incl pubkey and keypair-file inputs
|
||||||
let keypair_file = make_tmp_path("keypair_file");
|
let keypair_file = make_tmp_path("keypair_file");
|
||||||
@ -2533,97 +2122,6 @@ mod tests {
|
|||||||
.get_matches_from(vec!["test", "confirm", "deadbeef"]);
|
.get_matches_from(vec!["test", "confirm", "deadbeef"]);
|
||||||
assert!(parse_command(&pubkey, &test_bad_signature).is_err());
|
assert!(parse_command(&pubkey, &test_bad_signature).is_err());
|
||||||
|
|
||||||
// Test DelegateStake Subcommand
|
|
||||||
fn make_tmp_path(name: &str) -> String {
|
|
||||||
let out_dir = std::env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_string());
|
|
||||||
let keypair = Keypair::new();
|
|
||||||
|
|
||||||
let path = format!("{}/tmp/{}-{}", out_dir, name, keypair.pubkey());
|
|
||||||
|
|
||||||
// whack any possible collision
|
|
||||||
let _ignored = std::fs::remove_dir_all(&path);
|
|
||||||
// whack any possible collision
|
|
||||||
let _ignored = std::fs::remove_file(&path);
|
|
||||||
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
let keypair_file = make_tmp_path("keypair_file");
|
|
||||||
gen_keypair_file(&keypair_file).unwrap();
|
|
||||||
let keypair = read_keypair(&keypair_file).unwrap();
|
|
||||||
|
|
||||||
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
|
|
||||||
"test",
|
|
||||||
"delegate-stake",
|
|
||||||
&keypair_file,
|
|
||||||
&pubkey_string,
|
|
||||||
"42",
|
|
||||||
"lamports",
|
|
||||||
]);
|
|
||||||
let stake_pubkey = keypair.pubkey();
|
|
||||||
assert_eq!(
|
|
||||||
parse_command(&pubkey, &test_delegate_stake).unwrap(),
|
|
||||||
WalletCommand::DelegateStake(
|
|
||||||
keypair,
|
|
||||||
pubkey,
|
|
||||||
42,
|
|
||||||
Authorized::auto(&stake_pubkey),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
let keypair = read_keypair(&keypair_file).unwrap();
|
|
||||||
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
|
|
||||||
"test",
|
|
||||||
"delegate-stake",
|
|
||||||
"--force",
|
|
||||||
&keypair_file,
|
|
||||||
&pubkey_string,
|
|
||||||
"42",
|
|
||||||
"lamports",
|
|
||||||
]);
|
|
||||||
let stake_pubkey = keypair.pubkey();
|
|
||||||
assert_eq!(
|
|
||||||
parse_command(&pubkey, &test_delegate_stake).unwrap(),
|
|
||||||
WalletCommand::DelegateStake(
|
|
||||||
keypair,
|
|
||||||
pubkey,
|
|
||||||
42,
|
|
||||||
Authorized::auto(&stake_pubkey),
|
|
||||||
true
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Test WithdrawStake Subcommand
|
|
||||||
let test_withdraw_stake = test_commands.clone().get_matches_from(vec![
|
|
||||||
"test",
|
|
||||||
"withdraw-stake",
|
|
||||||
&keypair_file,
|
|
||||||
&pubkey_string,
|
|
||||||
"42",
|
|
||||||
"lamports",
|
|
||||||
]);
|
|
||||||
let keypair = read_keypair(&keypair_file).unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
parse_command(&pubkey, &test_withdraw_stake).unwrap(),
|
|
||||||
WalletCommand::WithdrawStake(keypair, pubkey, 42)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Test DeactivateStake Subcommand
|
|
||||||
let keypair_file = make_tmp_path("keypair_file");
|
|
||||||
gen_keypair_file(&keypair_file).unwrap();
|
|
||||||
let keypair = read_keypair(&keypair_file).unwrap();
|
|
||||||
let test_deactivate_stake = test_commands.clone().get_matches_from(vec![
|
|
||||||
"test",
|
|
||||||
"deactivate-stake",
|
|
||||||
&keypair_file,
|
|
||||||
&pubkey_string,
|
|
||||||
]);
|
|
||||||
assert_eq!(
|
|
||||||
parse_command(&pubkey, &test_deactivate_stake).unwrap(),
|
|
||||||
WalletCommand::DeactivateStake(keypair, pubkey)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Test Deploy Subcommand
|
// Test Deploy Subcommand
|
||||||
let test_deploy =
|
let test_deploy =
|
||||||
test_commands
|
test_commands
|
||||||
@ -2831,36 +2329,35 @@ mod tests {
|
|||||||
let signature = process_command(&config);
|
let signature = process_command(&config);
|
||||||
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
||||||
|
|
||||||
let bob_keypair = Keypair::new();
|
|
||||||
let new_authorized_pubkey = Pubkey::new_rand();
|
let new_authorized_pubkey = Pubkey::new_rand();
|
||||||
config.command = WalletCommand::VoteAuthorize(
|
config.command =
|
||||||
|
WalletCommand::VoteAuthorize(bob_pubkey, new_authorized_pubkey, VoteAuthorize::Voter);
|
||||||
|
let signature = process_command(&config);
|
||||||
|
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
||||||
|
|
||||||
|
let bob_pubkey = Pubkey::new_rand();
|
||||||
|
let custodian = Pubkey::new_rand();
|
||||||
|
config.command = WalletCommand::CreateStakeAccount(
|
||||||
bob_pubkey,
|
bob_pubkey,
|
||||||
bob_keypair,
|
Authorized {
|
||||||
new_authorized_pubkey,
|
staker: config.keypair.pubkey(),
|
||||||
VoteAuthorize::Voter,
|
withdrawer: config.keypair.pubkey(),
|
||||||
|
},
|
||||||
|
Lockup { slot: 0, custodian },
|
||||||
|
10,
|
||||||
);
|
);
|
||||||
let signature = process_command(&config);
|
let signature = process_command(&config);
|
||||||
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
||||||
|
|
||||||
// TODO: Need to add mock GetAccountInfo to mock_rpc_client_request.rs to re-enable the
|
let stake_pubkey = Pubkey::new_rand();
|
||||||
// DeactivateStake test.
|
|
||||||
/*
|
|
||||||
let bob_keypair = Keypair::new();
|
|
||||||
let vote_pubkey = Pubkey::new_rand();
|
|
||||||
config.command = WalletCommand::DelegateStake(bob_keypair.into(), vote_pubkey, 100, true);
|
|
||||||
let signature = process_command(&config);
|
|
||||||
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
|
||||||
*/
|
|
||||||
|
|
||||||
let bob_keypair = Keypair::new();
|
|
||||||
let to_pubkey = Pubkey::new_rand();
|
let to_pubkey = Pubkey::new_rand();
|
||||||
config.command = WalletCommand::WithdrawStake(bob_keypair.into(), to_pubkey, 100);
|
config.command = WalletCommand::WithdrawStake(stake_pubkey, to_pubkey, 100);
|
||||||
let signature = process_command(&config);
|
let signature = process_command(&config);
|
||||||
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
||||||
|
|
||||||
let bob_keypair = Keypair::new();
|
let stake_pubkey = Pubkey::new_rand();
|
||||||
let vote_pubkey = Pubkey::new_rand();
|
let vote_pubkey = Pubkey::new_rand();
|
||||||
config.command = WalletCommand::DeactivateStake(bob_keypair.into(), vote_pubkey);
|
config.command = WalletCommand::DeactivateStake(stake_pubkey, vote_pubkey);
|
||||||
let signature = process_command(&config);
|
let signature = process_command(&config);
|
||||||
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
||||||
|
|
||||||
@ -3000,12 +2497,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert!(process_command(&config).is_err());
|
assert!(process_command(&config).is_err());
|
||||||
|
|
||||||
config.command = WalletCommand::VoteAuthorize(
|
config.command = WalletCommand::VoteAuthorize(bob_pubkey, bob_pubkey, VoteAuthorize::Voter);
|
||||||
bob_pubkey,
|
|
||||||
Keypair::new(),
|
|
||||||
bob_pubkey,
|
|
||||||
VoteAuthorize::Voter,
|
|
||||||
);
|
|
||||||
assert!(process_command(&config).is_err());
|
assert!(process_command(&config).is_err());
|
||||||
|
|
||||||
config.command = WalletCommand::GetSlot;
|
config.command = WalletCommand::GetSlot;
|
||||||
|
@ -311,8 +311,7 @@ impl RpcClient {
|
|||||||
|
|
||||||
response
|
response
|
||||||
.and_then(|account_json| {
|
.and_then(|account_json| {
|
||||||
let account: Account =
|
let account: Account = serde_json::from_value(account_json)?;
|
||||||
serde_json::from_value(account_json).expect("deserialize account");
|
|
||||||
trace!("Response account {:?} {:?}", pubkey, account);
|
trace!("Response account {:?} {:?}", pubkey, account);
|
||||||
Ok(account)
|
Ok(account)
|
||||||
})
|
})
|
||||||
|
@ -162,8 +162,8 @@ pub(crate) mod tests {
|
|||||||
&from_account.pubkey(),
|
&from_account.pubkey(),
|
||||||
&stake_account_pubkey,
|
&stake_account_pubkey,
|
||||||
vote_pubkey,
|
vote_pubkey,
|
||||||
amount,
|
|
||||||
&Authorized::auto(&stake_account_pubkey),
|
&Authorized::auto(&stake_account_pubkey),
|
||||||
|
amount,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -464,8 +464,8 @@ impl LocalCluster {
|
|||||||
&from_account.pubkey(),
|
&from_account.pubkey(),
|
||||||
&stake_account_pubkey,
|
&stake_account_pubkey,
|
||||||
&vote_account_pubkey,
|
&vote_account_pubkey,
|
||||||
amount,
|
|
||||||
&StakeAuthorized::auto(&stake_account_pubkey),
|
&StakeAuthorized::auto(&stake_account_pubkey),
|
||||||
|
amount,
|
||||||
),
|
),
|
||||||
client.get_recent_blockhash().unwrap().0,
|
client.get_recent_blockhash().unwrap().0,
|
||||||
);
|
);
|
||||||
|
@ -104,5 +104,7 @@ set -x
|
|||||||
$solana_cli "${common_args[@]}" \
|
$solana_cli "${common_args[@]}" \
|
||||||
show-vote-account "$vote_keypair_path"
|
show-vote-account "$vote_keypair_path"
|
||||||
$solana_cli "${common_args[@]}" \
|
$solana_cli "${common_args[@]}" \
|
||||||
delegate-stake $maybe_force "$stake_keypair_path" "$vote_keypair_path" "$stake_lamports" lamports
|
create-stake-account $maybe_force "$stake_keypair_path" lamports
|
||||||
|
$solana_cli "${common_args[@]}" \
|
||||||
|
delegate-stake $maybe_force "$stake_keypair_path" "$vote_keypair_path"
|
||||||
$solana_cli "${common_args[@]}" show-stake-account "$stake_keypair_path"
|
$solana_cli "${common_args[@]}" show-stake-account "$stake_keypair_path"
|
||||||
|
@ -110,9 +110,9 @@ pub enum StakeInstruction {
|
|||||||
pub fn create_stake_account_with_lockup(
|
pub fn create_stake_account_with_lockup(
|
||||||
from_pubkey: &Pubkey,
|
from_pubkey: &Pubkey,
|
||||||
stake_pubkey: &Pubkey,
|
stake_pubkey: &Pubkey,
|
||||||
lamports: u64,
|
|
||||||
authorized: &Authorized,
|
authorized: &Authorized,
|
||||||
lockup: &Lockup,
|
lockup: &Lockup,
|
||||||
|
lamports: u64,
|
||||||
) -> Vec<Instruction> {
|
) -> Vec<Instruction> {
|
||||||
vec![
|
vec![
|
||||||
system_instruction::create_account(
|
system_instruction::create_account(
|
||||||
@ -133,15 +133,15 @@ pub fn create_stake_account_with_lockup(
|
|||||||
pub fn create_stake_account(
|
pub fn create_stake_account(
|
||||||
from_pubkey: &Pubkey,
|
from_pubkey: &Pubkey,
|
||||||
stake_pubkey: &Pubkey,
|
stake_pubkey: &Pubkey,
|
||||||
lamports: u64,
|
|
||||||
authorized: &Authorized,
|
authorized: &Authorized,
|
||||||
|
lamports: u64,
|
||||||
) -> Vec<Instruction> {
|
) -> Vec<Instruction> {
|
||||||
create_stake_account_with_lockup(
|
create_stake_account_with_lockup(
|
||||||
from_pubkey,
|
from_pubkey,
|
||||||
stake_pubkey,
|
stake_pubkey,
|
||||||
lamports,
|
|
||||||
authorized,
|
authorized,
|
||||||
&Lockup::default(),
|
&Lockup::default(),
|
||||||
|
lamports,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,11 +149,15 @@ pub fn create_stake_account_and_delegate_stake(
|
|||||||
from_pubkey: &Pubkey,
|
from_pubkey: &Pubkey,
|
||||||
stake_pubkey: &Pubkey,
|
stake_pubkey: &Pubkey,
|
||||||
vote_pubkey: &Pubkey,
|
vote_pubkey: &Pubkey,
|
||||||
lamports: u64,
|
|
||||||
authorized: &Authorized,
|
authorized: &Authorized,
|
||||||
|
lamports: u64,
|
||||||
) -> Vec<Instruction> {
|
) -> Vec<Instruction> {
|
||||||
let mut instructions = create_stake_account(from_pubkey, stake_pubkey, lamports, authorized);
|
let mut instructions = create_stake_account(from_pubkey, stake_pubkey, authorized, lamports);
|
||||||
instructions.push(delegate_stake(stake_pubkey, vote_pubkey));
|
instructions.push(delegate_stake(
|
||||||
|
stake_pubkey,
|
||||||
|
&authorized.staker,
|
||||||
|
vote_pubkey,
|
||||||
|
));
|
||||||
instructions
|
instructions
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,32 +210,54 @@ pub fn redeem_vote_credits(stake_pubkey: &Pubkey, vote_pubkey: &Pubkey) -> Instr
|
|||||||
Instruction::new(id(), &StakeInstruction::RedeemVoteCredits, account_metas)
|
Instruction::new(id(), &StakeInstruction::RedeemVoteCredits, account_metas)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delegate_stake(stake_pubkey: &Pubkey, vote_pubkey: &Pubkey) -> Instruction {
|
pub fn delegate_stake(
|
||||||
let account_metas = vec![
|
stake_pubkey: &Pubkey,
|
||||||
AccountMeta::new(*stake_pubkey, true),
|
authorized_pubkey: &Pubkey,
|
||||||
AccountMeta::new_credit_only(*vote_pubkey, false),
|
vote_pubkey: &Pubkey,
|
||||||
AccountMeta::new_credit_only(sysvar::clock::id(), false),
|
) -> Instruction {
|
||||||
AccountMeta::new_credit_only(crate::config::id(), false),
|
let account_metas = metas_for_authorized_signer(
|
||||||
];
|
stake_pubkey,
|
||||||
|
authorized_pubkey,
|
||||||
|
&[
|
||||||
|
AccountMeta::new_credit_only(*vote_pubkey, false),
|
||||||
|
AccountMeta::new_credit_only(sysvar::clock::id(), false),
|
||||||
|
AccountMeta::new_credit_only(crate::config::id(), false),
|
||||||
|
],
|
||||||
|
);
|
||||||
Instruction::new(id(), &StakeInstruction::DelegateStake, account_metas)
|
Instruction::new(id(), &StakeInstruction::DelegateStake, account_metas)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn withdraw(stake_pubkey: &Pubkey, to_pubkey: &Pubkey, lamports: u64) -> Instruction {
|
pub fn withdraw(
|
||||||
let account_metas = vec![
|
stake_pubkey: &Pubkey,
|
||||||
AccountMeta::new(*stake_pubkey, true),
|
authorized_pubkey: &Pubkey,
|
||||||
AccountMeta::new_credit_only(*to_pubkey, false),
|
to_pubkey: &Pubkey,
|
||||||
AccountMeta::new_credit_only(sysvar::clock::id(), false),
|
lamports: u64,
|
||||||
AccountMeta::new_credit_only(sysvar::stake_history::id(), false),
|
) -> Instruction {
|
||||||
];
|
let account_metas = metas_for_authorized_signer(
|
||||||
|
stake_pubkey,
|
||||||
|
authorized_pubkey,
|
||||||
|
&[
|
||||||
|
AccountMeta::new_credit_only(*to_pubkey, false),
|
||||||
|
AccountMeta::new_credit_only(sysvar::clock::id(), false),
|
||||||
|
AccountMeta::new_credit_only(sysvar::stake_history::id(), false),
|
||||||
|
],
|
||||||
|
);
|
||||||
Instruction::new(id(), &StakeInstruction::Withdraw(lamports), account_metas)
|
Instruction::new(id(), &StakeInstruction::Withdraw(lamports), account_metas)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deactivate_stake(stake_pubkey: &Pubkey, vote_pubkey: &Pubkey) -> Instruction {
|
pub fn deactivate_stake(
|
||||||
let account_metas = vec![
|
stake_pubkey: &Pubkey,
|
||||||
AccountMeta::new(*stake_pubkey, true),
|
authorized_pubkey: &Pubkey,
|
||||||
AccountMeta::new_credit_only(*vote_pubkey, false),
|
vote_pubkey: &Pubkey,
|
||||||
AccountMeta::new_credit_only(sysvar::clock::id(), false),
|
) -> Instruction {
|
||||||
];
|
let account_metas = metas_for_authorized_signer(
|
||||||
|
stake_pubkey,
|
||||||
|
authorized_pubkey,
|
||||||
|
&[
|
||||||
|
AccountMeta::new_credit_only(*vote_pubkey, false),
|
||||||
|
AccountMeta::new_credit_only(sysvar::clock::id(), false),
|
||||||
|
],
|
||||||
|
);
|
||||||
Instruction::new(id(), &StakeInstruction::Deactivate, account_metas)
|
Instruction::new(id(), &StakeInstruction::Deactivate, account_metas)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,15 +387,28 @@ mod tests {
|
|||||||
Err(InstructionError::InvalidAccountData),
|
Err(InstructionError::InvalidAccountData),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&delegate_stake(&Pubkey::default(), &Pubkey::default())),
|
process_instruction(&delegate_stake(
|
||||||
|
&Pubkey::default(),
|
||||||
|
&Pubkey::default(),
|
||||||
|
&Pubkey::default()
|
||||||
|
)),
|
||||||
Err(InstructionError::InvalidAccountData),
|
Err(InstructionError::InvalidAccountData),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&withdraw(&Pubkey::default(), &Pubkey::new_rand(), 100)),
|
process_instruction(&withdraw(
|
||||||
|
&Pubkey::default(),
|
||||||
|
&Pubkey::default(),
|
||||||
|
&Pubkey::default(),
|
||||||
|
100
|
||||||
|
)),
|
||||||
Err(InstructionError::InvalidAccountData),
|
Err(InstructionError::InvalidAccountData),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_instruction(&deactivate_stake(&Pubkey::default(), &Pubkey::default())),
|
process_instruction(&deactivate_stake(
|
||||||
|
&Pubkey::default(),
|
||||||
|
&Pubkey::default(),
|
||||||
|
&Pubkey::default()
|
||||||
|
)),
|
||||||
Err(InstructionError::InvalidAccountData),
|
Err(InstructionError::InvalidAccountData),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -101,8 +101,8 @@ fn test_stake_account_delegate() {
|
|||||||
&mint_pubkey,
|
&mint_pubkey,
|
||||||
&staker_pubkey,
|
&staker_pubkey,
|
||||||
&vote_pubkey,
|
&vote_pubkey,
|
||||||
1_000_000,
|
|
||||||
&authorized,
|
&authorized,
|
||||||
|
1_000_000,
|
||||||
));
|
));
|
||||||
bank_client
|
bank_client
|
||||||
.send_message(&[&mint_keypair, &staker_keypair], message)
|
.send_message(&[&mint_keypair, &staker_keypair], message)
|
||||||
@ -120,6 +120,7 @@ fn test_stake_account_delegate() {
|
|||||||
// Test that we cannot withdraw staked lamports
|
// Test that we cannot withdraw staked lamports
|
||||||
let message = Message::new_with_payer(
|
let message = Message::new_with_payer(
|
||||||
vec![stake_instruction::withdraw(
|
vec![stake_instruction::withdraw(
|
||||||
|
&staker_pubkey,
|
||||||
&staker_pubkey,
|
&staker_pubkey,
|
||||||
&Pubkey::new_rand(),
|
&Pubkey::new_rand(),
|
||||||
1_000_000,
|
1_000_000,
|
||||||
@ -187,6 +188,7 @@ fn test_stake_account_delegate() {
|
|||||||
// Deactivate the stake
|
// Deactivate the stake
|
||||||
let message = Message::new_with_payer(
|
let message = Message::new_with_payer(
|
||||||
vec![stake_instruction::deactivate_stake(
|
vec![stake_instruction::deactivate_stake(
|
||||||
|
&staker_pubkey,
|
||||||
&staker_pubkey,
|
&staker_pubkey,
|
||||||
&vote_pubkey,
|
&vote_pubkey,
|
||||||
)],
|
)],
|
||||||
@ -199,6 +201,7 @@ fn test_stake_account_delegate() {
|
|||||||
// Test that we cannot withdraw staked lamports due to cooldown period
|
// Test that we cannot withdraw staked lamports due to cooldown period
|
||||||
let message = Message::new_with_payer(
|
let message = Message::new_with_payer(
|
||||||
vec![stake_instruction::withdraw(
|
vec![stake_instruction::withdraw(
|
||||||
|
&staker_pubkey,
|
||||||
&staker_pubkey,
|
&staker_pubkey,
|
||||||
&Pubkey::new_rand(),
|
&Pubkey::new_rand(),
|
||||||
1_000_000,
|
1_000_000,
|
||||||
@ -220,6 +223,7 @@ fn test_stake_account_delegate() {
|
|||||||
|
|
||||||
let message = Message::new_with_payer(
|
let message = Message::new_with_payer(
|
||||||
vec![stake_instruction::withdraw(
|
vec![stake_instruction::withdraw(
|
||||||
|
&staker_pubkey,
|
||||||
&staker_pubkey,
|
&staker_pubkey,
|
||||||
&Pubkey::new_rand(),
|
&Pubkey::new_rand(),
|
||||||
1_000_000,
|
1_000_000,
|
||||||
@ -233,6 +237,7 @@ fn test_stake_account_delegate() {
|
|||||||
|
|
||||||
let message = Message::new_with_payer(
|
let message = Message::new_with_payer(
|
||||||
vec![stake_instruction::withdraw(
|
vec![stake_instruction::withdraw(
|
||||||
|
&staker_pubkey,
|
||||||
&staker_pubkey,
|
&staker_pubkey,
|
||||||
&Pubkey::new_rand(),
|
&Pubkey::new_rand(),
|
||||||
250_000,
|
250_000,
|
||||||
@ -257,6 +262,7 @@ fn test_stake_account_delegate() {
|
|||||||
// Test that we can withdraw now
|
// Test that we can withdraw now
|
||||||
let message = Message::new_with_payer(
|
let message = Message::new_with_payer(
|
||||||
vec![stake_instruction::withdraw(
|
vec![stake_instruction::withdraw(
|
||||||
|
&staker_pubkey,
|
||||||
&staker_pubkey,
|
&staker_pubkey,
|
||||||
&Pubkey::new_rand(),
|
&Pubkey::new_rand(),
|
||||||
750_000,
|
750_000,
|
||||||
|
Reference in New Issue
Block a user