Skip to content

Commit 6a7e7e2

Browse files
committed
add ERC721SeaDropPausable
1 parent 347d58e commit 6a7e7e2

File tree

2 files changed

+162
-0
lines changed

2 files changed

+162
-0
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.17;
3+
4+
import { ERC721SeaDrop } from "../ERC721SeaDrop.sol";
5+
6+
/**
7+
* @title ERC721SeaDropPausable
8+
* @notice A token contract that extends ERC721SeaDrop to be able to
9+
* pause token transfers. By default on deployment transfers are paused,
10+
* and the owner of the token contract can pause or unpause.
11+
*/
12+
contract ERC721SeaDropPausable is ERC721SeaDrop {
13+
/// @notice Revert when transfers are paused.
14+
error TransfersPaused();
15+
16+
/// @notice Emit an event when transfers are paused or unpaused.
17+
event TransfersPausedChanged(bool paused);
18+
19+
/// @notice Boolean if transfers are paused.
20+
bool public transfersPaused = true;
21+
22+
/**
23+
* @notice Deploy the token contract with its name, symbol,
24+
* and allowed SeaDrop addresses.
25+
*/
26+
constructor(
27+
string memory name,
28+
string memory symbol,
29+
address[] memory allowedSeaDrop
30+
) ERC721SeaDrop(name, symbol, allowedSeaDrop) {
31+
emit TransfersPausedChanged(transfersPaused);
32+
}
33+
34+
function updateTransfersPaused(bool paused) external onlyOwner {
35+
transfersPaused = paused;
36+
emit TransfersPausedChanged(paused);
37+
}
38+
39+
function setApprovalForAll(
40+
address, /* operator */
41+
bool /* approved */
42+
) public virtual override {
43+
if (transfersPaused) {
44+
revert TransfersPaused();
45+
}
46+
}
47+
48+
function approve(
49+
address, /* to */
50+
uint256 /* tokenId */
51+
) public virtual override {
52+
if (transfersPaused) {
53+
revert TransfersPaused();
54+
}
55+
}
56+
57+
function _beforeTokenTransfers(
58+
address from,
59+
address, /* to */
60+
uint256, /* startTokenId */
61+
uint256 /* quantity */
62+
) internal virtual override {
63+
if (from != address(0) && transfersPaused) {
64+
revert TransfersPaused();
65+
}
66+
}
67+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.17;
3+
4+
import { TestHelper } from "test/foundry/utils/TestHelper.sol";
5+
6+
import {
7+
ERC721SeaDropPausable
8+
} from "seadrop/extensions/ERC721SeaDropPausable.sol";
9+
10+
import { TwoStepOwnable } from "utility-contracts/TwoStepOwnable.sol";
11+
12+
contract ERC721SeaDropPausableWithMint is ERC721SeaDropPausable {
13+
constructor(
14+
string memory name,
15+
string memory symbol,
16+
address[] memory allowedSeaDrop
17+
) ERC721SeaDropPausable(name, symbol, allowedSeaDrop) {}
18+
19+
function mint(address to, uint256 amount) public onlyOwner {
20+
_mint(to, amount);
21+
}
22+
}
23+
24+
contract ERC721SeaDropSoulboundTest is TestHelper {
25+
ERC721SeaDropPausableWithMint token_;
26+
27+
address greg = makeAddr("greg");
28+
29+
function setUp() public {
30+
token_ = new ERC721SeaDropPausableWithMint("", "", new address[](0));
31+
}
32+
33+
function testCannotSetApprovalWhenPaused() public {
34+
token_.mint(address(this), 1);
35+
36+
vm.expectRevert(ERC721SeaDropPausable.TransfersPaused.selector);
37+
token_.approve(greg, 1);
38+
39+
vm.expectRevert(ERC721SeaDropPausable.TransfersPaused.selector);
40+
token_.setApprovalForAll(greg, true);
41+
42+
// Unpause transfers
43+
token_.updateTransfersPaused(false);
44+
45+
// Now approval should succeed
46+
token_.approve(greg, 1);
47+
token_.setApprovalForAll(greg, true);
48+
}
49+
50+
function testCannotTransferWhenPaused() public {
51+
token_.mint(address(this), 1);
52+
53+
vm.expectRevert(ERC721SeaDropPausable.TransfersPaused.selector);
54+
token_.transferFrom(address(this), greg, 1);
55+
56+
vm.expectRevert(ERC721SeaDropPausable.TransfersPaused.selector);
57+
token_.safeTransferFrom(address(this), greg, 1);
58+
59+
vm.expectRevert(ERC721SeaDropPausable.TransfersPaused.selector);
60+
token_.safeTransferFrom(address(this), greg, 1, "");
61+
62+
// Unpause transfers
63+
token_.updateTransfersPaused(false);
64+
65+
// Now transfer should succeed
66+
token_.safeTransferFrom(address(this), greg, 1);
67+
assertEq(token_.ownerOf(1), greg);
68+
69+
vm.prank(greg);
70+
token_.transferFrom(greg, address(this), 1);
71+
}
72+
73+
function testOnlyOwnerCanSetPaused() public {
74+
// Ensure only the owner can pause transfers
75+
vm.prank(greg);
76+
vm.expectRevert(TwoStepOwnable.OnlyOwner.selector);
77+
token_.updateTransfersPaused(false);
78+
79+
// Ensure owner can toggle transfersPaused
80+
token_.updateTransfersPaused(false);
81+
assertEq(token_.transfersPaused(), false);
82+
83+
token_.updateTransfersPaused(true);
84+
assertEq(token_.transfersPaused(), true);
85+
}
86+
87+
function onERC721Received(
88+
address,
89+
address,
90+
uint256,
91+
bytes calldata
92+
) public pure returns (bytes4) {
93+
return this.onERC721Received.selector;
94+
}
95+
}

0 commit comments

Comments
 (0)