Skip to content

Commit 533cbee

Browse files
committed
style: order functions per Solidity style guide and add NatSpec across src/ mocks (behaviour-preserving)
1 parent f531660 commit 533cbee

6 files changed

Lines changed: 144 additions & 55 deletions

File tree

src/mocks/AggregatorV3Mock.sol

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,29 @@ import {AggregatorV3Interface} from "../rules/interfaces/AggregatorV3Interface.s
99
* `decimals()` or `latestRoundData()` so the failure paths of the Proof of Reserve rule can be exercised.
1010
*/
1111
contract AggregatorV3Mock is AggregatorV3Interface {
12+
/**
13+
* @notice Decimals reported by the feed.
14+
*/
1215
uint8 private _decimals;
16+
/**
17+
* @notice The reserve answer returned by `latestRoundData`.
18+
*/
1319
int256 private _answer;
20+
/**
21+
* @notice Round identifier, bumped on every {setAnswer}.
22+
*/
1423
uint80 private _roundId;
24+
/**
25+
* @notice Timestamp reported as `updatedAt`; 0 simulates an incomplete round.
26+
*/
1527
uint256 private _updatedAt;
28+
/**
29+
* @notice When true, `decimals()` reverts.
30+
*/
1631
bool private _revertOnDecimals;
32+
/**
33+
* @notice When true, `latestRoundData()` reverts.
34+
*/
1735
bool private _revertOnLatestRoundData;
1836

1937
/**

src/mocks/ERC3643TokenMock.sol

Lines changed: 100 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,47 @@ import {IERC734KeyHasPurpose, IIdentityRegistryERC3643} from "../registry/interf
99
* compute an ERC-165 interface ID and is explicitly not meant to be used as a type.
1010
*/
1111
interface IERC3643ComplianceForToken {
12+
/**
13+
* @notice Binds a token to this compliance contract.
14+
* @param token The token being bound.
15+
*/
1216
function bindToken(address token) external;
17+
18+
/**
19+
* @notice Unbinds a previously bound token.
20+
* @param token The token being unbound.
21+
*/
1322
function unbindToken(address token) external;
23+
24+
/**
25+
* @notice Notifies the compliance contract that a transfer has occurred.
26+
* @param from The sender.
27+
* @param to The recipient.
28+
* @param value The amount moved.
29+
*/
1430
function transferred(address from, address to, uint256 value) external;
31+
32+
/**
33+
* @notice Notifies the compliance contract that tokens have been minted.
34+
* @param to The recipient.
35+
* @param value The amount minted.
36+
*/
1537
function created(address to, uint256 value) external;
38+
39+
/**
40+
* @notice Notifies the compliance contract that tokens have been burned.
41+
* @param from The holder burned from.
42+
* @param value The amount burned.
43+
*/
1644
function destroyed(address from, uint256 value) external;
45+
46+
/**
47+
* @notice Returns whether a transfer is allowed.
48+
* @param from The sender, or the zero address for a mint.
49+
* @param to The recipient.
50+
* @param value The amount to move.
51+
* @return True when the transfer is allowed.
52+
*/
1753
function canTransfer(address from, address to, uint256 value) external view returns (bool);
1854
}
1955

@@ -42,6 +78,9 @@ interface IERC3643ComplianceForToken {
4278
* the cross-check circular.
4379
*/
4480
contract ERC3643TokenMock {
81+
/**
82+
* @notice The identity registry this token consults on every inbound transfer.
83+
*/
4584
IIdentityRegistryERC3643 public identityRegistry;
4685
/**
4786
* @notice The compliance contract, i.e. a `RuleEngine`.
@@ -51,11 +90,32 @@ contract ERC3643TokenMock {
5190
*/
5291
IERC3643ComplianceForToken public compliance;
5392

93+
/**
94+
* @notice Token balance per account.
95+
*/
5496
mapping(address account => uint256 balance) public balanceOf;
97+
/**
98+
* @notice Whether an account holds the ERC-3643 agent role.
99+
*/
55100
mapping(address account => bool isAgent) public isAgent;
101+
/**
102+
* @notice Total token supply.
103+
*/
56104
uint256 public totalSupply;
57105

106+
/**
107+
* @notice Emitted on every balance movement, including mint and burn.
108+
* @param from The sender, or the zero address for a mint.
109+
* @param to The recipient, or the zero address for a burn.
110+
* @param value The amount moved.
111+
*/
58112
event Transfer(address indexed from, address indexed to, uint256 value);
113+
/**
114+
* @notice Emitted when a position is recovered onto a replacement wallet.
115+
* @param lostWallet The wallet recovered from.
116+
* @param newWallet The replacement wallet.
117+
* @param investorOnchainId The identity contract that vouched for the replacement wallet.
118+
*/
59119
event RecoverySuccess(address indexed lostWallet, address indexed newWallet, address indexed investorOnchainId);
60120

61121
error ERC3643TokenMock_OnlyAgent();
@@ -147,27 +207,6 @@ contract ERC3643TokenMock {
147207
revert("Transfer not possible");
148208
}
149209

150-
/**
151-
* @notice Agent-forced transfer; the recipient must still be verified.
152-
* @dev `Token.forcedTransfer`: bypasses freezes but NOT the registry check on `_to`.
153-
* @param _from Sender.
154-
* @param _to Recipient.
155-
* @param _amount Amount to transfer.
156-
* @return True on success.
157-
*/
158-
function forcedTransfer(address _from, address _to, uint256 _amount) public onlyAgent returns (bool) {
159-
require(balanceOf[_from] >= _amount, "sender balance too low");
160-
// NOTE: `Token.forcedTransfer` does NOT consult `canTransfer` -- it only notifies
161-
// `transferred` afterwards. A compliance contract that reverts in `transferred` (as a
162-
// RuleEngine does) still blocks the move; one that only answers `canTransfer` does not.
163-
if (identityRegistry.isVerified(_to)) {
164-
_transfer(_from, _to, _amount);
165-
_complianceTransferred(_from, _to, _amount);
166-
return true;
167-
}
168-
revert("Transfer not possible");
169-
}
170-
171210
/**
172211
* @notice Mints tokens; the recipient must be verified.
173212
* @dev `Token.mint`: `require(isVerified(_to), "Identity is not verified.")`.
@@ -205,56 +244,62 @@ contract ERC3643TokenMock {
205244
* @notice Moves an investor's position to a replacement wallet.
206245
* @dev Transcribed from `Token.recoveryAddress`, preserving the order that matters:
207246
* 1. `keyHasPurpose(keccak256(abi.encode(_newWallet)), 1)` on the **caller-supplied**
208-
* `_investorOnchainID` -- reverts "Recovery not possible" when false;
247+
* `_investorOnchainId` -- reverts "Recovery not possible" when false;
209248
* 2. `investorCountry(_lostWallet)` read from the registry;
210-
* 3. `registerIdentity(_newWallet, _investorOnchainID, country)` -- called BY THE TOKEN;
249+
* 3. `registerIdentity(_newWallet, _investorOnchainId, country)` -- called BY THE TOKEN;
211250
* 4. `forcedTransfer(_lostWallet, _newWallet, balance)`;
212251
* 5. `deleteIdentity(_lostWallet)` -- also called BY THE TOKEN.
213252
* @param _lostWallet The wallet to recover from.
214253
* @param _newWallet The replacement wallet.
215-
* @param _investorOnchainID The contract answering `keyHasPurpose`.
254+
* @param _investorOnchainId The contract answering `keyHasPurpose`.
216255
* @return True on success.
217256
*/
218-
// forge-lint: disable-next-line(mixed-case-variable)
219-
function recoveryAddress(address _lostWallet, address _newWallet, address _investorOnchainID)
257+
function recoveryAddress(address _lostWallet, address _newWallet, address _investorOnchainId)
220258
external
221259
onlyAgent
222260
returns (bool)
223261
{
224262
require(balanceOf[_lostWallet] != 0, "no tokens to recover");
225263
// forge-lint: disable-next-line(asm-keccak256)
226264
bytes32 _key = keccak256(abi.encode(_newWallet));
227-
if (IERC734KeyHasPurpose(_investorOnchainID).keyHasPurpose(_key, 1)) {
265+
if (IERC734KeyHasPurpose(_investorOnchainId).keyHasPurpose(_key, 1)) {
228266
uint256 investorTokens = balanceOf[_lostWallet];
229267
identityRegistry.registerIdentity(
230-
_newWallet, _investorOnchainID, identityRegistry.investorCountry(_lostWallet)
268+
_newWallet, _investorOnchainId, identityRegistry.investorCountry(_lostWallet)
231269
);
232270
forcedTransfer(_lostWallet, _newWallet, investorTokens);
233271
identityRegistry.deleteIdentity(_lostWallet);
234-
emit RecoverySuccess(_lostWallet, _newWallet, _investorOnchainID);
272+
emit RecoverySuccess(_lostWallet, _newWallet, _investorOnchainId);
235273
return true;
236274
}
237275
revert("Recovery not possible");
238276
}
239277

240-
/*//////////////////////////////////////////////////////////////
241-
INTERNAL FUNCTIONS
242-
//////////////////////////////////////////////////////////////*/
243-
244278
/**
245-
* @notice Asks the compliance contract whether a move is allowed; true when none is set.
246-
* @param from Sender, or the zero address for a mint.
247-
* @param to Recipient.
248-
* @param amount Amount to move.
249-
* @return True when the move is allowed.
279+
* @notice Agent-forced transfer; the recipient must still be verified.
280+
* @dev `Token.forcedTransfer`: bypasses freezes but NOT the registry check on `_to`.
281+
* @param _from Sender.
282+
* @param _to Recipient.
283+
* @param _amount Amount to transfer.
284+
* @return True on success.
250285
*/
251-
function _canTransfer(address from, address to, uint256 amount) internal view returns (bool) {
252-
if (address(compliance) == address(0)) {
286+
function forcedTransfer(address _from, address _to, uint256 _amount) public onlyAgent returns (bool) {
287+
require(balanceOf[_from] >= _amount, "sender balance too low");
288+
// NOTE: `Token.forcedTransfer` does NOT consult `canTransfer` -- it only notifies
289+
// `transferred` afterwards. A compliance contract that reverts in `transferred` (as a
290+
// RuleEngine does) still blocks the move; one that only answers `canTransfer` does not.
291+
if (identityRegistry.isVerified(_to)) {
292+
_transfer(_from, _to, _amount);
293+
_complianceTransferred(_from, _to, _amount);
253294
return true;
254295
}
255-
return compliance.canTransfer(from, to, amount);
296+
revert("Transfer not possible");
256297
}
257298

299+
/*//////////////////////////////////////////////////////////////
300+
INTERNAL FUNCTIONS
301+
//////////////////////////////////////////////////////////////*/
302+
258303
/**
259304
* @notice Notifies the compliance contract that a transfer happened; no-op when none is set.
260305
* @param from Sender.
@@ -278,4 +323,18 @@ contract ERC3643TokenMock {
278323
balanceOf[to] += amount;
279324
emit Transfer(from, to, amount);
280325
}
326+
327+
/**
328+
* @notice Asks the compliance contract whether a move is allowed; true when none is set.
329+
* @param from Sender, or the zero address for a mint.
330+
* @param to Recipient.
331+
* @param amount Amount to move.
332+
* @return True when the move is allowed.
333+
*/
334+
function _canTransfer(address from, address to, uint256 amount) internal view returns (bool) {
335+
if (address(compliance) == address(0)) {
336+
return true;
337+
}
338+
return compliance.canTransfer(from, to, amount);
339+
}
281340
}

src/mocks/OnchainIdMock.sol

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ import {IERC734KeyHasPurpose} from "../registry/interfaces/IIdentityRegistryERC3
1515
* WARNING: test scaffolding only. Holds no real keys and performs no authorisation.
1616
*/
1717
contract OnchainIdMock is IERC734KeyHasPurpose {
18+
/**
19+
* @notice Keys this identity vouches for, per ERC-734 purpose.
20+
*/
1821
mapping(bytes32 key => mapping(uint256 purpose => bool held)) private _keys;
1922

2023
/**

src/mocks/TotalSupplyDecimalsMock.sol

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,17 @@ pragma solidity ^0.8.20;
77
* cross-check performed when configuring a rule can be exercised.
88
*/
99
contract TotalSupplyDecimalsMock {
10+
/**
11+
* @notice The stored total supply value.
12+
*/
1013
uint256 private _totalSupply;
14+
/**
15+
* @notice Decimals reported by the token; fixed at construction.
16+
*/
1117
uint8 private immutable _DECIMALS;
18+
/**
19+
* @notice When true, `totalSupply()` reverts.
20+
*/
1221
bool private _revertOnTotalSupply;
1322

1423
/**

src/registry/interfaces/IIdentityRegistryERC3643.sol

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,6 @@ pragma solidity ^0.8.20;
1414
* has exactly the same selector as ERC-3643's, without dragging in the ONCHAINID dependency.
1515
*/
1616
interface IIdentityRegistryERC3643 {
17-
/**
18-
* @notice Returns whether a wallet is a verified investor.
19-
* @dev Called by `transfer`, `transferFrom`, `forcedTransfer` and `mint`.
20-
* @param _userAddress The wallet to check.
21-
* @return True if the wallet is verified.
22-
*/
23-
function isVerified(address _userAddress) external view returns (bool);
24-
2517
/**
2618
* @notice Registers a wallet as a verified investor.
2719
* @dev Called by the token itself inside `recoveryAddress`, and by a registrar off-chain.
@@ -38,6 +30,14 @@ interface IIdentityRegistryERC3643 {
3830
*/
3931
function deleteIdentity(address _userAddress) external;
4032

33+
/**
34+
* @notice Returns whether a wallet is a verified investor.
35+
* @dev Called by `transfer`, `transferFrom`, `forcedTransfer` and `mint`.
36+
* @param _userAddress The wallet to check.
37+
* @return True if the wallet is verified.
38+
*/
39+
function isVerified(address _userAddress) external view returns (bool);
40+
4141
/**
4242
* @notice Returns the country code recorded for a wallet.
4343
* @dev Called by `recoveryAddress` to carry the country over to the replacement wallet.

src/rules/validation/abstract/base/RuleChainlinkPoRBase.sol

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -197,12 +197,6 @@ abstract contract RuleChainlinkPoRBase is RuleTransferValidation, RuleChainlinkP
197197
_;
198198
}
199199

200-
/**
201-
* @notice Authorization hook invoked before any configuration change.
202-
* @dev Implemented by concrete subclasses with the desired access-control policy.
203-
*/
204-
function _authorizeChainlinkPoRManager() internal view virtual;
205-
206200
/*//////////////////////////////////////////////////////////////
207201
INTERNAL FUNCTIONS
208202
//////////////////////////////////////////////////////////////*/
@@ -273,6 +267,12 @@ abstract contract RuleChainlinkPoRBase is RuleTransferValidation, RuleChainlinkP
273267
emit MaxStalenessSecondsUpdated(newMaxStalenessSeconds);
274268
}
275269

270+
/**
271+
* @notice Authorization hook invoked before any configuration change.
272+
* @dev Implemented by concrete subclasses with the desired access-control policy.
273+
*/
274+
function _authorizeChainlinkPoRManager() internal view virtual;
275+
276276
/**
277277
* @notice Reads the feed and derives the supply currently backed by the reserves.
278278
* @dev Never reverts: the feed address is code-checked and the call is wrapped in `try/catch`.

0 commit comments

Comments
 (0)