Skip to content

Commit

Permalink
Interface and clean-up
Browse files Browse the repository at this point in the history
  • Loading branch information
vimageDE committed Dec 16, 2024
1 parent 611cee3 commit 9d26c19
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 31 deletions.
45 changes: 14 additions & 31 deletions src/examples/allocator/SimpleAllocator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,38 @@

pragma solidity ^0.8.27;

import { ERC6909 } from "lib/solady/src/tokens/ERC6909.sol";
import { ERC6909 } from "lib/solady/src/tokens/ERC6909.sol";
import { IERC1271 } from "openzeppelin-contracts/contracts/interfaces/IERC1271.sol";
import { Ownable } from "openzeppelin-contracts/contracts/access/Ownable.sol";
import { Ownable2Step } from "openzeppelin-contracts/contracts/access/Ownable2Step.sol";
import { ECDSA } from "openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol";
import { IAllocator } from "src/interfaces/IAllocator.sol";
import { ITheCompactClaims } from "src/interfaces/ITheCompactClaims.sol";
import { ITheCompact } from "src/interfaces/ITheCompact.sol";
import { BasicClaim } from "src/types/Claims.sol";
import { ISimpleAllocator } from "src/interfaces/ISimpleAllocator.sol";
import { Compact } from "src/types/EIP712Types.sol";
import { ResetPeriod } from "src/lib/IdLib.sol";

contract SimpleAllocator is Ownable2Step, IAllocator {
struct LockedAllocation {
uint216 amount;
uint40 expires;
}
contract SimpleAllocator is ISimpleAllocator {

// The slot holding the current active claim, transiently. bytes32(uint256(keccak256("ActiveClaim")) - 1)
uint256 private constant _ACTIVE_CLAIM_SLOT = 0x52878b5aadd152a1719f94d6380573e67df5b5f15153bef7af957f0c05d2a1bf;
// The slot holding the current active claim sponsor, transiently. bytes32(uint256(keccak256("ActiveClaimSponsor")) - 1)
uint256 private constant _ACTIVE_CLAIM_SPONSOR_SLOT = 0x5c0cba9a91a791e685f0a43b1ceba6e6670ab2d235795af4fe5350bca1423e19;
address private immutable _COMPACT_CONTRACT;
address private immutable _ARBITER;
uint256 private immutable _MIN_WITHDRAWAL_DELAY;
uint256 private immutable _MAX_WITHDRAWAL_DELAY;

// mapping(bytes32 tokenHash => LockedAllocation allocation) private _locked;

/// @dev mapping of tokenHash to the expiration of the lock
mapping(bytes32 tokenHash => uint256 expiration) private _claim;
/// @dev mapping of tokenHash to the amount of the lock
mapping(bytes32 tokenHash => uint256 amount) private _amount;
/// @dev mapping of tokenHash to the nonce of the lock
mapping(bytes32 tokenHash => uint256 nonce) private _nonce;
/// @dev mapping of the lock digest to the tokenHash of the lock
mapping(bytes32 digest => bytes32 tokenHash) private _sponsor;

error ClaimActive(address sponsor);
error InvalidCaller(address caller, address expected);
error InvalidArbiter(address arbiter);
error NonceAlreadyConsumed(uint256 nonce);
error InsufficientBalance(address sponsor, uint256 id);
error InvalidExpiration(uint256 expires);
error ForceWithdrawalAvailable(uint256 expires, uint256 forcedWithdrawalExpiration);
error InvalidLock(bytes32 digest, uint256 expiration);

event Locked(address sponsor, uint256 id, uint256 amount, uint256 expires);

constructor(address compactContract_, address arbiter_, uint256 minWithdrawalDelay_, uint256 maxWithdrawalDelay_, address owner_) Ownable(owner_) {
constructor(address compactContract_, address arbiter_, uint256 minWithdrawalDelay_, uint256 maxWithdrawalDelay_) {
_COMPACT_CONTRACT = compactContract_;
_ARBITER = arbiter_;
_MIN_WITHDRAWAL_DELAY = minWithdrawalDelay_;
_MAX_WITHDRAWAL_DELAY = maxWithdrawalDelay_;
}

/// @dev locks all tokens of a sponsor for an id
/// @inheritdoc ISimpleAllocator
function lock(Compact calldata compact_) external {
// Check msg.sender is sponsor
if (msg.sender != compact_.sponsor) {
Expand Down Expand Up @@ -125,6 +103,7 @@ contract SimpleAllocator is Ownable2Step, IAllocator {
emit Locked(compact_.sponsor, compact_.id, compact_.amount, compact_.expires);
}

/// @inheritdoc IAllocator
function attest(address operator_, address from_, address, uint256 id_, uint256 amount_) external view returns (bytes4) {
if (msg.sender != _COMPACT_CONTRACT) {
revert InvalidCaller(msg.sender, _COMPACT_CONTRACT);
Expand All @@ -143,8 +122,10 @@ contract SimpleAllocator is Ownable2Step, IAllocator {
return 0x1a808f91;
}

/// @inheritdoc IERC1271
/// @dev we trust the compact contract to check the nonce is not already consumed
function isValidSignature(bytes32 hash, bytes calldata) external view returns (bytes4 magicValue) {
// The hash is the digest of the compact
bytes32 tokenHash = _sponsor[hash];
if (tokenHash == bytes32(0) || _claim[tokenHash] <= block.timestamp) {
revert InvalidLock(hash, _claim[tokenHash]);
Expand All @@ -153,7 +134,8 @@ contract SimpleAllocator is Ownable2Step, IAllocator {
return IERC1271.isValidSignature.selector;
}

function checkTokensLocked(uint256 id_, address sponsor_) internal view returns (uint256 amount_, uint256 expires_) {
/// @inheritdoc ISimpleAllocator
function checkTokensLocked(uint256 id_, address sponsor_) external view returns (uint256 amount_, uint256 expires_) {
bytes32 tokenHash = _getTokenHash(id_, sponsor_);
uint256 expires = _claim[tokenHash];
if (expires <= block.timestamp) {
Expand All @@ -163,6 +145,7 @@ contract SimpleAllocator is Ownable2Step, IAllocator {
return (_amount[tokenHash], expires);
}

/// @inheritdoc ISimpleAllocator
function checkCompactLocked(Compact calldata compact_) external view returns (bool locked_, uint256 expires_) {
// TODO: Check the force unlock time in the compact contract and adapt expires_ if needed
if (compact_.arbiter != _ARBITER) {
Expand Down
61 changes: 61 additions & 0 deletions src/interfaces/ISimpleAllocator.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.27;

import { IAllocator } from "src/interfaces/IAllocator.sol";
import { Compact } from "src/types/EIP712Types.sol";


interface ISimpleAllocator is IAllocator {

/// @notice Thrown if a claim is already active
error ClaimActive(address sponsor);

/// @notice Thrown if the caller is invalid
error InvalidCaller(address caller, address expected);

/// @notice Thrown if the suggested arbiter is not the arbiter of the allocator
error InvalidArbiter(address arbiter);

/// @notice Thrown if the nonce has already been consumed on the compact contract
error NonceAlreadyConsumed(uint256 nonce);

/// @notice Thrown if the sponsor does not have enough balance to lock the amount
error InsufficientBalance(address sponsor, uint256 id);

/// @notice Thrown if the provided expiration is not valid
error InvalidExpiration(uint256 expires);

/// @notice Thrown if the expiration is longer then the tokens forced withdrawal time
error ForceWithdrawalAvailable(uint256 expires, uint256 forcedWithdrawalExpiration);

/// @notice Thrown if the provided lock is not available or expired
/// @dev The expiration will be '0' if no lock is available
error InvalidLock(bytes32 digest, uint256 expiration);

/// @notice Emitted when a lock is successfully created
/// @param sponsor The address of the sponsor
/// @param id The id of the token
/// @param amount The amount of the token that was available for locking (the full balance of the token will get locked)
/// @param expires The expiration of the lock
event Locked(address sponsor, uint256 id, uint256 amount, uint256 expires);

/// @notice Locks the tokens of an id for a claim
/// @dev Locks all tokens of a sponsor for an id
/// @param compact_ The compact that contains the data about the lock
function lock(Compact calldata compact_) external;

/// @notice Checks if the tokens of a sponsor for an id are locked
/// @param id_ The id of the token
/// @param sponsor_ The address of the sponsor
/// @return amount_ The amount of the token that was available for locking (the full balance of the token will get locked)
/// @return expires_ The expiration of the lock
function checkTokensLocked(uint256 id_, address sponsor_) external view returns (uint256 amount_, uint256 expires_);

/// @notice Checks if the a lock for the compact exists and is active
/// @dev Also checks if the provided nonce has not yet been consumed on the compact contract
/// @param compact_ The compact that contains the data about the lock
/// @return locked_ Whether the compact is locked
/// @return expires_ The expiration of the lock
function checkCompactLocked(Compact calldata compact_) external view returns (bool locked_, uint256 expires_);
}

0 comments on commit 9d26c19

Please sign in to comment.