diff --git a/.github/workflows/apply-scoring.yml b/.github/workflows/apply-scoring.yml index 581bd4fc..4588a5b8 100644 --- a/.github/workflows/apply-scoring.yml +++ b/.github/workflows/apply-scoring.yml @@ -96,12 +96,13 @@ jobs: docker run --rm --user "$(id -u):$(id -g)" \ -v /tmp/solana-config.yml:/.config/solana/cli/config.yml \ -v /tmp/id.json:/.config/solana/id.json \ - -v "$(pwd)/$scores_csv:/scores.csv" \ + -v "$(realpath "$SCORES_CSV"):/scores.csv" \ "$ECR_REGISTRY/$ECR_REPOSITORY:$latest" \ ./validator-manager -s update-scores2 --scores-file /scores.csv env: ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} ECR_REPOSITORY: marinade.finance/marinade-anchor + SCORES_CSV: ${{ env.scores_csv }} - name: Publish scoring results run: | @@ -153,3 +154,95 @@ jobs: # exclude-workflow-initiator-as-approver: false # additional-approved-words: '' # additional-denied-words: '' + + emergency_unstake: + needs: apply_scoring + runs-on: ubuntu-latest + steps: + - name: Checkout the repository + uses: actions/checkout@master + with: + ref: master + fetch-depth: 20 + + - name: Load scoring details + run: | + set -ex + unstake_hints_json=$(git log -1 --name-only --pretty=format: --grep 'scoring run' | grep unstake-hints.json) + scoring_run_ui_id=$(git log -1 --name-only --pretty=format: --grep 'scoring run' | head -1 | awk -F / '{print $2}') + epoch=$(<<<"$scoring_run_ui_id" awk -F . '{print $1}') + + if [[ -z $unstake_hints_json ]] + then + echo "Failed to find JSON with unstake hints in the PR!" + exit 1 + fi + + if [[ -z $epoch ]] + then + echo "Failed to detect epoch from the UI ID!" + exit 1 + fi + + echo "unstake_hints_json=$unstake_hints_json" >> $GITHUB_ENV + echo "epoch=$epoch" >> $GITHUB_ENV + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_DEFAULT_REGION }} + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v1 + + - name: Prepare solana config + run: | + cat < /tmp/solana-config.yml + json_rpc_url: "$RPC_URL" + websocket_url: "" + keypair_path: /.config/solana/id.json + address_labels: + "11111111111111111111111111111111": System Program + commitment: confirmed + EOF + echo "$KEYPAIR" > /tmp/id.json + + env: + RPC_URL: ${{ secrets.RPC_URL }} + KEYPAIR: ${{ secrets.VALIDATOR_MANAGEMENT_KEYPAIR }} + + - name: Emergency unstake - simulation + run: | + images=$(aws ecr describe-images --repository-name marinade.finance/marinade-anchor) + latest=$(<<<"$images" jq '.imageDetails[] | .imagePushedAt + " " + .imageTags[0]' -r | sort | tail -1 | cut -d' ' -f2) + + <"$UNSTAKE_HINTS_JSON" jq '.unstake_hints[].vote_account' -r | xargs -I{} \ + docker run --rm --user "$(id -u):$(id -g)" \ + -v /tmp/solana-config.yml:/.config/solana/cli/config.yml \ + -v /tmp/id.json:/.config/solana/id.json \ + "$ECR_REGISTRY/$ECR_REPOSITORY:$latest" \ + ./validator-manager -s emergency-unstake {} + env: + ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} + ECR_REPOSITORY: marinade.finance/marinade-anchor + UNSTAKE_HINTS_JSON: ${{ env.unstake_hints_json }} + + - name: Send Discord Notification + run: | + detail=$(<"$UNSTAKE_HINTS_JSON" jq '[.unstake_hints[].marinade_stake] | ((length | tostring) + " validators, " + (add | tostring) + " SOL")' -r) + curl "$DISCORD_WEBHOOK" -H "Content-Type: application/json" -d '{ + "username": "Delegation Strategy - Emergency Unstake", + "avatar_url": "https://public.marinade.finance/ds-emergency-bot.png", + "embeds": [ + { + "title": "Emergency unstake successfully applied. ('"$detail"')", + "color": "52224" + } + ] + }' + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} + UNSTAKE_HINTS_JSON: ${{ env.unstake_hints_json }} \ No newline at end of file diff --git a/README.md b/README.md index 5674dcc8..1eb50797 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,8 @@ flowchart TB publish_a[Score publisher pipeline] -->publish_b publish_b[Publish scoring to DS API] -->publish_c publish_c[Publish scoring on-chain] -->publish_d - publish_d(( )) + publish_d[Emergency unstake] -->publish_e + publish_e(( )) end scheduler_d -->scoring_a scoring_e -->|PR approved and merged| publish_a