Skip to content

Commit 148e431

Browse files
committed
refactor(workflow): streamline daily balance snapshot process
- Replaced inline shell script with a Node.js script for better maintainability. - Added steps for checking out the repository, setting up Node.js, and installing dependencies. - Updated the balance snapshot logic to utilize the new BalanceSnapshotService for improved structure and clarity.
1 parent 1927fa3 commit 148e431

File tree

3 files changed

+315
-343
lines changed

3 files changed

+315
-343
lines changed

.github/workflows/daily-balance-snapshots.yml

Lines changed: 22 additions & 186 deletions
Original file line numberDiff line numberDiff line change
@@ -15,192 +15,28 @@ jobs:
1515
runs-on: ubuntu-latest
1616

1717
steps:
18-
- name: Take balance snapshots
19-
run: |
20-
# Configuration - adjust these values based on your needs
21-
API_BASE_URL="https://multisig.meshjs.dev"
22-
AUTH_TOKEN="${{ secrets.SNAPSHOT_AUTH_TOKEN }}"
23-
24-
# Rate limiting configuration
25-
BATCH_SIZE=3 # Wallets per batch (adjust based on Blockfrost plan)
26-
DELAY_BETWEEN_REQUESTS=3 # Seconds between requests (20/min = 3s)
27-
DELAY_BETWEEN_BATCHES=15 # Seconds between batches
28-
MAX_RETRIES=3 # Max retries for failed requests
29-
REQUEST_TIMEOUT=30 # Request timeout in seconds
30-
31-
echo "🔄 Starting daily balance snapshot process..."
32-
echo "📊 Configuration: batch_size=$BATCH_SIZE, request_delay=${DELAY_BETWEEN_REQUESTS}s, batch_delay=${DELAY_BETWEEN_BATCHES}s"
33-
34-
# Step 1: Get all wallets
35-
echo "📋 Fetching all wallets..."
36-
wallets_response=$(curl -s -w "\n%{http_code}" \
37-
-H "Authorization: Bearer $AUTH_TOKEN" \
38-
"$API_BASE_URL/api/v1/aggregatedBalances/wallets")
39-
40-
wallets_http_code=$(echo "$wallets_response" | tail -n1)
41-
wallets_body=$(echo "$wallets_response" | head -n -1)
42-
43-
echo "Wallets HTTP Status: $wallets_http_code"
44-
45-
if [ "$wallets_http_code" -ne 200 ]; then
46-
echo "❌ Failed to fetch wallets. HTTP Status: $wallets_http_code"
47-
echo "Response: $wallets_body"
48-
exit 1
49-
fi
50-
51-
# Extract wallet data
52-
wallet_count=$(echo "$wallets_body" | jq -r '.walletCount')
53-
echo "✅ Found $wallet_count wallets"
54-
55-
if [ "$wallet_count" -eq 0 ]; then
56-
echo "ℹ️ No wallets found, skipping snapshot process"
57-
exit 0
58-
fi
59-
60-
# Step 2: Get balances for each wallet with rate limiting
61-
echo "💰 Fetching balances for each wallet with rate limiting..."
62-
63-
# Create temporary files for collecting results
64-
temp_balances="/tmp/wallet_balances.json"
65-
temp_failed="/tmp/failed_wallets.txt"
66-
echo "[]" > "$temp_balances"
67-
echo "0" > "$temp_failed"
68-
69-
# Process wallets in batches to respect rate limits
70-
batch_size=$BATCH_SIZE
71-
delay_between_requests=$DELAY_BETWEEN_REQUESTS
72-
delay_between_batches=$DELAY_BETWEEN_BATCHES
73-
74-
# Convert wallets to array for batch processing
75-
wallets_array=$(echo "$wallets_body" | jq -r '.wallets')
76-
total_wallets=$(echo "$wallets_array" | jq 'length')
77-
echo "Processing $total_wallets wallets in batches of $batch_size"
78-
79-
# Process wallets in batches
80-
for ((i=0; i<total_wallets; i+=batch_size)); do
81-
batch_end=$((i + batch_size))
82-
if [ $batch_end -gt $total_wallets ]; then
83-
batch_end=$total_wallets
84-
fi
85-
86-
echo "📦 Processing batch $((i/batch_size + 1)): wallets $((i+1))-$batch_end"
87-
88-
# Process each wallet in the current batch
89-
for ((j=i; j<batch_end; j++)); do
90-
wallet=$(echo "$wallets_array" | jq -r ".[$j]")
91-
wallet_id=$(echo "$wallet" | jq -r '.walletId')
92-
wallet_name=$(echo "$wallet" | jq -r '.walletName')
93-
94-
echo " Processing wallet: $wallet_name ($wallet_id)"
95-
96-
# Build query parameters
97-
query_params="walletId=$(echo "$wallet" | jq -r '.walletId')"
98-
query_params="$query_params&walletName=$(echo "$wallet" | jq -r '.walletName')"
99-
query_params="$query_params&signersAddresses=$(echo "$wallet" | jq -r '.signersAddresses | @json')"
100-
query_params="$query_params&numRequiredSigners=$(echo "$wallet" | jq -r '.numRequiredSigners')"
101-
query_params="$query_params&type=$(echo "$wallet" | jq -r '.type')"
102-
query_params="$query_params&stakeCredentialHash=$(echo "$wallet" | jq -r '.stakeCredentialHash // ""')"
103-
query_params="$query_params&isArchived=$(echo "$wallet" | jq -r '.isArchived')"
104-
query_params="$query_params&network=$(echo "$wallet" | jq -r '.network')"
105-
query_params="$query_params&paymentAddress=$(echo "$wallet" | jq -r '.paymentAddress')"
106-
query_params="$query_params&stakeableAddress=$(echo "$wallet" | jq -r '.stakeableAddress')"
107-
108-
# Fetch balance for this wallet with retry logic
109-
max_retries=$MAX_RETRIES
110-
retry_count=0
111-
success=false
112-
113-
while [ $retry_count -lt $max_retries ] && [ "$success" = false ]; do
114-
balance_response=$(curl -s -w "\n%{http_code}" \
115-
--max-time $REQUEST_TIMEOUT \
116-
--connect-timeout 10 \
117-
-H "Authorization: Bearer $AUTH_TOKEN" \
118-
"$API_BASE_URL/api/v1/aggregatedBalances/balance?$query_params")
119-
120-
balance_http_code=$(echo "$balance_response" | tail -n1)
121-
balance_body=$(echo "$balance_response" | head -n -1)
122-
123-
if [ "$balance_http_code" -eq 200 ]; then
124-
wallet_balance=$(echo "$balance_body" | jq -r '.walletBalance')
125-
echo " ✅ Balance: $(echo "$wallet_balance" | jq -r '.adaBalance') ADA"
126-
127-
# Add to balances array
128-
current_balances=$(cat "$temp_balances")
129-
updated_balances=$(echo "$current_balances" | jq ". + [$(echo "$wallet_balance" | jq -c .)]")
130-
echo "$updated_balances" > "$temp_balances"
131-
132-
success=true
133-
elif [ "$balance_http_code" -eq 429 ]; then
134-
# Rate limited - wait longer before retry
135-
retry_delay=$((delay_between_requests * (retry_count + 1) * 2))
136-
echo " ⚠️ Rate limited (429). Waiting ${retry_delay}s before retry $((retry_count + 1))/$max_retries"
137-
sleep $retry_delay
138-
retry_count=$((retry_count + 1))
139-
else
140-
echo " ❌ Failed to fetch balance for wallet $wallet_id: $balance_http_code"
141-
failed_count=$(cat "$temp_failed")
142-
echo $((failed_count + 1)) > "$temp_failed"
143-
success=true # Don't retry on non-rate-limit errors
144-
fi
145-
done
146-
147-
if [ "$success" = false ]; then
148-
echo " ❌ Max retries exceeded for wallet $wallet_id"
149-
failed_count=$(cat "$temp_failed")
150-
echo $((failed_count + 1)) > "$temp_failed"
151-
fi
152-
153-
# Delay between requests within a batch
154-
if [ $((j+1)) -lt $batch_end ]; then
155-
sleep $delay_between_requests
156-
fi
157-
done
158-
159-
# Delay between batches (except for the last batch)
160-
if [ $batch_end -lt $total_wallets ]; then
161-
echo " ⏳ Waiting ${delay_between_batches}s before next batch..."
162-
sleep $delay_between_batches
163-
fi
164-
done
165-
166-
# Read final results
167-
wallet_balances=$(cat "$temp_balances")
168-
failed_wallets=$(cat "$temp_failed")
169-
170-
echo "📊 Balance fetching completed. Failed wallets: $failed_wallets"
171-
echo "✅ Successfully processed: $(echo "$wallet_balances" | jq 'length') wallets"
172-
173-
# Step 3: Store snapshots using the collected balances
174-
echo "💾 Storing balance snapshots..."
175-
snapshots_response=$(curl -s -w "\n%{http_code}" \
176-
-H "Authorization: Bearer $AUTH_TOKEN" \
177-
-H "Content-Type: application/json" \
178-
-d "{\"walletBalances\": $wallet_balances}" \
179-
"$API_BASE_URL/api/v1/aggregatedBalances/snapshots")
180-
181-
snapshots_http_code=$(echo "$snapshots_response" | tail -n1)
182-
snapshots_body=$(echo "$snapshots_response" | head -n -1)
183-
184-
echo "Snapshots HTTP Status: $snapshots_http_code"
185-
echo "Response: $snapshots_body"
186-
187-
# Check if the request was successful
188-
if [ "$snapshots_http_code" -eq 200 ]; then
189-
# Parse the response to get the number of snapshots stored
190-
snapshots_stored=$(echo "$snapshots_body" | jq -r '.snapshotsStored // 0')
191-
total_tvl=$(echo "$snapshots_body" | jq -r '.totalValueLocked.ada')
192-
echo "✅ Successfully stored $snapshots_stored balance snapshots"
193-
echo "💰 Total Value Locked: $total_tvl ADA"
194-
195-
# Optional: Send notification on success (you can add Discord/Slack webhook here)
196-
# curl -X POST -H 'Content-type: application/json' \
197-
# --data "{\"text\":\"✅ Daily balance snapshots completed: $snapshots_stored snapshots stored, TVL: $total_tvl ADA\"}" \
198-
# ${{ secrets.DISCORD_WEBHOOK_URL }}
199-
else
200-
echo "❌ Failed to store balance snapshots. HTTP Status: $snapshots_http_code"
201-
echo "Response: $snapshots_body"
202-
exit 1
203-
fi
18+
- name: Checkout repository
19+
uses: actions/checkout@v4
20+
21+
- name: Setup Node.js
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: '18'
25+
cache: 'npm'
26+
27+
- name: Install dependencies
28+
run: npm ci
29+
30+
- name: Run balance snapshots
31+
run: node scripts/balance-snapshots.js
32+
env:
33+
API_BASE_URL: "https://multisig.meshjs.dev"
34+
SNAPSHOT_AUTH_TOKEN: ${{ secrets.SNAPSHOT_AUTH_TOKEN }}
35+
BATCH_SIZE: 3
36+
DELAY_BETWEEN_REQUESTS: 3
37+
DELAY_BETWEEN_BATCHES: 15
38+
MAX_RETRIES: 3
39+
REQUEST_TIMEOUT: 30
20440

20541
- name: Notify on failure
20642
if: failure()

0 commit comments

Comments
 (0)