@@ -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