Skip to content

Commit

Permalink
create WithdrawalLogic
Browse files Browse the repository at this point in the history
  • Loading branch information
0age committed Oct 31, 2024
1 parent 54d144b commit efd14f4
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 182 deletions.
7 changes: 5 additions & 2 deletions src/lib/ClaimProcessorLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ import { EfficiencyLib } from "./EfficiencyLib.sol";
import { FunctionCastLib } from "./FunctionCastLib.sol";
import { HashLib } from "./HashLib.sol";
import { IdLib } from "./IdLib.sol";
import { DepositLogic } from "./DepositLogic.sol";
import { WithdrawalLogic } from "./WithdrawalLogic.sol";
import { ValidityLib } from "./ValidityLib.sol";

contract ClaimProcessorLogic is DepositLogic {
contract ClaimProcessorLogic is WithdrawalLogic {
using HashLib for address;
using HashLib for bytes32;
using HashLib for uint256;
Expand Down Expand Up @@ -130,6 +130,9 @@ contract ClaimProcessorLogic is DepositLogic {
using FunctionCastLib for function(bytes32, bytes32, uint256, uint256, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool);
using FunctionCastLib for function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool);

/// @dev `keccak256(bytes("Claim(address,address,address,bytes32)"))`.
uint256 private constant _CLAIM_EVENT_SIGNATURE = 0x770c32a2314b700d6239ee35ba23a9690f2fceb93a55d8c753e953059b3b18d4;

function _processSimpleClaim(bytes32 messageHash, uint256 calldataPointer, uint256 offsetToId, bytes32 typehash, function(address, address, uint256, uint256) internal returns (bool) operation)
internal
returns (bool)
Expand Down
187 changes: 7 additions & 180 deletions src/lib/InternalLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ contract InternalLogic is Tstorish {
_PERMIT2_INITIALLY_DEPLOYED = _checkPermit2Deployment();
}

function _emitClaim(address sponsor, bytes32 messageHash, address allocator) internal {
assembly ("memory-safe") {
mstore(0, messageHash)
log4(0, 0x20, _CLAIM_EVENT_SIGNATURE, shr(0x60, shl(0x60, sponsor)), shr(0x60, shl(0x60, allocator)), caller())
}
}

function _notExpiredAndSignedByAllocator(bytes32 messageHash, address allocator, BasicTransfer calldata transferPayload) internal {
transferPayload.expires.later();

Expand All @@ -100,71 +107,6 @@ contract InternalLogic is Tstorish {
_clearTstorish(_REENTRANCY_GUARD_SLOT);
}

function _deriveConsistentAllocatorAndConsumeNonce(TransferComponent[] calldata components, uint256 nonce) internal returns (address allocator) {
uint256 totalComponents = components.length;

uint256 errorBuffer = (totalComponents == 0).asUint256();

// TODO: bounds checks on these array accesses can be skipped as an optimization
uint96 allocatorId = components[0].id.toAllocatorId();

allocator = allocatorId.fromRegisteredAllocatorIdWithConsumed(nonce);

unchecked {
for (uint256 i = 1; i < totalComponents; ++i) {
errorBuffer |= (components[i].id.toAllocatorId() != allocatorId).asUint256();
}
}

assembly ("memory-safe") {
if errorBuffer {
// revert InvalidBatchAllocation()
mstore(0, 0x3a03d3bb)
revert(0x1c, 0x04)
}
}
}

function _deriveConsistentAllocatorAndConsumeNonce(SplitByIdComponent[] calldata components, uint256 nonce) internal returns (address allocator) {
uint256 totalComponents = components.length;

uint256 errorBuffer = (totalComponents == 0).asUint256();

// TODO: bounds checks on these array accesses can be skipped as an optimization
uint96 allocatorId = components[0].id.toAllocatorId();

allocator = allocatorId.fromRegisteredAllocatorIdWithConsumed(nonce);

unchecked {
for (uint256 i = 1; i < totalComponents; ++i) {
errorBuffer |= (components[i].id.toAllocatorId() != allocatorId).asUint256();
}
}

assembly ("memory-safe") {
if errorBuffer {
// revert InvalidBatchAllocation()
mstore(0, 0x3a03d3bb)
revert(0x1c, 0x04)
}
}
}

function _emitClaim(address sponsor, bytes32 messageHash, address allocator) internal {
assembly ("memory-safe") {
mstore(0, messageHash)
log4(0, 0x20, _CLAIM_EVENT_SIGNATURE, shr(0x60, shl(0x60, sponsor)), shr(0x60, shl(0x60, allocator)), caller())
}
}

function _emitForcedWithdrawalStatusUpdatedEvent(uint256 id, uint256 withdrawableAt) internal {
assembly ("memory-safe") {
mstore(0, iszero(iszero(withdrawableAt)))
mstore(0x20, withdrawableAt)
log3(0, 0x40, _FORCED_WITHDRAWAL_STATUS_UPDATED_SIGNATURE, caller(), id)
}
}

function _register(address sponsor, bytes32 claimHash, bytes32 typehash, uint256 duration) internal {
assembly ("memory-safe") {
let m := mload(0x40)
Expand Down Expand Up @@ -204,56 +146,6 @@ contract InternalLogic is Tstorish {
return true;
}

function _enableForcedWithdrawal(uint256 id) internal returns (uint256 withdrawableAt) {
// overflow check not necessary as reset period is capped
unchecked {
withdrawableAt = block.timestamp + id.toResetPeriod().toSeconds();
}

uint256 cutoffTimeSlotLocation = _getCutoffTimeSlot(msg.sender, id);
assembly ("memory-safe") {
sstore(cutoffTimeSlotLocation, withdrawableAt)
}

_emitForcedWithdrawalStatusUpdatedEvent(id, withdrawableAt);
}

function _disableForcedWithdrawal(uint256 id) internal returns (bool) {
uint256 cutoffTimeSlotLocation = _getCutoffTimeSlot(msg.sender, id);

assembly ("memory-safe") {
if iszero(sload(cutoffTimeSlotLocation)) {
// revert ForcedWithdrawalAlreadyDisabled(msg.sender, id)
mstore(0, 0xe632dbad)
mstore(0x20, caller())
mstore(0x40, id)
revert(0x1c, 0x44)
}

sstore(cutoffTimeSlotLocation, 0)
}

_emitForcedWithdrawalStatusUpdatedEvent(id, uint256(0).asStubborn());

return true;
}

function _processForcedWithdrawal(uint256 id, address recipient, uint256 amount) internal returns (bool) {
uint256 cutoffTimeSlotLocation = _getCutoffTimeSlot(msg.sender, id);

assembly ("memory-safe") {
let withdrawableAt := sload(cutoffTimeSlotLocation)
if or(iszero(withdrawableAt), gt(withdrawableAt, timestamp())) {
// revert PrematureWithdrawal(id)
mstore(0, 0x9287bcb0)
mstore(0x20, id)
revert(0x1c, 0x24)
}
}

return _withdraw(msg.sender, recipient, id, amount);
}

function _consume(uint256[] calldata nonces) internal returns (bool) {
// NOTE: this may not be necessary, consider removing
msg.sender.usingAllocatorId().mustHaveARegisteredAllocator();
Expand Down Expand Up @@ -292,60 +184,6 @@ contract InternalLogic is Tstorish {
allocatorId = allocator.register();
}

function _getForcedWithdrawalStatus(address account, uint256 id) internal view returns (ForcedWithdrawalStatus status, uint256 forcedWithdrawalAvailableAt) {
uint256 cutoffTimeSlotLocation = _getCutoffTimeSlot(account, id);
assembly ("memory-safe") {
forcedWithdrawalAvailableAt := sload(cutoffTimeSlotLocation)
status := mul(iszero(iszero(forcedWithdrawalAvailableAt)), sub(2, gt(forcedWithdrawalAvailableAt, timestamp())))
}
}

/// @dev Burns `amount` token `id` from `from` without checking transfer hooks and sends
/// the corresponding underlying tokens to `to`. Emits a {Transfer} event.
function _withdraw(address from, address to, uint256 id, uint256 amount) internal returns (bool) {
_setReentrancyGuard();
address token = id.toToken();

if (token == address(0)) {
to.safeTransferETH(amount);
} else {
uint256 initialBalance = token.balanceOf(address(this));
token.safeTransfer(to, amount);
// NOTE: if the balance increased, this will underflow to a massive number causing
// the burn to fail; furthermore, this scenario would indicate a very broken token
unchecked {
amount = initialBalance - token.balanceOf(address(this));
}
}

assembly ("memory-safe") {
// Compute the balance slot.
mstore(0x20, _ERC6909_MASTER_SLOT_SEED)
mstore(0x14, from)
mstore(0x00, id)
let fromBalanceSlot := keccak256(0x00, 0x40)
let fromBalance := sload(fromBalanceSlot)
// Revert if insufficient balance.
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
// Subtract and store the updated balance.
sstore(fromBalanceSlot, sub(fromBalance, amount))

let account := shr(0x60, shl(0x60, from))

// Emit the {Transfer} and {Withdrawal} events.
mstore(0x00, caller())
mstore(0x20, amount)
log4(0x00, 0x40, _TRANSFER_EVENT_SIGNATURE, account, 0, id)
}

_clearReentrancyGuard();

return true;
}

function _getLockDetails(uint256 id) internal view returns (address token, address allocator, ResetPeriod resetPeriod, Scope scope) {
token = id.toToken();
allocator = id.toAllocatorId().toRegisteredAllocator();
Expand Down Expand Up @@ -400,15 +238,4 @@ contract InternalLogic is Tstorish {
function _tokenURI(uint256 id) internal view returns (string memory) {
return _METADATA_RENDERER.uri(id.toLock(), id);
}

function _getCutoffTimeSlot(address account, uint256 id) internal pure returns (uint256 cutoffTimeSlotLocation) {
assembly ("memory-safe") {
let m := mload(0x40)
mstore(0x14, account)
mstore(0, _FORCED_WITHDRAWAL_ACTIVATIONS_SCOPE)
mstore(0x34, id)
cutoffTimeSlotLocation := keccak256(0x1c, 0x38)
mstore(0x40, m)
}
}
}
50 changes: 50 additions & 0 deletions src/lib/TransferLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,54 @@ contract TransferLogic is InternalLogic {
}
}
}

function _deriveConsistentAllocatorAndConsumeNonce(TransferComponent[] calldata components, uint256 nonce) internal returns (address allocator) {
uint256 totalComponents = components.length;

uint256 errorBuffer = (totalComponents == 0).asUint256();

// TODO: bounds checks on these array accesses can be skipped as an optimization
uint96 allocatorId = components[0].id.toAllocatorId();

allocator = allocatorId.fromRegisteredAllocatorIdWithConsumed(nonce);

unchecked {
for (uint256 i = 1; i < totalComponents; ++i) {
errorBuffer |= (components[i].id.toAllocatorId() != allocatorId).asUint256();
}
}

assembly ("memory-safe") {
if errorBuffer {
// revert InvalidBatchAllocation()
mstore(0, 0x3a03d3bb)
revert(0x1c, 0x04)
}
}
}

function _deriveConsistentAllocatorAndConsumeNonce(SplitByIdComponent[] calldata components, uint256 nonce) internal returns (address allocator) {
uint256 totalComponents = components.length;

uint256 errorBuffer = (totalComponents == 0).asUint256();

// TODO: bounds checks on these array accesses can be skipped as an optimization
uint96 allocatorId = components[0].id.toAllocatorId();

allocator = allocatorId.fromRegisteredAllocatorIdWithConsumed(nonce);

unchecked {
for (uint256 i = 1; i < totalComponents; ++i) {
errorBuffer |= (components[i].id.toAllocatorId() != allocatorId).asUint256();
}
}

assembly ("memory-safe") {
if errorBuffer {
// revert InvalidBatchAllocation()
mstore(0, 0x3a03d3bb)
revert(0x1c, 0x04)
}
}
}
}
Loading

0 comments on commit efd14f4

Please sign in to comment.