-
Notifications
You must be signed in to change notification settings - Fork 32
Support compliance modules for confidential RWAs #197
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
Open
james-toussaint
wants to merge
57
commits into
master
Choose a base branch
from
feature/confidential-rwa-compliance
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 46 commits
Commits
Show all changes
57 commits
Select commit
Hold shift + click to select a range
61729c2
Init `ERC7984Rwa` extension.
james-toussaint 639e5a2
Fix typos
james-toussaint 85546dd
Add agent role
james-toussaint 0029ad7
Update spelling
james-toussaint b2174ea
Add pausable & roles tests
james-toussaint ce8286c
Add mint/burn/force/transfer tests
james-toussaint 6cb98a5
Remove tmp freezable
james-toussaint 46d6800
Merge remote-tracking branch 'origin/master' into feature/confidentia…
james-toussaint d2562aa
Name ERC7984Rwa
james-toussaint f58c1f3
Name confidential
james-toussaint 76b21ae
Move RWA test
james-toussaint 127aff5
Test with & without proof
james-toussaint 84af687
Rwa mock uses freezable
james-toussaint b0d5ffa
Check transferred amounts in tests
james-toussaint 6fb7f97
Bypass hardhat fhevm behaviour
james-toussaint 0cb0208
Add support interface test
james-toussaint 90ebfa0
Add should not force transfer if anyone
james-toussaint c5d07fe
Move some modifiers to mock
james-toussaint e484066
Update doc
james-toussaint 4ec0bd1
Merge remote-tracking branch 'origin/master' into feature/confidentia…
james-toussaint 64c6c9b
Swap items in doc
james-toussaint 1ad9ccd
Add suggestions
james-toussaint 628d143
Remove lint annotation
james-toussaint 0b1d87c
Update test name
james-toussaint b6b6827
Add restriction to ERC7984Rwa
james-toussaint 3185336
Move gates
james-toussaint b4f8c03
Remove ExpectedPause error
james-toussaint 28973a2
Rename block functions
james-toussaint 0facae5
Rename fixture
james-toussaint 2d0ef0e
Force transfer with all update effects
james-toussaint 5451777
Update set frozen doc
james-toussaint 3065002
Refactor event checks in freezable tests
james-toussaint 4a2e41e
Init compliance modules for confidential RWAs
james-toussaint 3946b30
Add abstract compliance modules
james-toussaint 4debb47
Compliance implements interface
james-toussaint 86d5250
Add post transfer hook
james-toussaint 30ca7df
Typo
james-toussaint 57ab500
Init investor cap module
james-toussaint ed06057
Move rwa compliance contracts
james-toussaint 4b4d558
Support confidential rwa module
james-toussaint 4c45948
Rename rwa mock functions
james-toussaint 9974fae
Immutable token in balance cap module
james-toussaint 3332581
Switch to always-on/transfer-only compliance modules
james-toussaint c81b703
Typo
james-toussaint 7d438c3
Use enum for compliance module type
james-toussaint fea22af
Enable token handles access to modules
james-toussaint b74c5ba
Increase coverage on modular compliance flow
james-toussaint b964c8b
Should not post update investors if not compliant
james-toussaint 3be8b00
Rename to `ModularCompliance` & `ComplianceModule`
james-toussaint 1bc4c3c
Add balance cap module tests
james-toussaint 1336085
Add max investor tests
james-toussaint 35b0771
Merge remote-tracking branch 'origin' into feature/confidential-rwa
james-toussaint 4f04222
Use agent for operations
james-toussaint 9e56fa5
Merge remote-tracking branch 'origin/feature/confidential-rwa' into f…
james-toussaint 020fe73
Merge remote-tracking branch 'origin' into feature/confidential-rwa-c…
james-toussaint 53ec926
Restore restricted and freezable
james-toussaint d3240e1
Update styling
james-toussaint File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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,5 @@ | ||
| --- | ||
| 'openzeppelin-confidential-contracts': minor | ||
| --- | ||
|
|
||
| `ERC7984Rwa`: An extension of `ERC7984`, that supports confidential Real World Assets (RWAs). |
This file contains hidden or 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,5 @@ | ||
| --- | ||
| 'openzeppelin-confidential-contracts': minor | ||
| --- | ||
|
|
||
| `ERC7984RwaCompliance`: Support compliance modules for confidential RWAs. |
This file contains hidden or 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,23 @@ | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| pragma solidity ^0.8.24; | ||
|
|
||
| /// @dev Interface for contracts that implements user account transfer restrictions. | ||
| interface IERC7984Restricted { | ||
| enum Restriction { | ||
| DEFAULT, // User has no explicit restriction | ||
| BLOCKED, // User is explicitly blocked | ||
| ALLOWED // User is explicitly allowed | ||
| } | ||
|
|
||
| /// @dev Emitted when a user account's restriction is updated. | ||
| event UserRestrictionUpdated(address indexed account, Restriction restriction); | ||
|
|
||
| /// @dev The operation failed because the user account is restricted. | ||
| error UserRestricted(address account); | ||
|
|
||
| /// @dev Returns the restriction of a user account. | ||
| function getRestriction(address account) external view returns (Restriction); | ||
| /// @dev Returns whether a user account is allowed to interact with the token. | ||
| function isUserAllowed(address account) external view returns (bool); | ||
| } |
This file contains hidden or 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,113 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.24; | ||
|
|
||
| import {ebool, externalEuint64, euint64} from "@fhevm/solidity/lib/FHE.sol"; | ||
| import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol"; | ||
| import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol"; | ||
| import {IERC7984} from "./IERC7984.sol"; | ||
| import {IERC7984Restricted} from "./IERC7984Restricted.sol"; | ||
|
|
||
| /// @dev Base interface for confidential RWA contracts. | ||
| interface IERC7984RwaBase { | ||
| /// @dev Emitted when the contract is paused. | ||
| event Paused(address account); | ||
| /// @dev Emitted when the contract is unpaused. | ||
| event Unpaused(address account); | ||
|
|
||
| /// @dev The caller account is not authorized to perform an operation. | ||
| error OwnableUnauthorizedAccount(address account); | ||
| /// @dev The owner is not a valid owner account. (eg. `address(0)`) | ||
| error OwnableInvalidOwner(address owner); | ||
| /// @dev The operation failed because the contract is paused. | ||
| error EnforcedPause(); | ||
|
|
||
| /// @dev Returns true if has admin role, false otherwise. | ||
| function isAdmin(address account) external view returns (bool); | ||
| /// @dev Returns true if agent, false otherwise. | ||
| function isAgent(address account) external view returns (bool); | ||
| /// @dev Returns true if the contract is paused, and false otherwise. | ||
| function paused() external view returns (bool); | ||
| /// @dev Pauses contract. | ||
| function pause() external; | ||
| /// @dev Unpauses contract. | ||
| function unpause() external; | ||
| /// @dev Returns the restriction of a user account. | ||
| function getRestriction(address account) external view returns (IERC7984Restricted.Restriction); | ||
| /// @dev Blocks a user account. | ||
| function blockUser(address account) external; | ||
| /// @dev Unblocks a user account. | ||
| function unblockUser(address account) external; | ||
| /// @dev Returns whether an account is allowed to interact with the token. | ||
| function isUserAllowed(address account) external view returns (bool); | ||
| /// @dev Returns the confidential frozen balance of an account. | ||
| function confidentialFrozen(address account) external view returns (euint64); | ||
| /// @dev Returns the available (unfrozen) balance of an account. Up to {confidentialBalanceOf}. | ||
| function confidentialAvailable(address account) external returns (euint64); | ||
| /// @dev Sets confidential amount of token for an account as frozen with proof. | ||
| function setConfidentialFrozen( | ||
| address account, | ||
| externalEuint64 encryptedAmount, | ||
| bytes calldata inputProof | ||
| ) external; | ||
| /// @dev Sets confidential amount of token for an account as frozen. | ||
| function setConfidentialFrozen(address account, euint64 encryptedAmount) external; | ||
| /// @dev Mints confidential amount of tokens to account with proof. | ||
| function confidentialMint( | ||
| address to, | ||
| externalEuint64 encryptedAmount, | ||
| bytes calldata inputProof | ||
| ) external returns (euint64); | ||
| /// @dev Mints confidential amount of tokens to account. | ||
| function confidentialMint(address to, euint64 encryptedAmount) external returns (euint64); | ||
| /// @dev Burns confidential amount of tokens from account with proof. | ||
| function confidentialBurn( | ||
| address account, | ||
| externalEuint64 encryptedAmount, | ||
| bytes calldata inputProof | ||
| ) external returns (euint64); | ||
| /// @dev Burns confidential amount of tokens from account. | ||
| function confidentialBurn(address account, euint64 encryptedAmount) external returns (euint64); | ||
| /// @dev Forces transfer of confidential amount of tokens from account to account with proof by skipping compliance checks. | ||
| function forceConfidentialTransferFrom( | ||
| address from, | ||
| address to, | ||
| externalEuint64 encryptedAmount, | ||
| bytes calldata inputProof | ||
| ) external returns (euint64); | ||
| /// @dev Forces transfer of confidential amount of tokens from account to account by skipping compliance checks. | ||
| function forceConfidentialTransferFrom( | ||
| address from, | ||
| address to, | ||
| euint64 encryptedAmount | ||
| ) external returns (euint64); | ||
| /// @dev Receives and executes a batch of function calls on this contract. | ||
| function multicall(bytes[] calldata data) external returns (bytes[] memory results); | ||
| } | ||
|
|
||
| /// @dev Full interface for confidential RWA contracts. | ||
| interface IERC7984Rwa is IERC7984, IERC7984RwaBase, IERC165, IAccessControl {} | ||
|
|
||
| /// @dev Interface for confidential RWA compliance. | ||
| interface IERC7984RwaCompliance { | ||
| enum ComplianceModuleType { | ||
| ALWAYS_ON, | ||
| TRANSFER_ONLY | ||
| } | ||
|
|
||
| /// @dev Installs a transfer compliance module. | ||
| function installModule(ComplianceModuleType moduleType, address module) external; | ||
| /// @dev Uninstalls a transfer compliance module. | ||
| function uninstallModule(ComplianceModuleType moduleType, address module) external; | ||
| /// @dev Checks if a compliance module is installed. | ||
| function isModuleInstalled(ComplianceModuleType moduleType, address module) external view returns (bool); | ||
| } | ||
|
|
||
| /// @dev Interface for confidential RWA transfer compliance module. | ||
| interface IERC7984RwaTransferComplianceModule { | ||
| /// @dev Returns magic number if it is a module. | ||
| function isModule() external returns (bytes4); | ||
| /// @dev Checks if a transfer is compliant. Should be non-mutating. | ||
| function isCompliantTransfer(address from, address to, euint64 encryptedAmount) external returns (ebool); | ||
| /// @dev Performs operation after transfer. | ||
| function postTransfer(address from, address to, euint64 encryptedAmount) external; | ||
| } |
This file contains hidden or 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,10 @@ | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| pragma solidity ^0.8.24; | ||
|
|
||
| import {SepoliaConfig} from "@fhevm/solidity/config/ZamaConfig.sol"; | ||
| import {ERC7984RwaBalanceCapModule} from "../../token/ERC7984/extensions/rwa/ERC7984RwaBalanceCapModule.sol"; | ||
|
|
||
| contract ERC7984RwaBalanceCapModuleMock is ERC7984RwaBalanceCapModule, SepoliaConfig { | ||
| constructor(address compliance) ERC7984RwaBalanceCapModule(compliance) {} | ||
| } |
This file contains hidden or 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,10 @@ | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| pragma solidity ^0.8.24; | ||
|
|
||
| import {SepoliaConfig} from "@fhevm/solidity/config/ZamaConfig.sol"; | ||
| import {ERC7984RwaInvestorCapModule} from "../../token/ERC7984/extensions/rwa/ERC7984RwaInvestorCapModule.sol"; | ||
|
|
||
| contract ERC7984RwaInvestorCapModuleMock is ERC7984RwaInvestorCapModule, SepoliaConfig { | ||
| constructor(address compliance, uint256 maxInvestor) ERC7984RwaInvestorCapModule(compliance, maxInvestor) {} | ||
| } |
This file contains hidden or 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,76 @@ | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| pragma solidity ^0.8.24; | ||
|
|
||
| import {SepoliaConfig} from "@fhevm/solidity/config/ZamaConfig.sol"; | ||
| import {FHE, ebool, euint64, externalEuint64} from "@fhevm/solidity/lib/FHE.sol"; | ||
| import {Impl} from "@fhevm/solidity/lib/Impl.sol"; | ||
| import {ERC7984Rwa} from "../../token/ERC7984/extensions/ERC7984Rwa.sol"; | ||
| import {FHESafeMath} from "../../utils/FHESafeMath.sol"; | ||
| import {HandleAccessManager} from "../../utils/HandleAccessManager.sol"; | ||
|
|
||
| // solhint-disable func-name-mixedcase | ||
| contract ERC7984RwaMock is ERC7984Rwa, HandleAccessManager, SepoliaConfig { | ||
| mapping(address account => euint64 encryptedAmount) private _frozenBalances; | ||
| bool public compliantTransfer = false; | ||
| bool public compliantForceTransfer = false; | ||
|
|
||
| // TODO: Move modifiers to `ERC7984Rwa` or remove from mock if useless | ||
| /// @dev Checks if the sender is an admin. | ||
| modifier onlyAdmin() { | ||
| require(isAdmin(_msgSender()), UnauthorizedSender(_msgSender())); | ||
| _; | ||
| } | ||
| /// @dev Checks if the sender is an agent. | ||
| modifier onlyAgent() { | ||
| require(isAgent(_msgSender()), UnauthorizedSender(_msgSender())); | ||
| _; | ||
| } | ||
|
|
||
| constructor(string memory name, string memory symbol, string memory tokenUri) ERC7984Rwa(name, symbol, tokenUri) {} | ||
|
|
||
| function createEncryptedAmount(uint64 amount) public returns (euint64 encryptedAmount) { | ||
| FHE.allowThis(encryptedAmount = FHE.asEuint64(amount)); | ||
| FHE.allow(encryptedAmount, msg.sender); | ||
| } | ||
|
|
||
| function $_setCompliantTransfer() public { | ||
| compliantTransfer = true; | ||
| } | ||
|
|
||
| function $_unsetCompliantTransfer() public { | ||
| compliantTransfer = false; | ||
| } | ||
|
|
||
| function $_setCompliantForceTransfer() public { | ||
| compliantForceTransfer = true; | ||
| } | ||
|
|
||
| function $_unsetCompliantForceTransfer() public { | ||
| compliantForceTransfer = false; | ||
| } | ||
|
|
||
| function $_mint(address to, uint64 amount) public returns (euint64 transferred) { | ||
| return _mint(to, FHE.asEuint64(amount)); | ||
| } | ||
|
|
||
| function _preCheckTransfer( | ||
| address /*from*/, | ||
| address /*to*/, | ||
| euint64 /*encryptedAmount*/ | ||
| ) internal override returns (ebool compliant) { | ||
| compliant = FHE.asEbool(compliantTransfer); | ||
| FHE.allowThis(compliant); | ||
| } | ||
|
|
||
| function _preCheckForceTransfer( | ||
| address /*from*/, | ||
| address /*to*/, | ||
| euint64 /*encryptedAmount*/ | ||
| ) internal override returns (ebool compliant) { | ||
| compliant = FHE.asEbool(compliantForceTransfer); | ||
| FHE.allowThis(compliant); | ||
| } | ||
|
|
||
| function _validateHandleAllowance(bytes32 handle) internal view override onlyAdminOrAgent {} | ||
| } |
This file contains hidden or 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,15 @@ | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| pragma solidity ^0.8.24; | ||
|
|
||
| import {SepoliaConfig} from "@fhevm/solidity/config/ZamaConfig.sol"; | ||
| import {FHE, ebool, euint64, externalEuint64} from "@fhevm/solidity/lib/FHE.sol"; | ||
| import {Impl} from "@fhevm/solidity/lib/Impl.sol"; | ||
| import {ERC7984Rwa} from "../../token/ERC7984/extensions/ERC7984Rwa.sol"; | ||
| import {ERC7984RwaCompliance} from "../../token/ERC7984/extensions/rwa/ERC7984RwaCompliance.sol"; | ||
| import {FHESafeMath} from "../../utils/FHESafeMath.sol"; | ||
| import {HandleAccessManager} from "../../utils/HandleAccessManager.sol"; | ||
|
|
||
| contract ERC7984RwaModularComplianceMock is ERC7984RwaCompliance, SepoliaConfig { | ||
| constructor(string memory name, string memory symbol, string memory tokenUri) ERC7984Rwa(name, symbol, tokenUri) {} | ||
| } |
This file contains hidden or 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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.