Skip to content
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
119 changes: 104 additions & 15 deletions contracts/config/BitmaskConfig.sol
Original file line number Diff line number Diff line change
@@ -1,41 +1,97 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/// @title BitmaskConfig
/// @notice Compresses multiple boolean configuration flags into a single bytes32
/// storage slot, eliminating redundant SLOAD operations.
/// @dev Uses inline Yul assembly for bitwise get/set to avoid Solidity's
/// stack-heavy boolean encoding. Each flag occupies one bit.
contract BitmaskConfig {
error Unauthorized();
error InvalidBitOffset();

address public immutable owner;

uint256 public constant PAUSED_BIT = 1 << 0;
uint256 public constant LOCKED_BIT = 1 << 1;
uint256 public constant ALLOW_PUBLIC_BIT = 1 << 2;
uint256 public constant FEE_SWITCH_BIT = 1 << 3;
// ─── Bit Offset Constants ───────────────────────────────────────────

uint256 public constant PAUSED_BIT = 1 << 0;
uint256 public constant LOCKED_BIT = 1 << 1;
uint256 public constant ALLOW_PUBLIC_BIT = 1 << 2;
uint256 public constant FEE_SWITCH_BIT = 1 << 3;
uint256 public constant EMERGENCY_STOP_BIT = 1 << 4;
uint256 public constant UPGRADEABLE_BIT = 1 << 5;
uint256 public constant UPGRADEABLE_BIT = 1 << 5;

/// @dev Convenience alias for PR compatibility.
uint256 private constant PUBLIC_BIT = ALLOW_PUBLIC_BIT;
uint256 private constant MIGRATED_BIT = FEE_SWITCH_BIT;

/// @dev Single storage slot holding all configuration flags as a bitmask.
bytes32 private _flags;

// ─── Events ─────────────────────────────────────────────────────────

event ConfigUpdated(bytes32 oldFlags, bytes32 newFlags);
event FlagSet(uint256 indexed bit, bool value);
event FlagToggled(uint256 indexed bit);

// ─── Modifiers ──────────────────────────────────────────────────────

modifier onlyOwner() {
if (msg.sender != owner) revert Unauthorized();
_;
}

constructor(address owner_, bool[6] memory initialFlags) {
owner = owner_;
bytes32 flags;
if (initialFlags[0]) flags |= bytes32(PAUSED_BIT);
if (initialFlags[1]) flags |= bytes32(LOCKED_BIT);
if (initialFlags[2]) flags |= bytes32(ALLOW_PUBLIC_BIT);
if (initialFlags[3]) flags |= bytes32(FEE_SWITCH_BIT);
if (initialFlags[4]) flags |= bytes32(EMERGENCY_STOP_BIT);
if (initialFlags[5]) flags |= bytes32(UPGRADEABLE_BIT);
_flags = flags;
// ─── Constructor ────────────────────────────────────────────────────

/// @dev Deployer becomes the owner. All flags start as false.
constructor() {
owner = msg.sender;
}

// ─── Convenience Getters (PR style) ─────────────────────────────────

function isPaused() external view returns (bool) {
return _getFlag(PAUSED_BIT);
}

function isLocked() external view returns (bool) {
return _getFlag(LOCKED_BIT);
}

function isPublic() external view returns (bool) {
return _getFlag(PUBLIC_BIT);
}

function isMigrated() external view returns (bool) {
return _getFlag(MIGRATED_BIT);
}

/// @dev Return the raw bytes32 bitmask.
function getRawConfig() external view returns (bytes32) {
return _flags;
}

// ─── Convenience Setters (PR style, owner-restricted) ───────────────

function setPaused(bool value) external onlyOwner {
_setFlag(PAUSED_BIT, value);
}

function setLocked(bool value) external onlyOwner {
_setFlag(LOCKED_BIT, value);
}

function setPublic(bool value) external onlyOwner {
_setFlag(PUBLIC_BIT, value);
}

function setMigrated(bool value) external onlyOwner {
_setFlag(MIGRATED_BIT, value);
}

// ─── Generic Methods (main style) ───────────────────────────────────

/// @dev Check if a specific bit is set.
function isSet(uint256 bit) external view returns (bool) {
uint256 result;
assembly {
Expand All @@ -45,6 +101,7 @@ contract BitmaskConfig {
return result != 0;
}

/// @dev Set or clear a specific bit (owner only).
function setFlag(uint256 bit, bool value) external onlyOwner {
if (bit > UPGRADEABLE_BIT) revert InvalidBitOffset();
assembly {
Expand All @@ -57,6 +114,7 @@ contract BitmaskConfig {
emit FlagSet(bit, value);
}

/// @dev Toggle a specific bit (owner only).
function toggleFlag(uint256 bit) external onlyOwner {
if (bit > UPGRADEABLE_BIT) revert InvalidBitOffset();
assembly {
Expand All @@ -67,6 +125,7 @@ contract BitmaskConfig {
emit FlagToggled(bit);
}

/// @dev Return all six flags as an array.
function getFlags() external view returns (bool[6] memory) {
bytes32 f = _flags;
bool[6] memory result;
Expand All @@ -78,4 +137,34 @@ contract BitmaskConfig {
result[5] = (f & bytes32(UPGRADEABLE_BIT)) != 0;
return result;
}

// ─── Internal Bitwise Operations ────────────────────────────────────

/// @dev Get a single bit flag using inline assembly.
function _getFlag(uint256 bit) private view returns (bool flag) {
assembly {
flag := and(sload(_flags.slot), bit)
}
}

/// @dev Set or clear a single bit flag using inline assembly.
function _setFlag(uint256 bit, bool value) private {
bytes32 oldFlags;
bytes32 newFlags;

assembly {
let slot := _flags.slot
oldFlags := sload(slot)

if value {
newFlags := or(oldFlags, bit)
}
if iszero(value) {
newFlags := and(oldFlags, not(bit))
}
sstore(slot, newFlags)
}

emit ConfigUpdated(oldFlags, newFlags);
}
}
50 changes: 50 additions & 0 deletions contracts/math/FastModMath.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/// @title FastModMath
/// @notice Gas-optimized modular arithmetic using native EVM Yul assembly opcodes.
/// @dev Bypasses Solidity's overflow safety checks by using `mulmod` and `addmod`
/// opcodes directly, which compute modular results natively in the EVM.
library FastModMath {
/// @notice Compute (x * y) % m using the native mulmod opcode.
/// @param x First multiplicand.
/// @param y Second multiplicand.
/// @param m Modulus (must be > 0).
/// @return result The result of (x * y) % m.
function safeMulMod(
uint256 x,
uint256 y,
uint256 m
) internal pure returns (uint256 result) {
assembly {
// Guard against division-by-zero: if m == 0, revert.
if iszero(m) {
mstore(0x00, 0x12) // Revert with "division by zero" error
revert(0x1c, 0x04)
}
// Execute native mulmod(x, y, m)
result := mulmod(x, y, m)
}
}

/// @notice Compute (x + y) % m using the native addmod opcode.
/// @param x First addend.
/// @param y Second addend.
/// @param m Modulus (must be > 0).
/// @return result The result of (x + y) % m.
function safeAddMod(
uint256 x,
uint256 y,
uint256 m
) internal pure returns (uint256 result) {
assembly {
// Guard against division-by-zero.
if iszero(m) {
mstore(0x00, 0x12)
revert(0x1c, 0x04)
}
// Execute native addmod(x, y, m)
result := addmod(x, y, m)
}
}
}
71 changes: 71 additions & 0 deletions contracts/router/ZeroCopyRouter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/// @title ZeroCopyRouter
/// @notice A low-level router that extracts calldata slices using Yul assembly
/// without allocating intermediate memory buffers.
/// @dev Uses `calldataload` and `calldatacopy` directly to pass payload pointers
/// to `delegatecall`. Payloads are copied to a safe memory region (0x80+)
/// to avoid overwriting the free memory pointer at 0x40.
contract ZeroCopyRouter {
/// @notice Execute a batch of delegatecalls to target addresses with
/// packed calldata. Per-call layout: [address (20B)] [uint16 len]
/// [payload bytes ...]
/// @param packedBatch ABI-encoded batch of targets + payloads.
/// @return results Array of success bools, one per sub-call.
function batchExecute(
bytes calldata packedBatch
) external returns (bool[] memory results) {
results = new bool[](16); // max batch size safety cap
uint256 ptr;
uint256 batchLen = packedBatch.length;
uint256 count;

assembly {
let dataPtr := add(packedBatch.offset, 4)
let dataEnd := add(dataPtr, batchLen)

for {

} lt(dataPtr, dataEnd) {

} {
// Load target address.
let target := calldataload(dataPtr)
// Load payload length (uint16, big-endian).
let payloadLen := shr(
240,
calldataload(add(dataPtr, 20))
)
dataPtr := add(dataPtr, 22)

// Copy payload to safe memory region (0x80 avoids 0x40 free ptr).
let payloadStart := dataPtr
calldatacopy(0x80, payloadStart, payloadLen)

// delegatecall with the payload slice.
let success := delegatecall(
gas(),
target,
0x80,
payloadLen,
0x80,
0x20
)

// Store result.
mstore(
add(results, add(0x20, mul(count, 0x20))),
success
)
dataPtr := add(dataPtr, payloadLen)
count := add(count, 1)
}
}

// Trim results to actual count.
assembly {
mstore(results, count)
}
}
}
Loading
Loading