Add authorized re-encryption of past transfers#66
Conversation
There was a problem hiding this comment.
Pull request overview
This PR implements “authorized re-encryption” for historical transfers, enabling selective disclosure of encrypted transfer data to permitted viewers (Issue #63), plus an automatic recipient-readable encrypted value event when the recipient has a registered public key.
Changes:
- Added on-chain historic transfer disclosure primitives:
EncryptedTransferemission, viewer authorization (time range / transferId), andrequestDecryptHistoricTransfer→ReEncryptedTransfer. - Added automatic per-transfer
TransferValueEncryptedForRecipientemission (ECIES to recipient key when registered). - Expanded test coverage and updated README + generated interface/contract docs for the new disclosure flows.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
contracts/ConfidentialToken.sol |
Core implementation for emitting encrypted transfer metadata and handling authorized historic re-encryption requests. |
contracts/interfaces/IConfidentialToken.sol |
Adds structs/events/errors and new public API for historic view authorization + decrypt requests. |
test/ConfidentialToken.ts |
Extensive tests for authorization, edge cases, fee charging, replay, and recipient auto-encryption. |
README.md |
Documents the historic transfer decryption feature and the recipient auto-encrypted value event. |
docs/interfaces/IConfidentialToken.md |
Generated interface docs updated to include new structs/events/functions. |
docs/ConfidentialToken.md |
Generated contract docs updated for new internal/external functions and updated signatures. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #66 +/- ##
===========================================
+ Coverage 96.66% 97.38% +0.71%
===========================================
Files 6 7 +1
Lines 270 382 +112
Branches 64 94 +30
===========================================
+ Hits 261 372 +111
- Misses 9 10 +1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
39201de to
3c26898
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 23 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 23 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
b66b604 to
da20709
Compare
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 23 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
5ffa472 to
1df43a8
Compare
1df43a8 to
8243fe1
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 23 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
8243fe1 to
571adc1
Compare
571adc1 to
2050616
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 23 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 23 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 23 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 23 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| (address from, address to) = _historicViewAuth.decodeIfAuthorized( | ||
| sender, | ||
| decryptedArguments[0] | ||
| ); |
There was a problem hiding this comment.
_handleHistoricViewRequest indexes decryptedArguments[0] without first validating that the callback provided at least one decrypted argument. If decryptedArguments is empty (or shorter than expected), this will revert with a panic (out-of-bounds) rather than a controlled custom error. Add an explicit length check (e.g., require decryptedArguments.length == 1) and revert with a project error like DecryptionBadFormat/WrongPlaintextFormat for predictable behavior.
| address sender = address(bytes20(plaintextArguments[1])); | ||
| require(_knownPublicKey(sender), PublicKeyIsNotRegistered(sender)); | ||
|
|
||
| (address from, address to) = _historicViewAuth.decodeIfAuthorized( | ||
| sender, | ||
| decryptedArguments[0] | ||
| ); | ||
| emit ReEncryptedTransfer( | ||
| sender, | ||
| from, | ||
| to, | ||
| BITE.encryptECIES( | ||
| encryptECIESAddress, | ||
| decryptedArguments[0], | ||
| publicKeys[sender] |
There was a problem hiding this comment.
In _handleHistoricViewRequest, the local variable sender is actually the historic-view viewer address extracted from plaintextArguments[1]. Renaming it to viewer/historicViewer would make the authorization and ReEncryptedTransfer emission logic much easier to follow and reduce confusion with msg.sender / transfer sender.
| address sender = address(bytes20(plaintextArguments[1])); | |
| require(_knownPublicKey(sender), PublicKeyIsNotRegistered(sender)); | |
| (address from, address to) = _historicViewAuth.decodeIfAuthorized( | |
| sender, | |
| decryptedArguments[0] | |
| ); | |
| emit ReEncryptedTransfer( | |
| sender, | |
| from, | |
| to, | |
| BITE.encryptECIES( | |
| encryptECIESAddress, | |
| decryptedArguments[0], | |
| publicKeys[sender] | |
| address historicViewer = address(bytes20(plaintextArguments[1])); | |
| require(_knownPublicKey(historicViewer), PublicKeyIsNotRegistered(historicViewer)); | |
| (address from, address to) = _historicViewAuth.decodeIfAuthorized( | |
| historicViewer, | |
| decryptedArguments[0] | |
| ); | |
| emit ReEncryptedTransfer( | |
| historicViewer, | |
| from, | |
| to, | |
| BITE.encryptECIES( | |
| encryptECIESAddress, | |
| decryptedArguments[0], | |
| publicKeys[historicViewer] |
| const deploy = async () => { | ||
| console.log(chalk.yellow("Deploying AccessManager...")); | ||
| const accessManagerFactory = await ethers.getContractFactory("AccessManager"); | ||
| accessManager = await accessManagerFactory.deploy(deployer); |
There was a problem hiding this comment.
accessManagerFactory.deploy(deployer) passes a SignerWithAddress object where the OpenZeppelin AccessManager constructor expects an address (initial admin). This is likely to throw at runtime with an “invalid address” error on ethers v6. Pass deployer.address (or await deployer.getAddress()) instead.
| accessManager = await accessManagerFactory.deploy(deployer); | |
| accessManager = await accessManagerFactory.deploy(deployer.address); |
| /// @notice Emitted when a holder revokes a viewer's access to transfers within a time range. | ||
| /// @param holder Address of the holder revoking access. | ||
| /// @param viewer Address of the viewer losing access. | ||
| event HistoricViewTimeRangeRevoked(address indexed holder,address indexed viewer); |
There was a problem hiding this comment.
Minor formatting: HistoricViewTimeRangeRevoked is declared as event HistoricViewTimeRangeRevoked(address indexed holder,address indexed viewer); (missing a space after the comma). Align spacing with the rest of the interface for readability.
| event HistoricViewTimeRangeRevoked(address indexed holder,address indexed viewer); | |
| event HistoricViewTimeRangeRevoked(address indexed holder, address indexed viewer); |
Fixes #63