-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add TransferEngineModule, remove snapshotModule
- Loading branch information
Showing
16 changed files
with
445 additions
and
177 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// SPDX-License-Identifier: MPL-2.0 | ||
|
||
pragma solidity ^0.8.20; | ||
|
||
/* | ||
* @dev minimum interface to define a RuleEngine | ||
*/ | ||
interface ITransferEngine { | ||
/** | ||
* @dev Returns true if the operation is a success, and false otherwise. | ||
*/ | ||
function operateOnTransfer(address from, address to, uint256 balanceFrom, uint256 balanceTo, uint256 totalSupply) external; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
//SPDX-License-Identifier: MPL-2.0 | ||
|
||
pragma solidity ^0.8.20; | ||
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; | ||
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; | ||
import "../modules/internal/base/SnapshotModuleBase.sol"; | ||
import "../interfaces/ICMTATSnapshot.sol"; | ||
import "../interfaces/engine/ITransferEngine.sol"; | ||
/* | ||
* @title a RuleEngine mock for testing, not suitable for production | ||
*/ | ||
contract TransferEngineMock is SnapshotModuleBase, AccessControlUpgradeable, ITransferEngine { | ||
ERC20Upgradeable erc20; | ||
constructor(ERC20Upgradeable erc20_, address admin) { | ||
erc20 = erc20_; | ||
_grantRole(DEFAULT_ADMIN_ROLE, admin); | ||
} | ||
/* ============ State Variables ============ */ | ||
bytes32 public constant SNAPSHOOTER_ROLE = keccak256("SNAPSHOOTER_ROLE"); | ||
|
||
/** | ||
* @dev Returns `true` if `account` has been granted `role`. | ||
*/ | ||
function hasRole( | ||
bytes32 role, | ||
address account | ||
) public view virtual override(AccessControlUpgradeable) returns (bool) { | ||
// The Default Admin has all roles | ||
if (AccessControlUpgradeable.hasRole(DEFAULT_ADMIN_ROLE, account)) { | ||
return true; | ||
} | ||
return AccessControlUpgradeable.hasRole(role, account); | ||
} | ||
/** | ||
* @dev Update balance and/or total supply snapshots before the values are modified. This is implemented | ||
* in the _beforeTokenTransfer hook, which is executed for _mint, _burn, and _transfer operations. | ||
*/ | ||
function operateOnTransfer(address from, address to, uint256 balanceFrom, uint256 balanceTo, uint256 totalSupply) public override { | ||
_setCurrentSnapshot(); | ||
if (from != address(0)) { | ||
// for both burn and transfer | ||
_updateAccountSnapshot(from, balanceFrom); | ||
if (to != address(0)) { | ||
// transfer | ||
_updateAccountSnapshot(to, balanceTo); | ||
} else { | ||
// burn | ||
_updateTotalSupplySnapshot(totalSupply); | ||
} | ||
} else { | ||
// mint | ||
_updateAccountSnapshot(to, balanceTo); | ||
_updateTotalSupplySnapshot(totalSupply); | ||
} | ||
} | ||
|
||
/*////////////////////////////////////////////////////////////// | ||
PUBLIC/EXTERNAL FUNCTIONS | ||
//////////////////////////////////////////////////////////////*/ | ||
/** | ||
* @notice Return snapshotBalanceOf and snapshotTotalSupply to avoid multiple calls | ||
* @return ownerBalance , totalSupply - see snapshotBalanceOf and snapshotTotalSupply | ||
*/ | ||
function snapshotInfo(uint256 time, address owner) public view returns (uint256 ownerBalance, uint256 totalSupply) { | ||
ownerBalance = snapshotBalanceOf(time, owner); | ||
totalSupply = snapshotTotalSupply(time); | ||
} | ||
|
||
/** | ||
* @notice Return snapshotBalanceOf for each address in the array and the total supply | ||
* @return ownerBalances array with the balance of each address, the total supply | ||
*/ | ||
function snapshotInfoBatch(uint256 time, address[] calldata addresses) public view returns (uint256[] memory ownerBalances, uint256 totalSupply) { | ||
ownerBalances = new uint256[](addresses.length); | ||
for(uint256 i = 0; i < addresses.length; ++i){ | ||
ownerBalances[i] = snapshotBalanceOf(time, addresses[i]); | ||
} | ||
totalSupply = snapshotTotalSupply(time); | ||
} | ||
|
||
/** | ||
* @notice Return snapshotBalanceOf for each address in the array and the total supply | ||
* @return ownerBalances array with the balance of each address, the total supply | ||
*/ | ||
function snapshotInfoBatch(uint256[] calldata times, address[] calldata addresses) public view returns (uint256[][] memory ownerBalances, uint256[] memory totalSupply) { | ||
ownerBalances = new uint256[][](times.length); | ||
totalSupply = new uint256[](times.length); | ||
for(uint256 iT = 0; iT < times.length; ++iT){ | ||
(ownerBalances[iT], totalSupply[iT]) = snapshotInfoBatch(times[iT],addresses); | ||
} | ||
} | ||
|
||
/** | ||
* @notice Return the number of tokens owned by the given owner at the time when the snapshot with the given time was created. | ||
* @return value stored in the snapshot, or the actual balance if no snapshot | ||
*/ | ||
function snapshotBalanceOf( | ||
uint256 time, | ||
address owner | ||
) public view returns (uint256) { | ||
return _snapshotBalanceOf(time, owner, erc20.balanceOf(owner)); | ||
} | ||
|
||
/** | ||
* @dev See {OpenZeppelin - ERC20Snapshot} | ||
* Retrieves the total supply at the specified time. | ||
* @return value stored in the snapshot, or the actual totalSupply if no snapshot | ||
*/ | ||
function snapshotTotalSupply(uint256 time) public view returns (uint256) { | ||
return _snapshotTotalSupply(time, erc20.totalSupply()); | ||
} | ||
/*////////////////////////////////////////////////////////////// | ||
PUBLIC/EXTERNAL FUNCTIONS | ||
//////////////////////////////////////////////////////////////*/ | ||
/** | ||
* @notice | ||
* Schedule a snapshot at the given time specified as a number of seconds since epoch. | ||
* The time cannot be before the time of the latest scheduled, but not yet created snapshot. | ||
*/ | ||
function scheduleSnapshot(uint256 time) public onlyRole(SNAPSHOOTER_ROLE) { | ||
_scheduleSnapshot(time); | ||
} | ||
|
||
/** | ||
* @notice | ||
* Schedule a snapshot at the given time specified as a number of seconds since epoch. | ||
* The time cannot be before the time of the latest scheduled, but not yet created snapshot. | ||
*/ | ||
function scheduleSnapshotNotOptimized( | ||
uint256 time | ||
) public onlyRole(SNAPSHOOTER_ROLE) { | ||
_scheduleSnapshotNotOptimized(time); | ||
} | ||
|
||
/** | ||
* @notice | ||
* Reschedule the scheduled snapshot, but not yet created snapshot with the given oldTime to be created at the given newTime specified as a number of seconds since epoch. | ||
* The newTime cannot be before the time of the previous scheduled, but not yet created snapshot, or after the time fo the next scheduled snapshot. | ||
*/ | ||
function rescheduleSnapshot( | ||
uint256 oldTime, | ||
uint256 newTime | ||
) public onlyRole(SNAPSHOOTER_ROLE) { | ||
_rescheduleSnapshot(oldTime, newTime); | ||
} | ||
|
||
/** | ||
* @notice | ||
* Cancel creation of the scheduled snapshot, but not yet created snapshot with the given time. | ||
* There should not be any other snapshots scheduled after this one. | ||
*/ | ||
function unscheduleLastSnapshot( | ||
uint256 time | ||
) public onlyRole(SNAPSHOOTER_ROLE) { | ||
_unscheduleLastSnapshot(time); | ||
} | ||
|
||
/** | ||
* @notice | ||
* Cancel creation of the scheduled snapshot, but not yet created snapshot with the given time. | ||
*/ | ||
function unscheduleSnapshotNotOptimized( | ||
uint256 time | ||
) public onlyRole(SNAPSHOOTER_ROLE) { | ||
_unscheduleSnapshotNotOptimized(time); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
contracts/modules/wrapper/extensions/TransferEngineModule.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
//SPDX-License-Identifier: MPL-2.0 | ||
|
||
pragma solidity ^0.8.20; | ||
|
||
import "../../security/AuthorizationModule.sol"; | ||
import "../../../libraries/Errors.sol"; | ||
import "../../../interfaces/engine/ITransferEngine.sol"; | ||
|
||
abstract contract TransferEngineModule is AuthorizationModule { | ||
/* ============ Events ============ */ | ||
/** | ||
* @dev Emitted when a rule engine is set. | ||
*/ | ||
event TransferEngine(ITransferEngine indexed newTransferEngine); | ||
/* ============ ERC-7201 ============ */ | ||
// keccak256(abi.encode(uint256(keccak256("CMTAT.storage.TransferModule")) - 1)) & ~bytes32(uint256(0xff)) | ||
bytes32 private constant TransferEngineModuleStorageLocation = 0x59b7f077fa4ad020f9053fd2197fef0113b19f0b11dcfe516e88cbc0e9226d00; | ||
/* ==== ERC-7201 State Variables === */ | ||
struct TransferEngineModuleStorage { | ||
ITransferEngine _transferEngine; | ||
} | ||
/* ============ Initializer Function ============ */ | ||
/** | ||
* @dev | ||
* | ||
* - The grant to the admin role is done by AccessControlDefaultAdminRules | ||
* - The control of the zero address is done by AccessControlDefaultAdminRules | ||
* | ||
*/ | ||
function __TransferModule_init_unchained(ITransferEngine TransferEngine_) | ||
internal onlyInitializing { | ||
if (address(TransferEngine_) != address (0)) { | ||
TransferEngineModuleStorage storage $ = _getTransferEngineModuleStorage(); | ||
$._transferEngine = TransferEngine_; | ||
emit TransferEngine(TransferEngine_); | ||
} | ||
} | ||
|
||
|
||
/*////////////////////////////////////////////////////////////// | ||
PUBLIC/EXTERNAL FUNCTIONS | ||
//////////////////////////////////////////////////////////////*/ | ||
|
||
function transferEngine() public view virtual returns (ITransferEngine) { | ||
TransferEngineModuleStorage storage $ = _getTransferEngineModuleStorage(); | ||
return $._transferEngine; | ||
} | ||
|
||
/* | ||
* @notice set an TransferEngine if not already set | ||
* @dev once an TransferEngine is set, it is not possible to unset it | ||
*/ | ||
function setTransferEngine( | ||
ITransferEngine transferEngine_ | ||
) external onlyRole(DEFAULT_ADMIN_ROLE) { | ||
TransferEngineModuleStorage storage $ = _getTransferEngineModuleStorage(); | ||
$._transferEngine = transferEngine_; | ||
emit TransferEngine(transferEngine_); | ||
} | ||
|
||
/*////////////////////////////////////////////////////////////// | ||
INTERNAL/PRIVATE FUNCTIONS | ||
//////////////////////////////////////////////////////////////*/ | ||
|
||
/* ============ ERC-7201 ============ */ | ||
function _getTransferEngineModuleStorage() private pure returns (TransferEngineModuleStorage storage $) { | ||
assembly { | ||
$.slot := TransferEngineModuleStorageLocation | ||
} | ||
} | ||
} |
Oops, something went wrong.