Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

♻️ Refactors and deployments #1

Merged
merged 5 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ cache/
artifacts/
cache/
out/
zkout/

# Ignore Environment Variables!
.env
Expand Down
2 changes: 1 addition & 1 deletion lib/dn404
2 changes: 1 addition & 1 deletion lib/solady
Submodule solady updated 60 files
+4 −2 .github/workflows/ci.yml
+6 −0 README.md
+10 −0 docs/index.html
+2 −2 docs/tokens/erc20votes.md
+1 −1 docs/utils/libtransient.md
+8 −8 docs/utils/signaturecheckerlib.md
+11 −11 ext/wake/test_erc1155.py
+7 −2 foundry.toml
+1 −1 package.json
+63 −0 prep/zksync-compat-analysis.js
+4 −2 src/accounts/ERC4337.sol
+9 −10 src/accounts/ERC4337Factory.sol
+11 −2 src/accounts/ERC7821.sol
+3 −0 src/accounts/LibERC7579.sol
+1 −0 src/accounts/Receiver.sol
+2 −0 src/accounts/Timelock.sol
+3 −3 src/tokens/ERC20Votes.sol
+1,143 −0 src/tokens/ext/zksync/ERC1155.sol
+915 −0 src/tokens/ext/zksync/ERC721.sol
+4 −2 src/utils/DynamicArrayLib.sol
+3 −2 src/utils/EnumerableSetLib.sol
+18 −7 src/utils/Initializable.sol
+5 −5 src/utils/LibClone.sol
+1 −1 src/utils/LibTransient.sol
+3 −3 src/utils/LibZip.sol
+32 −23 src/utils/MinHeapLib.sol
+1 −1 src/utils/Multicallable.sol
+1 −1 src/utils/P256.sol
+6 −5 src/utils/RedBlackTreeLib.sol
+5 −2 src/utils/SafeTransferLib.sol
+84 −76 src/utils/SignatureCheckerLib.sol
+1 −0 src/utils/UUPSUpgradeable.sol
+1 −1 src/utils/ext/delegatexyz/DelegateCheckerLib.sol
+6 −60 src/utils/ext/ithaca/BLS.sol
+78 −0 src/utils/ext/zksync/ERC1967BeaconProxy.sol
+457 −0 src/utils/ext/zksync/ERC1967Factory.sol
+9 −0 src/utils/ext/zksync/ERC1967FactoryConstants.sol
+82 −0 src/utils/ext/zksync/ERC1967Proxy.sol
+381 −0 src/utils/ext/zksync/SafeTransferLib.sol
+367 −0 src/utils/ext/zksync/SignatureCheckerLib.sol
+52 −0 src/utils/ext/zksync/SingleUseETHVault.sol
+62 −0 src/utils/ext/zksync/UpgradeableBeacon.sol
+4 −2 src/utils/g/DynamicArrayLib.sol
+3 −2 src/utils/g/EnumerableSetLib.sol
+1 −1 src/utils/g/LibTransient.sol
+32 −23 src/utils/g/MinHeapLib.sol
+6 −5 src/utils/g/RedBlackTreeLib.sol
+14 −24 test/ERC4337Factory.t.sol
+1 −1 test/P256.t.sol
+20 −1 test/SafeTransferLib.t.sol
+7 −3 test/SignatureCheckerLib.t.sol
+2 −0 test/Timelock.t.sol
+34 −6 test/ext/ithaca/BLS.t.sol
+1,221 −0 test/ext/zksync/ERC1155.t.sol
+104 −0 test/ext/zksync/ERC1967Factory.t.sol
+1,005 −0 test/ext/zksync/ERC721.t.sol
+743 −0 test/ext/zksync/SafeTransferLib.t.sol
+387 −0 test/ext/zksync/SignatureCheckerLib.t.sol
+124 −0 test/utils/mocks/ext/zksync/MockERC1155.sol
+139 −0 test/utils/mocks/ext/zksync/MockERC721.sol
19 changes: 19 additions & 0 deletions script/DeployAll.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {Script} from "forge-std/Script.sol";
import "../src/Sheepy404.sol";
import "../src/Sheepy404Mirror.sol";
import "../src/SheepySale.sol";

contract DeployAllScript is Script {
function run() external {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(deployerPrivateKey);
bytes32 salt = keccak256(abi.encode(block.timestamp, "hehe"));
new Sheepy404{salt: salt}();
new Sheepy404Mirror{salt: salt}();
new SheepySale{salt: salt}();
vm.stopBroadcast();
}
}
14 changes: 14 additions & 0 deletions script/DeploySheepy404.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {Script} from "forge-std/Script.sol";
import "../src/Sheepy404.sol";

contract DeploySheepy404Script is Script {
function run() external {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(deployerPrivateKey);
new Sheepy404();
vm.stopBroadcast();
}
}
45 changes: 37 additions & 8 deletions src/Sheepy404.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@ pragma solidity ^0.8.4;
import {SheepyBase} from "./SheepyBase.sol";
import {DN404} from "dn404/src/DN404.sol";
import {LibString} from "solady/utils/LibString.sol";
import {LibBitmap} from "solady/utils/LibBitmap.sol";
import {DynamicArrayLib} from "solady/utils/DynamicArrayLib.sol";

/// @dev This contract can be used by itself or as an proxy's implementation.
contract Sheepy404 is DN404, SheepyBase {
using LibBitmap for *;
using DynamicArrayLib for *;

/*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
/* EVENTS */
/*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/
Expand All @@ -30,6 +35,9 @@ contract Sheepy404 is DN404, SheepyBase {
/// @dev The base URI of the contract.
string internal _baseURI;

/// @dev Whether a certain `tokenId` has been revealed.
LibBitmap.Bitmap internal _revealed;

/// @dev How much native currency required to reveal a token.
uint256 public revealPrice;

Expand All @@ -38,12 +46,14 @@ contract Sheepy404 is DN404, SheepyBase {
/*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

/// @dev For initialization.
function initialize(address initialOwner, address initialAdmin, address mirror)
public
virtual
{
function initialize(
address initialOwner,
address initialAdmin,
address mirror,
string memory notSoSecret
) public virtual {
uint256 initialSupply = 1_000_000_000 * 10 ** 18;
_initializeSheepyBase(initialOwner, initialAdmin);
_initializeSheepyBase(initialOwner, initialAdmin, notSoSecret);
_initializeDN404(initialSupply, initialOwner, mirror);
}

Expand Down Expand Up @@ -75,15 +85,25 @@ contract Sheepy404 is DN404, SheepyBase {
/*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

/// @dev Allows the public to pay to reveal the `tokenIds`.
function reveal(uint256[] calldata tokenIds) public payable virtual {
function reveal(uint256[] memory tokenIds) public payable virtual {
require(msg.value == revealPrice * tokenIds.length, "Wrong payment.");
for (uint256 i; i < tokenIds.length; ++i) {
uint256 id = tokenIds[i];
uint256 id = tokenIds.get(i);
if (!_exists(id)) revert TokenDoesNotExist();
_revealed.set(id);
emit Reveal(id);
}
}

/// @dev Returns if each of the `tokenIds` has been revealed.
function revealed(uint256[] memory tokenIds) public view returns (bool[] memory) {
uint256[] memory results = DynamicArrayLib.malloc(tokenIds.length);
for (uint256 i; i < tokenIds.length; ++i) {
results.set(i, _revealed.get(tokenIds.get(i)));
}
return results.asBoolArray();
}

/*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
/* ADMIN FUNCTIONS */
/*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/
Expand Down Expand Up @@ -127,8 +147,17 @@ contract Sheepy404 is DN404, SheepyBase {
// Emit a {Reset} event for each id if the caller isn't the mirror.
if (msg.sender != _getDN404Storage().mirrorERC721) {
for (uint256 i; i < ids.length; ++i) {
if (from[i] != to[i]) emit Reset(ids[i]);
if (from.toUint256Array().get(i) != to.toUint256Array().get(i)) {
uint256 id = ids.get(i);
_revealed.unset(id);
emit Reset(id);
}
}
}
}

/// @dev Need to override this.
function _useAfterNFTTransfers() internal virtual override returns (bool) {
return true;
}
}
10 changes: 9 additions & 1 deletion src/SheepyBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,16 @@ contract SheepyBase is Ownable, EnumerableRoles {
/*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

/// @dev For initialization.
function _initializeSheepyBase(address initialOwner, address initialAdmin) internal virtual {
function _initializeSheepyBase(
address initialOwner,
address initialAdmin,
string memory notSoSecret
) internal virtual {
_initializeOwner(initialOwner);
require(
keccak256(bytes(notSoSecret))
== 0x9f6dc27901fd3c0399e319e16bba7e24d8bb2b077fe896daffd2108aa65c40cc
);
if (initialAdmin != address(0)) _setRole(initialAdmin, ADMIN_ROLE, true);
}

Expand Down
12 changes: 7 additions & 5 deletions src/SheepySale.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ contract SheepySale is SheepyBase {
/// @dev For configuring a sale.
struct SaleConfig {
address erc20ToSell;
uint256 price; // Per `10** erc20.decimals()`.
uint256 price; // Per `10 ** erc20ToSell.decimals()`.
uint256 startTime;
uint256 endTime;
uint256 totalQuota; // The maximum amount that can be bought.
Expand Down Expand Up @@ -69,8 +69,11 @@ contract SheepySale is SheepyBase {
/*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

/// @dev For initialization.
function initialize(address initialOwner, address initialAdmin) public virtual {
_initializeSheepyBase(initialOwner, initialAdmin);
function initialize(address initialOwner, address initialAdmin, string memory notSoSecret)
public
virtual
{
_initializeSheepyBase(initialOwner, initialAdmin, notSoSecret);
}

/*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
Expand All @@ -88,8 +91,7 @@ contract SheepySale is SheepyBase {
) public payable {
Sale storage s = _sales[saleId];
require(s.erc20ToSell != address(0), "ERC20 not set.");
require(s.startTime <= block.timestamp, "Not open.");
require(block.timestamp <= s.endTime, "Not open.");
require(s.startTime <= block.timestamp && block.timestamp <= s.endTime, "Not open.");
require((s.totalBought += amount) <= s.totalQuota, "Exceeded total quota.");
uint256 minAddressQuota = FixedPointMathLib.min(customAddressQuota, s.addressQuota);
require((s.bought[msg.sender] += amount) <= minAddressQuota, "Exceeded address quota.");
Expand Down
90 changes: 84 additions & 6 deletions test/Sheepy404.t.sol
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;

import "./utils/SoladyTest.sol";
import "forge-std/Test.sol";
import "../src/Sheepy404.sol";
import "../src/Sheepy404Mirror.sol";
import "../src/SheepySale.sol";
import "solady/utils/DynamicArrayLib.sol";

import "solady/utils/LibClone.sol";
contract Sheepy404Test is Test {
using DynamicArrayLib for *;

event Reveal(uint256 indexed tokenId);
event Reset(uint256 indexed tokenId);

contract Sheepy404Test is SoladyTest {
Sheepy404 sheepy;
Sheepy404Mirror mirror;
SheepySale sale;

address internal _ALICE = address(0x111);
address internal _BOB = address(0x222);
Expand All @@ -19,18 +25,21 @@ contract Sheepy404Test is SoladyTest {
uint256 internal _WAD = 10 ** 18;
uint256 internal _INITIAL_SUPPLY = 1_000_000_000 * _WAD;
uint256 internal _UNIT = _INITIAL_SUPPLY / 10_000;
uint256 internal _REVEAL_PRICE = 0.001 ether;

string internal constant _NAME = "Sheepy";
string internal constant _SYMBOL = "Sheepy404";
string internal constant _BASE_URI = "https://sheepyapi.com/{id}.json";
string internal constant _NOT_SO_SECRET = "SomethingSomethingNoGrief";

function setUp() public {
sheepy = new Sheepy404();
mirror = new Sheepy404Mirror();
sale = new SheepySale();
}

function testInitialize() public {
sheepy.initialize(_ALICE, _BOB, address(mirror));
function _initialize() internal {
sheepy.initialize(_ALICE, _BOB, address(mirror), _NOT_SO_SECRET);
assertEq(sheepy.balanceOf(_ALICE), _INITIAL_SUPPLY);
mirror.pullOwner();
assertEq(mirror.owner(), _ALICE);
Expand All @@ -40,12 +49,22 @@ contract Sheepy404Test is SoladyTest {
vm.prank(_ALICE);
sheepy.setNameAndSymbol(_NAME, _SYMBOL);

vm.prank(_ALICE);
sheepy.setRevealPrice(_REVEAL_PRICE);

sale.initialize(_ALICE, address(0), _NOT_SO_SECRET);
}

function testInitialize() public {
_initialize();

assertEq(sheepy.name(), _NAME);
assertEq(sheepy.symbol(), _SYMBOL);

assertEq(mirror.name(), _NAME);
assertEq(mirror.symbol(), _SYMBOL);

assertEq(sheepy.revealPrice(), _REVEAL_PRICE);

assertEq(mirror.balanceOf(_BOB), 0);
vm.prank(_ALICE);
sheepy.transfer(_BOB, _UNIT - 1);
Expand All @@ -57,4 +76,63 @@ contract Sheepy404Test is SoladyTest {

assertEq(mirror.tokenURI(1), "https://sheepyapi.com/1.json");
}

function testSale() public {
_initialize();

SheepySale.SaleConfig memory c;
c.erc20ToSell = address(sheepy);
c.price = 0.03 ether;
c.startTime = 1;
c.endTime = 10000;
c.totalQuota = 10;
c.addressQuota = 2;

vm.prank(_ALICE);
sale.setSale(1, c);
}

function testSalePriceOf() public view {
uint256 amount = _WAD / 50;
uint256 pricePerWad = 0.03 ether;
uint256 totalPrice = sale.priceOf(address(sheepy), amount, pricePerWad);
assertEq(totalPrice, (10 ** 18 / 50) * 0.03 ether / 10 ** 18);
}

function testResetAndReveal() public {
_initialize();

vm.expectEmit();
emit Reset(1);
vm.prank(_ALICE);
sheepy.transfer(_BOB, _UNIT * 2);
assertEq(mirror.balanceOf(_BOB), 2);
assertEq(mirror.ownerOf(1), _BOB);
assertEq(mirror.ownerOf(2), _BOB);

vm.recordLogs();
vm.prank(_BOB);
mirror.transferFrom(_BOB, _CHARLIE, 1);
Vm.Log[] memory entries = vm.getRecordedLogs();
for (uint256 i; i < entries.length; ++i) {
assert(entries[i].topics[0] != keccak256("Reset(uint256)"));
}
assertEq(mirror.ownerOf(1), _CHARLIE);

assertEq(_revealed(1), false);
vm.deal(_CHARLIE, 100 ether);
vm.prank(_CHARLIE);
vm.expectEmit();
emit Reveal(1);
sheepy.reveal{value: _REVEAL_PRICE}(DynamicArrayLib.p(1).asUint256Array());
assertEq(_revealed(1), true);

vm.prank(_CHARLIE);
sheepy.transfer(_BOB, _UNIT);
assertEq(mirror.ownerOf(1), _BOB);
}

function _revealed(uint256 i) internal view returns (bool) {
return sheepy.revealed(DynamicArrayLib.p(i).asUint256Array())[0];
}
}
Loading
Loading