Skip to content

Commit 9bb994b

Browse files
authored
Merge pull request #363 from IyanuOluwaJesuloba/main
Feat/Implementing Reentrancy Guard
2 parents 630f80f + 029b5bd commit 9bb994b

40 files changed

Lines changed: 2484 additions & 2085 deletions

File tree

Cargo.lock

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ members = [
1414
"contracts/fees",
1515
"contracts/dex",
1616
"contracts/compliance_registry",
17+
"contracts/property-management",
1718
"contracts/tax-compliance",
1819
"contracts/fractional",
1920
"contracts/prediction-market",

check_output.txt

-19 KB
Binary file not shown.

contracts/bridge/src/errors.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub enum Error {
1616
DuplicateRequest,
1717
GasLimitExceeded,
1818
RateLimitExceeded,
19+
ReentrantCall,
1920
}
2021

2122
impl core::fmt::Display for Error {
@@ -34,6 +35,7 @@ impl core::fmt::Display for Error {
3435
Error::DuplicateRequest => write!(f, "Duplicate bridge request"),
3536
Error::GasLimitExceeded => write!(f, "Gas limit exceeded"),
3637
Error::RateLimitExceeded => write!(f, "Rate limit exceeded"),
38+
Error::ReentrantCall => write!(f, "Reentrant call"),
3739
}
3840
}
3941
}
@@ -54,6 +56,7 @@ impl ContractError for Error {
5456
Error::DuplicateRequest => bridge_codes::BRIDGE_DUPLICATE_REQUEST,
5557
Error::GasLimitExceeded => bridge_codes::BRIDGE_GAS_LIMIT_EXCEEDED,
5658
Error::RateLimitExceeded => bridge_codes::BRIDGE_RATE_LIMIT_EXCEEDED,
59+
Error::ReentrantCall => bridge_codes::REENTRANT_CALL,
5760
}
5861
}
5962

@@ -76,6 +79,7 @@ impl ContractError for Error {
7679
Error::DuplicateRequest => "A bridge request with these parameters already exists",
7780
Error::GasLimitExceeded => "The operation exceeded the gas limit",
7881
Error::RateLimitExceeded => "The operation exceeded the daily rate limit",
82+
Error::ReentrantCall => "Reentrancy guard detected a reentrant call",
7983
}
8084
}
8185

contracts/bridge/src/lib.rs

Lines changed: 106 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,16 @@ use scale_info::prelude::vec::Vec;
1010
#[ink::contract]
1111
mod bridge {
1212
use super::*;
13+
use propchain_contracts::{non_reentrant, ReentrancyError, ReentrancyGuard};
1314

1415
include!("errors.rs");
1516

17+
impl From<ReentrancyError> for Error {
18+
fn from(_: ReentrancyError) -> Self {
19+
Error::ReentrantCall
20+
}
21+
}
22+
1623
/// Bridge contract for cross-chain property token transfers
1724
#[ink(storage)]
1825
pub struct PropertyBridge {
@@ -66,6 +73,9 @@ mod bridge {
6673

6774
/// Chain last reset day for rate limiting
6875
chain_last_reset_day: Mapping<ChainId, u64>,
76+
77+
/// Reentrancy protection
78+
reentrancy_guard: ReentrancyGuard,
6979
}
7080

7181
/// Events for bridge operations
@@ -163,6 +173,7 @@ mod bridge {
163173
account_last_reset_day: Mapping::default(),
164174
chain_daily_volume: Mapping::default(),
165175
chain_last_reset_day: Mapping::default(),
176+
reentrancy_guard: ReentrancyGuard::new(),
166177
};
167178

168179
// Set up default chain information
@@ -351,66 +362,68 @@ mod bridge {
351362
/// Executes a bridge request after collecting required signatures
352363
#[ink(message)]
353364
pub fn execute_bridge(&mut self, request_id: u64) -> Result<(), Error> {
354-
let caller = self.env().caller();
365+
non_reentrant!(self, {
366+
let caller = self.env().caller();
355367

356-
// Check if caller is a bridge operator
357-
if !self.bridge_operators.contains(&caller) {
358-
return Err(Error::Unauthorized);
359-
}
360-
361-
let mut request = self
362-
.bridge_requests
363-
.get(request_id)
364-
.ok_or(Error::InvalidRequest)?;
368+
// Check if caller is a bridge operator
369+
if !self.bridge_operators.contains(&caller) {
370+
return Err(Error::Unauthorized);
371+
}
365372

366-
// Check if request is ready for execution
367-
if request.status != BridgeOperationStatus::Locked {
368-
return Err(Error::InvalidRequest);
369-
}
373+
let mut request = self
374+
.bridge_requests
375+
.get(request_id)
376+
.ok_or(Error::InvalidRequest)?;
370377

371-
// Check if enough signatures are collected
372-
if request.signatures.len() < request.required_signatures as usize {
373-
return Err(Error::InsufficientSignatures);
374-
}
378+
// Check if request is ready for execution
379+
if request.status != BridgeOperationStatus::Locked {
380+
return Err(Error::InvalidRequest);
381+
}
375382

376-
// Generate transaction hash
377-
let transaction_hash = self.generate_transaction_hash(&request);
383+
// Check if enough signatures are collected
384+
if request.signatures.len() < request.required_signatures as usize {
385+
return Err(Error::InsufficientSignatures);
386+
}
378387

379-
// Create bridge transaction record
380-
self.transaction_counter += 1;
381-
let transaction = BridgeTransaction {
382-
transaction_id: self.transaction_counter,
383-
token_id: request.token_id,
384-
source_chain: request.source_chain,
385-
destination_chain: request.destination_chain,
386-
sender: request.sender,
387-
recipient: request.recipient,
388-
transaction_hash,
389-
timestamp: self.env().block_timestamp(),
390-
gas_used: self.estimate_gas_usage(&request),
391-
status: BridgeOperationStatus::InTransit,
392-
metadata: request.metadata.clone(),
393-
};
388+
// Generate transaction hash
389+
let transaction_hash = self.generate_transaction_hash(&request);
390+
391+
// Create bridge transaction record
392+
self.transaction_counter += 1;
393+
let transaction = BridgeTransaction {
394+
transaction_id: self.transaction_counter,
395+
token_id: request.token_id,
396+
source_chain: request.source_chain,
397+
destination_chain: request.destination_chain,
398+
sender: request.sender,
399+
recipient: request.recipient,
400+
transaction_hash,
401+
timestamp: self.env().block_timestamp(),
402+
gas_used: self.estimate_gas_usage(&request),
403+
status: BridgeOperationStatus::InTransit,
404+
metadata: request.metadata.clone(),
405+
};
394406

395-
// Update request status
396-
request.status = BridgeOperationStatus::Completed;
397-
self.bridge_requests.insert(request_id, &request);
407+
// Update request status
408+
request.status = BridgeOperationStatus::Completed;
409+
self.bridge_requests.insert(request_id, &request);
398410

399-
// Store transaction verification
400-
self.verified_transactions.insert(transaction_hash, &true);
411+
// Store transaction verification
412+
self.verified_transactions.insert(transaction_hash, &true);
401413

402-
// Add to bridge history
403-
let mut history = self.bridge_history.get(request.sender).unwrap_or_default();
404-
history.push(transaction.clone());
405-
self.bridge_history.insert(request.sender, &history);
414+
// Add to bridge history
415+
let mut history = self.bridge_history.get(request.sender).unwrap_or_default();
416+
history.push(transaction.clone());
417+
self.bridge_history.insert(request.sender, &history);
406418

407-
self.env().emit_event(BridgeExecuted {
408-
request_id,
409-
token_id: request.token_id,
410-
transaction_hash,
411-
});
419+
self.env().emit_event(BridgeExecuted {
420+
request_id,
421+
token_id: request.token_id,
422+
transaction_hash,
423+
});
412424

413-
Ok(())
425+
Ok(())
426+
})
414427
}
415428

416429
/// Recovers from a failed bridge operation
@@ -420,54 +433,56 @@ mod bridge {
420433
request_id: u64,
421434
recovery_action: RecoveryAction,
422435
) -> Result<(), Error> {
423-
let caller = self.env().caller();
424-
425-
// Only admin can recover failed bridges
426-
if caller != self.admin {
427-
return Err(Error::Unauthorized);
428-
}
429-
430-
let mut request = self
431-
.bridge_requests
432-
.get(request_id)
433-
.ok_or(Error::InvalidRequest)?;
436+
non_reentrant!(self, {
437+
let caller = self.env().caller();
434438

435-
// Check if request is in a failed state
436-
if !matches!(
437-
request.status,
438-
BridgeOperationStatus::Failed | BridgeOperationStatus::Expired
439-
) {
440-
return Err(Error::InvalidRequest);
441-
}
442-
443-
// Execute recovery action
444-
match recovery_action {
445-
RecoveryAction::UnlockToken => {
446-
// Logic to unlock the token would be implemented here
447-
// This would typically call back to the property token contract
448-
}
449-
RecoveryAction::RefundGas => {
450-
// Logic to refund gas costs would be implemented here
439+
// Only admin can recover failed bridges
440+
if caller != self.admin {
441+
return Err(Error::Unauthorized);
451442
}
452-
RecoveryAction::RetryBridge => {
453-
// Reset request to pending for retry
454-
request.status = BridgeOperationStatus::Pending;
455-
request.signatures.clear();
443+
444+
let mut request = self
445+
.bridge_requests
446+
.get(request_id)
447+
.ok_or(Error::InvalidRequest)?;
448+
449+
// Check if request is in a failed state
450+
if !matches!(
451+
request.status,
452+
BridgeOperationStatus::Failed | BridgeOperationStatus::Expired
453+
) {
454+
return Err(Error::InvalidRequest);
456455
}
457-
RecoveryAction::CancelBridge => {
458-
// Mark as cancelled
459-
request.status = BridgeOperationStatus::Failed;
456+
457+
// Execute recovery action
458+
match recovery_action {
459+
RecoveryAction::UnlockToken => {
460+
// Logic to unlock the token would be implemented here
461+
// This would typically call back to the property token contract
462+
}
463+
RecoveryAction::RefundGas => {
464+
// Logic to refund gas costs would be implemented here
465+
}
466+
RecoveryAction::RetryBridge => {
467+
// Reset request to pending for retry
468+
request.status = BridgeOperationStatus::Pending;
469+
request.signatures.clear();
470+
}
471+
RecoveryAction::CancelBridge => {
472+
// Mark as cancelled
473+
request.status = BridgeOperationStatus::Failed;
474+
}
460475
}
461-
}
462476

463-
self.bridge_requests.insert(request_id, &request);
477+
self.bridge_requests.insert(request_id, &request);
464478

465-
self.env().emit_event(BridgeRecovered {
466-
request_id,
467-
recovery_action,
468-
});
479+
self.env().emit_event(BridgeRecovered {
480+
request_id,
481+
recovery_action,
482+
});
469483

470-
Ok(())
484+
Ok(())
485+
})
471486
}
472487

473488
/// Gets gas estimation for a bridge operation

contracts/crowdfunding/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ publish = false
1515
ink = { workspace = true }
1616
scale = { workspace = true }
1717
scale-info = { workspace = true }
18+
propchain-traits = { path = "../traits", default-features = false }
1819

1920
[dev-dependencies]
2021
ink_e2e = "5.0.0"
@@ -30,6 +31,7 @@ std = [
3031
"ink/std",
3132
"scale/std",
3233
"scale-info/std",
34+
"propchain-traits/std",
3335
]
3436
ink-as-dependency = []
3537
e2e-tests = []

0 commit comments

Comments
 (0)