Skip to content

Commit 8ef3073

Browse files
Merge pull request #1059 from brightMedina5050/feature/reentrancy-guards-and-safety
Add reentrancy guards to payable functions and handle attached value safely
2 parents 03ad43d + 1cc3c65 commit 8ef3073

7 files changed

Lines changed: 348 additions & 332 deletions

File tree

contracts/factory/src/lib.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ pub mod contract_factory {
6767
CodeHashNotSet,
6868
ContractNotFound,
6969
InvalidParameters,
70+
/// Native tokens were attached to `deploy_contract` but deployment
71+
/// fees are not supported. Send zero value.
72+
UnexpectedValue,
7073
}
7174

7275
/// Contract Factory storage
@@ -151,13 +154,19 @@ pub mod contract_factory {
151154
self.code_hashes.get(contract_type)
152155
}
153156

154-
/// Deploys a new contract instance
157+
/// Deploys a new contract instance.
158+
///
159+
/// Attaching native tokens is not supported; deployment is free.
160+
/// Send zero value with this call.
155161
#[ink(message, payable)]
156162
pub fn deploy_contract(
157163
&mut self,
158164
config: DeploymentConfig,
159165
version: String,
160166
) -> Result<AccountId, Error> {
167+
if self.env().transferred_value() > 0 {
168+
return Err(Error::UnexpectedValue);
169+
}
161170
let code_hash = self
162171
.code_hashes
163172
.get(config.contract_type)

contracts/fractional/src/lib.rs

Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -978,61 +978,65 @@ pub mod fractional {
978978

979979
/// Bid on a Dutch auction at the current descending price.
980980
/// Buyer must attach sufficient payment for the current price of all shares.
981+
///
982+
/// Wrapped in a reentrancy guard, matching `buy_shares` and `add_liquidity`.
981983
#[ink(message, payable)]
982984
pub fn bid_dutch_auction(&mut self, auction_id: u64) -> Result<(), FractionalError> {
983-
let caller = self.env().caller();
984-
let payment = self.env().transferred_value();
985+
non_reentrant!(self, {
986+
let caller = self.env().caller();
987+
let payment = self.env().transferred_value();
985988

986-
let mut auction = self
987-
.dutch_auctions
988-
.get(auction_id)
989-
.ok_or(FractionalError::AuctionNotFound)?;
989+
let mut auction = self
990+
.dutch_auctions
991+
.get(auction_id)
992+
.ok_or(FractionalError::AuctionNotFound)?;
990993

991-
if auction.has_bids {
992-
return Err(FractionalError::AuctionAlreadyBid);
993-
}
994+
if auction.has_bids {
995+
return Err(FractionalError::AuctionAlreadyBid);
996+
}
994997

995-
let current_block = self.env().block_number() as u64;
996-
let current_price = self.calculate_dutch_price(&auction, current_block);
997-
let total_price = current_price.saturating_mul(auction.shares);
998+
let current_block = self.env().block_number() as u64;
999+
let current_price = self.calculate_dutch_price(&auction, current_block);
1000+
let total_price = current_price.saturating_mul(auction.shares);
9981001

999-
if payment < total_price {
1000-
return Err(FractionalError::InsufficientPayment);
1001-
}
1002+
if payment < total_price {
1003+
return Err(FractionalError::InsufficientPayment);
1004+
}
10021005

1003-
// Transfer shares from seller to buyer
1004-
let seller_held = self
1005-
.balances
1006-
.get((auction.seller, auction.token_id))
1007-
.unwrap_or(0);
1008-
self.balances.insert(
1009-
(auction.seller, auction.token_id),
1010-
&seller_held.saturating_sub(auction.shares),
1011-
);
1006+
// Transfer shares from seller to buyer
1007+
let seller_held = self
1008+
.balances
1009+
.get((auction.seller, auction.token_id))
1010+
.unwrap_or(0);
1011+
self.balances.insert(
1012+
(auction.seller, auction.token_id),
1013+
&seller_held.saturating_sub(auction.shares),
1014+
);
10121015

1013-
let buyer_held = self.balances.get((caller, auction.token_id)).unwrap_or(0);
1014-
self.balances.insert(
1015-
(caller, auction.token_id),
1016-
&buyer_held.saturating_add(auction.shares),
1017-
);
1016+
let buyer_held = self.balances.get((caller, auction.token_id)).unwrap_or(0);
1017+
self.balances.insert(
1018+
(caller, auction.token_id),
1019+
&buyer_held.saturating_add(auction.shares),
1020+
);
10181021

1019-
// Mark auction as complete
1020-
auction.has_bids = true;
1021-
self.dutch_auctions.insert(auction_id, &auction);
1022+
// Mark auction as complete
1023+
auction.has_bids = true;
1024+
self.dutch_auctions.insert(auction_id, &auction);
10221025

1023-
// Pay the seller
1024-
if self.env().transfer(auction.seller, total_price).is_err() {
1025-
// Non-fatal: payment forwarding failed (e.g. in unit tests)
1026-
}
1026+
// Pay the seller
1027+
if self.env().transfer(auction.seller, total_price).is_err() {
1028+
// Non-fatal: payment forwarding failed (e.g. in unit tests)
1029+
}
10271030

1028-
self.env().emit_event(DutchAuctionBid {
1029-
auction_id,
1030-
buyer: caller,
1031-
shares: auction.shares,
1032-
price_paid: total_price,
1033-
});
1031+
self.env().emit_event(DutchAuctionBid {
1032+
auction_id,
1033+
buyer: caller,
1034+
shares: auction.shares,
1035+
price_paid: total_price,
1036+
});
10341037

1035-
Ok(())
1038+
Ok(())
1039+
})
10361040
}
10371041

10381042
/// Cancel a Dutch auction (seller only, before any bid).

0 commit comments

Comments
 (0)