Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update documentModule #284

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
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
14 changes: 14 additions & 0 deletions contracts/interfaces/engine/ITransferEngine.sol
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;

}
10 changes: 8 additions & 2 deletions contracts/interfaces/engine/draft-IERC1643.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ pragma solidity ^0.8.20;
/// @title IERC1643 Document Management
/// (part of the ERC1400 Security Token Standards)
interface IERC1643 {
struct Document {
string uri;
bytes32 documentHash;
uint256 lastModified;
}

// Document Management
function getDocument(bytes32 _name) external view returns (string memory , bytes32, uint256);
function getAllDocuments() external view returns (bytes32[] memory);
function getDocument(string memory name) external view returns (Document memory doc);
function getAllDocuments() external view returns (string[] memory);
}
2 changes: 2 additions & 0 deletions contracts/libraries/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ library Errors {
error CMTAT_AuthorizationModule_InvalidAuthorization();
error CMTAT_AuthorizationModule_AuthorizationEngineAlreadySet();

error CMTAT_TransferEngineModule_TransferEngineAlreadySet();

// DocumentModule
error CMTAT_DocumentModule_SameValue();

Expand Down
100 changes: 44 additions & 56 deletions contracts/mocks/DocumentEngineMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,94 +3,82 @@
pragma solidity ^0.8.20;
import "../interfaces/engine/draft-IERC1643.sol";
interface IERC1643Whole is IERC1643{

/// uri The URI of the document
/// @return documentHash The hash of the document contents
/// @return lastModified The timestamp of the last modification
struct DocumentInfo {
string name;
string uri;
bytes32 documentHash;
}
// Document Management
function setDocument(bytes32 _name, string memory _uri, bytes32 _documentHash) external;
function removeDocument(bytes32 _name) external;
function setDocument(DocumentInfo calldata doc) external;
function removeDocument(string memory name) external;

// Document Events
event DocumentRemoved(bytes32 indexed _name, string _uri, bytes32 _documentHash);
event DocumentUpdated(bytes32 indexed _name, string _uri, bytes32 _documentHash);
event DocumentRemoved(string indexed name, Document doc);
event DocumentUpdated(string indexed name, Document doc);

}
/*
* @title a DocumentEngine mock for testing, not suitable for production
*/
contract DocumentEngineMock is IERC1643Whole {
struct Document {
string uri;
bytes32 documentHash;
uint256 lastModified;
}

mapping(bytes32 => Document) private documents;
bytes32[] private documentNames;
/*struct DocumentStorage {
uint256 key;
Document doc;
}*/
mapping(string => Document) private documents;
mapping(string => uint256) private documentKey;
string[] private documentNames;

/// @dev Error thrown when a document does not exist
error DocumentDoesNotExist();

/// @notice Retrieves the document details by name
/// @param name_ The name of the document
/// @return uri The URI of the document
/// @return documentHash The hash of the document contents
/// @return lastModified The timestamp of the last modification
function getDocument(bytes32 name_)
/// @param name The name of the document
function getDocument(string memory name)
external
view
override
returns (string memory uri, bytes32 documentHash, uint256 lastModified)
returns (Document memory doc)
{
if (bytes(documents[name_].uri).length == 0) {
return("", 0x0, 0);
}

Document storage doc = documents[name_];
return (doc.uri, doc.documentHash, doc.lastModified);
return documents[name];
}

/// @notice Sets or updates a document
/// @param name_ The name of the document
/// @param uri_ The URI of the document
/// @param documentHash_ The hash of the document contents
function setDocument(bytes32 name_, string memory uri_, bytes32 documentHash_) external override {
Document storage doc = documents[name_];
bool isUpdate = bytes(doc.uri).length != 0;

doc.uri = uri_;
doc.documentHash = documentHash_;
/// @param doc_ the document
function setDocument(DocumentInfo calldata doc_) external override {
Document storage doc = documents[doc_.name];
doc.uri = doc_.uri;
doc.documentHash = doc_.documentHash;
doc.lastModified = block.timestamp;

if (!isUpdate) {
documentNames.push(name_);
if (documentKey[doc_.name] == 0) {
// To avoid key == 0
uint256 key = documentNames.length + 1;
documentKey[doc_.name] = key;
documentNames.push(doc_.name);
}

emit DocumentUpdated(name_, uri_, documentHash_);
emit DocumentUpdated(doc_.name, doc);
}

/// @notice Removes a document
/// @param name_ The name of the document
function removeDocument(bytes32 name_) external override {
if (bytes(documents[name_].uri).length == 0) {
/// @param name The name of the document
function removeDocument(string calldata name) external override {
if (documentKey[name] == 0) {
revert DocumentDoesNotExist();
}

Document memory doc = documents[name_];
delete documents[name_];

for (uint256 i = 0; i < documentNames.length; i++) {
if (documentNames[i] == name_) {
documentNames[i] = documentNames[documentNames.length - 1];
documentNames.pop();
break;
}
}

emit DocumentRemoved(name_, doc.uri, doc.documentHash);
Document memory doc = documents[name];
documentNames[documentKey[name] - 1] = documentNames[documentNames.length - 1];
documentNames.pop();
delete documents[name];
documentKey[name] = 0;
emit DocumentRemoved(name, doc);
}

/// @notice Retrieves all document names
/// @return An array of document names
function getAllDocuments() external view override returns (bytes32[] memory) {
function getAllDocuments() external view override returns (string[] memory) {
return documentNames;
}
}
167 changes: 167 additions & 0 deletions contracts/mocks/TransferEngineMock.sol
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);
}
}
Loading
Loading