Skip to content

Commit e87679b

Browse files
Krishang NadgaudaKrishang Nadgauda
authored andcommitted
merge main
2 parents 8d944e6 + e68775c commit e87679b

File tree

8 files changed

+139
-42
lines changed

8 files changed

+139
-42
lines changed

contracts/drop/DropERC1155.sol

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ contract DropERC1155 is
7070
uint256 private constant MAX_BPS = 10_000;
7171

7272
/// @dev The thirdweb contract with fee related information.
73-
ITWFee public immutable thirdwebFee;
73+
ITWFee private immutable thirdwebFee;
7474

7575
/// @dev Owner of the contract (purpose: OpenSea compatibility)
7676
address private _owner;
@@ -265,6 +265,8 @@ contract DropERC1155 is
265265
bytes32[] calldata _proofs,
266266
uint256 _proofMaxQuantityPerTransaction
267267
) external payable nonReentrant {
268+
require(isTrustedForwarder(msg.sender) || _msgSender() == tx.origin, "BOT");
269+
268270
// Get the active claim condition index.
269271
uint256 activeConditionId = getActiveClaimConditionId(_tokenId);
270272

contracts/drop/DropERC20.sol

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ contract DropERC20 is
5454
bytes32 private constant TRANSFER_ROLE = keccak256("TRANSFER_ROLE");
5555

5656
/// @dev The thirdweb contract with fee related information.
57-
ITWFee internal immutable thirdwebFee;
57+
ITWFee private immutable thirdwebFee;
5858

5959
/// @dev Contract level metadata.
6060
string public contractURI;
@@ -185,6 +185,8 @@ contract DropERC20 is
185185
bytes32[] calldata _proofs,
186186
uint256 _proofMaxQuantityPerTransaction
187187
) external payable nonReentrant {
188+
require(isTrustedForwarder(msg.sender) || _msgSender() == tx.origin, "BOT");
189+
188190
// Get the claim conditions.
189191
uint256 activeConditionId = getActiveClaimConditionId();
190192

contracts/drop/DropERC721.sol

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ contract DropERC721 is
6363
uint256 private constant MAX_BPS = 10_000;
6464

6565
/// @dev The thirdweb contract with fee related information.
66-
ITWFee public immutable thirdwebFee;
66+
ITWFee private immutable thirdwebFee;
6767

6868
/// @dev Owner of the contract (purpose: OpenSea compatibility)
6969
address private _owner;
@@ -328,6 +328,8 @@ contract DropERC721 is
328328
bytes32[] calldata _proofs,
329329
uint256 _proofMaxQuantityPerTransaction
330330
) external payable nonReentrant {
331+
require(isTrustedForwarder(msg.sender) || _msgSender() == tx.origin, "BOT");
332+
331333
uint256 tokenIdToClaim = nextTokenIdToClaim;
332334

333335
// Get the claim conditions.

docs/DropERC1155.md

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,23 +1008,6 @@ function symbol() external view returns (string)
10081008
|---|---|---|
10091009
| _0 | string | undefined
10101010

1011-
### thirdwebFee
1012-
1013-
```solidity
1014-
function thirdwebFee() external view returns (contract ITWFee)
1015-
```
1016-
1017-
1018-
1019-
*The thirdweb contract with fee related information.*
1020-
1021-
1022-
#### Returns
1023-
1024-
| Name | Type | Description |
1025-
|---|---|---|
1026-
| _0 | contract ITWFee | undefined
1027-
10281011
### totalSupply
10291012

10301013
```solidity

docs/DropERC721.md

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,23 +1080,6 @@ function symbol() external view returns (string)
10801080
|---|---|---|
10811081
| _0 | string | undefined
10821082

1083-
### thirdwebFee
1084-
1085-
```solidity
1086-
function thirdwebFee() external view returns (contract ITWFee)
1087-
```
1088-
1089-
1090-
1091-
*The thirdweb contract with fee related information.*
1092-
1093-
1094-
#### Returns
1095-
1096-
| Name | Type | Description |
1097-
|---|---|---|
1098-
| _0 | contract ITWFee | undefined
1099-
11001083
### tokenByIndex
11011084

11021085
```solidity

scripts/addImplementation.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { ethers } from "hardhat";
2+
3+
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
4+
import { TWFactory } from "typechain/TWFactory";
5+
6+
async function main() {
7+
8+
const [caller]: SignerWithAddress[] = await ethers.getSigners();
9+
10+
console.log("\nCaller address: ", caller.address);
11+
12+
const twFactoryAddress: string = ethers.constants.AddressZero; // replace
13+
const twFactory: TWFactory = await ethers.getContractAt("TWFactory", twFactoryAddress);
14+
15+
const hasFactoryRole = await twFactory.hasRole(
16+
ethers.utils.solidityKeccak256(["string"], ["FACTORY_ROLE"]),
17+
caller.address
18+
)
19+
if(!hasFactoryRole) {
20+
throw new Error("Caller does not have FACTORY_ROLE on new factory");
21+
}
22+
23+
const implementations: string[] = []; // replace
24+
const data = implementations.map((impl) => twFactory.interface.encodeFunctionData("addImplementation", [impl]));
25+
26+
const tx = await twFactory.multicall(data);
27+
console.log("Adding implementations: ", tx.hash);
28+
29+
await tx.wait();
30+
31+
console.log("Done.");
32+
}
33+
34+
main()
35+
.then(() => process.exit(0))
36+
.catch((e) => {
37+
console.error(e)
38+
process.exit(1)
39+
})

scripts/transferBalance.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ async function main() {
1010
console.log(`\nTransferring balance from ${caller.address} to ${receiver}`);
1111

1212
const balance = await ethers.provider.getBalance(caller.address);
13-
const cost = ethers.utils.parseUnits("300", "gwei").mul(21_000);
13+
const gasPrice = ethers.utils.parseUnits("0", "gwei"); // replace
14+
const cost = gasPrice.mul(21_000);
1415

1516
const tx = await caller.sendTransaction({
1617
to: receiver,
17-
gasPrice: ethers.utils.parseUnits("300", "gwei"),
18+
gasPrice: gasPrice,
1819
value: balance.sub(cost)
1920
});
2021
console.log("Transferring balance: ", tx.hash);

src/test/drop/DropERC721.t.sol

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,54 @@ import "contracts/drop/DropERC721.sol";
66
// Test imports
77
import "../utils/BaseTest.sol";
88

9-
contract BaseDropERC721Test is BaseTest {
9+
contract SubExploitContract is ERC721Holder, ERC1155Holder {
10+
DropERC721 internal drop;
11+
address payable internal master;
12+
13+
constructor(address _drop) {
14+
drop = DropERC721(_drop);
15+
master = payable(msg.sender);
16+
}
17+
18+
/// @dev Lets an account claim NFTs.
19+
function claimDrop(
20+
address _receiver,
21+
uint256 _quantity,
22+
address _currency,
23+
uint256 _pricePerToken,
24+
bytes32[] calldata _proofs,
25+
uint256 _proofMaxQuantityPerTransaction
26+
) external {
27+
drop.claim(_receiver, _quantity, _currency, _pricePerToken, _proofs, _proofMaxQuantityPerTransaction);
28+
29+
selfdestruct(master);
30+
}
31+
}
32+
33+
contract MasterExploitContract is ERC721Holder, ERC1155Holder {
34+
address internal drop;
35+
36+
constructor(address _drop) {
37+
drop = _drop;
38+
}
39+
40+
/// @dev Lets an account claim NFTs.
41+
function performExploit(
42+
address _receiver,
43+
uint256 _quantity,
44+
address _currency,
45+
uint256 _pricePerToken,
46+
bytes32[] calldata _proofs,
47+
uint256 _proofMaxQuantityPerTransaction
48+
) external {
49+
for (uint256 i = 0; i < 100; i++) {
50+
SubExploitContract sub = new SubExploitContract(address(drop));
51+
sub.claimDrop(_receiver, _quantity, _currency, _pricePerToken, _proofs, _proofMaxQuantityPerTransaction);
52+
}
53+
}
54+
}
55+
56+
contract DropERC721Test is BaseTest {
1057
DropERC721 public drop;
1158

1259
function setUp() public override {
@@ -99,7 +146,6 @@ contract BaseDropERC721Test is BaseTest {
99146
}
100147

101148
function test_claimCondition_waitTimeInSecondsBetweenClaims() public {
102-
vm.startPrank(deployer);
103149
vm.warp(1);
104150

105151
address receiver = getActor(0);
@@ -110,16 +156,20 @@ contract BaseDropERC721Test is BaseTest {
110156
conditions[0].quantityLimitPerTransaction = 100;
111157
conditions[0].waitTimeInSecondsBetweenClaims = type(uint256).max;
112158

159+
vm.prank(deployer);
113160
drop.lazyMint(100, "ipfs://", bytes(""));
161+
vm.prank(deployer);
114162
drop.setClaimConditions(conditions, false);
163+
164+
vm.prank(getActor(5), getActor(5));
115165
drop.claim(receiver, 1, address(0), 0, proofs, 0);
116166

117167
vm.expectRevert("cannot claim.");
168+
vm.prank(getActor(5), getActor(5));
118169
drop.claim(receiver, 1, address(0), 0, proofs, 0);
119170
}
120171

121172
function test_claimCondition_resetEligibility_waitTimeInSecondsBetweenClaims() public {
122-
vm.startPrank(deployer);
123173
vm.warp(1);
124174

125175
address receiver = getActor(0);
@@ -130,12 +180,47 @@ contract BaseDropERC721Test is BaseTest {
130180
conditions[0].quantityLimitPerTransaction = 100;
131181
conditions[0].waitTimeInSecondsBetweenClaims = type(uint256).max;
132182

183+
vm.prank(deployer);
133184
drop.lazyMint(100, "ipfs://", bytes(""));
134185

186+
vm.prank(deployer);
135187
drop.setClaimConditions(conditions, false);
188+
189+
vm.prank(getActor(5), getActor(5));
136190
drop.claim(receiver, 1, address(0), 0, proofs, 0);
137191

192+
vm.prank(deployer);
138193
drop.setClaimConditions(conditions, true);
194+
195+
vm.prank(getActor(5), getActor(5));
139196
drop.claim(receiver, 1, address(0), 0, proofs, 0);
140197
}
198+
199+
function test_multiple_claim_exploit() public {
200+
MasterExploitContract masterExploit = new MasterExploitContract(address(drop));
201+
202+
DropERC721.ClaimCondition[] memory conditions = new DropERC721.ClaimCondition[](1);
203+
conditions[0].maxClaimableSupply = 100;
204+
conditions[0].quantityLimitPerTransaction = 1;
205+
conditions[0].waitTimeInSecondsBetweenClaims = type(uint256).max;
206+
207+
vm.prank(deployer);
208+
drop.lazyMint(100, "ipfs://", bytes(""));
209+
210+
vm.prank(deployer);
211+
drop.setClaimConditions(conditions, false);
212+
213+
bytes32[] memory proofs = new bytes32[](0);
214+
215+
vm.startPrank(getActor(5));
216+
vm.expectRevert(bytes("BOT"));
217+
masterExploit.performExploit(
218+
address(masterExploit),
219+
conditions[0].quantityLimitPerTransaction,
220+
conditions[0].currency,
221+
conditions[0].pricePerToken,
222+
proofs,
223+
0
224+
);
225+
}
141226
}

0 commit comments

Comments
 (0)