Skip to content

Instantly share code, notes, and snippets.

@apetresc
Last active March 28, 2023 05:44
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save apetresc/caaf222c31b02354dbc11a333cdb688e to your computer and use it in GitHub Desktop.
Save apetresc/caaf222c31b02354dbc11a333cdb688e to your computer and use it in GitHub Desktop.
A script to automatically claim Crypto.org CRO staking rewards and re-stake them
#!/bin/bash -e
# redelegate-cro.sh is a script that automatically claims all your delegation
# rewards (across any number of validators) in a single transaction (assuming a
# minimum reward threshold is met, to avoid spurious transactions). The rewards
# are then automatically redelegated to the provided validator address, leaving
# behind at least a 0.005 CRO buffer to ensure there is always enough for
# regular transaction fees.
#
# The idea is that it is safe to run this script on a fixed cron schedule and
# feel confident that you are minimizing fees and maximizing APY.
#
# TODO: Currently, the delegation only happens to a single validator (although
# rewards are claimed from all). In future, you will be able to specify
# multiple <validator-address>es to evenly split the stake across multiple.
#
# REQUIREMENTS:
# - chain-maind
# - jq
#
# Updates will be posted to the gist at:
# https://gist.github.com/apetresc/caaf222c31b02354dbc11a333cdb688e
if [[ "$1" == "-h" || "$1" == "" || "$2" == "" ]]
then
echo "Usage: $0 <wallet-address> <validator-address> [-y]"
exit
fi
# Arguments
WALLET=$1
VALIDATOR=$2
YES=$3
# Global parameters
REWARDS_THRESHOLD=10
RPC_NODE="https://mainnet.crypto.org:26657"
CHAIN_ID="crypto-org-chain-mainnet-1"
echo "Wallet is: $WALLET"
BALANCE=$(chain-maind --chain-id $CHAIN_ID query bank balances $WALLET --node $RPC_NODE --output json | jq -r '.balances[] | select(.denom == "basecro") .amount')
echo "Balance is: $BALANCE"
REWARDS=$(chain-maind --chain-id $CHAIN_ID query distribution rewards $WALLET --node $RPC_NODE --output json)
REWARDS_AMOUNT=$(echo $REWARDS | jq -r '.total[] | select(.denom == "basecro") .amount|tonumber/100000000')
echo "There are $REWARDS_AMOUNT CRO rewards across $(echo $REWARDS | jq -r '.rewards | length') validators to be claimed."
if awk 'BEGIN {exit !('$REWARDS_AMOUNT' >= '$REWARDS_THRESHOLD')}'
then
echo "Claiming rewards..."
chain-maind --chain-id $CHAIN_ID tx distribution withdraw-all-rewards \
--from $WALLET \
--gas=auto --gas-prices=0.1basecro --gas-adjustment=1.2 \
--node $RPC_NODE $YES
NEW_BALANCE=$(chain-maind --chain-id $CHAIN_ID query bank balances $WALLET --node $RPC_NODE --output json | jq -r '.balances[] | select(.denom == "basecro") .amount')
while awk 'BEGIN {exit !('$NEW_BALANCE' <= '$BALANCE')}'
do
echo "Waiting for rewards to appear..."
NEW_BALANCE=$(chain-maind --chain-id $CHAIN_ID query bank balances $WALLET --node $RPC_NODE --output json | jq -r '.balances[] | select(.denom == "basecro") .amount')
done
BALANCE=$NEW_BALANCE
echo "New balance is: $BALANCE"
STAKING_AMOUNT=$(expr $BALANCE - 500000)
echo "Amount to stake: $STAKING_AMOUNT"
chain-maind --chain-id $CHAIN_ID tx staking delegate \
$VALIDATOR \
"${STAKING_AMOUNT}basecro" \
--from $WALLET \
--gas=auto --gas-prices=0.1basecro --gas-adjustment=1.2 \
--node $RPC_NODE $YES
echo "Done!"
else
echo "Need at least $REWARDS_THRESHOLD CRO to claim, skipping claim..."
fi
@Nayruden
Copy link

Nayruden commented Apr 9, 2021

Thanks for the script! I suggest you put a URL in there linking to the Reddit post for this or to the gist itself. That way six months from now someone can remember where they got this from to check for updates.

@apetresc
Copy link
Author

apetresc commented Apr 9, 2021

@Nayruden Good idea; done!

@oliverste
Copy link

Thank you for the script!
Unfortunately I run into an issue during staking the claimed rewards. Chain-maind asks me a second time for the keyring passphrase but fails with an error that decoding bech32 failed due to string not all lowercase or all uppercase. I'm not really sure why that happens because the first time entering the passphrase for claiming the rewards is no problem at all.
That's why I changed the script a bit. If there are no rewards to be claimed the script checks if there is a balance greater than the rewards threshold. So this can not only be used to redelegate but also to delegate.
Perhaps other users are also interested in the change. Best regards.

@jlavos
Copy link

jlavos commented Apr 16, 2021

Greate script, thank you!!

Trying to run as a schedule but it keeps asking me for the passphrase. Is there a way to pass the passphrase to chain-maind or not to have to type it ever?
Can't run this on a schedule if passphrase needs to be typed in all the time.

@apetresc
Copy link
Author

apetresc commented Apr 16, 2021

@jlavos Yup, you can use a keyring backend that doesn't require a passphrase, as long as you understand the security implications. That's done on chain-maind directly, here's how: https://crypto.org/docs/wallets/cli.html#the-keyring-keyring-backend-option

@jlavos
Copy link

jlavos commented Apr 16, 2021

Thanks @aptresc. The only option I see that does not require as passphrase is using the "test backend" method. Is that it?

@jlavos
Copy link

jlavos commented Apr 16, 2021

got it working, ;), thanks.

@jcdmacleod
Copy link

Thank you for sharing this!

I get this error "Error: error unmarshalling: invalid character '<' looking for beginning of value" however the balance in the wallet I am testing with is below 10 CRO.

@jlavos
Copy link

jlavos commented Apr 18, 2021

I get that on some calls (e.g. 1st time I run the script it fails, if I run it right after it works), haven't figured out why yet.

@apetresc
Copy link
Author

@jcdmacleod Yeah, that's a normal error that just means the public RPC node we're using (one of Crypto.com's) rejected our query for whatever reason, presumably due to congestion. As @jlavos points out, retrying immediately afterwards will usually solve it.

I suppose I should just add a little retry logic directly in the script, thanks for the idea 👍

@geolectric
Copy link

Did the RPC_NODE change? I keep getting an error:

"Error: post failed: Post "https://mainnet.crypto.org:26657": dial tcp: lookup mainnet.crypto.org: no such host"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment