Skip to content
This repository was archived by the owner on Mar 13, 2026. It is now read-only.

Commit 994583e

Browse files
authored
Prevent admin rugpull on a failed sale, as reported on #25 (#26)
1 parent b0950c6 commit 994583e

File tree

3 files changed

+34
-2
lines changed

3 files changed

+34
-2
lines changed

src/Sale.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ contract Sale is ISale, RisingTide, ERC165, AccessControl, ReentrancyGuard {
169169
require(block.timestamp > end, "sale not ended yet");
170170
require(!withdrawn, "already withdrawn");
171171
require(custodian != address(0), CustodianNotSet());
172+
require(totalUncappedAllocations >= minTarget, "minTarget not reached");
172173

173174
withdrawn = true;
174175

test/SaleLegacy.d.sol

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ contract SaleLegacyTest is TestSetup {
122122
uint256 mintAmount = usdc(2);
123123
uint256 buyAmount = usdc(2);
124124

125+
ctx.sale.setMinTarget(buyAmount);
125126
mintUsdc(alice, mintAmount);
126127

127128
vm.startPrank(alice);
@@ -142,6 +143,7 @@ contract SaleLegacyTest is TestSetup {
142143
uint256 mintAmount = usdc(2);
143144
uint256 buyAmount = usdc(2);
144145

146+
ctx.sale.setMinTarget(buyAmount);
145147
mintUsdc(alice, mintAmount);
146148

147149
vm.startPrank(alice);
@@ -192,7 +194,10 @@ contract SaleLegacyTest is TestSetup {
192194
vm.stopPrank();
193195

194196
uint256 ownerBalanceAfter = ctx.usdc.balanceOf(address(this));
195-
assertEq(ownerBalanceAfter - ownerBalanceBefore, (amount * 2) - aliceRefund - bobRefund);
197+
assertEq(
198+
ownerBalanceAfter - ownerBalanceBefore,
199+
(amount * 2) - aliceRefund - bobRefund
200+
);
196201
}
197202

198203
function test_SetIndividualCap() public {
@@ -240,7 +245,9 @@ contract SaleLegacyTest is TestSetup {
240245
assertEq(ctx.sale.refundAmount(alice), 0);
241246
}
242247

243-
function test_RefundAmountIsZeroIfIndividualCapIsHigherThanInvestedTotal() public {
248+
function test_RefundAmountIsZeroIfIndividualCapIsHigherThanInvestedTotal()
249+
public
250+
{
244251
ctx.sale.setMinTarget(usdc(1));
245252
ctx.sale.setMaxTarget(usdc(10));
246253

test/SaleMinTargetNotReached.d.sol

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,28 @@ contract SaleMinTargetNotReachedTest is TestSetup {
7676

7777
assertEq(ctx.usdc.balanceOf(address(ctx.sale)), 0);
7878
}
79+
80+
function test_WithdrawRevertsWhenMinTargetNotReached() public {
81+
ctx.sale.setMinTarget(1 ether);
82+
83+
uint256 amount = (ctx.sale.minTarget() / 2) - (usdc(1));
84+
85+
invest(alice, amount);
86+
invest(bob, amount);
87+
88+
assertEq(ctx.sale.totalUncappedAllocations(), amount * 2);
89+
assertLt(ctx.sale.totalUncappedAllocations(), ctx.sale.minTarget());
90+
91+
endSale();
92+
setCap();
93+
94+
assertEq(ctx.sale.allocation(alice), 0);
95+
assertEq(ctx.sale.refundAmount(alice), amount);
96+
97+
vm.expectRevert("minTarget not reached");
98+
ctx.sale.withdraw();
99+
100+
assertEq(ctx.usdc.balanceOf(address(ctx.sale)), amount * 2);
101+
assertEq(ctx.usdc.balanceOf(address(this)), 0);
102+
}
79103
}

0 commit comments

Comments
 (0)