forked from digibyte/digibyte
-
Notifications
You must be signed in to change notification settings - Fork 97
Expand file tree
/
Copy pathtest_digidollar_qt_testnet.sh
More file actions
executable file
·2789 lines (2367 loc) · 108 KB
/
Copy pathtest_digidollar_qt_testnet.sh
File metadata and controls
executable file
·2789 lines (2367 loc) · 108 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/bin/bash
# DigiDollar Qt GUI TestNet Test with Live Oracle
# VERSION 9: COMPREHENSIVE ALL-TIER + TRANSFER CHAIN + WALLET PERSISTENCE TESTING
# Tests the full DigiDollar cycle on TestNet with real-time exchange price data
# Opens 3 SEPARATE Qt wallet instances (Bob, Alice, Charlie)
#
# TEST PLAN:
# - Bob mints $100 at tier 0, then $110 at tier 0 and tiers 1-8 = 10 mints total
# - Mine past tier 0 lock (240 blocks)
# - Bob redeems 2x tier 0 mints successfully
# - Test partial redemption (should FAIL)
# - Alice mints $100 at tier 3 (180 days) and tier 5 (3 years)
# - Charlie mints $100 at tier 7 (7 years) and tier 8 (10 years)
# - Comprehensive transfer chain: Bob->Alice($55), Alice->Charlie($22), Charlie->Bob($10), Bob->Charlie($5)
# - Full balance verification at EVERY step
# - Transaction confirmation verification
# - Network-wide DD supply and collateral tracking
#
# WALLET PERSISTENCE TESTS (NEW in V9):
# - Step 28: WALLET RESTART - Stop Bob's Qt, restart, verify DD balances persist
# - Step 29: WALLET BACKUP/RESTORE - Backup wallet, restore, verify DD balances
# - Step 30: REINDEX TEST - Stop node, restart with -reindex, verify DD rebuilt
set -e
# Create log file with timestamp
LOG_DIR="/tmp/digidollar_debug_logs"
mkdir -p "$LOG_DIR"
LOG_FILE="$LOG_DIR/test_run_$(date +%Y%m%d_%H%M%S).log"
echo "=========================================="
echo "DigiDollar Qt TestNet Automated Test"
echo "VERSION 9 - COMPREHENSIVE ALL-TIER + TRANSFER CHAIN + WALLET PERSISTENCE"
echo "=========================================="
echo "Log file: $LOG_FILE"
echo ""
# Tee output to both console and log file
exec > >(tee -a "$LOG_FILE") 2>&1
echo "=========================================="
echo "DigiDollar Qt TestNet Automated Test"
echo "With 3 SEPARATE Qt GUI Instances"
echo "Using LIVE Oracle Price Data"
echo "VERSION 9: ALL-TIER + TRANSFER + WALLET PERSISTENCE"
echo "=========================================="
echo "Test started: $(date)"
echo ""
# Configuration
ORACLE_PRIVATE_KEY="0000000000000000000000000000000000000000000000000000000000000001"
# Mini Testnet ports
BOB_PORT=12027
BOB_RPC=14027
ALICE_PORT=12029
ALICE_RPC=14029
CHARLIE_PORT=12030
CHARLIE_RPC=14030
# Data directories
BOB_DATADIR="/tmp/bob_minitestnet"
ALICE_DATADIR="/tmp/alice_minitestnet"
CHARLIE_DATADIR="/tmp/charlie_minitestnet"
# CLI commands
BOB_CLI="./src/digibyte-cli -testnet -datadir=$BOB_DATADIR -rpcport=$BOB_RPC"
ALICE_CLI="./src/digibyte-cli -testnet -datadir=$ALICE_DATADIR -rpcport=$ALICE_RPC"
CHARLIE_CLI="./src/digibyte-cli -testnet -datadir=$CHARLIE_DATADIR -rpcport=$CHARLIE_RPC"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
NC='\033[0m'
# EXPECTED DD balances (updated after each operation)
EXPECT_BOB_DD=0
EXPECT_ALICE_DD=0
EXPECT_CHARLIE_DD=0
# Track mints for redemption
declare -A BOB_MINTS # txid -> dd_amount
declare -A BOB_COLLATERAL # txid -> collateral_dgb
BOB_TIER0_MINT1=""
BOB_TIER0_MINT2=""
# Test counters
TOTAL_TESTS=0
PASSED_TESTS=0
FAILED_TESTS=0
print_status() {
local status=$1
local message=$2
TOTAL_TESTS=$((TOTAL_TESTS + 1))
if [ "$status" = "ok" ]; then
echo -e "${GREEN}[OK]${NC} $message"
PASSED_TESTS=$((PASSED_TESTS + 1))
elif [ "$status" = "fail" ]; then
echo -e "${RED}[FAIL]${NC} $message"
FAILED_TESTS=$((FAILED_TESTS + 1))
elif [ "$status" = "warn" ]; then
echo -e "${YELLOW}[WARN]${NC} $message"
elif [ "$status" = "info" ]; then
echo -e "${CYAN}[INFO]${NC} $message"
TOTAL_TESTS=$((TOTAL_TESTS - 1)) # Don't count info as test
else
echo "[INFO] $message"
TOTAL_TESTS=$((TOTAL_TESTS - 1))
fi
}
print_header() {
echo ""
echo -e "${BLUE}==========================================${NC}"
echo -e "${BLUE}$1${NC}"
echo -e "${BLUE}==========================================${NC}"
}
print_subheader() {
echo ""
echo -e "${CYAN}--- $1 ---${NC}"
}
wait_for_rpc() {
local cli=$1
local name=$2
local max=30
for i in $(seq 1 $max); do
if $cli getblockchaininfo > /dev/null 2>&1; then
return 0
fi
sleep 2
done
return 1
}
# Get balances safely
get_dgb_balance() {
local cli=$1
local wallet=$2
$cli -rpcwallet=$wallet getbalance 2>/dev/null || echo "0"
}
get_dd_balance() {
local cli=$1
local wallet=$2
$cli -rpcwallet=$wallet getdigidollarbalance 2>/dev/null | jq -r '.total // 0' 2>/dev/null || echo "0"
}
get_immature_balance() {
local cli=$1
local wallet=$2
$cli -rpcwallet=$wallet getbalances 2>/dev/null | jq -r '.mine.immature // 0' 2>/dev/null || echo "0"
}
get_network_collateral() {
$BOB_CLI getdigidollarstats 2>/dev/null | jq -r '.total_collateral_dgb // "0"' 2>/dev/null || echo "0"
}
get_network_dd_supply() {
$BOB_CLI getdigidollarstats 2>/dev/null | jq -r '.total_dd_supply // 0' 2>/dev/null || echo "0"
}
# VERIFY DD BALANCE with expected value
verify_dd_balance() {
local name=$1
local cli=$2
local wallet=$3
local expected=$4
local actual=$(get_dd_balance "$cli" "$wallet")
if [ "$actual" = "$expected" ]; then
echo -e " ${GREEN}[OK]${NC} $name DD: $actual cents (expected: $expected)"
PASSED_TESTS=$((PASSED_TESTS + 1))
TOTAL_TESTS=$((TOTAL_TESTS + 1))
return 0
else
echo -e " ${RED}[FAIL]${NC} $name DD: $actual cents (EXPECTED: $expected)"
FAILED_TESTS=$((FAILED_TESTS + 1))
TOTAL_TESTS=$((TOTAL_TESTS + 1))
return 1
fi
}
# COMPREHENSIVE BALANCE VERIFICATION at each step
verify_all_balances() {
local step_desc=$1
local block_height=$($BOB_CLI getblockcount 2>/dev/null || echo "0")
print_header "VERIFICATION: $step_desc (Block $block_height)"
echo ""
echo "========== DIGIBYTE (DGB) BALANCES =========="
# Get all DGB balances
local bob_dgb=$(get_dgb_balance "$BOB_CLI" "bob")
local bob_immature=$(get_immature_balance "$BOB_CLI" "bob")
local alice_dgb=$(get_dgb_balance "$ALICE_CLI" "alice")
local alice_immature=$(get_immature_balance "$ALICE_CLI" "alice")
local charlie_dgb=$(get_dgb_balance "$CHARLIE_CLI" "charlie")
local charlie_immature=$(get_immature_balance "$CHARLIE_CLI" "charlie")
echo " BOB: $bob_dgb DGB (immature: $bob_immature)"
echo " ALICE: $alice_dgb DGB (immature: $alice_immature)"
echo " CHARLIE: $charlie_dgb DGB (immature: $charlie_immature)"
echo ""
echo "========== DIGIDOLLAR (DD) BALANCES =========="
# Verify each DD balance against expected
verify_dd_balance "BOB" "$BOB_CLI" "bob" "$EXPECT_BOB_DD"
verify_dd_balance "ALICE" "$ALICE_CLI" "alice" "$EXPECT_ALICE_DD"
verify_dd_balance "CHARLIE" "$CHARLIE_CLI" "charlie" "$EXPECT_CHARLIE_DD"
local total_expected_dd=$((EXPECT_BOB_DD + EXPECT_ALICE_DD + EXPECT_CHARLIE_DD))
echo ""
echo " Total Expected DD: $total_expected_dd cents (\$$(echo "scale=2; $total_expected_dd / 100" | bc 2>/dev/null || echo "0"))"
echo ""
echo "========== NETWORK STATS =========="
# IMPORTANT: Sync validation interface queue before checking network stats
# The DigiDollar stats index is updated asynchronously, so we need to wait
# for it to process all pending block notifications. Without this, the stats
# may lag behind by 1-2 blocks, causing supply mismatches.
$BOB_CLI syncwithvalidationinterfacequeue 2>/dev/null
sleep 1
local network_dd=$(get_network_dd_supply)
local network_collateral=$(get_network_collateral)
local oracle_price=$($BOB_CLI getoracleprice 2>/dev/null | jq -r '.price_usd // "N/A"')
echo " Oracle Price: \$$oracle_price per DGB"
echo " Network DD Supply: $network_dd cents"
echo " Network Collateral: $network_collateral DGB"
# Verify network DD matches expected total
if [ "$network_dd" = "$total_expected_dd" ]; then
echo -e " ${GREEN}[OK]${NC} Network DD supply matches expected ($network_dd = $total_expected_dd)"
PASSED_TESTS=$((PASSED_TESTS + 1))
TOTAL_TESTS=$((TOTAL_TESTS + 1))
else
echo -e " ${RED}[FAIL]${NC} Network DD supply mismatch: $network_dd != expected $total_expected_dd"
FAILED_TESTS=$((FAILED_TESTS + 1))
TOTAL_TESTS=$((TOTAL_TESTS + 1))
fi
echo "=========================================="
}
# List DD positions for a wallet
list_dd_positions() {
local cli=$1
local wallet=$2
local name=$3
print_subheader "$name's DD Positions"
local positions=$($cli -rpcwallet=$wallet listdigidollarpositions false 2>/dev/null || echo "[]")
if [ "$positions" = "[]" ] || [ -z "$positions" ]; then
echo " No DD positions found"
return
fi
local count=$(echo "$positions" | jq 'length')
echo " Total positions: $count"
echo "$positions" | jq -r '.[] | " [\(.status)] \(.dd_minted) cents - \(.dgb_collateral) DGB - tier \(.lock_tier) - \(.position_id[0:12])..."' 2>/dev/null || echo " Error parsing positions"
}
# Sync all nodes to the same height
sync_all_nodes() {
local target_height=$($BOB_CLI getblockcount)
echo "Syncing all nodes to height $target_height..."
for i in {1..30}; do
local alice_height=$($ALICE_CLI getblockcount 2>/dev/null || echo "0")
local charlie_height=$($CHARLIE_CLI getblockcount 2>/dev/null || echo "0")
if [ "$alice_height" = "$target_height" ] && [ "$charlie_height" = "$target_height" ]; then
return 0
fi
sleep 2
done
echo "Warning: Nodes may not be fully synced"
return 1
}
# Tier descriptions (9 tiers: 0-8)
get_tier_description() {
local tier=$1
# Must match consensus/digidollar.h collateralRatios
case $tier in
0) echo "1 hour (240 blocks)" ;;
1) echo "30 days" ;;
2) echo "90 days" ;;
3) echo "180 days" ;;
4) echo "1 year" ;;
5) echo "3 years" ;;
6) echo "5 years" ;;
7) echo "7 years" ;;
8) echo "10 years" ;;
*) echo "unknown" ;;
esac
}
# ============================================================================
# MAIN TEST EXECUTION
# ============================================================================
# Step 1: Clean environment
print_header "Step 1: Cleaning environment"
# Kill any existing testnet processes (try graceful first, then force)
echo "Stopping any existing testnet processes..."
pkill -f "digibyte-qt.*testnet" 2>/dev/null || true
pkill -f "digibyted.*testnet" 2>/dev/null || true
sleep 2
# Force kill if still running
pkill -9 -f "digibyte-qt.*testnet" 2>/dev/null || true
pkill -9 -f "digibyted.*testnet" 2>/dev/null || true
sleep 1
# Clean up ALL test data directories to prevent stale wallet data issues
echo "Removing old test data directories..."
rm -rf $BOB_DATADIR $ALICE_DATADIR $CHARLIE_DATADIR
rm -rf /tmp/bob_testnet*.log /tmp/alice_testnet*.log /tmp/charlie_testnet*.log
rm -rf /tmp/bob_descriptors.json /tmp/alice_descriptors.json
rm -rf /tmp/bob_import_request.json /tmp/alice_import_request.json
# Verify directories are actually removed
if [ -d "$BOB_DATADIR" ] || [ -d "$ALICE_DATADIR" ] || [ -d "$CHARLIE_DATADIR" ]; then
echo -e "${RED}WARNING: Failed to remove data directories. Retrying...${NC}"
sleep 2
rm -rf $BOB_DATADIR $ALICE_DATADIR $CHARLIE_DATADIR
fi
# Create fresh directories
mkdir -p $BOB_DATADIR $ALICE_DATADIR $CHARLIE_DATADIR
print_status "ok" "Clean environment ready (all stale data removed)"
# Step 2: Start Bob's Qt node
print_header "Step 2: Starting Bob's Qt node"
env -i \
DISPLAY="${DISPLAY}" \
XAUTHORITY="${XAUTHORITY}" \
WAYLAND_DISPLAY="${WAYLAND_DISPLAY}" \
XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR}" \
XDG_SESSION_TYPE="${XDG_SESSION_TYPE}" \
HOME="${HOME}" \
USER="${USER}" \
PATH="${PATH}" \
./src/qt/digibyte-qt \
-testnet \
-easypow \
-datadir=$BOB_DATADIR \
-port=$BOB_PORT \
-rpcport=$BOB_RPC \
-server \
-listen=1 \
-discover=0 \
-digidollar=1 \
-txindex=1 \
-fallbackfee=0.0001 \
-dandelion=0 \
-debug=digidollar \
> /tmp/bob_testnet.log 2>&1 &
BOB_PID=$!
echo "Bob's Qt started (PID: $BOB_PID)"
if wait_for_rpc "$BOB_CLI" "Bob"; then
print_status "ok" "Bob's Qt RPC is ready"
else
print_status "fail" "Bob's Qt failed to start"
exit 1
fi
# Step 3: Setup Bob's wallet and generate lots of DGB for 12+ mints
print_header "Step 3: Setting up Bob's wallet with sufficient DGB"
$BOB_CLI createwallet "bob" 2>/dev/null || true
BOB_ADDR=$($BOB_CLI -rpcwallet=bob getnewaddress "mining" "bech32")
echo "Bob's mining address: $BOB_ADDR"
# Bob needs DGB for 12 mints at ~$100 each. At $0.01/DGB that's ~$12,000 collateral
# Plus 150% collateralization = ~$18,000 worth of DGB = ~1,800,000 DGB
# Mining 300 blocks = 300 * 72000 = 21,600,000 DGB (plenty)
echo "Mining 350 blocks for Bob's coinbase maturity and DGB..."
$BOB_CLI generatetoaddress 350 "$BOB_ADDR" > /dev/null 2>&1
HEIGHT=$($BOB_CLI getblockcount)
print_status "ok" "Mined to height $HEIGHT"
BOB_BALANCE=$($BOB_CLI -rpcwallet=bob getbalance)
echo "Bob's DGB balance: $BOB_BALANCE DGB"
# Step 4: Start oracle
print_header "Step 4: Starting Live Oracle on Bob's node"
$BOB_CLI startoracle 0 "$ORACLE_PRIVATE_KEY" 2>/dev/null || true
sleep 2
$BOB_CLI generatetoaddress 1 "$BOB_ADDR" > /dev/null 2>&1
for i in {1..20}; do
STATUS=$($BOB_CLI getoracleprice 2>/dev/null | jq -r '.status // "inactive"')
if [ "$STATUS" = "active" ]; then
print_status "ok" "Oracle is active"
break
fi
sleep 2
done
ORACLE_PRICE=$($BOB_CLI getoracleprice 2>/dev/null | jq -r '.price_usd // "N/A"')
echo "LIVE Oracle Price: \$$ORACLE_PRICE per DGB"
# Step 5: Start Alice's Qt node
print_header "Step 5: Starting Alice's Qt node"
env -i \
DISPLAY="${DISPLAY}" \
XAUTHORITY="${XAUTHORITY}" \
WAYLAND_DISPLAY="${WAYLAND_DISPLAY}" \
XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR}" \
XDG_SESSION_TYPE="${XDG_SESSION_TYPE}" \
HOME="${HOME}" \
USER="${USER}" \
PATH="${PATH}" \
./src/qt/digibyte-qt \
-testnet \
-easypow \
-datadir=$ALICE_DATADIR \
-port=$ALICE_PORT \
-rpcport=$ALICE_RPC \
-server \
-listen=1 \
-discover=0 \
-digidollar=1 \
-txindex=1 \
-fallbackfee=0.0001 \
-dandelion=0 \
-debug=digidollar \
-connect=127.0.0.1:$BOB_PORT \
> /tmp/alice_testnet.log 2>&1 &
ALICE_PID=$!
echo "Alice's Qt started (PID: $ALICE_PID)"
if wait_for_rpc "$ALICE_CLI" "Alice"; then
print_status "ok" "Alice's Qt RPC is ready"
fi
$ALICE_CLI createwallet "alice" 2>/dev/null || true
ALICE_ADDR=$($ALICE_CLI -rpcwallet=alice getnewaddress "receive" "bech32")
echo "Alice's address: $ALICE_ADDR"
# Step 6: Start Charlie's Qt node
print_header "Step 6: Starting Charlie's Qt node"
env -i \
DISPLAY="${DISPLAY}" \
XAUTHORITY="${XAUTHORITY}" \
WAYLAND_DISPLAY="${WAYLAND_DISPLAY}" \
XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR}" \
XDG_SESSION_TYPE="${XDG_SESSION_TYPE}" \
HOME="${HOME}" \
USER="${USER}" \
PATH="${PATH}" \
./src/qt/digibyte-qt \
-testnet \
-easypow \
-datadir=$CHARLIE_DATADIR \
-port=$CHARLIE_PORT \
-rpcport=$CHARLIE_RPC \
-server \
-listen=1 \
-discover=0 \
-digidollar=1 \
-txindex=1 \
-fallbackfee=0.0001 \
-dandelion=0 \
-debug=digidollar \
-connect=127.0.0.1:$BOB_PORT \
> /tmp/charlie_testnet.log 2>&1 &
CHARLIE_PID=$!
echo "Charlie's Qt started (PID: $CHARLIE_PID)"
if wait_for_rpc "$CHARLIE_CLI" "Charlie"; then
print_status "ok" "Charlie's Qt RPC is ready"
fi
$CHARLIE_CLI createwallet "charlie" 2>/dev/null || true
CHARLIE_ADDR=$($CHARLIE_CLI -rpcwallet=charlie getnewaddress "receive" "bech32")
echo "Charlie's address: $CHARLIE_ADDR"
# Step 7: Fund Alice and Charlie with DGB for their mints
print_header "Step 7: Funding Alice and Charlie with DGB"
echo "Alice needs DGB for 2 mints ($200 worth of collateral)"
echo "Charlie needs DGB for 2 mints ($200 worth of collateral)"
# Mine blocks to Alice (100 blocks = 7.2M DGB)
echo "Mining 100 blocks to Alice..."
$BOB_CLI generatetoaddress 100 "$ALICE_ADDR" > /dev/null 2>&1
print_status "ok" "Alice funded: 100 blocks mined"
# Mine blocks to Charlie (100 blocks = 7.2M DGB)
echo "Mining 100 blocks to Charlie..."
$BOB_CLI generatetoaddress 100 "$CHARLIE_ADDR" > /dev/null 2>&1
print_status "ok" "Charlie funded: 100 blocks mined"
# Step 8: Sync chains
print_header "Step 8: Syncing chains"
$BOB_CLI generatetoaddress 5 "$BOB_ADDR" > /dev/null 2>&1
sleep 5
sync_all_nodes
print_status "ok" "All nodes synced"
# ====================================================================================
# INITIAL STATE - All balances should be 0
# ====================================================================================
print_header "Step 9: Initial DigiDollar State"
# Expected: All DD balances = 0
EXPECT_BOB_DD=0
EXPECT_ALICE_DD=0
EXPECT_CHARLIE_DD=0
verify_all_balances "Initial State (No DD Minted)"
# ====================================================================================
# Step 10: BOB MINTS DD AT EVERY TIER (0-8) - First mint $100, rest $110 for DD change test
# ====================================================================================
print_header "Step 10: Bob Mints DD at ALL Collateral Tiers (0-8)"
echo ""
echo "Bob will mint \$100 (first tier 0) and \$110 (all others) to test DD change."
echo "Total: \$100 + 9x\$110 = \$1090 (109000 cents)"
echo ""
ORACLE_PRICE=$($BOB_CLI getoracleprice 2>/dev/null | jq -r '.price_usd')
echo "Current LIVE Oracle Price: \$$ORACLE_PRICE per DGB"
echo ""
# Mint $100 at tier 0 TWICE (for redemption testing later)
print_subheader "Tier 0 - First Mint (for redemption test)"
echo "Minting \$100 DD (10000 cents) with tier 0 [$(get_tier_description 0)]..."
MINT_RESULT=$($BOB_CLI -rpcwallet=bob mintdigidollar 10000 0 2>&1)
if echo "$MINT_RESULT" | jq -e '.txid' > /dev/null 2>&1; then
BOB_TIER0_MINT1=$(echo "$MINT_RESULT" | jq -r '.txid')
COLLATERAL=$(echo "$MINT_RESULT" | jq -r '.dgb_collateral')
print_status "ok" "Tier 0 Mint #1: TX ${BOB_TIER0_MINT1:0:12}... Collateral: $COLLATERAL DGB"
EXPECT_BOB_DD=$((EXPECT_BOB_DD + 10000))
else
print_status "fail" "Tier 0 Mint #1 failed: $MINT_RESULT"
fi
$BOB_CLI generatetoaddress 2 "$BOB_ADDR" > /dev/null 2>&1
sleep 2
print_subheader "Tier 0 - Second Mint (larger amount for DD change test)"
echo "Minting \$110 DD (11000 cents) with tier 0 [$(get_tier_description 0)]..."
MINT_RESULT=$($BOB_CLI -rpcwallet=bob mintdigidollar 11000 0 2>&1)
if echo "$MINT_RESULT" | jq -e '.txid' > /dev/null 2>&1; then
BOB_TIER0_MINT2=$(echo "$MINT_RESULT" | jq -r '.txid')
COLLATERAL=$(echo "$MINT_RESULT" | jq -r '.dgb_collateral')
print_status "ok" "Tier 0 Mint #2: TX ${BOB_TIER0_MINT2:0:12}... Collateral: $COLLATERAL DGB"
EXPECT_BOB_DD=$((EXPECT_BOB_DD + 11000))
else
print_status "fail" "Tier 0 Mint #2 failed: $MINT_RESULT"
fi
$BOB_CLI generatetoaddress 2 "$BOB_ADDR" > /dev/null 2>&1
sleep 2
# Now mint at tiers 1-8 (9 tiers total: 0-8) - Using $110 to test DD change scenario
for tier in 1 2 3 4 5 6 7 8; do
print_subheader "Tier $tier - $(get_tier_description $tier)"
echo "Minting \$110 DD (11000 cents) with tier $tier..."
MINT_RESULT=$($BOB_CLI -rpcwallet=bob mintdigidollar 11000 $tier 2>&1)
if echo "$MINT_RESULT" | jq -e '.txid' > /dev/null 2>&1; then
TXID=$(echo "$MINT_RESULT" | jq -r '.txid')
COLLATERAL=$(echo "$MINT_RESULT" | jq -r '.dgb_collateral')
print_status "ok" "Tier $tier Mint: TX ${TXID:0:12}... Collateral: $COLLATERAL DGB"
EXPECT_BOB_DD=$((EXPECT_BOB_DD + 11000))
else
print_status "fail" "Tier $tier Mint failed: $MINT_RESULT"
fi
$BOB_CLI generatetoaddress 2 "$BOB_ADDR" > /dev/null 2>&1
sleep 1
done
# Sync and verify after all mints
$BOB_CLI generatetoaddress 5 "$BOB_ADDR" > /dev/null 2>&1
sleep 5
sync_all_nodes
# Bob should have 1 x 10000 + 9 x 11000 = 109000 DD
echo ""
echo "Bob completed 10 mints (tier0 \$100, tier0 \$110, tiers 1-8 \$110 each)"
echo "Expected Bob DD: $EXPECT_BOB_DD cents (\$$(echo "scale=2; $EXPECT_BOB_DD / 100" | bc))"
verify_all_balances "After Bob's 10 Mints (\$1090 total)"
list_dd_positions "$BOB_CLI" "bob" "Bob"
# ====================================================================================
# Step 11: Early redemption test (should FAIL - tier 0 still locked)
# ====================================================================================
print_header "Step 11: Early Redemption Test (should FAIL)"
echo "Bob's tier 0 vaults are still locked (need 240 blocks)..."
echo "Attempting to redeem BEFORE lock expires..."
CURRENT_HEIGHT=$($BOB_CLI getblockcount)
echo "Current height: $CURRENT_HEIGHT"
set +e
EARLY_REDEEM=$($BOB_CLI -rpcwallet=bob redeemdigidollar "$BOB_TIER0_MINT1" 10000 2>&1)
EARLY_EXIT=$?
set -e
if [ $EARLY_EXIT -ne 0 ] || echo "$EARLY_REDEEM" | grep -qi "error\|lock"; then
print_status "ok" "Early redemption correctly REJECTED (position still locked)"
echo " Response: $(echo $EARLY_REDEEM | head -c 100)..."
else
print_status "fail" "Early redemption unexpectedly succeeded"
echo " Response: $EARLY_REDEEM"
fi
# ====================================================================================
# Step 12: Mine past tier 0 lock period (240 blocks)
# ====================================================================================
print_header "Step 12: Mining Past Tier 0 Lock Period"
echo "Tier 0 lock period is 240 blocks (~1 hour at 15s/block on testnet)"
echo "Mining 250 blocks to pass the lock period..."
$BOB_CLI generatetoaddress 250 "$BOB_ADDR" > /dev/null 2>&1
sleep 3
NEW_HEIGHT=$($BOB_CLI getblockcount)
echo "Current height: $NEW_HEIGHT (tier 0 locks should now be expired)"
sync_all_nodes
print_status "ok" "Mined 250 blocks, tier 0 positions should be unlocked"
# Check Bob's positions status
echo ""
echo "Bob's tier 0 positions status:"
$BOB_CLI -rpcwallet=bob listdigidollarpositions 2>/dev/null | jq -r '.[] | select(.lock_tier == 0) | " [\(.status)] \(.dd_minted) cents - unlock: \(.unlock_height)"' 2>/dev/null || echo " Error reading positions"
# ====================================================================================
# Step 12B: DD CHANGE TEST - Create mixed-size UTXOs via transfers
# ====================================================================================
print_header "Step 12B: DD Change Bug Test Setup"
echo "Creating mixed-size DD UTXOs via transfers to test DD change during redemption..."
echo ""
echo "SCENARIO:"
echo " 1. Bob sends \$50 to Alice -> Bob has \$50 change UTXO"
echo " 2. Alice sends \$25 to Charlie -> Alice has \$25 change UTXO"
echo " 3. Charlie sends \$10 to Bob -> Bob gets \$10 UTXO"
echo ""
echo "Result: Bob has mixed UTXOs (\$50 change + \$10 received + remaining \$100 UTXOs)"
echo "When redeeming \$100 vault, SelectDDCoins may select >100 and generate DD change"
echo ""
# Get DD addresses for Alice and Charlie
ALICE_DD_ADDR_EARLY=$($ALICE_CLI -rpcwallet=alice getdigidollaraddress 2>/dev/null)
CHARLIE_DD_ADDR_EARLY=$($CHARLIE_CLI -rpcwallet=charlie getdigidollaraddress 2>/dev/null)
BOB_DD_ADDR_EARLY=$($BOB_CLI -rpcwallet=bob getdigidollaraddress 2>/dev/null)
echo "DD Addresses:"
echo " Alice: $ALICE_DD_ADDR_EARLY"
echo " Charlie: $CHARLIE_DD_ADDR_EARLY"
echo " Bob: $BOB_DD_ADDR_EARLY"
echo ""
BOB_DD_START=$(get_dd_balance "$BOB_CLI" "bob")
echo "Bob's DD before transfers: $BOB_DD_START cents"
# Transfer 1: Bob sends $50 to Alice
echo ""
echo "Transfer 1: Bob sends \$50 (5000 cents) to Alice..."
set +e
XFER1=$($BOB_CLI -rpcwallet=bob senddigidollar "$ALICE_DD_ADDR_EARLY" 5000 2>&1)
XFER1_EXIT=$?
set -e
if [ $XFER1_EXIT -eq 0 ] && echo "$XFER1" | jq -e '.txid' > /dev/null 2>&1; then
TX1=$(echo "$XFER1" | jq -r '.txid')
print_status "ok" "Bob->Alice \$50: ${TX1:0:16}..."
EXPECT_BOB_DD=$((EXPECT_BOB_DD - 5000))
EXPECT_ALICE_DD=$((EXPECT_ALICE_DD + 5000))
else
print_status "warn" "Transfer 1 failed: $XFER1"
fi
$BOB_CLI generatetoaddress 2 "$BOB_ADDR" > /dev/null 2>&1
sleep 2
# Transfer 2: Alice sends $25 to Charlie
echo "Transfer 2: Alice sends \$25 (2500 cents) to Charlie..."
set +e
XFER2=$($ALICE_CLI -rpcwallet=alice senddigidollar "$CHARLIE_DD_ADDR_EARLY" 2500 2>&1)
XFER2_EXIT=$?
set -e
if [ $XFER2_EXIT -eq 0 ] && echo "$XFER2" | jq -e '.txid' > /dev/null 2>&1; then
TX2=$(echo "$XFER2" | jq -r '.txid')
print_status "ok" "Alice->Charlie \$25: ${TX2:0:16}..."
EXPECT_ALICE_DD=$((EXPECT_ALICE_DD - 2500))
EXPECT_CHARLIE_DD=$((EXPECT_CHARLIE_DD + 2500))
else
print_status "warn" "Transfer 2 failed: $XFER2"
fi
# Mine blocks and give Charlie time to see the incoming DD
$BOB_CLI generatetoaddress 5 "$BOB_ADDR" > /dev/null 2>&1
sleep 5
sync_all_nodes
sleep 3
# Check Charlie's balance before trying to send
CHARLIE_DD_CHECK=$(get_dd_balance "$CHARLIE_CLI" "charlie")
echo "Charlie's DD balance after receiving from Alice: $CHARLIE_DD_CHECK cents"
# Transfer 3: Charlie sends $10 to Bob
echo "Transfer 3: Charlie sends \$10 (1000 cents) to Bob..."
set +e
XFER3=$($CHARLIE_CLI -rpcwallet=charlie senddigidollar "$BOB_DD_ADDR_EARLY" 1000 2>&1)
XFER3_EXIT=$?
set -e
if [ $XFER3_EXIT -eq 0 ] && echo "$XFER3" | jq -e '.txid' > /dev/null 2>&1; then
TX3=$(echo "$XFER3" | jq -r '.txid')
print_status "ok" "Charlie->Bob \$10: ${TX3:0:16}..."
EXPECT_CHARLIE_DD=$((EXPECT_CHARLIE_DD - 1000))
EXPECT_BOB_DD=$((EXPECT_BOB_DD + 1000))
else
print_status "warn" "Transfer 3 failed: $XFER3"
fi
# Mine extra blocks and give wallet time to process incoming DD
# This fixes timing issue where received DD isn't detected immediately
$BOB_CLI generatetoaddress 5 "$BOB_ADDR" > /dev/null 2>&1
sleep 3
sync_all_nodes
sleep 2
# Force Bob's wallet to rescan for any missed DD UTXOs
$BOB_CLI -rpcwallet=bob rescanblockchain > /dev/null 2>&1 || true
sleep 2
BOB_DD_AFTER=$(get_dd_balance "$BOB_CLI" "bob")
echo ""
echo "Bob's DD after transfers: $BOB_DD_AFTER cents"
echo "Expected: $EXPECT_BOB_DD cents"
echo ""
echo "Bob now has mixed-size DD UTXOs. Proceeding with redemption tests..."
echo ""
# ====================================================================================
# Step 13: Partial Redemption Test (should FAIL - exact amount required)
# ====================================================================================
print_header "Step 13: Partial Redemption Test (should FAIL)"
echo "Testing that partial redemption is NOT allowed..."
echo "Bob's tier 0 vault #1 has 10000 cents - trying to redeem only 5000 cents..."
set +e
PARTIAL_REDEEM=$($BOB_CLI -rpcwallet=bob redeemdigidollar "$BOB_TIER0_MINT1" 5000 2>&1)
PARTIAL_EXIT=$?
set -e
if [ $PARTIAL_EXIT -ne 0 ] || echo "$PARTIAL_REDEEM" | grep -qi "error\|exact\|must\|full"; then
print_status "ok" "Partial redemption correctly REJECTED (exact amount required)"
echo " Response: $(echo $PARTIAL_REDEEM | head -c 120)..."
else
print_status "fail" "Partial redemption unexpectedly succeeded (should require exact amount)"
echo " Response: $PARTIAL_REDEEM"
fi
# ====================================================================================
# Step 14: Bob's First Successful Redemption (tier 0 mint #1)
# ====================================================================================
print_header "Step 14: Bob Redeems Tier 0 Vault #1 (\$100)"
echo "Bob's tier 0 position is now unlocked - redeeming EXACT amount of 10000 cents..."
BOB_DGB_BEFORE=$($BOB_CLI -rpcwallet=bob getbalance 2>/dev/null || echo "0")
BOB_DD_BEFORE=$(get_dd_balance "$BOB_CLI" "bob")
echo "Before redemption: Bob has $BOB_DD_BEFORE DD cents and $BOB_DGB_BEFORE DGB"
set +e
REDEEM_RESULT=$($BOB_CLI -rpcwallet=bob redeemdigidollar "$BOB_TIER0_MINT1" 10000 2>&1)
REDEEM_EXIT=$?
set -e
if [ $REDEEM_EXIT -eq 0 ] && echo "$REDEEM_RESULT" | jq -e '.txid' > /dev/null 2>&1; then
REDEEM_TXID=$(echo "$REDEEM_RESULT" | jq -r '.txid')
DGB_RETURNED=$(echo "$REDEEM_RESULT" | jq -r '.dgb_returned // .collateral_returned // "unknown"')
print_status "ok" "REDEMPTION #1 SUCCESSFUL! TX: ${REDEEM_TXID:0:16}..."
echo " DD Burned: 10000 cents (\$100)"
echo " DGB Returned: $DGB_RETURNED DGB"
EXPECT_BOB_DD=$((EXPECT_BOB_DD - 10000))
else
print_status "fail" "Redemption #1 failed: $(echo $REDEEM_RESULT | head -c 150)..."
fi
$BOB_CLI generatetoaddress 2 "$BOB_ADDR" > /dev/null 2>&1
sleep 3
sync_all_nodes
# ====================================================================================
# CRITICAL DD CHANGE VERIFICATION
# ====================================================================================
echo ""
echo "${CYAN}=== DD CHANGE BUG VERIFICATION ===${NC}"
BOB_DD_AFTER=$(get_dd_balance "$BOB_CLI" "bob")
EXPECTED_DD_AFTER=$((BOB_DD_BEFORE - 10000)) # Should be before - $100 burned
echo " DD BEFORE redemption: $BOB_DD_BEFORE cents"
echo " DD burned: 10000 cents (\$100)"
echo " EXPECTED DD after: $EXPECTED_DD_AFTER cents"
echo " ACTUAL DD after: $BOB_DD_AFTER cents"
# Check if DD change was properly tracked
if [ "$BOB_DD_AFTER" -eq "$EXPECTED_DD_AFTER" ]; then
print_status "ok" "DD CHANGE CORRECTLY TRACKED! Balance is exactly as expected."
elif [ "$BOB_DD_AFTER" -gt "$EXPECTED_DD_AFTER" ]; then
print_status "warn" "DD balance higher than expected (possible duplicate UTXO tracking)"
else
DD_LOSS=$((EXPECTED_DD_AFTER - BOB_DD_AFTER))
print_status "fail" "DD CHANGE BUG DETECTED! Lost $DD_LOSS cents of DD change!"
echo " This indicates the DD change output was not properly tracked."
echo " The wallet burned more DD than necessary without returning change."
fi
echo ""
verify_all_balances "After Bob's First Redemption"
# ====================================================================================
# Step 15: Bob's Second Successful Redemption (tier 0 mint #2)
# ====================================================================================
print_header "Step 15: Bob Redeems Tier 0 Vault #2 (\$110)"
echo "Redeeming Bob's second tier 0 position (the \$110 vault)..."
BOB_DGB_BEFORE=$($BOB_CLI -rpcwallet=bob getbalance 2>/dev/null || echo "0")
BOB_DD_BEFORE=$(get_dd_balance "$BOB_CLI" "bob")
echo "Before redemption: Bob has $BOB_DD_BEFORE DD cents and $BOB_DGB_BEFORE DGB"
set +e
REDEEM_RESULT=$($BOB_CLI -rpcwallet=bob redeemdigidollar "$BOB_TIER0_MINT2" 11000 2>&1)
REDEEM_EXIT=$?
set -e
if [ $REDEEM_EXIT -eq 0 ] && echo "$REDEEM_RESULT" | jq -e '.txid' > /dev/null 2>&1; then
REDEEM_TXID=$(echo "$REDEEM_RESULT" | jq -r '.txid')
DGB_RETURNED=$(echo "$REDEEM_RESULT" | jq -r '.dgb_returned // .collateral_returned // "unknown"')
print_status "ok" "REDEMPTION #2 SUCCESSFUL! TX: ${REDEEM_TXID:0:16}..."
echo " DD Burned: 11000 cents (\$110)"
echo " DGB Returned: $DGB_RETURNED DGB"
EXPECT_BOB_DD=$((EXPECT_BOB_DD - 11000))
else
print_status "fail" "Redemption #2 failed: $(echo $REDEEM_RESULT | head -c 150)..."
fi
$BOB_CLI generatetoaddress 2 "$BOB_ADDR" > /dev/null 2>&1
sleep 3
sync_all_nodes
verify_all_balances "After Bob's Second Redemption"
list_dd_positions "$BOB_CLI" "bob" "Bob"
# ====================================================================================
# Step 16: Alice Mints $100 at Tier 3 (90 days)
# ====================================================================================
print_header "Step 16: Alice Mints \$100 at Tier 3 (90 days)"
ALICE_DGB=$($ALICE_CLI -rpcwallet=alice getbalance 2>/dev/null || echo "0")
echo "Alice's DGB balance: $ALICE_DGB DGB"
echo "Alice minting \$100 DD (10000 cents) with tier 3 [$(get_tier_description 3)]..."
set +e
ALICE_MINT=$($ALICE_CLI -rpcwallet=alice mintdigidollar 10000 3 2>&1)
ALICE_MINT_EXIT=$?
set -e
if [ $ALICE_MINT_EXIT -eq 0 ] && echo "$ALICE_MINT" | jq -e '.txid' > /dev/null 2>&1; then
ALICE_TIER3_TX=$(echo "$ALICE_MINT" | jq -r '.txid')
COLLATERAL=$(echo "$ALICE_MINT" | jq -r '.dgb_collateral')
print_status "ok" "Alice Tier 3 Mint: TX ${ALICE_TIER3_TX:0:12}... Collateral: $COLLATERAL DGB"
EXPECT_ALICE_DD=$((EXPECT_ALICE_DD + 10000))
else
print_status "fail" "Alice Tier 3 Mint failed: $ALICE_MINT"
fi
# Alice generates her own block to include her TX (TX is in Alice's mempool, not Bob's)
$ALICE_CLI generatetoaddress 2 "$ALICE_ADDR" > /dev/null 2>&1
sleep 3
sync_all_nodes
# ====================================================================================
# Step 17: Alice Mints $100 at Tier 5 (1 year)
# ====================================================================================
print_header "Step 17: Alice Mints \$100 at Tier 5 (1 year)"
ALICE_DGB=$($ALICE_CLI -rpcwallet=alice getbalance 2>/dev/null || echo "0")
echo "Alice's DGB balance: $ALICE_DGB DGB"
echo "Alice minting \$100 DD (10000 cents) with tier 5 [$(get_tier_description 5)]..."
set +e
ALICE_MINT=$($ALICE_CLI -rpcwallet=alice mintdigidollar 10000 5 2>&1)
ALICE_MINT_EXIT=$?
set -e
if [ $ALICE_MINT_EXIT -eq 0 ] && echo "$ALICE_MINT" | jq -e '.txid' > /dev/null 2>&1; then
ALICE_TIER5_TX=$(echo "$ALICE_MINT" | jq -r '.txid')
COLLATERAL=$(echo "$ALICE_MINT" | jq -r '.dgb_collateral')
print_status "ok" "Alice Tier 5 Mint: TX ${ALICE_TIER5_TX:0:12}... Collateral: $COLLATERAL DGB"
EXPECT_ALICE_DD=$((EXPECT_ALICE_DD + 10000))
else
print_status "fail" "Alice Tier 5 Mint failed: $ALICE_MINT"
fi
# Alice generates her own block to include her TX (TX is in Alice's mempool, not Bob's)
$ALICE_CLI generatetoaddress 2 "$ALICE_ADDR" > /dev/null 2>&1
sleep 3
sync_all_nodes
verify_all_balances "After Alice's 2 Mints (Tier 3 + Tier 5)"
list_dd_positions "$ALICE_CLI" "alice" "Alice"
# ====================================================================================
# Step 18: Charlie Mints $100 at Tier 7 (3 years)
# ====================================================================================
print_header "Step 18: Charlie Mints \$100 at Tier 7 (3 years)"
CHARLIE_DGB=$($CHARLIE_CLI -rpcwallet=charlie getbalance 2>/dev/null || echo "0")
echo "Charlie's DGB balance: $CHARLIE_DGB DGB"
echo "Charlie minting \$100 DD (10000 cents) with tier 7 [$(get_tier_description 7)]..."
set +e
CHARLIE_MINT=$($CHARLIE_CLI -rpcwallet=charlie mintdigidollar 10000 7 2>&1)
CHARLIE_MINT_EXIT=$?
set -e
if [ $CHARLIE_MINT_EXIT -eq 0 ] && echo "$CHARLIE_MINT" | jq -e '.txid' > /dev/null 2>&1; then
CHARLIE_TIER7_TX=$(echo "$CHARLIE_MINT" | jq -r '.txid')
COLLATERAL=$(echo "$CHARLIE_MINT" | jq -r '.dgb_collateral')
print_status "ok" "Charlie Tier 7 Mint: TX ${CHARLIE_TIER7_TX:0:12}... Collateral: $COLLATERAL DGB"
EXPECT_CHARLIE_DD=$((EXPECT_CHARLIE_DD + 10000))
else
print_status "fail" "Charlie Tier 7 Mint failed: $CHARLIE_MINT"
fi
# Charlie generates his own block to include his TX (TX is in Charlie's mempool, not Bob's)
$CHARLIE_CLI generatetoaddress 2 "$CHARLIE_ADDR" > /dev/null 2>&1
sleep 3
sync_all_nodes
# ====================================================================================
# Step 19: Charlie Mints $100 at Tier 8 (10 years)
# ====================================================================================
print_header "Step 19: Charlie Mints \$100 at Tier 8 (10 years)"
CHARLIE_DGB=$($CHARLIE_CLI -rpcwallet=charlie getbalance 2>/dev/null || echo "0")
echo "Charlie's DGB balance: $CHARLIE_DGB DGB"
echo "Charlie minting \$100 DD (10000 cents) with tier 8 [$(get_tier_description 8)]..."
set +e
CHARLIE_MINT=$($CHARLIE_CLI -rpcwallet=charlie mintdigidollar 10000 8 2>&1)
CHARLIE_MINT_EXIT=$?
set -e
if [ $CHARLIE_MINT_EXIT -eq 0 ] && echo "$CHARLIE_MINT" | jq -e '.txid' > /dev/null 2>&1; then
CHARLIE_TIER8_TX=$(echo "$CHARLIE_MINT" | jq -r '.txid')
COLLATERAL=$(echo "$CHARLIE_MINT" | jq -r '.dgb_collateral')
print_status "ok" "Charlie Tier 8 Mint: TX ${CHARLIE_TIER8_TX:0:12}... Collateral: $COLLATERAL DGB"
EXPECT_CHARLIE_DD=$((EXPECT_CHARLIE_DD + 10000))
else
print_status "fail" "Charlie Tier 8 Mint failed: $CHARLIE_MINT"
fi
# Charlie generates his own block to include his TX (TX is in Charlie's mempool, not Bob's)
$CHARLIE_CLI generatetoaddress 2 "$CHARLIE_ADDR" > /dev/null 2>&1
sleep 3
sync_all_nodes
verify_all_balances "After Charlie's 2 Mints (Tier 7 + Tier 8)"
list_dd_positions "$CHARLIE_CLI" "charlie" "Charlie"
# ====================================================================================
# Step 20: DD Transfer Tests (Bob sends to Alice and Charlie)
# ====================================================================================
print_header "Step 20: DD Transfer Tests"
# Get DD addresses
ALICE_DD_ADDR=$($ALICE_CLI -rpcwallet=alice getdigidollaraddress 2>/dev/null)
CHARLIE_DD_ADDR=$($CHARLIE_CLI -rpcwallet=charlie getdigidollaraddress 2>/dev/null)
echo "Alice's DD address: $ALICE_DD_ADDR"
echo "Charlie's DD address: $CHARLIE_DD_ADDR"