Validatus’s Strategic Approach to Overcoming the Evmos Slashing Challenge

Validatus
7 min readDec 23, 2023

--

Embracing Transparency in Our Reimbursement Journey

The recent event in the Evmos blockchain have been a true test of resilience and integrity for Validatus. Faced with the challenge of a slashing event, our team committed to a transparent and meticulous process to ensure that every delegator was compensated.

We took immediate action to ensure the security and integrity of our system and infrastructure. In the spirit of transparency, we would like to provide an overview of the event and the steps we have taken to address it.

To gain comprehensive insights and view our transparent communication history, explore our detailed thread on Twitter.

While migrating our validator to a new server, an unexpected double-signing event occurred. This was our final validator to transition to TMKMS. Unfortunately, the presence of the private validator key on the original server triggered the double-signing. We have taken all the necessary steps to prevent such occurrences in the future.

In response to the slashing event, we have initiated a refund process to compensate affected delegators. The compensation amount has been calculated based on the delegation balance before the slashing occurred. We have created a RefundList.json file, which contains the details of the compensation for each delegation. This ensures that affected delegators are appropriately refunded for any potential losses incurred.

We understand the importance of transparency and accountability, and we are committed to providing updates and communication regarding the refund process.

The Reimbursement Process: A Blend of Technology and Trust

We have provided a precise overview of the whole process in the first part of the article, while a technical overview of the whole process is discussed in the second part of the article.

A precise overview

1. Meticulous Data Gathering: At the heart of our response was a detailed data gathering process. We utilized a tailored Bash script to query staking delegations after the slashing event. This step ensured we had accurate and comprehensive data, crucial for fair compensation.

2. Precise Compensation Calculation: Leveraging the power of Python, our team developed a script to accurately calculate the compensation for each delegation. This script considered the double-sign slashing parameter of the Evmos blockhain, which is 10%. We calculated the pre-slashing amount using the post-slashing amounts, ensuring every delegator was reimbursed fairly for their loss.

3. Transparent Transaction Preparation: To maintain transparency and precision, we crafted a transaction file that outlined every wallet address with the right compensation amount. This file was meticulously prepared to ensure every delegator was accounted for, reflecting our commitment to fairness and accuracy.

4. Secure and Public Execution: The final step was signing and broadcasting the transaction. We executed this with the highest standards of security and transparency and published the transaction hash publically, so anyone can verify it, ensuring the integrity of the entire process.

This process, while technical, was essential in upholding our values of transparency and trust.

In-depth technical overview

Step 1. Query the RPC endpoint using evmosd-query.sh script, to get Evmos-Unique-Delegators.json file.

#!/bin/bash
# Initialize limit
limit=200

# Event height
height=17798355

# Get the total count of delegations
total_count=$(evmosd query staking delegations-to evmosvaloper15fezptqfn3rmxtl4006ze9plealy4w9xdfamnv --count-total --node https://rpc.evmos.validatus.com:443 --output json | jq -r '.pagination.total')
echo "unique delegatos: $total_count"

# Calculate the maximum offset based on the total count
max_offset=$((total_count > 0 ? total_count - 1 : 0))

offset=0
while (( offset < max_offset )); do
# Construct the filename
filename="Evmos-Unique-Delegators-$offset-$((offset+limit)).json"

# Run the query with the current offset and limit, and output to the constructed filename
evmosd query staking delegations-to evmosvaloper15fezptqfn3rmxtl4006ze9plealy4w9xdfamnv \
--height=$height \
--limit $limit \
--offset=$offset \
--node https://rpc.evmos.validatus.com:443 \
--output json > $filename

# Increase the offset by the limit for the next iteration
offset=$((offset+limit))
# Wait for 15 seconds to avoid rate limit
sleep 15
done

# Concatenate all JSON files into one
jq -s '.' Evmos-Unique-Delegators-*.json > Evmos-Unique-Delegators.jsonIn-depth technical overview

Step 2. Create the RefundList.json using the Python script RefundList.py :

#!/usr/bin/python3

import csv
import json

# Open and load JSON data from the file 'Evmos-Unique-Delegators.json'
with open('Evmos-Unique-Delegators.json', 'r') as f:
data = json.load(f)

# Function to normalize the amount by converting it from string to float and dividing by 10^18
def convert_amount(amount):
return float(amount) / (1 * 10**18)

# Function to calculate the compensation for each delegation response
def calculate_compensation(data):
# Initialize an empty list to store the compensation data for each delegation response
compensation_data = []

# Iterate over each item in the data list
for data_item in data:
# Iterate over each delegation response in the current data item
for delegation_response in data_item['delegation_responses']:
# Convert the amount to a float
amount = float(delegation_response['balance']['amount'])

# Convert the amount to a different unit (e.g., from wei to ether)
converted_amount = convert_amount(delegation_response['balance']['amount'])

# Calculate the amount that was delegated before the slashing event
delegated_amount_before_slashing = amount / 0.9

# Calculate the compensation amount
compensation_amount = delegated_amount_before_slashing - amount

# Format the compensation amount as a string with no decimal places
formatted_compensation_amount = "{:.0f}".format(compensation_amount)

# Convert the compensation amount to a different unit (e.g., from wei to ether)
converted_compensation_amount = convert_amount(compensation_amount)

# Create a dictionary with the compensation data for the current delegation response
compensated_item = {
'delegation': delegation_response['delegation'],
'balance': delegation_response['balance'],
'converted_amount': converted_amount,
'delegated_amount_before_slashing': delegated_amount_before_slashing,
'compensation_amount': formatted_compensation_amount,
'converted_compensation_amount': converted_compensation_amount
}

# Add the compensated item to the compensation data list
compensation_data.append(compensated_item)

# Return the compensation data list
return compensation_data

# Calculate the compensation for each delegation response in the data
compensation_data = calculate_compensation(data)
# Print the compensation data to the console
print(compensation_data)

# Write the compensation data to a new JSON file 'RefundList.json'
with open('RefundList.json', 'w') as f:
json.dump(compensation_data, f, indent=4)


# We're writing the data to a CSV file because it's a common, simple, and standardized format
# that can be opened in many different programs. This makes it easy for anyone to inspect,
# analyze, and verify the data manually. It also provides a level of transparency, as anyone
# can easily understand the structure of a CSV file and see the raw data.

# Load JSON data
with open('RefundList.json') as file:
data = json.load(file)

# Open (or create) a CSV file and write the data into it
with open('RefundList.csv', 'w', newline='') as file:
writer = csv.writer(file, delimiter=';')

# Write the header
headers = list(data[0]['delegation'].keys()) + list(data[0]['balance'].keys()) + ['converted_amount', 'delegated_amount_before_slashing', 'compensation_amount', 'converted_compensation_amount']
writer.writerow(headers)

# Write data rows
for data_item in data:
delegation_values = list(data_item['delegation'].values())
balance_values = list(data_item['balance'].values())
other_values = [data_item['converted_amount'], data_item['delegated_amount_before_slashing'], data_item['compensation_amount'], data_item['converted_compensation_amount']]
writer.writerow(delegation_values + balance_values + other_values)

Step 3. Now we will prepare a transaction file using the PrepareTX.sh script, to get TransactionReadyToSign.json:

#!/bin/bash
# Define the source address and file paths
SOURCE="evmos15fezptqfn3rmxtl4006ze9plealy4w9xq8jtj3"
TRANSACTION_JSON="./TransactionReadyToSign.json"
TRANSACTION_CSV="./Transaction.csv"
COMPENSATION_JSON="./RefundList.json"

# Extract addresses and compensation amounts from the compensation JSON file using jq
addresses=($(jq -r '.[] | .delegation.delegator_address' "$COMPENSATION_JSON"))
compensation_amounts=($(jq -r '.[] | .compensation_amount' "$COMPENSATION_JSON"))

# Check if the arrays of addresses and compensation amounts have the same length
if [ "${#addresses[@]}" -ne "${#compensation_amounts[@]}" ]; then
echo "Error: The number of addresses does not match the number of compensation amounts."
exit 1
fi

# Create the transaction JSON file and write the opening part of the JSON structure
cat > "$TRANSACTION_JSON" << EOF
{"body":{
"messages":[
EOF

# Loop through the arrays of addresses and compensation amounts
for ((index=0; index<${#addresses[@]}; index++)); do
# If the compensation amount is "0", skip this iteration
# Note: Entries with a compensation amount of "0" are not included in the transaction JSON file
if [ "${compensation_amounts[$index]}" == "0" ]; then
continue
fi

# For each address and compensation amount, append a new message to the transaction JSON file
if [ $index -eq $((${#addresses[@]} - 1)) ]; then
cat >> "$TRANSACTION_JSON" << EOF
{"@type":"/cosmos.bank.v1beta1.MsgSend","from_address":"${SOURCE}","to_address":"${addresses[$index]}","amount":[{"denom":"aevmos","amount":"${compensation_amounts[$index]}"}]}
EOF
else
cat >> "$TRANSACTION_JSON" << EOF
{"@type":"/cosmos.bank.v1beta1.MsgSend","from_address":"${SOURCE}","to_address":"${addresses[$index]}","amount":[{"denom":"aevmos","amount":"${compensation_amounts[$index]}"}]},
EOF
fi
done

# Write the closing part of the JSON structure to the transaction JSON file
cat >> "$TRANSACTION_JSON" << EOF
],"memo":"Validatus Slashing Refund [12/20/2023] with ❤️","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]
},
"auth_info":{"signer_infos":[],"fee":{"amount":[{"denom":"aevmos","amount":"1200000000000000000"}],"gas_limit":"40000000","payer":"","granter":""}},
"signatures":[]
}
EOF

Step 4. Signing the TransactionReadyToSign.json file:

# sign transaction:
evmosd tx sign TransactionReadyToSign.json --from evmos15fezptqfn3rmxtl4006ze9plealy4w9xq8jtj3 --chain-id=evmos_9001-2 --node https://rpc.evmos.validatus.com:443 > signedTX.json

Step 5. Broadcasting the signedTX.json:

# Broadcast transaction
evmosd tx broadcast signedTX.json --chain-id=evmos_9001-2 --broadcast-mode=block --node https://rpc.evmos.validatus.com:443

All the files can be downloaded directly from here:

evmosd-query.sh

Evmos-Unique-Delegators.json

RefundList.py

RefundList.json

RefundList-spreadsheet.csv

PrepareTX.sh

TransactionReadyToSign.json

signedTX.json

Providing Access to Evmos Blockchain Data for Enhanced Transparency

In line with our commitment to transparency and full disclosure, we have taken the initiative to host our own history of Evmos blockchain data. This resource is available for anyone interested in exploring the data in detail and verifying our actions during the event. We believe this offers an unparalleled level of insight and openness.

Our hosted data is a temporary resource. We ensure it will be accessible for a full quarter, remaining available until the end of the first quarter of 2024. This limitation is due to storage constraints, as our servers can only maintain this extensive data for a limited period. We encourage interested parties to access and review this information soon to gain a deeper understanding of the event and our response.

You can query the RPC endpoint for detailed Evmos blockchain data using this link: https://rpc.evmos.validatus.com:443.

🚀 Beyond Reimbursement: Strengthening

The journey through this event has been more than just a technical response. It has been a reaffirmation of our commitment to the Cosmos Ecosystem. We’ve emerged stronger, wiser, and more united. As we continue to grow within the Cosmos ecosystem, our focus remains on maintaining the trust you’ve placed in us and ensuring the security and performance of our systems.

Our journey in the blockchain world continues, and strengthened by our experiences, we are poised to turn these challenges into opportunities for innovation and growth. Our commitment to navigating the complexities of blockchain technology is unwavering, and we are excited about the possibilities that lie ahead for Validatus and the entire Cosmos ecosystem.

Let us embrace the transformative potential of blockchain technology together, remaining steadfast in our journey towards a decentralized and interconnected future. Your unwavering support and trust in Validatus have been the cornerstone of our resilience. Together, we’ve turned a challenge into a remarkable triumph. Here’s to continuing our journey, fortified by the lessons learned, and the bonds strengthened within our community.

The journey ahead may be filled with challenges, but these are the growing pains typical of any emerging technology. By taking strategic risks, forming robust relationships, and making well-considered trade-offs, we can navigate the evolving landscape of blockchain technology and harness its full potential.

Together, let’s look forward to a future where blockchain technology becomes a powerful solution to longstanding problems, driven by collective effort and shared vision.

--

--

Validatus
Validatus

Written by Validatus

Validatus.com provides independent infrastructure, to ensure the integrity and reliability of transactions across various blockchain ecosystems. Visit us!

No responses yet