main.adl
1 // Staking Contract for Delta Chain 2 // DX token staking, delegation, and rewards 3 // 4 // Target: Delta (account-based model) 5 6 program staking.adl; 7 8 // Validator status 9 enum ValidatorStatus { 10 Active, 11 Jailed, 12 Unbonding, 13 Inactive, 14 } 15 16 // Storage mappings 17 mapping validators: address => Validator; 18 mapping delegations: field => Delegation; 19 mapping unbondings: field => Unbonding; 20 mapping total_staked: u8 => u64; // key 0 = total 21 22 struct Validator { 23 address: address, 24 commission: u16, // basis points (100 = 1%) 25 total_stake: u64, 26 self_stake: u64, 27 status: ValidatorStatus, 28 jailed_until: u64, 29 } 30 31 struct Delegation { 32 delegator: address, 33 validator: address, 34 amount: u64, 35 reward_debt: u64, 36 delegated_at: u64, 37 } 38 39 struct Unbonding { 40 delegator: address, 41 validator: address, 42 amount: u64, 43 complete_height: u64, 44 } 45 46 // Configuration 47 const MIN_SELF_STAKE: u64 = 10_000_000_000_000u64; // 10k DX 48 const MAX_COMMISSION: u16 = 2000u16; // 20% 49 const UNBONDING_PERIOD: u64 = 151200u64; // ~21 days 50 51 // Register as validator 52 transition register_validator( 53 public commission: u16, 54 public self_stake: u64, 55 ) { 56 assert(commission <= MAX_COMMISSION); 57 assert(self_stake >= MIN_SELF_STAKE); 58 59 // Check not already registered 60 let existing = validators.get_or_use(self.caller, Validator { 61 address: self.caller, 62 commission: 0u16, 63 total_stake: 0u64, 64 self_stake: 0u64, 65 status: ValidatorStatus::Inactive, 66 jailed_until: 0u64, 67 }); 68 assert(existing.status == ValidatorStatus::Inactive); 69 70 let validator = Validator { 71 address: self.caller, 72 commission: commission, 73 total_stake: self_stake, 74 self_stake: self_stake, 75 status: ValidatorStatus::Active, 76 jailed_until: 0u64, 77 }; 78 79 validators.set(self.caller, validator); 80 81 // Update total staked 82 let current_total = total_staked.get_or_use(0u8, 0u64); 83 total_staked.set(0u8, current_total + self_stake); 84 } 85 86 // Delegate to validator 87 transition delegate( 88 public validator_addr: address, 89 public amount: u64, 90 ) { 91 // Get validator 92 let validator = validators.get(validator_addr); 93 assert(validator.status == ValidatorStatus::Active); 94 95 // Create or update delegation 96 let delegation_key = BHP256::hash_to_field(self.caller, validator_addr); 97 let existing = delegations.get_or_use(delegation_key, Delegation { 98 delegator: self.caller, 99 validator: validator_addr, 100 amount: 0u64, 101 reward_debt: 0u64, 102 delegated_at: block.height, 103 }); 104 105 let delegation = Delegation { 106 delegator: self.caller, 107 validator: validator_addr, 108 amount: existing.amount + amount, 109 reward_debt: existing.reward_debt, 110 delegated_at: existing.delegated_at, 111 }; 112 113 delegations.set(delegation_key, delegation); 114 115 // Update validator total 116 let updated_validator = Validator { 117 address: validator.address, 118 commission: validator.commission, 119 total_stake: validator.total_stake + amount, 120 self_stake: validator.self_stake, 121 status: validator.status, 122 jailed_until: validator.jailed_until, 123 }; 124 125 validators.set(validator_addr, updated_validator); 126 127 // Update global total 128 let current_total = total_staked.get_or_use(0u8, 0u64); 129 total_staked.set(0u8, current_total + amount); 130 } 131 132 // Undelegate from validator 133 transition undelegate( 134 public validator_addr: address, 135 public amount: u64, 136 ) { 137 // Get delegation 138 let delegation_key = BHP256::hash_to_field(self.caller, validator_addr); 139 let delegation = delegations.get(delegation_key); 140 141 assert(delegation.delegator == self.caller); 142 assert(delegation.amount >= amount); 143 144 // Update delegation 145 let updated_delegation = Delegation { 146 delegator: delegation.delegator, 147 validator: delegation.validator, 148 amount: delegation.amount - amount, 149 reward_debt: delegation.reward_debt, 150 delegated_at: delegation.delegated_at, 151 }; 152 153 delegations.set(delegation_key, updated_delegation); 154 155 // Create unbonding entry 156 let unbonding_key = BHP256::hash_to_field(self.caller, validator_addr, block.height); 157 let unbonding = Unbonding { 158 delegator: self.caller, 159 validator: validator_addr, 160 amount: amount, 161 complete_height: block.height + UNBONDING_PERIOD, 162 }; 163 164 unbondings.set(unbonding_key, unbonding); 165 166 // Update validator 167 let validator = validators.get(validator_addr); 168 let updated_validator = Validator { 169 address: validator.address, 170 commission: validator.commission, 171 total_stake: validator.total_stake - amount, 172 self_stake: validator.self_stake, 173 status: validator.status, 174 jailed_until: validator.jailed_until, 175 }; 176 177 validators.set(validator_addr, updated_validator); 178 179 // Update global total 180 let current_total = total_staked.get_or_use(0u8, 0u64); 181 total_staked.set(0u8, current_total - amount); 182 } 183 184 // Claim unbonded tokens 185 transition claim_unbonded( 186 public validator_addr: address, 187 public unbonding_height: u64, 188 ) -> u64 { 189 let unbonding_key = BHP256::hash_to_field(self.caller, validator_addr, unbonding_height); 190 let unbonding = unbondings.get(unbonding_key); 191 192 assert(unbonding.delegator == self.caller); 193 assert(block.height >= unbonding.complete_height); 194 195 // Remove unbonding entry 196 unbondings.remove(unbonding_key); 197 198 return unbonding.amount; 199 } 200 201 // Claim staking rewards 202 transition claim_rewards( 203 public validator_addr: address, 204 ) -> u64 { 205 let delegation_key = BHP256::hash_to_field(self.caller, validator_addr); 206 let delegation = delegations.get(delegation_key); 207 208 assert(delegation.delegator == self.caller); 209 210 // Calculate rewards (simplified) 211 // In production, this would track accumulated rewards per share 212 let rewards = 0u64; // Placeholder 213 214 // Update reward debt 215 let updated = Delegation { 216 delegator: delegation.delegator, 217 validator: delegation.validator, 218 amount: delegation.amount, 219 reward_debt: delegation.reward_debt + rewards, 220 delegated_at: delegation.delegated_at, 221 }; 222 223 delegations.set(delegation_key, updated); 224 225 return rewards; 226 }