|
| 1 | +// SPDX-License-Identifier: BUSL-1.1 |
| 2 | +pragma solidity ^0.8.20; |
| 3 | + |
| 4 | +import {Lib128Fields} from "./Lib128Fields.sol"; |
| 5 | + |
| 6 | +/// @title LibMintAuth |
| 7 | +/// @notice Library for gas-efficient storage and manipulation of PT and YT mint authorization data. |
| 8 | +/// @dev Implements packed storage where PT and YT mint authorization values are stored together in single uint256 slots: |
| 9 | +/// - Lower 128 bits: PT (Principal Token) mint authorization |
| 10 | +/// - Upper 128 bits: YT (Yield Token) mint authorization |
| 11 | +/// This packing reduces storage costs and enables atomic updates of both authorization values. |
| 12 | +/// The actual bit manipulation and storage operations are delegated to {Lib128Fields}, |
| 13 | +/// which provides gas-optimized assembly implementations for reading and writing packed uint128 fields. |
| 14 | +/// Used to track minting authorizations for addresses across the dual-token system. |
| 15 | +library LibMintAuth { |
| 16 | + using Lib128Fields for uint256; |
| 17 | + |
| 18 | + /// @dev Seed used to derive mint authorization storage slots for each minter address. |
| 19 | + /// The mint auth slot for a `minter` is computed as: |
| 20 | + /// ``` |
| 21 | + /// mstore(0x0c, _MINT_AUTH_SLOT_SEED) |
| 22 | + /// mstore(0x00, minter) |
| 23 | + /// let mintAuthSlot := keccak256(0x0c, 0x20) |
| 24 | + /// ``` |
| 25 | + /// Each slot contains: [YT mint auth (upper 128 bits) | PT mint auth (lower 128 bits)] |
| 26 | + uint256 internal constant _MINT_AUTH_SLOT_SEED = 0x08395086; |
| 27 | + |
| 28 | + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ |
| 29 | + /* SLOT COMPUTATION */ |
| 30 | + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ |
| 31 | + |
| 32 | + /// @notice Computes the storage slot for a minter's PT and YT mint authorizations. |
| 33 | + /// @dev Uses keccak256 to derive a unique storage slot from the mint auth seed and minter address. |
| 34 | + /// The resulting slot contains packed PT (lower 128 bits) and YT (upper 128 bits) mint authorizations. |
| 35 | + /// |
| 36 | + /// Slot Derivation: |
| 37 | + /// 1. Place _MINT_AUTH_SLOT_SEED at memory position 0x0c |
| 38 | + /// 2. Place minter address at memory position 0x00 |
| 39 | + /// 3. Hash 0x20 bytes starting from 0x0c |
| 40 | + /// |
| 41 | + /// This approach ensures deterministic, collision-resistant storage locations for each minter. |
| 42 | + /// @param minter The address to compute the mint authorization slot for |
| 43 | + /// @return slot The storage slot containing the packed PT and YT mint authorizations |
| 44 | + function mintAuthSlot(address minter) internal pure returns (uint256 slot) { |
| 45 | + /// @solidity memory-safe-assembly |
| 46 | + assembly { |
| 47 | + mstore(0x0c, _MINT_AUTH_SLOT_SEED) |
| 48 | + mstore(0x00, minter) |
| 49 | + slot := keccak256(0x0c, 0x20) |
| 50 | + } |
| 51 | + } |
| 52 | + |
| 53 | + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ |
| 54 | + /* MINT AUTHORIZATION */ |
| 55 | + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ |
| 56 | + |
| 57 | + /// @notice Returns both PT and YT mint authorizations for a given minter in a single read. |
| 58 | + /// @dev Computes the storage slot using keccak256 and reads the packed mint authorizations using {Lib128Fields.fromSlot}. |
| 59 | + /// Gas-efficient single storage read. No validation is performed; the caller must ensure proper usage. |
| 60 | + /// @param minter The address to query mint authorizations for |
| 61 | + /// @return ptMintAuth The PT mint authorization (lower 128 bits) as uint128 |
| 62 | + /// @return ytMintAuth The YT mint authorization (upper 128 bits) as uint128 |
| 63 | + function mintAuth(address minter) internal view returns (uint128 ptMintAuth, uint128 ytMintAuth) { |
| 64 | + (ptMintAuth, ytMintAuth) = mintAuthSlot(minter).fromSlot(); |
| 65 | + } |
| 66 | + |
| 67 | + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ |
| 68 | + /* UPDATES */ |
| 69 | + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ |
| 70 | + |
| 71 | + /// @notice Updates both PT and YT mint authorizations for a given minter atomically. |
| 72 | + /// @dev Computes the storage slot using keccak256, packs both authorizations into a single uint256 using |
| 73 | + /// {Lib128Fields.write}, and writes to storage. More gas-efficient than separate writes. |
| 74 | + /// No validation is performed; the caller must ensure values fit in uint128. |
| 75 | + /// @param minter The address whose mint authorizations to update |
| 76 | + /// @param ptMintAuth The new PT mint authorization (stored in lower 128 bits) |
| 77 | + /// @param ytMintAuth The new YT mint authorization (stored in upper 128 bits) |
| 78 | + function updateMintAuth(address minter, uint128 ptMintAuth, uint128 ytMintAuth) internal { |
| 79 | + mintAuthSlot(minter).write(ptMintAuth, ytMintAuth); |
| 80 | + } |
| 81 | +} |
0 commit comments