From ef60667e8f2a9fc200e9b7f8045a6139cc20ff7f Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Wed, 20 Aug 2025 11:00:44 -0600 Subject: [PATCH 01/33] feat: added additional node role for technical referendum council --- contracts/access/AccessManager.sol | 13 ++- contracts/core/primitives/Constants.sol | 3 +- contracts/governance/Governance.sol | 137 ------------------------ contracts/governance/TimeLockCtl.sol | 14 --- 4 files changed, 11 insertions(+), 156 deletions(-) delete mode 100644 contracts/governance/Governance.sol delete mode 100644 contracts/governance/TimeLockCtl.sol diff --git a/contracts/access/AccessManager.sol b/contracts/access/AccessManager.sol index fd4b4b4..f3cf75f 100644 --- a/contracts/access/AccessManager.sol +++ b/contracts/access/AccessManager.sol @@ -42,8 +42,10 @@ contract AccessManager is Initializable, UUPSUpgradeable, AccessManagerUpgradeab // Handles protocol upgrades, pause mechanisms, and operational role assignments. // - MOD_ROLE: Managed by a smart account or council. // Approves policy submissions and moderates hook operations. - // - REF_ROLE: Managed by a smart account or council. - // Participates in governance referenda for content curation and distributor selection. + // - VAL_ROLE: Managed by a smart account or council. + // Participates in governance referenda for content curation/validation. + // - NOD_ROLE: Managed by a smart account or council. + // Participates in governance referenda for nodes validation. // // Individual/Contract Based Roles: // - OPS_ROLE: Internal operational role assigned to protocol-trusted contracts @@ -60,13 +62,16 @@ contract AccessManager is Initializable, UUPSUpgradeable, AccessManagerUpgradeab │ │ │ └── OPS_ROLE (Internal Contract Role) │ - ├── REF_ROLE (Smart Account / Council) + ├── VAL_ROLE (Smart Account / Council) + │ + ├── NOD_ROLE (Smart Account / Council) │ ├── VER_ROLE (Individual Trusted Creator) */ _setRoleAdmin(C.VER_ROLE, C.GOV_ROLE); - _setRoleAdmin(C.REF_ROLE, C.GOV_ROLE); + _setRoleAdmin(C.VAL_ROLE, C.GOV_ROLE); + _setRoleAdmin(C.NOD_ROLE, C.GOV_ROLE); _setRoleAdmin(C.MOD_ROLE, C.ADMIN_ROLE); _setRoleAdmin(C.OPS_ROLE, C.ADMIN_ROLE); } diff --git a/contracts/core/primitives/Constants.sol b/contracts/core/primitives/Constants.sol index 5294ebe..6172471 100644 --- a/contracts/core/primitives/Constants.sol +++ b/contracts/core/primitives/Constants.sol @@ -16,7 +16,8 @@ library C { uint64 internal constant MOD_ROLE = 2; // moderator role uint64 internal constant VER_ROLE = 3; // account verified role uint64 internal constant OPS_ROLE = 4; // operations roles - uint64 internal constant REF_ROLE = 5; // referendum roles + uint64 internal constant VAL_ROLE = 5; // content validation/curation roles + uint64 internal constant NOD_ROLE = 6; // nodes validations roles bytes32 internal constant REFERENDUM_SUBMIT_TYPEHASH = keccak256("Submission(uint256 assetId, address initiator, uint256 nonce)"); diff --git a/contracts/governance/Governance.sol b/contracts/governance/Governance.sol deleted file mode 100644 index f1d14d4..0000000 --- a/contracts/governance/Governance.sol +++ /dev/null @@ -1,137 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -// NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html -pragma solidity 0.8.26; - -import { Governor } from "@openzeppelin/contracts/governance/Governor.sol"; -import { ERC20Votes } from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol"; -import { TimelockController } from "@openzeppelin/contracts/governance/TimelockController.sol"; -import { GovernorVotes } from "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol"; -import { GovernorSettings } from "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol"; -import { GovernorCountingSimple } from "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol"; -import { GovernorTimelockControl } from "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol"; -// solhint-disable-next-line max-line-length -import { GovernorVotesQuorumFraction } from "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol"; - -/** - * @title Governance - * @notice This contract implements a governance mechanism based on OpenZeppelin's Governor contract. - * It uses an ERC20Votes token for voting, a TimelockController for queuing and executing proposals, and - * several governance extensions for enhanced functionality. - */ -contract Governance is - Governor, - GovernorVotes, - GovernorCountingSimple, - GovernorVotesQuorumFraction, - GovernorSettings, - GovernorTimelockControl -{ - /** - * @notice Initializes the governance contract with the specified parameters. - * @param _mmc The ERC20Votes token contract to be used for voting. - * @param _timelock The TimelockController contract to be used for queuing and executing proposals. - * - * The constructor sets up the governance contract with: - * - Governor("MMCGovernance"): The name of the governance contract. - * - GovernorVotes(_mmc): The ERC20 token with voting capabilities. - * - GovernorVotesQuorumFraction(4): The quorum required is 4% of the total token supply. - * - GovernorSettings(1, 45818, 0): Configures the governance settings: - * - Voting Delay: 1 block (the time that must pass between the creation of a proposal and the start of voting). - * - Voting Period: 45818 blocks (approximately 1 week, the period during which voting is open). - * - Proposal Threshold: 0 tokens (the minimum number of tokens required to propose a new proposal). - */ - constructor( - ERC20Votes _mmc, - TimelockController _timelock - ) - Governor("MMCGovernance") - GovernorVotes(_mmc) - GovernorVotesQuorumFraction(4) - GovernorSettings(1 /* 1 block */, 45818 /* 1 week */, 0) - GovernorTimelockControl(_timelock) - {} - - /// @notice Returns the state of a proposal. - /// @param proposalId The ID of the proposal. - function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) { - return super.state(proposalId); - } - - /// @notice Checks if a proposal needs to be queued. - /// @param proposalId The ID of the proposal. - function proposalNeedsQueuing( - uint256 proposalId - ) public view virtual override(Governor, GovernorTimelockControl) returns (bool) { - return super.proposalNeedsQueuing(proposalId); - } - - /** - * @notice Queues a proposal's operations. - * @param proposalId The ID of the proposal. - * @param targets The addresses of the contracts to call. - * @param values The values (in wei) to send with the calls. - * @param calldatas The calldata to send with the calls. - * @param descriptionHash The hash of the proposal's description. - * @return The timestamp at which the operations are queued. - */ - function _queueOperations( - uint256 proposalId, - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - bytes32 descriptionHash - ) internal override(Governor, GovernorTimelockControl) returns (uint48) { - return super._queueOperations(proposalId, targets, values, calldatas, descriptionHash); - } - - /** - * @notice Executes a proposal's operations. - * @param proposalId The ID of the proposal. - * @param targets The addresses of the contracts to call. - * @param values The values (in wei) to send with the calls. - * @param calldatas The calldata to send with the calls. - * @param descriptionHash The hash of the proposal's description. - */ - function _executeOperations( - uint256 proposalId, - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - bytes32 descriptionHash - ) internal override(Governor, GovernorTimelockControl) { - super._executeOperations(proposalId, targets, values, calldatas, descriptionHash); - } - - /** - * @notice Cancels a proposal. - * @param targets The addresses of the contracts to call. - * @param values The values (in wei) to send with the calls. - * @param calldatas The calldata to send with the calls. - * @param descriptionHash The hash of the proposal's description. - * @return The ID of the canceled proposal. - */ - function _cancel( - address[] memory targets, - uint256[] memory values, - bytes[] memory calldatas, - bytes32 descriptionHash - ) internal override(Governor, GovernorTimelockControl) returns (uint256) { - return super._cancel(targets, values, calldatas, descriptionHash); - } - - /** - * @notice Returns the address of the executor. - * @return The address of the executor. - */ - function _executor() internal view override(Governor, GovernorTimelockControl) returns (address) { - return super._executor(); - } - - /** - * @notice Returns the proposal threshold. - * @return The minimum number of tokens required to propose a new proposal. - */ - function proposalThreshold() public view virtual override(Governor, GovernorSettings) returns (uint256) { - return super.proposalThreshold(); - } -} diff --git a/contracts/governance/TimeLockCtl.sol b/contracts/governance/TimeLockCtl.sol deleted file mode 100644 index 94b3d3f..0000000 --- a/contracts/governance/TimeLockCtl.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -// NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html -pragma solidity 0.8.26; - -import { TimelockController } from "@openzeppelin/contracts/governance/TimelockController.sol"; - -contract Timelock is TimelockController { - constructor( - uint256 minDelay, - address[] memory proposers, - address[] memory executors, - address admin - ) TimelockController(minDelay, proposers, executors, admin) {} -} From 9218fcc2a5e884ffcefa64d5d763a9f57b5aef52 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Wed, 20 Aug 2025 16:46:53 -0600 Subject: [PATCH 02/33] test: fixed tests and added council logics --- contracts/access/AccessManager.sol | 17 +-- contracts/assets/AssetOwnership.sol | 2 +- .../custody/ICustodianExpirable.sol | 15 --- .../custody/ICustodianInspectable.sol | 5 - .../custody/ICustodianReferendum.sol | 2 - .../custody/ICustodianRegistrable.sol | 9 +- .../core/interfaces/policies/IPolicy.sol | 16 +-- contracts/core/primitives/Constants.sol | 5 +- contracts/custody/CustodianImpl.sol | 1 + contracts/custody/CustodianReferendum.sol | 110 ++------------- ...0_Deploy_Custody_CustodianReferendum.s.sol | 3 +- .../01_Orchestrate_ProtocolHydration.s.sol | 6 - ...Orchestrate_ProtocolCustodianNetwork.s.sol | 15 +-- .../Permissions_CustodianReferendum.sol | 1 - ..._Upgrade_Custody_CustodianReferendum.s.sol | 3 +- test/BaseTest.t.sol | 33 ++++- test/assets/AssetReferendum.t.sol | 46 ++++--- test/assets/AssetSafe.t.sol | 3 +- test/custody/CustodianImpl.t.sol | 65 +++++---- test/custody/CustodianReferendum.t.sol | 126 ++++-------------- test/rights/RightAssetCustodian.t.sol | 52 ++++---- test/shared/CustodianShared.t.sol | 52 ++------ 22 files changed, 203 insertions(+), 384 deletions(-) delete mode 100644 contracts/core/interfaces/custody/ICustodianExpirable.sol diff --git a/contracts/access/AccessManager.sol b/contracts/access/AccessManager.sol index f3cf75f..bce5066 100644 --- a/contracts/access/AccessManager.sol +++ b/contracts/access/AccessManager.sol @@ -42,9 +42,9 @@ contract AccessManager is Initializable, UUPSUpgradeable, AccessManagerUpgradeab // Handles protocol upgrades, pause mechanisms, and operational role assignments. // - MOD_ROLE: Managed by a smart account or council. // Approves policy submissions and moderates hook operations. - // - VAL_ROLE: Managed by a smart account or council. - // Participates in governance referenda for content curation/validation. - // - NOD_ROLE: Managed by a smart account or council. + // - CONTENT_COUNCIL_ROLE: Managed by a smart account or council. + // Participates in governance referenda for content curation. + // - NODE_VALIDATOR_ROLE: Managed by a smart account or council. // Participates in governance referenda for nodes validation. // // Individual/Contract Based Roles: @@ -62,18 +62,19 @@ contract AccessManager is Initializable, UUPSUpgradeable, AccessManagerUpgradeab │ │ │ └── OPS_ROLE (Internal Contract Role) │ - ├── VAL_ROLE (Smart Account / Council) + ├── CONTENT_COUNCIL_ROLE (Smart Account / Council) │ - ├── NOD_ROLE (Smart Account / Council) + ├── NODE_VALIDATOR_ROLE (Smart Account / Council) │ ├── VER_ROLE (Individual Trusted Creator) */ - _setRoleAdmin(C.VER_ROLE, C.GOV_ROLE); - _setRoleAdmin(C.VAL_ROLE, C.GOV_ROLE); - _setRoleAdmin(C.NOD_ROLE, C.GOV_ROLE); _setRoleAdmin(C.MOD_ROLE, C.ADMIN_ROLE); _setRoleAdmin(C.OPS_ROLE, C.ADMIN_ROLE); + + _setRoleAdmin(C.VER_ROLE, C.GOV_ROLE); + _setRoleAdmin(C.NODE_VALIDATOR_ROLE, C.GOV_ROLE); + _setRoleAdmin(C.CONTENT_COUNCIL_ROLE, C.GOV_ROLE); } // TODO pause protocol based on permission and roles diff --git a/contracts/assets/AssetOwnership.sol b/contracts/assets/AssetOwnership.sol index da5d8c3..4d327d4 100644 --- a/contracts/assets/AssetOwnership.sol +++ b/contracts/assets/AssetOwnership.sol @@ -143,7 +143,7 @@ contract AssetOwnership is /// @notice Transfers an asset to a new owner. /// @param to The address of the new owner. /// @param assetId The unique identifier of the asset being transferred. - function transfer(address to, uint256 assetId) external { + function transfer(address to, uint256 assetId) external onlyOwner(assetId) { _transfer(msg.sender, to, assetId); emit TransferredAsset(msg.sender, to, assetId); } diff --git a/contracts/core/interfaces/custody/ICustodianExpirable.sol b/contracts/core/interfaces/custody/ICustodianExpirable.sol deleted file mode 100644 index 365d7c5..0000000 --- a/contracts/core/interfaces/custody/ICustodianExpirable.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -// NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html -pragma solidity 0.8.26; - -/// @title ICustodianExpirable Interface -/// @notice This interface defines the methods for managing expiration periods -/// related to enrollments or registrations. -interface ICustodianExpirable { - /// @notice Retrieves the current expiration period for enrollments or registrations. - function getExpirationPeriod() external view returns (uint256); - - /// @notice Sets a new expiration period for an enrollment or registration. - /// @param period The new expiration period, in seconds. - function setExpirationPeriod(uint256 period) external; -} diff --git a/contracts/core/interfaces/custody/ICustodianInspectable.sol b/contracts/core/interfaces/custody/ICustodianInspectable.sol index f63da5a..eb4e7df 100644 --- a/contracts/core/interfaces/custody/ICustodianInspectable.sol +++ b/contracts/core/interfaces/custody/ICustodianInspectable.sol @@ -4,11 +4,6 @@ pragma solidity 0.8.26; /// @title ICustodianInspectable /// @dev Interface for retrieving custodian enrollment data. interface ICustodianInspectable { - /// @notice Retrieves the enrollment deadline for a custodian. - /// @param custodian The address of the custodian. - /// @return The enrollment deadline timestamp. - function getEnrollmentDeadline(address custodian) external view returns (uint256); - /// @notice Retrieves the total number of enrollments. /// @return The number of enrollments. function getEnrollmentCount() external view returns (uint256); diff --git a/contracts/core/interfaces/custody/ICustodianReferendum.sol b/contracts/core/interfaces/custody/ICustodianReferendum.sol index 75cb022..6e7c8b3 100644 --- a/contracts/core/interfaces/custody/ICustodianReferendum.sol +++ b/contracts/core/interfaces/custody/ICustodianReferendum.sol @@ -2,7 +2,6 @@ // NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html pragma solidity 0.8.26; -import { ICustodianExpirable } from "@synaps3/core/interfaces/custody/ICustodianExpirable.sol"; import { ICustodianRegistrable } from "@synaps3/core/interfaces/custody/ICustodianRegistrable.sol"; import { ICustodianInspectable } from "@synaps3/core/interfaces/custody/ICustodianInspectable.sol"; import { ICustodianVerifiable } from "@synaps3/core/interfaces/custody/ICustodianVerifiable.sol"; @@ -13,7 +12,6 @@ import { ICustodianRevokable } from "@synaps3/core/interfaces/custody/ICustodian interface ICustodianReferendum is ICustodianRegistrable, ICustodianVerifiable, - ICustodianExpirable, ICustodianInspectable, ICustodianRevokable {} diff --git a/contracts/core/interfaces/custody/ICustodianRegistrable.sol b/contracts/core/interfaces/custody/ICustodianRegistrable.sol index ca7919a..3794b3f 100644 --- a/contracts/core/interfaces/custody/ICustodianRegistrable.sol +++ b/contracts/core/interfaces/custody/ICustodianRegistrable.sol @@ -7,12 +7,11 @@ pragma solidity 0.8.26; /// @dev This interface indirectly implements the FSM defined in `IQuorum` using `QuorumUpgradeable`. /// Functions here are semantically equivalent to the FSM transitions: register → approve. interface ICustodianRegistrable { - /// @notice Registers data with a given identifier. - /// @param proof The unique identifier of the agreement to be enforced. - /// @param currency The currency used to pay enrollment. - function register(uint256 proof, address currency) external; + /// @notice Registers a custodian to be approved by council. + /// @param custodian The address of the custodian to register. + function register(address custodian) external; - /// @notice Approves the data associated with the given identifier. + /// @notice Approves the data custodian with the given address. /// @param custodian The address of the custodian to approve. function approve(address custodian) external; } diff --git a/contracts/core/interfaces/policies/IPolicy.sol b/contracts/core/interfaces/policies/IPolicy.sol index 5afe759..a8d2753 100644 --- a/contracts/core/interfaces/policies/IPolicy.sol +++ b/contracts/core/interfaces/policies/IPolicy.sol @@ -8,14 +8,6 @@ import { T } from "@synaps3/core/primitives/Types.sol"; /// @notice Interface for managing access to content based on licensing terms. /// @dev This interface defines the basic information about the policy, such as its name and description. interface IPolicy { - /// @notice Returns the string identifier associated with the policy. - /// @dev This function provides a way to identify the specific policy being used. - function name() external pure returns (string memory); - - /// @notice Returns the business/strategy model implemented by the policy. - /// @dev A description of the business model as bytes, allowing more complex representations (such as encoded data). - function description() external pure returns (string memory); - /// @notice Initializes the policy with specific data for a given holder. /// @dev Only the Rights Policies Authorizer contract has permission to call this function. /// @param holder The address of the holder for whom the policy is being initialized. @@ -46,4 +38,12 @@ interface IPolicy { /// @notice Retrieves the address of the attestation provider. /// @return The address of the provider associated with the policy. function getAttestationProvider() external view returns (address); + + /// @notice Returns the string identifier associated with the policy. + /// @dev This function provides a way to identify the specific policy being used. + function name() external pure returns (string memory); + + /// @notice Returns the business/strategy model implemented by the policy. + /// @dev A description of the business model as bytes, allowing more complex representations (such as encoded data). + function description() external pure returns (string memory); } diff --git a/contracts/core/primitives/Constants.sol b/contracts/core/primitives/Constants.sol index 6172471..5afa68b 100644 --- a/contracts/core/primitives/Constants.sol +++ b/contracts/core/primitives/Constants.sol @@ -16,8 +16,9 @@ library C { uint64 internal constant MOD_ROLE = 2; // moderator role uint64 internal constant VER_ROLE = 3; // account verified role uint64 internal constant OPS_ROLE = 4; // operations roles - uint64 internal constant VAL_ROLE = 5; // content validation/curation roles - uint64 internal constant NOD_ROLE = 6; // nodes validations roles + + uint64 internal constant CONTENT_COUNCIL_ROLE = 5; // content validation/curation roles + uint64 internal constant NODE_VALIDATOR_ROLE = 6; // nodes validations roles bytes32 internal constant REFERENDUM_SUBMIT_TYPEHASH = keccak256("Submission(uint256 assetId, address initiator, uint256 nonce)"); diff --git a/contracts/custody/CustodianImpl.sol b/contracts/custody/CustodianImpl.sol index 4cfe613..3f55e7d 100644 --- a/contracts/custody/CustodianImpl.sol +++ b/contracts/custody/CustodianImpl.sol @@ -48,6 +48,7 @@ contract CustodianImpl is /// @dev Ensures that the provided endpoint is valid and initializes ERC165 and Ownable contracts. function initialize(string calldata endpoint, address owner) external initializer { if (bytes(endpoint).length == 0) revert InvalidEndpoint(); + __ERC165_init(); __Ownable_init(owner); _endpoint = endpoint; diff --git a/contracts/custody/CustodianReferendum.sol b/contracts/custody/CustodianReferendum.sol index d675c3d..8a369f9 100644 --- a/contracts/custody/CustodianReferendum.sol +++ b/contracts/custody/CustodianReferendum.sol @@ -7,11 +7,8 @@ import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/I // solhint-disable-next-line max-line-length import { AccessControlledUpgradeable } from "@synaps3/core/primitives/upgradeable/AccessControlledUpgradeable.sol"; import { QuorumUpgradeable } from "@synaps3/core/primitives/upgradeable/QuorumUpgradeable.sol"; -import { IAgreementSettler } from "@synaps3/core/interfaces/financial/IAgreementSettler.sol"; -import { IFeeSchemeValidator } from "@synaps3/core/interfaces/economics/IFeeSchemeValidator.sol"; import { ICustodianReferendum } from "@synaps3/core/interfaces/custody/ICustodianReferendum.sol"; import { ICustodianFactory } from "@synaps3/core/interfaces/custody/ICustodianFactory.sol"; -import { FinancialOps } from "@synaps3/core/libraries/FinancialOps.sol"; import { T } from "@synaps3/core/primitives/Types.sol"; /// @title CustodianReferendum @@ -24,27 +21,17 @@ contract CustodianReferendum is UUPSUpgradeable, QuorumUpgradeable, AccessControlledUpgradeable, - ICustodianReferendum, - IFeeSchemeValidator + ICustodianReferendum { - using FinancialOps for address; - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - IAgreementSettler public immutable AGREEMENT_SETTLER; ICustodianFactory public immutable CUSTODIAN_FACTORY; //slither-disable-end naming-convention - /// @dev Defines the expiration period for enrollment, determining how long a custodian remains active. - uint256 private _expirationPeriod; /// @dev Tracks the number of active enrollments within the system. uint256 private _enrollmentsCount; - /// @dev Maps a custodian's address to their respective enrollment deadline timestamp. - mapping(address => uint256) private _enrollmentDeadline; - /// @notice Event emitted when a custodian is registered /// @param custodian The address of the registered custodian - /// @param paidFees The amount of fees that were paid upon registration - event Registered(address indexed custodian, uint256 paidFees); + event Registered(address indexed custodian); /// @notice Event emitted when a custodian is approved /// @param custodian The address of the approved custodian @@ -54,34 +41,25 @@ contract CustodianReferendum is /// @param custodian The address of the revoked custodian event Revoked(address indexed custodian); - /// @notice Emitted when a new period is set - /// @param newPeriod The new period that is set, could be in seconds, blocks, or any other unit - event PeriodSet(uint256 newPeriod); - /// @notice Error thrown when the custodian is not recognized by the factory. /// @param custodian The address of the unregistered custodian contract. error UnregisteredCustodian(address custodian); - /// @notice Error thrown when the custodian does not match the agreement's registered party. - /// @param custodian The custodian provided for the operation.s - error CustodianAgreementMismatch(address custodian); - /// @notice Modifier to ensure the custodian was deployed through the trusted factory. /// @param custodian The address of the custodian contract to verify. modifier onlyValidCustodian(address custodian) { // ensure the custodian was deployed through the trusted factory and is known to the protocol if (!CUSTODIAN_FACTORY.isRegistered(custodian)) { - revert UnregisteredCustodian(msg.sender); + revert UnregisteredCustodian(custodian); } _; } /// @custom:oz-upgrades-unsafe-allow constructor - constructor(address agreementSettler, address custodianFactory) { + constructor(address custodianFactory) { /// https://forum.openzeppelin.com/t/what-does-disableinitializers-function-mean/28730/5 /// https://forum.openzeppelin.com/t/uupsupgradeable-vulnerability-post-mortem/15680 _disableInitializers(); - AGREEMENT_SETTLER = IAgreementSettler(agreementSettler); CUSTODIAN_FACTORY = ICustodianFactory(custodianFactory); } @@ -90,54 +68,19 @@ contract CustodianReferendum is __Quorum_init(); __UUPSUpgradeable_init(); __AccessControlled_init(accessManager); - // 6 months initially.. - _expirationPeriod = 180 days; - } - - /// @notice Checks if the given fee scheme is supported in this context. - /// @param scheme The fee scheme to validate. - /// @return True if the scheme is supported. - function isFeeSchemeSupported(T.Scheme scheme) external pure returns (bool) { - // support only FLAT scheme - return scheme == T.Scheme.FLAT; - } - - /// @notice Retrieves the current expiration period for enrollments or registrations. - function getExpirationPeriod() external view returns (uint256) { - return _expirationPeriod; - } - - /// @notice Retrieves the enrollment deadline for a custodian. - /// @param custodian The address of the custodian. - function getEnrollmentDeadline(address custodian) external view returns (uint256) { - return _enrollmentDeadline[custodian]; - } - - /// @notice Retrieves the total number of enrollments. - function getEnrollmentCount() external view returns (uint256) { - return _enrollmentsCount; } /// @notice Checks if the entity is active. /// @dev This function verifies the active status of the custodian. /// @param custodian The custodian's address to check. function isActive(address custodian) external view returns (bool) { - // TODO a renovation mechanism is needed to update the enrollment time - /// It ensures that custodians remain engaged and do not become inactive for extended periods. - /// The enrollment deadline enforces a time-based mechanism where custodians must renew - /// their registration to maintain their active status. This prevents dormant custodians - /// from continuing to benefit from the protocol without contributing. - // TODO add stateful management to custodians contract, the custodian can // change his state to "maintenance mode" or "inactive" if its facing issues // in that way the custodian is omitted during load balancing. // in this line we can check if the custodian contract is active custodian.isActive() // this is important feature if the custodians want to avoid harm reputation - // This mechanism helps to verify the availability of the custodian, - // forcing recurrent registrations and ensuring ongoing participation. - bool notExpiredDeadline = _enrollmentDeadline[custodian] > block.timestamp; - return _status(uint160(custodian)) == T.Status.Active && notExpiredDeadline; + return _status(uint160(custodian)) == T.Status.Active; } /// @notice Checks if the entity is waiting. @@ -154,61 +97,34 @@ contract CustodianReferendum is return _status(uint160(custodian)) == T.Status.Blocked; } - /// @notice Registers a custodian by sending a payment to the contract. - /// @param proof The unique identifier of the agreement to be enforced. + /// @notice Registers a custodian to be approved by council. /// @param custodian The address of the custodian to register. - function register(uint256 proof, address custodian) external onlyValidCustodian(custodian) { - /// TODO penalize invalid endpoints, and revoked during referendum - // !IMPORTANT: - // Fees act as a mechanism to prevent abuse or spam by users - // when submitting custodians for approval. This discourages users from - // making frivolous or excessive registrations without genuine intent. - // - // Additionally, the fees establish a foundation of real interest and commitment - // from the custodian. This ensures that only those who see value in the protocol - // and are willing to contribute to its ecosystem will participate. - // - // The collected fees are used to support the protocol's operations, aligning - // individual actions with the broader sustainability of the network. - - // IMPORTANT: - // The expected fees are locked in the agreement, based on the custodians fees defined by the tollgate. - // If the fee amount is insufficient, the transaction will revert during agreement creation. - // Only valid agreements can be settled; the validity is guaranteed by the proof. - T.Agreement memory agreement = AGREEMENT_SETTLER.settleAgreement(proof, msg.sender); - if (agreement.parties[0] != custodian) { - revert CustodianAgreementMismatch(custodian); - } - + function register(address custodian) external onlyValidCustodian(custodian) { // register custodian as pending approval _register(uint160(custodian)); // set the custodian active enrollment period.. - // after this time the custodian is considered inactive and cannot collect his profits... - _enrollmentDeadline[custodian] = block.timestamp + _expirationPeriod; - emit Registered(custodian, agreement.fees); + emit Registered(custodian); } /// @notice Approves a custodian's registration. /// @param custodian The address of the custodian to approve. function approve(address custodian) external restricted { - _enrollmentsCount++; _approve(uint160(custodian)); + _enrollmentsCount++; emit Approved(custodian); } /// @notice Revokes the registration of a custodian. /// @param custodian The address of the custodian to revoke. function revoke(address custodian) external restricted { - _enrollmentsCount--; _revoke(uint160(custodian)); + _enrollmentsCount--; emit Revoked(custodian); } - /// @notice Sets a new expiration period for an enrollment or registration. - /// @param newPeriod The new expiration period, in seconds. - function setExpirationPeriod(uint256 newPeriod) external restricted { - _expirationPeriod = newPeriod; - emit PeriodSet(newPeriod); + /// @notice Retrieves the total number of enrollments. + function getEnrollmentCount() external view returns (uint256) { + return _enrollmentsCount; } /// @notice Function that should revert when msg.sender is not authorized to upgrade the contract. diff --git a/script/deployment/10_Deploy_Custody_CustodianReferendum.s.sol b/script/deployment/10_Deploy_Custody_CustodianReferendum.s.sol index 67d2ad4..d607a4f 100644 --- a/script/deployment/10_Deploy_Custody_CustodianReferendum.s.sol +++ b/script/deployment/10_Deploy_Custody_CustodianReferendum.s.sol @@ -8,10 +8,9 @@ import { C } from "contracts/core/primitives/Constants.sol"; contract DeployCustodianReferendum is DeployBase { function run() external returns (address) { vm.startBroadcast(getAdminPK()); - address agreementSettler = computeCreate3Address("SALT_AGREEMENT_SETTLER"); address custodianFactory = computeCreate3Address("SALT_CUSTODIAN_FACTORY"); address accessManager = computeCreate3Address("SALT_ACCESS_MANAGER"); - address impl = address(new CustodianReferendum(agreementSettler, custodianFactory)); + address impl = address(new CustodianReferendum(custodianFactory)); bytes memory init = abi.encodeCall(CustodianReferendum.initialize, (accessManager)); address referendum = deployUUPS(impl, init, "SALT_CUSTODIAN_REFERENDUM"); vm.stopBroadcast(); diff --git a/script/orchestration/01_Orchestrate_ProtocolHydration.s.sol b/script/orchestration/01_Orchestrate_ProtocolHydration.s.sol index 1d1cc30..d211d5d 100644 --- a/script/orchestration/01_Orchestrate_ProtocolHydration.s.sol +++ b/script/orchestration/01_Orchestrate_ProtocolHydration.s.sol @@ -65,20 +65,14 @@ contract OrchestrateProtocolHydration is Script { // 2 set mmc as the initial currency and fees uint256 agrFee = vm.envUint("AGREEMENT_FEES"); // 5% 500 bps - uint256 synFees = vm.envUint("CUSTODY_FEES"); // 100 MMC flat fee address currency = vm.envAddress("MMC"); ITollgate tollgate = ITollgate(tollgateAddress); // assign bps scheme to right policy manager + fees + mmc tollgate.setFees(T.Scheme.BPS, rightPolicyManager, agrFee, currency); - tollgate.setFees(T.Scheme.FLAT, custodianReferendum, synFees, currency); (uint256 feeA, ) = tollgate.getFees(rightPolicyManager, currency); - (uint256 feeB, ) = tollgate.getFees(custodianReferendum, currency); - require(feeA == agrFee); - require(feeB == synFees); - vm.stopBroadcast(); } } diff --git a/script/orchestration/02_Orchestrate_ProtocolCustodianNetwork.s.sol b/script/orchestration/02_Orchestrate_ProtocolCustodianNetwork.s.sol index edeed37..e584d35 100644 --- a/script/orchestration/02_Orchestrate_ProtocolCustodianNetwork.s.sol +++ b/script/orchestration/02_Orchestrate_ProtocolCustodianNetwork.s.sol @@ -17,7 +17,6 @@ contract OrchestrateProtocolCustodianNetwork is DeployBase { address vault = computeCreate3Address("SALT_LEDGER_VAULT"); address custodianFactory = vm.envAddress("CUSTODIAN_FACTORY"); address custodianReferendum = vm.envAddress("CUSTODIAN_REFERENDUM"); - address agreementManager = vm.envAddress("AGREEMENT_MANAGER"); vm.startBroadcast(admin); // approve initial custodian @@ -35,19 +34,7 @@ contract OrchestrateProtocolCustodianNetwork is DeployBase { ILedgerVault(vault).deposit(vm.addr(admin), fees, mmc); ILedgerVault(vault).approve(address(referendum), fees, mmc); - address custody = address(custodian); - address[] memory parties = new address[](1); - parties[0] = custody; - - uint256 proof = IAgreementManager(agreementManager).createAgreement( - fees, - mmc, - address(referendum), - parties, - "" - ); - - referendum.register(proof, address(custodian)); + referendum.register(address(custodian)); referendum.approve(address(custodian)); vm.stopBroadcast(); diff --git a/script/permissions/Permissions_CustodianReferendum.sol b/script/permissions/Permissions_CustodianReferendum.sol index ba41c74..68ceeb2 100644 --- a/script/permissions/Permissions_CustodianReferendum.sol +++ b/script/permissions/Permissions_CustodianReferendum.sol @@ -4,7 +4,6 @@ import { CustodianReferendum } from "contracts/custody/CustodianReferendum.sol"; function getGovPermissions() pure returns (bytes4[] memory) { bytes4[] memory custodianReferendumAllowed = new bytes4[](3); - custodianReferendumAllowed[0] = CustodianReferendum.setExpirationPeriod.selector; custodianReferendumAllowed[1] = CustodianReferendum.revoke.selector; custodianReferendumAllowed[2] = CustodianReferendum.approve.selector; return custodianReferendumAllowed; diff --git a/script/upgrades/10_Upgrade_Custody_CustodianReferendum.s.sol b/script/upgrades/10_Upgrade_Custody_CustodianReferendum.s.sol index ad0ae96..d3b2dd2 100644 --- a/script/upgrades/10_Upgrade_Custody_CustodianReferendum.s.sol +++ b/script/upgrades/10_Upgrade_Custody_CustodianReferendum.s.sol @@ -8,9 +8,8 @@ import { C } from "contracts/core/primitives/Constants.sol"; contract UpgradeCustodianReferendum is UpgradeBase { function run() external returns (address) { vm.startBroadcast(getAdminPK()); - address agreementSettler = vm.envAddress("AGREEMENT_SETTLER"); address custodianFactory = vm.envAddress("CUSTODIAN_FACTORY"); - address impl = address(new CustodianReferendum(agreementSettler, custodianFactory)); + address impl = address(new CustodianReferendum(custodianFactory)); address referendumProxy = vm.envAddress("CUSTODIAN_REFERENDUM"); // address accessManager = vm.envAddress("ACCESS_MANAGER"); //!IMPORTANT: This is not a safe upgrade, take any caution or 2-check needed before run this method diff --git a/test/BaseTest.t.sol b/test/BaseTest.t.sol index a6ffe61..a001ee9 100644 --- a/test/BaseTest.t.sol +++ b/test/BaseTest.t.sol @@ -36,6 +36,8 @@ abstract contract BaseTest is Test { address admin; address user; address governor; + address contentCouncil; + address nodesCouncil; address accessManager; address agreementManager; @@ -59,6 +61,8 @@ abstract contract BaseTest is Test { // setup the admin to operate in tests.. user = vm.addr(2); governor = vm.addr(1); + contentCouncil = vm.addr(2); + nodesCouncil = vm.addr(2); admin = vm.addr(vm.envUint("PRIVATE_KEY")); deployCreate3Factory(); @@ -95,6 +99,12 @@ abstract contract BaseTest is Test { // add to governor the gov role IAccessManager authority = IAccessManager(accessManager); authority.grantRole(C.GOV_ROLE, governor, 0); + + vm.startPrank(governor); + // add to councils the corresponding role + authority.grantRole(C.CONTENT_COUNCIL_ROLE, contentCouncil, 0); + authority.grantRole(C.NODE_VALIDATOR_ROLE, nodesCouncil, 0); + vm.stopPrank(); } // 02_DeployTollgate @@ -159,7 +169,7 @@ abstract contract BaseTest is Test { DeployAssetReferendum assetReferendumDeployer = new DeployAssetReferendum(); bytes4[] memory referendumAllowed = AssetReferendumGovPermissions(); assetReferendum = assetReferendum == address(0) ? assetReferendumDeployer.run() : assetReferendum; - _setGovPermissions(assetReferendum, referendumAllowed); + _setContentCouncilPermissions(assetReferendum, referendumAllowed); } function deployAssetOwnership() public { @@ -171,11 +181,8 @@ abstract contract BaseTest is Test { function deployAssetSafe() public { deployAssetOwnership(); - DeployAssetSafe assetVaultDeployer = new DeployAssetSafe(); - bytes4[] memory referendumAllowed = AssetReferendumGovPermissions(); assetSafe = assetSafe == address(0) ? assetVaultDeployer.run() : assetSafe; - _setGovPermissions(assetSafe, referendumAllowed); } // 08_DeployCustodian @@ -193,7 +200,7 @@ abstract contract BaseTest is Test { bytes4[] memory custodianReferendumAllowed = CustodianReferendumGovPermissions(); custodianReferendum = custodianReferendum == address(0) ? distReferendumDeployer.run() : custodianReferendum; // GOV permission set to custodian referendum functions - _setGovPermissions(custodianReferendum, custodianReferendumAllowed); + _setNodesCouncilPermissions(custodianReferendum, custodianReferendumAllowed); } @@ -204,6 +211,22 @@ abstract contract BaseTest is Test { rightAssetCustodian = rightAssetCustodian == address(0) ? rightAssetCustodianDeployer.run() : rightAssetCustodian; } + function _setContentCouncilPermissions(address target, bytes4[] memory allowed) public { + vm.startPrank(admin); + IAccessManager authority = IAccessManager(accessManager); + // assign permissions to VAL_ROLE for allowed functions to call in target + authority.setTargetFunctionRole(target, allowed, C.CONTENT_COUNCIL_ROLE); + vm.stopPrank(); + } + + function _setNodesCouncilPermissions(address target, bytes4[] memory allowed) public { + vm.startPrank(admin); + IAccessManager authority = IAccessManager(accessManager); + // assign permissions to VAL_ROLE for allowed functions to call in target + authority.setTargetFunctionRole(target, allowed, C.NODE_VALIDATOR_ROLE); + vm.stopPrank(); + } + function _setGovPermissions(address target, bytes4[] memory allowed) public { vm.startPrank(admin); IAccessManager authority = IAccessManager(accessManager); diff --git a/test/assets/AssetReferendum.t.sol b/test/assets/AssetReferendum.t.sol index d3f43fd..3f25700 100644 --- a/test/assets/AssetReferendum.t.sol +++ b/test/assets/AssetReferendum.t.sol @@ -28,15 +28,16 @@ contract AssetReferendumTest is BaseTest { function test_Submit_SubmittedValidStates() public { _submitContentAsUser(1); - assertFalse(IAssetVerifiable(assetReferendum).isActive(1), "Asset should not be active yet"); - assertFalse(IAssetVerifiable(assetReferendum).isApproved(user, 1), "Asset should not be approved yet"); + IAssetVerifiable referendum = IAssetVerifiable(assetReferendum); + assertFalse(referendum.isActive(1), "Asset should not be active yet"); + assertFalse(referendum.isApproved(user, 1), "Asset should not be approved yet"); } function test_Approve_ApprovedEventEmitted() public { uint256 assetId = 1; _submitContentAsUser(assetId); vm.warp(1641070805); - vm.startPrank(governor); // approve by governance.. + vm.startPrank(contentCouncil); // approve by council.. vm.expectEmit(true, false, false, true, address(assetReferendum)); emit AssetReferendum.Approved(assetId); IAssetRegistrable(assetReferendum).approve(assetId); @@ -44,22 +45,26 @@ contract AssetReferendumTest is BaseTest { } function test_Approve_ApprovedValidStates() public { - uint256 assetId; + uint256 assetId = 1; + _submitContentAsUser(assetId); - - vm.prank(governor); // approve by governance.. + + vm.prank(contentCouncil); // approve by council.. IAssetRegistrable(assetReferendum).approve(assetId); - assertTrue(IAssetVerifiable(assetReferendum).isActive(assetId), "Asset should be active"); - assertTrue(IAssetVerifiable(assetReferendum).isApproved(user, assetId), "Asset should be approved"); + + IAssetVerifiable referendum = IAssetVerifiable(assetReferendum); + assertTrue(referendum.isActive(assetId), "Asset should be active"); + assertTrue(referendum.isApproved(user, assetId), "Asset should be approved"); } function test_Reject_RejectedEventEmitted() public { uint256 assetId = 1; _submitContentAsUser(assetId); vm.warp(1641070805); - vm.prank(governor); // approve by governance.. + vm.prank(contentCouncil); // approve by council.. vm.expectEmit(true, false, false, true, address(assetReferendum)); emit AssetReferendum.Rejected(assetId); + IAssetRevokable(assetReferendum).reject(assetId); } @@ -67,19 +72,22 @@ contract AssetReferendumTest is BaseTest { uint256 assetId = 1; _submitContentAsUser(assetId); - vm.prank(governor); // approve by governance.. + vm.prank(contentCouncil); // approve by council.. IAssetRevokable(assetReferendum).reject(assetId); - assertFalse(IAssetVerifiable(assetReferendum).isActive(assetId), "Asset should not be active"); - assertFalse(IAssetVerifiable(assetReferendum).isApproved(user, assetId), "Asset should not be approved"); + + IAssetVerifiable referendum = IAssetVerifiable(assetReferendum); + assertFalse(referendum.isActive(assetId), "Asset should not be active"); + assertFalse(referendum.isApproved(user, assetId), "Asset should not be approved"); } function test_Revoked_RevokedEventEmitted() public { uint256 assetId = 1; _submitContentAsUser(assetId); vm.warp(1641070805); - vm.startPrank(governor); // approve by governance.. + + vm.startPrank(contentCouncil); // approve by council.. // first an approval should ve done - // then a revoke should ve done + // then a revoke IAssetRegistrable(assetReferendum).approve(assetId); vm.expectEmit(true, false, false, true, address(assetReferendum)); @@ -91,16 +99,18 @@ contract AssetReferendumTest is BaseTest { function test_Revoked_RevokedValidStates() public { uint256 assetId = 1; _submitAndApproveContent(assetId); - vm.prank(governor); // approve by governance.. + vm.prank(contentCouncil); // approve by council.. IAssetRevokable(assetReferendum).revoke(assetId); - assertFalse(IAssetVerifiable(assetReferendum).isActive(assetId), "Asset should not be active"); - assertFalse(IAssetVerifiable(assetReferendum).isApproved(user, assetId), "Asset should not be approved"); + + IAssetVerifiable referendum = IAssetVerifiable(assetReferendum); + assertFalse(referendum.isActive(assetId), "Asset should not be active"); + assertFalse(referendum.isApproved(user, assetId), "Asset should not be approved"); } function _submitAndApproveContent(uint256 assetId) internal { _submitContentAsUser(assetId); vm.warp(1641070805); - vm.startPrank(governor); // approve by governance.. + vm.prank(contentCouncil); // approve by council.. IAssetRegistrable(assetReferendum).approve(assetId); vm.stopPrank(); // approve by governance.. } diff --git a/test/assets/AssetSafe.t.sol b/test/assets/AssetSafe.t.sol index f94cb2a..6b8c90c 100644 --- a/test/assets/AssetSafe.t.sol +++ b/test/assets/AssetSafe.t.sol @@ -97,7 +97,8 @@ contract AssetSafeTest is BaseTest { function _registerAndApproveAsset(address to, uint256 assetId) private { vm.prank(to); IAssetRegistrable(assetReferendum).submit(assetId); - vm.prank(governor); + + vm.prank(contentCouncil); IAssetRegistrable(assetReferendum).approve(assetId); vm.prank(to); diff --git a/test/custody/CustodianImpl.t.sol b/test/custody/CustodianImpl.t.sol index eef3595..67e7afa 100644 --- a/test/custody/CustodianImpl.t.sol +++ b/test/custody/CustodianImpl.t.sol @@ -16,33 +16,42 @@ contract CustodianImplTest is BaseTest { deployCustodianFactory(); } - function deployCustodian(string memory endpoint) public returns (address) { - vm.prank(admin); + function deployCustodian(string memory endpoint, address owner) public returns (address) { + vm.prank(owner); ICustodianFactory factory = ICustodianFactory(custodianFactory); return factory.create(endpoint); } - function test_Create_ValidCustodian() public { - address custodian = deployCustodian("test.com"); + function testFuzz_Create_ValidCustodian(string memory endpoint) public { + vm.assume(bytes(endpoint).length > 0); + + address custodian = deployCustodian(endpoint, user); bool supportedInterface = IERC165(custodian).supportsInterface(type(ICustodian).interfaceId); assertEq(supportedInterface, true, "Custodian should support ICustodian interface"); } - function test_GetOwner_ExpectedDeployer() public { - address custodian = deployCustodian("test2.com"); - assertEq(ICustodian(custodian).getManager(), admin, "Expected owner should be the deployer"); + function testFuzz_GetOwner_ExpectedDeployer(address manager, string memory endpoint) public { + vm.assume(manager != address(0)); + vm.assume(bytes(endpoint).length > 0); + vm.assume(manager.code.length == 0); + + address custodian = deployCustodian(endpoint, manager); + address currentManager = ICustodian(custodian).getManager(); + assertEq(currentManager, manager, "Expected owner should be the deployer"); } - function test_GetEndpoint_ExpectedEndpoint() public { - address custodian = deployCustodian("test3.com"); - assertEq(ICustodian(custodian).getEndpoint(), "test3.com", "Expected endpoint should match"); + function testFuzz_GetEndpoint_ExpectedEndpoint(string memory endpoint) public { + vm.assume(bytes(endpoint).length > 0); + + address custodian = deployCustodian(endpoint, user); + string memory got = ICustodian(custodian).getEndpoint(); + assertEq(endpoint, got, "Expected endpoint should match"); } function test_SetEndpoint_ValidEndpoint() public { // created with an initial endpoint - address custodian = deployCustodian("1.1.1.1"); - // changed to a dns domain - vm.prank(admin); // only owner can do this + address custodian = deployCustodian("1.1.1.1", user); + vm.prank(user); // only owner can do this ICustodian(custodian).setEndpoint("mynew.com"); string memory endpoint = ICustodian(custodian).getEndpoint(); assertEq(endpoint, "mynew.com", "Expected endpoint should be updated"); @@ -50,15 +59,17 @@ contract CustodianImplTest is BaseTest { function test_SetEndpoint_RevertWhen_InvalidOwner() public { // created with an initial endpoint - address custodian = deployCustodian("1.1.1.1"); - vm.prank(user); - vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", user)); + address custodian = deployCustodian("1.1.1.1", user); + address invalidOwner = vm.addr(10); + + vm.prank(invalidOwner); + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", invalidOwner)); ICustodian(custodian).setEndpoint("mynew.com"); } function test_GetBalance_ValidBalance() public { // created with an initial endpoint - address custodian = deployCustodian("1.1.1.1"); + address custodian = deployCustodian("1.1.1.1", user); uint256 expected = 100 * 1e18; // admin acting as reward system to transfer funds // here the expected is that rewards system do it. @@ -72,14 +83,14 @@ contract CustodianImplTest is BaseTest { function test_Withdraw_ValidFundsWithdrawn() public { // created with an initial endpoint uint256 expected = 100 * 1e18; - address custodian = deployCustodian("1.1.1.1"); + address custodian = deployCustodian("1.1.1.1", admin); vm.startPrank(admin); // only owner can get balance by default deployer IERC20(token).transfer(custodian, expected); // only owner can withdraw funds by default deployer IBalanceWithdrawable(custodian).withdraw(user, expected, token); vm.stopPrank(); - + uint256 userBalance = IERC20(token).balanceOf(user); assertEq(userBalance, expected, "User should receive the withdrawn funds"); } @@ -87,7 +98,7 @@ contract CustodianImplTest is BaseTest { function test_Withdraw_EmitFundsWithdrawn() public { // created with an initial endpoint uint256 expected = 100 * 1e18; - address custodian = deployCustodian("1.1.1.1"); + address custodian = deployCustodian("1.1.1.1", admin); vm.startPrank(admin); // only owner can get balance by default deployer IERC20(token).transfer(custodian, expected); @@ -95,14 +106,18 @@ contract CustodianImplTest is BaseTest { vm.expectEmit(true, true, false, true, address(custodian)); emit IBalanceWithdrawable.FundsWithdrawn(user, admin, expected, token); IBalanceWithdrawable(custodian).withdraw(user, expected, token); + vm.stopPrank(); + + assertEq(IERC20(token).balanceOf(user), expected, "user with funds"); + assertEq(IERC20(token).balanceOf(custodian), 0, "custodian must be zero"); } function test_Withdraw_RevertWhen_NoBalance() public { // created with an initial endpoint uint256 expected = 100 * 1e18; - address custodian = deployCustodian("1.1.1.1"); + address custodian = deployCustodian("1.1.1.1", user); - vm.startPrank(admin); // only owner can get balance by default deployer + vm.prank(user); // only owner can get balance by default deployer vm.expectRevert(abi.encodeWithSignature("NoFundsToWithdraw()")); IBalanceWithdrawable(custodian).withdraw(user, expected, token); } @@ -110,10 +125,10 @@ contract CustodianImplTest is BaseTest { function test_Withdraw_RevertWhen_InvalidOwner() public { // created with an initial endpoint uint256 expected = 100 * 1e18; - address custodian = deployCustodian("1.1.1.1"); + address custodian = deployCustodian("1.1.1.1", user); - vm.prank(user); - vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", user)); + vm.prank(admin); + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", admin)); IBalanceWithdrawable(custodian).withdraw(user, expected, token); } } diff --git a/test/custody/CustodianReferendum.t.sol b/test/custody/CustodianReferendum.t.sol index 3509297..d992aa8 100644 --- a/test/custody/CustodianReferendum.t.sol +++ b/test/custody/CustodianReferendum.t.sol @@ -3,9 +3,7 @@ pragma solidity 0.8.26; import "forge-std/Test.sol"; - import { ICustodianVerifiable } from "contracts/core/interfaces/custody/ICustodianVerifiable.sol"; -import { ICustodianExpirable } from "contracts/core/interfaces/custody/ICustodianExpirable.sol"; import { ICustodianRegistrable } from "contracts/core/interfaces/custody/ICustodianRegistrable.sol"; import { ICustodianInspectable } from "contracts/core/interfaces/custody/ICustodianInspectable.sol"; import { ICustodianRevokable } from "contracts/core/interfaces/custody/ICustodianRevokable.sol"; @@ -15,107 +13,40 @@ import { CustodianShared } from "test/shared/CustodianShared.t.sol"; import { CustodianReferendum } from "contracts/custody/CustodianReferendum.sol"; import { CustodianImpl } from "contracts/custody/CustodianImpl.sol"; - contract CustodianReferendumTest is CustodianShared { /// ---------------------------------------------------------------- - function test_Init_ExpirationPeriod() public view { - // test initialized treasury address - uint256 expected = 180 days; - uint256 period = ICustodianExpirable(custodianReferendum).getExpirationPeriod(); - assertEq(period, expected, "Expected expiration period should be 180 days"); - } - - function test_SetExpirationPeriod_ValidExpiration() public { - uint256 expireIn = 3600; // seconds - vm.prank(governor); - ICustodianExpirable(custodianReferendum).setExpirationPeriod(expireIn); - uint256 currentExpiration = ICustodianExpirable(custodianReferendum).getExpirationPeriod(); - assertEq(currentExpiration, expireIn, "Expected expiration period should match"); - } - - function test_SetExpirationPeriod_EmitPeriodSet() public { - uint256 expireIn = 3600; // seconds - vm.prank(governor); - vm.expectEmit(true, false, false, true, address(custodianReferendum)); - emit CustodianReferendum.PeriodSet(expireIn); - ICustodianExpirable(custodianReferendum).setExpirationPeriod(expireIn); - } - - function test_SetExpirationPeriod_RevertWhen_Unauthorized() public { - vm.expectRevert(); - ICustodianExpirable(custodianReferendum).setExpirationPeriod(10); - } - function test_Register_RegisteredEventEmitted() public { - uint256 expectedFees = 100 * 1e18; - address custodian = deployCustodian("contentrider.com"); - _setFeesAsGovernor(expectedFees); // free enrollment: test purpose + address custodian = _deployCustodian("contentrider.com", user); // after register a custodian a Registered event is expected vm.warp(1641070803); vm.startPrank(admin); - // approve fees payment: admin default account - address[] memory parties = new address[](1); - parties[0] = custodian; - uint256 proof = _createAgreement(expectedFees, parties); vm.expectEmit(true, false, false, true, address(custodianReferendum)); - emit CustodianReferendum.Registered(custodian, expectedFees); - ICustodianRegistrable(custodianReferendum).register(proof, custodian); + emit CustodianReferendum.Registered(custodian); + ICustodianRegistrable(custodianReferendum).register(custodian); vm.stopPrank(); } - function test_Register_RevertIf_InvalidAgreement() public { - uint256 expectedFees = 100 * 1e18; // 100 MMC - address custodian = deployCustodian("contentrider.com"); - _setFeesAsGovernor(expectedFees); - // expected revert if not valid allowance - vm.prank(user); - vm.expectRevert(abi.encodeWithSignature("UnauthorizedEscrowAgent()")); - ICustodianRegistrable(custodianReferendum).register(0, custodian); - } - - function test_Register_SetValidEnrollmentTime() public { - address custodian = deployCustodian("contentrider.com"); - ICustodianInspectable inspectable = ICustodianInspectable(custodianReferendum); - ICustodianExpirable expirable = ICustodianExpirable(custodianReferendum); - - _setFeesAsGovernor(1 * 1e18); - uint256 expectedExpiration = expirable.getExpirationPeriod(); - uint256 currentTime = 1727976358; - vm.warp(currentTime); // set block.time to current time - - // register the custodian expecting the right enrollment time.. - _registerCustodianWithApproval(custodian, 1 * 1e18); - uint256 expected = currentTime + expectedExpiration; - uint256 got = inspectable.getEnrollmentDeadline(custodian); - assertEq(got, expected, "Expected enrollment deadline should match"); - } - function test_Register_SetWaitingState() public { - _setFeesAsGovernor(1 * 1e18); - address custodian = deployCustodian("contentrider.com"); + address custodian = _deployCustodian("contentrider.com", user); // register the custodian expecting the right status. - _registerCustodianWithApproval(custodian, 1 * 1e18); + ICustodianRegistrable(custodianReferendum).register(custodian); bool isWaiting = ICustodianVerifiable(custodianReferendum).isWaiting(custodian); assertTrue(isWaiting, "Custodian should be in waiting state"); } - function test_Register_RevertIf_InvalidCustodian() public { - vm.prank(user); - address custodian = address(new CustodianImpl()); - + function testFuzz_Register_RevertIf_InvalidCustodian(address custodian) public { vm.prank(admin); // - vm.expectRevert(abi.encodeWithSignature("UnregisteredCustodian(address)", admin)); - ICustodianRegistrable(custodianReferendum).register(0, custodian); + vm.expectRevert(abi.encodeWithSignature("UnregisteredCustodian(address)", custodian)); + ICustodianRegistrable(custodianReferendum).register(custodian); } function test_Approve_ApprovedEventEmitted() public { - _setFeesAsGovernor(1 * 1e18); - address custodian = deployCustodian("contentrider.com"); - _registerCustodianWithApproval(custodian, 1 * 1e18); + address custodian = _deployCustodian("contentrider.com", user); + _registerCustodian(custodian); - vm.prank(governor); // as governor. + vm.prank(nodesCouncil); // as governor. vm.warp(1641070802); // after register a custodian a Registered event is expected vm.expectEmit(true, false, false, true, address(custodianReferendum)); @@ -124,30 +55,31 @@ contract CustodianReferendumTest is CustodianShared { } function test_Approve_SetActiveState() public { - address custodian = deployCustodian("contentrider.com"); + address custodian = _deployCustodian("contentrider.com", user); + _registerAndApproveCustodian(custodian); bool isActive = ICustodianVerifiable(custodianReferendum).isActive(custodian); assertTrue(isActive, "Custodian should be active after approval"); } - function test_Approve_IncrementEnrollmentCount() public { - address custodian = deployCustodian("contentrider.com"); - address custodian2 = deployCustodian("test2.com"); - address custodian3 = deployCustodian("test3.com"); + function testFuzz_Approve_IncrementEnrollmentCount(uint256 rawN) public { + uint256 n = bound(rawN, 1, 20); - _registerAndApproveCustodian(custodian); - _registerAndApproveCustodian(custodian2); // still governor prank - _registerAndApproveCustodian(custodian3); // still governor prank + for (uint256 i = 0; i < n; i++) { + address custodian = _deployCustodian(string.concat("content", vm.toString(i), ".com"), user); + _registerAndApproveCustodian(custodian); + } // valid approvals, increments the total of enrollments uint256 enrollment = ICustodianInspectable(custodianReferendum).getEnrollmentCount(); - assertEq(enrollment, 3, "Enrollment count should be 3"); + assertEq(enrollment, n, "Enrollment count should be 3"); } function test_Revoke_RevokedEventEmitted() public { - address custodian = deployCustodian("contentrider.com"); + address custodian = _deployCustodian("contentrider.com", user); _registerAndApproveCustodian(custodian); // still governor prank - vm.prank(governor); + + vm.prank(nodesCouncil); vm.warp(1641070801); // after register a custodian a Registered event is expected vm.expectEmit(true, false, false, true, address(custodianReferendum)); @@ -156,24 +88,24 @@ contract CustodianReferendumTest is CustodianShared { } function test_Revoke_DecrementEnrollmentCount() public { - address custodian = deployCustodian("contentrider.com"); + address custodian = _deployCustodian("contentrider.com", user); _registerAndApproveCustodian(custodian); // still governor prank + // valid approvals, increments the total of enrollments - vm.prank(governor); + vm.prank(nodesCouncil); ICustodianRevokable(custodianReferendum).revoke(custodian); uint256 enrollment = ICustodianInspectable(custodianReferendum).getEnrollmentCount(); assertEq(enrollment, 0, "Enrollment count should be 0 after revocation"); } function test_Revoke_SetBlockedState() public { - address custodian = deployCustodian("contentrider.com"); + address custodian = _deployCustodian("contentrider.com", user); _registerAndApproveCustodian(custodian); // still governor prank + // custodian get revoked by governance.. - vm.prank(governor); + vm.prank(nodesCouncil); ICustodianRevokable(custodianReferendum).revoke(custodian); bool isBlocked = ICustodianVerifiable(custodianReferendum).isBlocked(custodian); assertTrue(isBlocked, "Custodian should be blocked after revocation"); } - - } diff --git a/test/rights/RightAssetCustodian.t.sol b/test/rights/RightAssetCustodian.t.sol index 3fab868..499a234 100644 --- a/test/rights/RightAssetCustodian.t.sol +++ b/test/rights/RightAssetCustodian.t.sol @@ -23,7 +23,7 @@ contract RightAssetCustodianTest is CustodianShared { function setUp() public override { super.setUp(); - custodian = deployCustodian("weare.com"); + custodian = _deployCustodian("weare.com", user); _registerAndApproveCustodian(custodian); deployRightsAssetCustodian(); deployToken(); @@ -75,23 +75,22 @@ contract RightAssetCustodianTest is CustodianShared { } function test_GrantCustody_RevertIf_ExceedAvailableRedundancy() public { - // MAX default = 3 - address custodian2 = deployCustodian("weare1.com"); - address custodian3 = deployCustodian("weare2.com"); - address custodian4 = deployCustodian("weare3.com"); - _registerAndApproveCustodian(custodian2); - _registerAndApproveCustodian(custodian3); + IRightsAssetCustodianRegistrable rightCustody = IRightsAssetCustodianRegistrable(rightAssetCustodian); - vm.startPrank(user); - // registered first time - IRightsAssetCustodianRegistrable(rightAssetCustodian).grantCustody(custodian); - IRightsAssetCustodianRegistrable(rightAssetCustodian).grantCustody(custodian2); - IRightsAssetCustodianRegistrable(rightAssetCustodian).grantCustody(custodian3); - // 3 is reached, the validation is effective after this line + for (uint256 i = 0; i < 3; i++) { + // MAX default = 3 + address custodianN = _deployCustodian(string.concat("weare", vm.toString(i), ".com"), user); + _registerAndApproveCustodian(custodianN); + + vm.prank(user); + // registered first time + rightCustody.grantCustody(custodianN); + } // second expected failing attempt + vm.prank(user); vm.expectRevert(abi.encodeWithSignature("MaxRedundancyAllowedReached()")); - IRightsAssetCustodianRegistrable(rightAssetCustodian).grantCustody(custodian4); + rightCustody.grantCustody(custodian); vm.stopPrank(); } @@ -100,7 +99,7 @@ contract RightAssetCustodianTest is CustodianShared { IRightsAssetCustodianRegistrable(rightAssetCustodian).grantCustody(custodian); IRightsAssetCustodianRegistrable(rightAssetCustodian).revokeCustody(custodian); vm.stopPrank(); - + bool isCustodian = IRightsAssetCustodianVerifiable(rightAssetCustodian).isCustodian(custodian, user); assertFalse(isCustodian, "Custodian should be revoked"); } @@ -131,7 +130,7 @@ contract RightAssetCustodianTest is CustodianShared { function test_SetPriority_EmitPrioritySet() public { // second expected failing attempt uint256 designedPriority = 2; - address custodian2 = deployCustodian("weare1.com"); + address custodian2 = _deployCustodian("weare1.com", user); vm.startPrank(user); vm.expectEmit(true, true, false, true, address(rightAssetCustodian)); @@ -143,7 +142,7 @@ contract RightAssetCustodianTest is CustodianShared { function test_SetPriority_ValidPriority() public { // second expected failing attempt uint256 designedPriority = 2; - address custodian2 = deployCustodian("weare1.com"); + address custodian2 = _deployCustodian("weare1.com", user); vm.prank(user); IRightsAssetCustodianManager(rightAssetCustodian).setPriority(custodian2, designedPriority); @@ -153,7 +152,7 @@ contract RightAssetCustodianTest is CustodianShared { function test_SetPriority_RevertIf_ValidPriority() public { // second expected failing attempt - address custodian2 = deployCustodian("weare1.com"); + address custodian2 = _deployCustodian("weare1.com", user); vm.expectRevert(abi.encodeWithSignature("InvalidPriority(uint256)", 0)); IRightsAssetCustodianManager(rightAssetCustodian).setPriority(custodian2, 0); } @@ -204,8 +203,8 @@ contract RightAssetCustodianTest is CustodianShared { } function test_GetCustodian_ValidGrantedCustodian() public { - address custodian2 = deployCustodian("weare1.com"); - address custodian3 = deployCustodian("weare2.com"); + address custodian2 = _deployCustodian("weare1.com", user); + address custodian3 = _deployCustodian("weare2.com", user); address user1 = vm.addr(4); IRightsAssetCustodianManager rightAssetCustodianMgr = IRightsAssetCustodianManager(rightAssetCustodian); @@ -219,11 +218,12 @@ contract RightAssetCustodianTest is CustodianShared { // higher demand for 'custodian' vm.prank(user1); rightAssetCustodianReg.grantCustody(custodian); + vm.startPrank(user); // assign custodians to user - IRightsAssetCustodianRegistrable(rightAssetCustodian).grantCustody(custodian); - IRightsAssetCustodianRegistrable(rightAssetCustodian).grantCustody(custodian2); - IRightsAssetCustodianRegistrable(rightAssetCustodian).grantCustody(custodian3); + rightAssetCustodianReg.grantCustody(custodian); + rightAssetCustodianReg.grantCustody(custodian2); + rightAssetCustodianReg.grantCustody(custodian3); vm.stopPrank(); // 1- sum the weights @@ -270,7 +270,7 @@ contract RightAssetCustodianTest is CustodianShared { function test_IsCustodian_ReturnFalseIfRevokedNorExist() public { // MAX default = 3 - address custodian2 = deployCustodian("weare1.com"); + address custodian2 = _deployCustodian("weare1.com", user); IRightsAssetCustodianVerifiable rightAssetCustodianVer = IRightsAssetCustodianVerifiable(rightAssetCustodian); IRightsAssetCustodianRegistrable rightAssetCustodianReg = IRightsAssetCustodianRegistrable(rightAssetCustodian); @@ -299,11 +299,9 @@ contract RightAssetCustodianTest is CustodianShared { bool isCustodian = rightAssetCustodianVer.isCustodian(custodian, user); assertTrue(isCustodian, "Custodian should be registered"); - vm.prank(governor); + vm.prank(nodesCouncil); ICustodianRevokable(custodianReferendum).revoke(custodian); bool isRevokedCustodian = rightAssetCustodianVer.isCustodian(custodian, user); assertFalse(isRevokedCustodian, "Custodian should not be registered after revocation by governance"); } - - // TODO assign demand + transfer balance and check calc of weight } diff --git a/test/shared/CustodianShared.t.sol b/test/shared/CustodianShared.t.sol index b9a7cb9..0d251fc 100644 --- a/test/shared/CustodianShared.t.sol +++ b/test/shared/CustodianShared.t.sol @@ -16,54 +16,20 @@ contract CustodianShared is BaseTest { deployCustodianFactory(); } - function deployCustodian(string memory endpoint) public returns (address) { - vm.prank(admin); + function _deployCustodian(string memory endpoint, address owner) internal returns (address) { + vm.prank(owner); ICustodianFactory custodianFactory = ICustodianFactory(custodianFactory); return custodianFactory.create(endpoint); } - function _setFeesAsGovernor(uint256 fees) internal { - vm.startPrank(governor); - ITollgate(tollgate).setFees(T.Scheme.FLAT, custodianReferendum, fees, token); - vm.stopPrank(); + function _registerAndApproveCustodian(address custodian) internal { + _registerCustodian(custodian); + vm.prank(nodesCouncil); // as governor. + ICustodianRegistrable(custodianReferendum).approve(custodian); } - function _registerCustodianWithApproval(address d9r, uint256 approval) internal { - // manager = contract deployer - // only manager can pay enrollment.. - vm.startPrank(admin); - // approve approval to ledger to deposit funds - address[] memory parties = new address[](1); - parties[0] = d9r; - - uint256 proof = _createAgreement(approval, parties); - // operate over msg.sender ledger registered funds - ICustodianRegistrable(custodianReferendum).register(proof, d9r); - vm.stopPrank(); - } - - function _createAgreement(uint256 amount, address[] memory parties) internal returns (uint256) { - IERC20(token).approve(ledger, amount); - ILedgerVault(ledger).deposit(admin, amount, token); - - uint256 proof = IAgreementManager(agreementManager).createAgreement( - amount, - token, - address(custodianReferendum), - parties, - "" - ); - - return proof; - } - - function _registerAndApproveCustodian(address d9r) internal { - // intially the balance = 0 - _setFeesAsGovernor(1 * 1e18); - // register the custodian with fees = 100 MMC - _registerCustodianWithApproval(d9r, 1 * 1e18); - vm.prank(governor); // as governor. - // distribuitor approved only by governor.. - ICustodianRegistrable(custodianReferendum).approve(d9r); + function _registerCustodian(address custodian) internal { + ICustodianRegistrable(custodianReferendum).register(custodian); } + } From 00702f5f3cf422494465dec79f1de6a52452369c Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Thu, 21 Aug 2025 13:06:35 -0600 Subject: [PATCH 03/33] refactor: added pause protocol --- contracts/assets/AssetOwnership.sol | 1 + .../core/interfaces/economics/ITreasury.sol | 3 +- .../interfaces/financial/ILedgerVault.sol | 21 +-- .../AccessControlledUpgradeable.sol | 19 ++- .../AllowanceOperatorUpgradeable.sol | 14 +- .../BalanceOperatorUpgradeable.sol | 21 +-- contracts/custody/CustodianReferendum.sol | 3 +- contracts/economics/Treasury.sol | 50 +++++-- contracts/financial/LedgerVault.sol | 136 ++++++++---------- test/primitives/BalanceOperator.t.sol | 14 +- 10 files changed, 151 insertions(+), 131 deletions(-) diff --git a/contracts/assets/AssetOwnership.sol b/contracts/assets/AssetOwnership.sol index 4d327d4..7ef4676 100644 --- a/contracts/assets/AssetOwnership.sol +++ b/contracts/assets/AssetOwnership.sol @@ -125,6 +125,7 @@ contract AssetOwnership is /// @dev Requires approval before an asset can be registered. /// @param to The address that will own the minted NFT. /// @param assetId The unique identifier for the asset, serving as the NFT ID. + // TODO pause function register(address to, uint256 assetId) external onlyApprovedAsset(to, assetId) { _mint(to, assetId); _enableAsset(assetId); diff --git a/contracts/core/interfaces/economics/ITreasury.sol b/contracts/core/interfaces/economics/ITreasury.sol index cb64d55..eeab4f5 100644 --- a/contracts/core/interfaces/economics/ITreasury.sol +++ b/contracts/core/interfaces/economics/ITreasury.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: BUSL-1.1 // NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html pragma solidity 0.8.26; +import { IBalanceOperator } from "@synaps3/core/interfaces/base/IBalanceOperator.sol"; /// @title ITreasury Interface /// @notice Defines the standard functions for a Treasury contract. -interface ITreasury { +interface ITreasury is IBalanceOperator { /// @notice Collects accrued fees for a specified currency from an authorized fee collector. /// @param collector The address of an authorized fee collector. /// @param currency The address of the currency for which fees are being collected. diff --git a/contracts/core/interfaces/financial/ILedgerVault.sol b/contracts/core/interfaces/financial/ILedgerVault.sol index 6a74bfc..fbcc936 100644 --- a/contracts/core/interfaces/financial/ILedgerVault.sol +++ b/contracts/core/interfaces/financial/ILedgerVault.sol @@ -4,28 +4,11 @@ pragma solidity 0.8.26; import { IBalanceOperator } from "@synaps3/core/interfaces/base/IBalanceOperator.sol"; import { IAllowanceOperator } from "@synaps3/core/interfaces/base/IAllowanceOperator.sol"; +import { ILockOperator } from "@synaps3/core/interfaces/base/ILockOperator.sol"; /// @title ILedgerVault /// @notice Interface for managing locked funds and their operations. /// @dev Extends IBalanceOperator for managing user balances in a vault-like system. -interface ILedgerVault is IBalanceOperator, IAllowanceOperator { - /// @notice Locks a specific amount of funds for a given account. - /// @dev The funds are immobilized and cannot be withdrawn or transferred until released or claimed. - /// @param account The address of the account for which the funds will be locked. - /// @param amount The amount of funds to lock. - /// @param currency The currency to associate fees with. Use address(0) for the native coin. - function lock(address account, uint256 amount, address currency) external returns (uint256); +interface ILedgerVault is IBalanceOperator, IAllowanceOperator, ILockOperator { - /// @notice Claims a specific amount of locked funds on behalf of a claimer. - /// @dev The claimer is authorized to withdraw or process the funds from the account. - /// @param account The address of the account whose funds are being claimed. - /// @param amount The amount of funds to claim. - /// @param currency The currency to associate fees with. Use address(0) for the native coin. - function claim(address account, uint256 amount, address currency) external returns (uint256); - - /// @notice Release a specific amount of funds from locked pool. - /// @param account The address of the account for which the funds will be released. - /// @param amount The amount of funds to release. - /// @param currency The currency to associate release with. Use address(0) for the native coin. - function release(address account, uint256 amount, address currency) external returns (uint256); } diff --git a/contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol b/contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol index 93ed73f..bcdbe3c 100644 --- a/contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol +++ b/contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol @@ -3,6 +3,7 @@ pragma solidity 0.8.26; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; // solhint-disable-next-line max-line-length import { AccessManagedUpgradeable } from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; import { IAccessManager } from "@synaps3/core/interfaces/access/IAccessManager.sol"; @@ -11,7 +12,7 @@ import { C } from "@synaps3/core/primitives/Constants.sol"; /// @title AccessControlledUpgradeable /// @dev Abstract contract that provides role-based access control functionality to upgradeable contracts. /// This contract requires an AccessManager to manage roles. -abstract contract AccessControlledUpgradeable is Initializable, AccessManagedUpgradeable { +abstract contract AccessControlledUpgradeable is Initializable, AccessManagedUpgradeable, PausableUpgradeable { /// @custom:storage-location erc7201:accesscontrolledupgradeable struct AccessControlStorage { address _accessManager; @@ -36,7 +37,21 @@ abstract contract AccessControlledUpgradeable is Initializable, AccessManagedUpg _; } - // @dev Initializes the contract and ensures it is upgradeable. + /// @notice Pauses the contract, disabling state-changing operations. + /// @dev Can only be called by an account with the operator/admin role (`restricted`). + /// Once paused, functions guarded by `whenNotPaused` will revert until `unpause` is called. + function pause() external restricted { + _pause(); + } + + /// @notice Unpauses the contract, re-enabling state-changing operations. + /// @dev Can only be called by an account with the operator/admin role (`restricted`). + /// Once unpaused, functions guarded by `whenNotPaused` will operate normally again. + function unpause() external restricted { + _unpause(); + } + + /// @dev Initializes the contract and ensures it is upgradeable. /// Even if the initialization is harmless, this ensures the contract follows upgradeable contract patterns. /// This is the method to initialize this contract and any other extended contracts. /// @param accessManager The address of the AccessManager contract. diff --git a/contracts/core/primitives/upgradeable/AllowanceOperatorUpgradeable.sol b/contracts/core/primitives/upgradeable/AllowanceOperatorUpgradeable.sol index 1706f42..1dfffb3 100644 --- a/contracts/core/primitives/upgradeable/AllowanceOperatorUpgradeable.sol +++ b/contracts/core/primitives/upgradeable/AllowanceOperatorUpgradeable.sol @@ -23,7 +23,7 @@ abstract contract AllowanceOperatorUpgradeable is Initializable, LedgerUpgradeab /// @dev Storage slot for AllowanceOperatorUpgradeable, calculated using a unique namespace to avoid conflicts. /// The `ALLOWANCE_OPERATOR_SLOT` constant is used to point to the location of the storage. bytes32 private constant ALLOWANCE_OPERATOR_SLOT = - 0xa8707513830ffbd3c47e0c83d1f5f0270db240ae37bb1f9a13f077f85b949c00; + 0x60503404921b66adfd164bd2cecacde1d9102b9421dba47f75ca95001753aa00; /// @dev Initializes the contract and ensures it is upgradeable. /// Even if the initialization is harmless, this ensures the contract follows upgradeable contract patterns. @@ -53,11 +53,11 @@ abstract contract AllowanceOperatorUpgradeable is Initializable, LedgerUpgradeab /// @param to The address of the recipient for whom the funds are being approved. /// @param amount The amount of funds to approve. /// @param currency The address of the ERC20 token to approve. Use `address(0)` for native tokens. - function approve( + function _approve( address to, uint256 amount, address currency - ) public virtual onlyValidOperation(to, amount) returns (uint256) { + ) internal onlyValidOperation(to, amount) returns (uint256) { if (msg.sender == to) revert InvalidOperationParameters(); _sumApprovedAmount(msg.sender, to, amount, currency); emit FundsApproved(msg.sender, to, amount, currency); @@ -68,11 +68,11 @@ abstract contract AllowanceOperatorUpgradeable is Initializable, LedgerUpgradeab /// @param to The address of the recipient whose approval is being revoked. /// @param currency The address of the ERC20 token associated with the approval. Use `address(0)` for native tokens. /// @return The amount of funds that were revoked from the approval. - function revoke( + function _revoke( address to, uint256 amount, address currency - ) public virtual onlyValidOperation(to, amount) returns (uint256) { + ) internal onlyValidOperation(to, amount) returns (uint256) { if (getApprovedAmount(msg.sender, to, currency) < amount) revert NoFundsToRevoke(); _subApprovedAmount(msg.sender, to, amount, currency); emit FundsRevoked(msg.sender, to, amount, currency); @@ -83,11 +83,11 @@ abstract contract AllowanceOperatorUpgradeable is Initializable, LedgerUpgradeab /// @param from The address of the account from which the approved funds are being collected. /// @param amount The amount of funds to collect. /// @param currency The address of the ERC20 token to collect. Use `address(0)` for native tokens. - function collect( + function _collect( address from, uint256 amount, address currency - ) public virtual onlyValidOperation(from, amount) returns (uint256) { + ) internal onlyValidOperation(from, amount) returns (uint256) { if (getApprovedAmount(from, msg.sender, currency) < amount) revert NoFundsToCollect(); // if (getLedgerBalance(from, currency) < amount) revert NoFundsToCollect(); // no balance diff --git a/contracts/core/primitives/upgradeable/BalanceOperatorUpgradeable.sol b/contracts/core/primitives/upgradeable/BalanceOperatorUpgradeable.sol index f7dc9b2..99aba4e 100644 --- a/contracts/core/primitives/upgradeable/BalanceOperatorUpgradeable.sol +++ b/contracts/core/primitives/upgradeable/BalanceOperatorUpgradeable.sol @@ -4,7 +4,6 @@ pragma solidity 0.8.26; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; // solhint-disable-next-line max-line-length -import { ReentrancyGuardTransientUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardTransientUpgradeable.sol"; import { LedgerUpgradeable } from "@synaps3/core/primitives/upgradeable/LedgerUpgradeable.sol"; import { IBalanceOperator } from "@synaps3/core/interfaces/base/IBalanceOperator.sol"; import { FinancialOps } from "@synaps3/core/libraries/FinancialOps.sol"; @@ -13,12 +12,7 @@ import { FinancialOps } from "@synaps3/core/libraries/FinancialOps.sol"; /// @dev Abstract contract for managing deposits and withdrawals with ledger tracking capabilities. /// Provides core functionalities to handle funds in an upgradeable system. /// This contract integrates with the ledger system to record balances and transactions. -abstract contract BalanceOperatorUpgradeable is - Initializable, - LedgerUpgradeable, - ReentrancyGuardTransientUpgradeable, - IBalanceOperator -{ +abstract contract BalanceOperatorUpgradeable is Initializable, LedgerUpgradeable, IBalanceOperator { using FinancialOps for address; /// @custom:storage-location erc7201:balanceoperatorupgradeable @@ -36,7 +30,6 @@ abstract contract BalanceOperatorUpgradeable is /// This is the method to initialize this contract and any other extended contracts. function __BalanceOperator_init() internal onlyInitializing { __Ledger_init(); - __ReentrancyGuardTransient_init(); } /// @dev Function to initialize the contract without chaining, typically used in child contracts. @@ -54,11 +47,11 @@ abstract contract BalanceOperatorUpgradeable is /// @param recipient The address of the account to credit with the deposit. /// @param amount The amount of currency to deposit. /// @param currency The address of the ERC20 token to deposit. - function deposit( + function _deposit( address recipient, uint256 amount, address currency - ) public virtual onlyValidOperation(recipient, amount) returns (uint256) { + ) internal onlyValidOperation(recipient, amount) returns (uint256) { uint256 confirmed = msg.sender.safeDeposit(amount, currency); _sumLedgerEntry(recipient, confirmed, currency); emit FundsDeposited(recipient, msg.sender, confirmed, currency); @@ -69,11 +62,11 @@ abstract contract BalanceOperatorUpgradeable is /// @param recipient The address that will receive the withdrawn tokens. /// @param amount The amount of tokens to withdraw. /// @param currency The currency to associate fees with. Use address(0) for the native coin. - function withdraw( + function _withdraw( address recipient, uint256 amount, address currency - ) public virtual onlyValidOperation(recipient, amount) nonReentrant returns (uint256) { + ) internal onlyValidOperation(recipient, amount) returns (uint256) { if (getLedgerBalance(msg.sender, currency) < amount) revert NoFundsToWithdraw(); _subLedgerEntry(msg.sender, amount, currency); recipient.transfer(amount, currency); // transfer fund to recipient @@ -85,11 +78,11 @@ abstract contract BalanceOperatorUpgradeable is /// @param recipient The address of the account to credit with the transfer. /// @param amount The amount of tokens to transfer. /// @param currency The address of the currency to transfer. Use `address(0)` for the native coin. - function transfer( + function _transfer( address recipient, uint256 amount, address currency - ) public virtual onlyValidOperation(recipient, amount) returns (uint256) { + ) internal onlyValidOperation(recipient, amount) returns (uint256) { if (msg.sender == recipient) revert InvalidOperationParameters(); if (getLedgerBalance(msg.sender, currency) < amount) revert NoFundsToTransfer(); diff --git a/contracts/custody/CustodianReferendum.sol b/contracts/custody/CustodianReferendum.sol index 8a369f9..bd58687 100644 --- a/contracts/custody/CustodianReferendum.sol +++ b/contracts/custody/CustodianReferendum.sol @@ -79,7 +79,6 @@ contract CustodianReferendum is // in that way the custodian is omitted during load balancing. // in this line we can check if the custodian contract is active custodian.isActive() // this is important feature if the custodians want to avoid harm reputation - return _status(uint160(custodian)) == T.Status.Active; } @@ -99,7 +98,7 @@ contract CustodianReferendum is /// @notice Registers a custodian to be approved by council. /// @param custodian The address of the custodian to register. - function register(address custodian) external onlyValidCustodian(custodian) { + function register(address custodian) external whenNotPaused onlyValidCustodian(custodian) { // register custodian as pending approval _register(uint160(custodian)); // set the custodian active enrollment period.. diff --git a/contracts/economics/Treasury.sol b/contracts/economics/Treasury.sol index 294bdb4..5b2c1fd 100644 --- a/contracts/economics/Treasury.sol +++ b/contracts/economics/Treasury.sol @@ -5,6 +5,7 @@ pragma solidity 0.8.26; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import { AccessControlledUpgradeable } from "@synaps3/core/primitives/upgradeable/AccessControlledUpgradeable.sol"; +import { ReentrancyGuardTransientUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardTransientUpgradeable.sol"; import { BalanceOperatorUpgradeable } from "@synaps3/core/primitives/upgradeable/BalanceOperatorUpgradeable.sol"; import { ITreasury } from "@synaps3/core/interfaces/economics/ITreasury.sol"; @@ -19,6 +20,7 @@ contract Treasury is Initializable, UUPSUpgradeable, AccessControlledUpgradeable, + ReentrancyGuardTransientUpgradeable, BalanceOperatorUpgradeable, ITreasury { @@ -41,6 +43,7 @@ contract Treasury is function initialize(address accessManager) public initializer { __UUPSUpgradeable_init(); __BalanceOperator_init(); + __ReentrancyGuardTransient_init(); __AccessControlled_init(accessManager); } @@ -52,18 +55,49 @@ contract Treasury is // function allocate(address pool, uint256 amount) restricted; // eg: proposal: deposit N fees to staking pool, deposit N fees to development pool, rewards, etc - /// @notice Deposits a specified amount of currency into the treasury for a given recipient. - /// @param pool The address of the pool to credit with the deposit. + /// @notice Deposits a specified amount of currency into the treasury for a given recipient (pool). + /// @dev Only whitelisted accounts (via `restricted`) can interact with this method. + /// This prevents arbitrary accounts from injecting funds into the treasury. + /// @param pool The address of the pool credited with the deposit. /// @param amount The amount of currency to deposit. - /// @param currency The address of the ERC20 token to deposit. + /// @param currency The address of the ERC20 token to deposit (use `address(0)` for native). + /// @return The confirmed deposited amount. function deposit( address pool, uint256 amount, address currency - ) public override(BalanceOperatorUpgradeable) restricted returns (uint256) { - // restricted deposit to avoid invalid operations - // only allowed accounts can interact with this method - return super.deposit(pool, amount, currency); + ) external whenNotPaused restricted returns (uint256) { + return _deposit(pool, amount, currency); + } + + /// @notice Withdraws tokens from the treasury to a specified recipient. + /// @dev Restricted to authorized accounts (via `restricted`). + /// Ensures treasury funds are only withdrawn under governance-approved flows. + /// @param recipient The address receiving the withdrawn tokens. + /// @param amount The amount of tokens to withdraw. + /// @param currency The token address for the withdrawal (use `address(0)` for native). + /// @return The confirmed withdrawn amount. + function withdraw( + address recipient, + uint256 amount, + address currency + ) external whenNotPaused restricted returns (uint256) { + return _withdraw(recipient, amount, currency); + } + + /// @notice Transfers tokens internally in the treasury ledger from the caller to a recipient. + /// @dev Restricted to authorized accounts (via `restricted`). + /// Unlike `withdraw`, this does not move funds externally but shifts balances inside the ledger. + /// @param recipient The address credited with the transfer. + /// @param amount The amount to transfer. + /// @param currency The token being transferred (use `address(0)` for native). + /// @return The confirmed transferred amount. + function transfer( + address recipient, + uint256 amount, + address currency + ) external whenNotPaused restricted returns (uint256) { + return _transfer(recipient, amount, currency); } /// @notice Collects accrued fees for a specified currency from an authorized fee collector. (visitable) @@ -72,7 +106,7 @@ contract Treasury is /// Only the governor can execute this function, ensuring controlled fee collection. /// @param collector The address of an authorized fee collector. /// @param currency The address of the ERC20 token for which fees are being collected. - function collectFees(address collector, address currency) external restricted nonReentrant { + function collectFees(address collector, address currency) external restricted whenNotPaused nonReentrant { // TODO update adding amount param on disburse call // IFeesCollector feesCollector = IFeesCollector(collector); // uint256 collected = feesCollector.disburse(currency); diff --git a/contracts/financial/LedgerVault.sol b/contracts/financial/LedgerVault.sol index 4c87bb3..e479280 100644 --- a/contracts/financial/LedgerVault.sol +++ b/contracts/financial/LedgerVault.sol @@ -6,6 +6,8 @@ import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/I import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import { AccessControlledUpgradeable } from "@synaps3/core/primitives/upgradeable/AccessControlledUpgradeable.sol"; import { AllowanceOperatorUpgradeable } from "@synaps3/core/primitives/upgradeable/AllowanceOperatorUpgradeable.sol"; +import { LockOperatorUpgradeable } from "@synaps3/core/primitives/upgradeable/LockOperatorUpgradeable.sol"; +import { ReentrancyGuardTransientUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardTransientUpgradeable.sol"; import { BalanceOperatorUpgradeable } from "@synaps3/core/primitives/upgradeable/BalanceOperatorUpgradeable.sol"; import { ILedgerVault } from "@synaps3/core/interfaces/financial/ILedgerVault.sol"; @@ -18,49 +20,13 @@ import { FinancialOps } from "@synaps3/core/libraries/FinancialOps.sol"; contract LedgerVault is Initializable, UUPSUpgradeable, + ReentrancyGuardTransientUpgradeable, AccessControlledUpgradeable, AllowanceOperatorUpgradeable, BalanceOperatorUpgradeable, + LockOperatorUpgradeable, ILedgerVault { - using FinancialOps for address; - - /// @dev Holds the registry of locked funds for accounts. - mapping(address => mapping(address => uint256)) private _locked; - - /// @notice Emitted when funds are locked in the ledger. - /// @param initiator The address of the entity initiating the lock. - /// @param from The address of the account whose funds were locked. - /// @param amount The amount of funds that were locked. - /// @param currency The address of the currency in which the funds were locked. - event FundsLocked(address indexed initiator, address indexed from, uint256 amount, address indexed currency); - - /// @notice Emitted when locked funds are successfully released. - /// @param initiator The address of the entity initiating the release. - /// @param recipient The address of the account whose funds were released. - /// @param amount The amount of funds that were locked. - /// @param currency The address of the currency in which the funds were locked. - event FundsReleased(address indexed initiator, address indexed recipient, uint256 amount, address indexed currency); - - /// @notice Emitted when locked funds are successfully claimed. - /// @param initiator The address of the entity initiating the claim. - /// @param from The address of the account whose funds were claimed. - /// @param amount The amount of funds claimed. - /// @param currency The address of the currency in which the funds were claimed. - event FundsClaimed(address indexed initiator, address indexed from, uint256 amount, address indexed currency); - - /// @notice Thrown when there are no available funds to lock. - /// @dev This error occurs if an account attempts to lock more funds than available. - error NoFundsToLock(); - - /// @notice Thrown when there are no locked funds available to claim. - /// @dev This error occurs if an account or claimer tries to claim funds that are not locked or insufficient. - error NoFundsToClaim(); - - /// @notice Thrown when there are no locked funds available to release. - /// @dev This error occurs if an operator tries to releases funds that are not locked or insufficient. - error NoFundsToRelease(); - /// @custom:oz-upgrades-unsafe-allow constructor constructor() { /// https://forum.openzeppelin.com/t/uupsupgradeable-vulnerability-post-mortem/15680 @@ -69,9 +35,12 @@ contract LedgerVault is } function initialize(address accessManager) public initializer { + __Pausable_init(); + __LockOperator_init(); __UUPSUpgradeable_init(); __BalanceOperator_init(); __AllowanceOperator_init(); + __ReentrancyGuardTransient_init(); __AccessControlled_init(accessManager); } @@ -86,12 +55,8 @@ contract LedgerVault is address account, uint256 amount, address currency - ) external restricted onlyValidOperation(account, amount) returns (uint256) { - if (getLedgerBalance(account, currency) < amount) revert NoFundsToLock(); - _subLedgerEntry(account, amount, currency); - _sumLockedAmount(account, amount, currency); - emit FundsLocked(msg.sender, account, amount, currency); - return amount; + ) external restricted whenNotPaused onlyValidOperation(account, amount) returns (uint256) { + return _lock(account, amount, currency); } /// @notice Release a specific amount of funds from locked pool. @@ -102,12 +67,8 @@ contract LedgerVault is address account, uint256 amount, address currency - ) external restricted onlyValidOperation(account, amount) returns (uint256) { - if (_getLockedAmount(account, currency) < amount) revert NoFundsToRelease(); - _subLockedAmount(account, amount, currency); - _sumLedgerEntry(account, amount, currency); - emit FundsReleased(msg.sender, account, amount, currency); - return amount; + ) external restricted whenNotPaused onlyValidOperation(account, amount) returns (uint256) { + return _release(account, amount, currency); } /// @notice Claims a specific amount of locked funds on behalf of a claimer. @@ -120,39 +81,60 @@ contract LedgerVault is address account, uint256 amount, address currency - ) external restricted onlyValidOperation(account, amount) returns (uint256) { - if (_getLockedAmount(account, currency) < amount) revert NoFundsToClaim(); - _subLockedAmount(account, amount, currency); // - _sumLedgerEntry(msg.sender, amount, currency); - emit FundsClaimed(msg.sender, account, amount, currency); - return amount; + ) external restricted whenNotPaused onlyValidOperation(account, amount) returns (uint256) { + return _claim(account, amount, currency); } - /// @notice Reduces the locked funds of an account for a specific currency. - /// @dev Deducts the specified `amount` from the `_locked` mapping for the given `account` and `currency`. - /// @param account The address of the account whose locked funds are being reduced. - /// @param amount The amount to subtract from the locked balance. - /// @param currency The address of the currency being reduced. - function _subLockedAmount(address account, uint256 amount, address currency) private { - _locked[account][currency] -= amount; + /// @notice Approves a specific amount of funds from the caller's balance for a recipient. + /// @param to The address of the recipient for whom the funds are being approved. + /// @param amount The amount of funds to approve. + /// @param currency The address of the ERC20 token to approve. Use `address(0)` for native tokens. + function approve(address to, uint256 amount, address currency) external whenNotPaused returns (uint256) { + return _approve(to, amount, currency); } - /// @notice Increases the locked funds of an account for a specific currency. - /// @dev Adds the specified `amount` to the `_locked` mapping for the given `account` and `currency`. - /// @param account The address of the account whose locked funds are being increased. - /// @param amount The amount to add to the locked balance. - /// @param currency The address of the currency being increased. - function _sumLockedAmount(address account, uint256 amount, address currency) private { - _locked[account][currency] += amount; + /// @notice Revokes the approved funds from the caller's balance for a specific recipient. + /// @param to The address of the recipient whose approval is being revoked. + /// @param currency The address of the ERC20 token associated with the approval. Use `address(0)` for native tokens. + /// @return The amount of funds that were revoked from the approval. + function revoke(address to, uint256 amount, address currency) external whenNotPaused returns (uint256) { + return _revoke(to, amount, currency); + } + + /// @notice Collects a specific amount of previously approved funds. + /// @param from The address of the account from which the approved funds are being collected. + /// @param amount The amount of funds to collect. + /// @param currency The address of the ERC20 token to collect. Use `address(0)` for native tokens. + function collect(address from, uint256 amount, address currency) external whenNotPaused returns (uint256) { + return _collect(from, amount, currency); + } + + /// @notice Deposits a specified amount of currency into the contract for a given recipient. + /// @param recipient The address of the account to credit with the deposit. + /// @param amount The amount of currency to deposit. + /// @param currency The address of the ERC20 token to deposit. + function deposit(address recipient, uint256 amount, address currency) external whenNotPaused returns (uint256) { + return _deposit(recipient, amount, currency); + } + + /// @notice Withdraws tokens from the contract to a specified recipient's address. + /// @param recipient The address that will receive the withdrawn tokens. + /// @param amount The amount of tokens to withdraw. + /// @param currency The currency to associate fees with. Use address(0) for the native coin. + function withdraw( + address recipient, + uint256 amount, + address currency + ) external whenNotPaused nonReentrant returns (uint256) { + return _withdraw(recipient, amount, currency); } - /// @notice Retrieves the locked balance of an account for a specific currency. - /// @dev Returns the value stored in the `_locked` mapping for the given `account` and `currency`. - /// @param account The address of the account whose locked balance is being queried. - /// @param currency The address of the currency to check the locked balance for. - /// @return The locked balance of the specified account for the given currency. - function _getLockedAmount(address account, address currency) private view returns (uint256) { - return _locked[account][currency]; + /// @notice Transfers tokens internally within the ledger from the caller to a specified recipient. + /// @param recipient The address of the account to credit with the transfer. + /// @param amount The amount of tokens to transfer. + /// @param currency The address of the currency to transfer. Use `address(0)` for the native coin. + function transfer(address recipient, uint256 amount, address currency) external whenNotPaused returns (uint256) { + return _transfer(recipient, amount, currency); } /// @notice Function that should revert when msg.sender is not authorized to upgrade the contract. diff --git a/test/primitives/BalanceOperator.t.sol b/test/primitives/BalanceOperator.t.sol index ab8c9b4..541dde8 100644 --- a/test/primitives/BalanceOperator.t.sol +++ b/test/primitives/BalanceOperator.t.sol @@ -11,7 +11,19 @@ import { IBalanceTransferable } from "contracts/core/interfaces/base/IBalanceTra import { IBalanceWithdrawable } from "contracts/core/interfaces/base/IBalanceWithdrawable.sol"; import { BalanceOperatorUpgradeable } from "contracts/core/primitives/upgradeable/BalanceOperatorUpgradeable.sol"; -contract BalanceOperatorWrapper is BalanceOperatorUpgradeable {} +contract BalanceOperatorWrapper is BalanceOperatorUpgradeable { + function deposit(address recipient, uint256 amount, address currency) external returns (uint256) { + return _deposit(recipient, amount, currency); + } + + function withdraw(address recipient, uint256 amount, address currency) external returns (uint256) { + return _withdraw(recipient, amount, currency); + } + + function transfer(address recipient, uint256 amount, address currency) external returns (uint256) { + return _transfer(recipient, amount, currency); + } +} contract BalanceOperatorTest is BaseTest { address op; From ba185abb79482b232731f2bfb893a3024db1a1f1 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Thu, 21 Aug 2025 13:07:12 -0600 Subject: [PATCH 04/33] refactor: added pause protocol --- .../core/interfaces/base/ILockClaimer.sol | 23 ++++ .../core/interfaces/base/ILockLocker.sol | 24 ++++ .../core/interfaces/base/ILockOperator.sol | 13 ++ .../core/interfaces/base/ILockReleaser.sol | 23 ++++ .../upgradeable/LockOperatorUpgradeable.sol | 128 ++++++++++++++++++ test/assets/AssetOwnership.sol | 22 +++ 6 files changed, 233 insertions(+) create mode 100644 contracts/core/interfaces/base/ILockClaimer.sol create mode 100644 contracts/core/interfaces/base/ILockLocker.sol create mode 100644 contracts/core/interfaces/base/ILockOperator.sol create mode 100644 contracts/core/interfaces/base/ILockReleaser.sol create mode 100644 contracts/core/primitives/upgradeable/LockOperatorUpgradeable.sol create mode 100644 test/assets/AssetOwnership.sol diff --git a/contracts/core/interfaces/base/ILockClaimer.sol b/contracts/core/interfaces/base/ILockClaimer.sol new file mode 100644 index 0000000..e8651ed --- /dev/null +++ b/contracts/core/interfaces/base/ILockClaimer.sol @@ -0,0 +1,23 @@ +/// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +/// @title ILockClaimer +/// @notice Interface for claiming locked funds in favor of an authorized claimer. +interface ILockClaimer { + /// @notice Emitted when locked funds are claimed. + /// @param initiator Address that initiates the operation (claimer). + /// @param from Account from which funds are claimed. + /// @param amount Amount claimed. + /// @param currency Currency address; use address(0) for native coin. + event FundsClaimed(address indexed initiator, address indexed from, uint256 amount, address indexed currency); + + /// @notice Error raised when there are not enough locked funds to claim. + error NoFundsToClaim(); + + /// @notice Claims a specific amount of locked funds on behalf of an authorized claimer. + /// @param account The address of the account whose funds are being claimed. + /// @param amount The amount of funds to claim. + /// @param currency The currency to associate with the claim; use address(0) for the native coin. + /// @return An identifier or updated state depending on implementation. + function claim(address account, uint256 amount, address currency) external returns (uint256); +} diff --git a/contracts/core/interfaces/base/ILockLocker.sol b/contracts/core/interfaces/base/ILockLocker.sol new file mode 100644 index 0000000..be92854 --- /dev/null +++ b/contracts/core/interfaces/base/ILockLocker.sol @@ -0,0 +1,24 @@ +/// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +/// @title ILockLocker +/// @notice Interface for locking funds in an account. +interface ILockLocker { + + /// @notice Emitted when funds are locked. + /// @param initiator Address that initiates the operation. + /// @param from Account whose funds are being locked. + /// @param amount Amount locked. + /// @param currency Currency address; use address(0) for native coin. + event FundsLocked(address indexed initiator, address indexed from, uint256 amount, address indexed currency); + + /// @notice Error raised when there are not enough funds to lock. + error NoFundsToLock(); + + /// @notice Locks a specific amount of funds for a given account. + /// @param account The address of the account whose funds will be locked. + /// @param amount The amount of funds to lock. + /// @param currency The currency to associate with the lock; use address(0) for the native coin. + /// @return An identifier or updated state depending on implementation. + function lock(address account, uint256 amount, address currency) external returns (uint256); +} diff --git a/contracts/core/interfaces/base/ILockOperator.sol b/contracts/core/interfaces/base/ILockOperator.sol new file mode 100644 index 0000000..98e3472 --- /dev/null +++ b/contracts/core/interfaces/base/ILockOperator.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import { ILockClaimer } from "@synaps3/core/interfaces/base/ILockClaimer.sol"; +import { ILockReleaser } from "@synaps3/core/interfaces/base/ILockReleaser.sol"; +import { ILockLocker } from "@synaps3/core/interfaces/base/ILockLocker.sol"; + +/// @title ILockOperator +/// @notice Unified interface that composes locker, releaser, and claimer capabilities. +/// @dev Adds a common read method to query the locked balance. +interface ILockOperator is ILockClaimer, ILockLocker, ILockReleaser { + +} diff --git a/contracts/core/interfaces/base/ILockReleaser.sol b/contracts/core/interfaces/base/ILockReleaser.sol new file mode 100644 index 0000000..df61de1 --- /dev/null +++ b/contracts/core/interfaces/base/ILockReleaser.sol @@ -0,0 +1,23 @@ +/// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +/// @title ILockReleaser +/// @notice Interface for releasing previously locked funds. +interface ILockReleaser { + /// @notice Emitted when locked funds are released. + /// @param initiator Address that initiates the operation. + /// @param recipient Account receiving the released funds. + /// @param amount Amount released. + /// @param currency Currency address; use address(0) for native coin. + event FundsReleased(address indexed initiator, address indexed recipient, uint256 amount, address indexed currency); + + /// @notice Error raised when there are not enough locked funds to release. + error NoFundsToRelease(); + + /// @notice Releases a specific amount of funds from the locked pool. + /// @param account The address of the account whose funds will be released. + /// @param amount The amount of funds to release. + /// @param currency The currency to associate with the release; use address(0) for the native coin. + /// @return An identifier or updated state depending on implementation. + function release(address account, uint256 amount, address currency) external returns (uint256); +} diff --git a/contracts/core/primitives/upgradeable/LockOperatorUpgradeable.sol b/contracts/core/primitives/upgradeable/LockOperatorUpgradeable.sol new file mode 100644 index 0000000..ce8f021 --- /dev/null +++ b/contracts/core/primitives/upgradeable/LockOperatorUpgradeable.sol @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: BUSL-1.1 +// NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html +pragma solidity 0.8.26; + +import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import { LedgerUpgradeable } from "@synaps3/core/primitives/upgradeable/LedgerUpgradeable.sol"; +import { ILockOperator } from "@synaps3/core/interfaces/base/ILockOperator.sol"; +import { FinancialOps } from "@synaps3/core/libraries/FinancialOps.sol"; + +abstract contract LockOperatorUpgradeable is Initializable, LedgerUpgradeable, ILockOperator { + using FinancialOps for address; + + /// @custom:storage-location erc7201:lockoperatorupgradeable + struct LockOperatorStorage { + /// @dev Holds the relation between approved funds, the currency, and amount + /// @dev Holds the registry of locked funds for accounts. + mapping(address => mapping(address => uint256)) _locked; + } + + /// @dev Storage slot for LockOperatorUpgradeable, calculated using a unique namespace to avoid conflicts. + /// The `LOCK_OPERATOR_SLOT` constant is used to point to the location of the storage. + bytes32 private constant LOCK_OPERATOR_SLOT = + 0xece3ff917f3a3127e521e0c3f2f90ff09a3c8199be32f9b40bff79e776960800; + + /// @dev Initializes the contract and ensures it is upgradeable. + /// Even if the initialization is harmless, this ensures the contract follows upgradeable contract patterns. + /// This is the method to initialize this contract and any other extended contracts. + /// slither-disable-next-line naming-convention + function __LockOperator_init() internal onlyInitializing { + __Ledger_init(); + } + + /// @dev Function to initialize the contract without chaining, typically used in child contracts. + /// This is the method to initialize this contract as standalone. + /// slither-disable-next-line naming-convention + function __LockOperator_init_unchained() internal onlyInitializing {} + + /// @notice Locks a specific amount of funds for a given account. + /// @dev The funds are immobilized and cannot be withdrawn or transferred until released. + /// Only operator role can handle this methods. + /// An approval is not needed, the protocol operate directly on the user funds to simplify operations. + /// @param account The address of the account for which the funds will be locked. + /// @param amount The amount of funds to lock. + /// @param currency The currency to associate lock with. Use address(0) for the native coin. + function _lock( + address account, + uint256 amount, + address currency + ) internal onlyValidOperation(account, amount) returns (uint256) { + if (getLedgerBalance(account, currency) < amount) revert NoFundsToLock(); + _subLedgerEntry(account, amount, currency); + _sumLockedAmount(account, amount, currency); + emit FundsLocked(msg.sender, account, amount, currency); + return amount; + } + + /// @notice Release a specific amount of funds from locked pool. + /// @param account The address of the account for which the funds will be released. + /// @param amount The amount of funds to release. + /// @param currency The currency to associate release with. Use address(0) for the native coin. + function _release( + address account, + uint256 amount, + address currency + ) internal onlyValidOperation(account, amount) returns (uint256) { + if (_getLockedAmount(account, currency) < amount) revert NoFundsToRelease(); + _subLockedAmount(account, amount, currency); + _sumLedgerEntry(account, amount, currency); + emit FundsReleased(msg.sender, account, amount, currency); + return amount; + } + + /// @notice Claims a specific amount of locked funds on behalf of a claimer. + /// @dev The claimer is authorized to process the funds from the account. + /// Only operator role can handle this methods. + /// @param account The address of the account whose funds are being claimed. + /// @param amount The amount of funds to claim. + /// @param currency The currency to associate claim with. Use address(0) for the native coin. + function _claim( + address account, + uint256 amount, + address currency + ) internal onlyValidOperation(account, amount) returns (uint256) { + if (_getLockedAmount(account, currency) < amount) revert NoFundsToClaim(); + _subLockedAmount(account, amount, currency); // + _sumLedgerEntry(msg.sender, amount, currency); + emit FundsClaimed(msg.sender, account, amount, currency); + return amount; + } + + /// @notice Reduces the locked funds of an account for a specific currency. + /// @dev Deducts the specified `amount` from the `_locked` mapping for the given `account` and `currency`. + /// @param account The address of the account whose locked funds are being reduced. + /// @param amount The amount to subtract from the locked balance. + /// @param currency The address of the currency being reduced. + function _subLockedAmount(address account, uint256 amount, address currency) private { + LockOperatorStorage storage $ = _getLockOperatorStorage(); + $._locked[account][currency] -= amount; + } + + /// @notice Increases the locked funds of an account for a specific currency. + /// @dev Adds the specified `amount` to the `_locked` mapping for the given `account` and `currency`. + /// @param account The address of the account whose locked funds are being increased. + /// @param amount The amount to add to the locked balance. + /// @param currency The address of the currency being increased. + function _sumLockedAmount(address account, uint256 amount, address currency) private { + LockOperatorStorage storage $ = _getLockOperatorStorage(); + $._locked[account][currency] += amount; + } + + /// @notice Retrieves the locked balance of an account for a specific currency. + /// @dev Returns the value stored in the `_locked` mapping for the given `account` and `currency`. + /// @param account The address of the account whose locked balance is being queried. + /// @param currency The address of the currency to check the locked balance for. + /// @return The locked balance of the specified account for the given currency. + function _getLockedAmount(address account, address currency) private view returns (uint256) { + LockOperatorStorage storage $ = _getLockOperatorStorage(); + return $._locked[account][currency]; + } + + /// @notice Internal function to get the allowance operator storage. + /// @dev Uses assembly to retrieve the storage at the pre-calculated storage slot. + function _getLockOperatorStorage() private pure returns (LockOperatorStorage storage $) { + assembly { + $.slot := LOCK_OPERATOR_SLOT + } + } +} diff --git a/test/assets/AssetOwnership.sol b/test/assets/AssetOwnership.sol new file mode 100644 index 0000000..541b861 --- /dev/null +++ b/test/assets/AssetOwnership.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import "forge-std/Test.sol"; +import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; +import { IAssetRegistrable } from "contracts/core/interfaces/assets/IAssetRegistrable.sol"; +import { IAssetRevokable } from "contracts/core/interfaces/assets/IAssetRevokable.sol"; +import { IAssetVerifiable } from "contracts/core/interfaces/assets/IAssetVerifiable.sol"; +import { AssetReferendum } from "contracts/assets/AssetReferendum.sol"; + +import { BaseTest } from "test/BaseTest.t.sol"; +import { T } from "contracts/core/primitives/Types.sol"; +import { C } from "contracts/core/primitives/Constants.sol"; + +contract AssetOwnershipTest is BaseTest { + function setUp() public initialize { + // setup the access manager to use during tests.. + deployAssetOwnership(); + } + + +} From 3f3ab1f6de3369be2b51c7b29564e5370b17875c Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Wed, 27 Aug 2025 18:21:13 -0600 Subject: [PATCH 05/33] tests: invariant balance operator --- contracts/access/AccessManager.sol | 12 +- contracts/assets/AssetOwnership.sol | 4 +- .../core/interfaces/base/ILockLocker.sol | 1 - .../core/interfaces/base/ILockOperator.sol | 4 +- .../interfaces/financial/ILedgerVault.sol | 4 +- contracts/core/primitives/Constants.sol | 5 +- contracts/core/primitives/Types.sol | 33 ++-- .../upgradeable/LockOperatorUpgradeable.sol | 5 +- contracts/custody/CustodianImpl.sol | 2 +- contracts/financial/AgreementManager.sol | 89 +++++++--- contracts/financial/AgreementSettler.sol | 30 +++- contracts/lifecycle/HookRegistry.sol | 7 +- contracts/policies/PolicyAudit.sol | 4 +- contracts/rights/RightsPolicyManager.sol | 4 + foundry.toml | 5 + .../01_Orchestrate_ProtocolHydration.s.sol | 13 +- test/BaseTest.t.sol | 4 +- test/custody/CustodianImpl.t.sol | 9 + test/primitives/BalanceOperator.t.sol | 154 ++++++++++++++---- 19 files changed, 275 insertions(+), 114 deletions(-) diff --git a/contracts/access/AccessManager.sol b/contracts/access/AccessManager.sol index bce5066..d33429a 100644 --- a/contracts/access/AccessManager.sol +++ b/contracts/access/AccessManager.sol @@ -39,12 +39,10 @@ contract AccessManager is Initializable, UUPSUpgradeable, AccessManagerUpgradeab // // Group/Council Based Roles: // - ADMIN_ROLE: Managed by a smart account or council. - // Handles protocol upgrades, pause mechanisms, and operational role assignments. - // - MOD_ROLE: Managed by a smart account or council. // Approves policy submissions and moderates hook operations. // - CONTENT_COUNCIL_ROLE: Managed by a smart account or council. // Participates in governance referenda for content curation. - // - NODE_VALIDATOR_ROLE: Managed by a smart account or council. + // - CUSTODY_COUNCIL_ROLE: Managed by a smart account or council. // Participates in governance referenda for nodes validation. // // Individual/Contract Based Roles: @@ -58,22 +56,18 @@ contract AccessManager is Initializable, UUPSUpgradeable, AccessManagerUpgradeab │ ├── ADMIN_ROLE (Smart Account / Council) │ │ - │ ├── MOD_ROLE (Smart Account / Council) - │ │ │ └── OPS_ROLE (Internal Contract Role) │ ├── CONTENT_COUNCIL_ROLE (Smart Account / Council) │ - ├── NODE_VALIDATOR_ROLE (Smart Account / Council) + ├── CUSTODY_COUNCIL_ROLE (Smart Account / Council) │ ├── VER_ROLE (Individual Trusted Creator) */ - _setRoleAdmin(C.MOD_ROLE, C.ADMIN_ROLE); _setRoleAdmin(C.OPS_ROLE, C.ADMIN_ROLE); - _setRoleAdmin(C.VER_ROLE, C.GOV_ROLE); - _setRoleAdmin(C.NODE_VALIDATOR_ROLE, C.GOV_ROLE); + _setRoleAdmin(C.CUSTODY_COUNCIL_ROLE, C.GOV_ROLE); _setRoleAdmin(C.CONTENT_COUNCIL_ROLE, C.GOV_ROLE); } diff --git a/contracts/assets/AssetOwnership.sol b/contracts/assets/AssetOwnership.sol index 7ef4676..21298a0 100644 --- a/contracts/assets/AssetOwnership.sol +++ b/contracts/assets/AssetOwnership.sol @@ -111,7 +111,6 @@ contract AssetOwnership is return super.supportsInterface(interfaceId); } - // TODO: build getURI => from custodian /erc721-metadata // TODO: Update asset info control version restricted/approved by governance // TODO: Transfer Ownership Fee: Introducing a fee for transferring // ownership discourages frequent or unnecessary transfers, @@ -125,8 +124,7 @@ contract AssetOwnership is /// @dev Requires approval before an asset can be registered. /// @param to The address that will own the minted NFT. /// @param assetId The unique identifier for the asset, serving as the NFT ID. - // TODO pause - function register(address to, uint256 assetId) external onlyApprovedAsset(to, assetId) { + function register(address to, uint256 assetId) external whenNotPaused onlyApprovedAsset(to, assetId) { _mint(to, assetId); _enableAsset(assetId); emit RegisteredAsset(to, assetId); diff --git a/contracts/core/interfaces/base/ILockLocker.sol b/contracts/core/interfaces/base/ILockLocker.sol index be92854..ec36cee 100644 --- a/contracts/core/interfaces/base/ILockLocker.sol +++ b/contracts/core/interfaces/base/ILockLocker.sol @@ -4,7 +4,6 @@ pragma solidity 0.8.26; /// @title ILockLocker /// @notice Interface for locking funds in an account. interface ILockLocker { - /// @notice Emitted when funds are locked. /// @param initiator Address that initiates the operation. /// @param from Account whose funds are being locked. diff --git a/contracts/core/interfaces/base/ILockOperator.sol b/contracts/core/interfaces/base/ILockOperator.sol index 98e3472..d85f4c2 100644 --- a/contracts/core/interfaces/base/ILockOperator.sol +++ b/contracts/core/interfaces/base/ILockOperator.sol @@ -8,6 +8,4 @@ import { ILockLocker } from "@synaps3/core/interfaces/base/ILockLocker.sol"; /// @title ILockOperator /// @notice Unified interface that composes locker, releaser, and claimer capabilities. /// @dev Adds a common read method to query the locked balance. -interface ILockOperator is ILockClaimer, ILockLocker, ILockReleaser { - -} +interface ILockOperator is ILockClaimer, ILockLocker, ILockReleaser {} diff --git a/contracts/core/interfaces/financial/ILedgerVault.sol b/contracts/core/interfaces/financial/ILedgerVault.sol index fbcc936..6fcc459 100644 --- a/contracts/core/interfaces/financial/ILedgerVault.sol +++ b/contracts/core/interfaces/financial/ILedgerVault.sol @@ -9,6 +9,4 @@ import { ILockOperator } from "@synaps3/core/interfaces/base/ILockOperator.sol"; /// @title ILedgerVault /// @notice Interface for managing locked funds and their operations. /// @dev Extends IBalanceOperator for managing user balances in a vault-like system. -interface ILedgerVault is IBalanceOperator, IAllowanceOperator, ILockOperator { - -} +interface ILedgerVault is IBalanceOperator, IAllowanceOperator, ILockOperator {} diff --git a/contracts/core/primitives/Constants.sol b/contracts/core/primitives/Constants.sol index 5afa68b..50beab8 100644 --- a/contracts/core/primitives/Constants.sol +++ b/contracts/core/primitives/Constants.sol @@ -13,12 +13,11 @@ library C { uint64 internal constant ADMIN_ROLE = 0; // alias type(uint64).min AccessManager uint64 internal constant GOV_ROLE = 1; // governance role - uint64 internal constant MOD_ROLE = 2; // moderator role + uint64 internal constant OPS_ROLE = 2; // operations roles uint64 internal constant VER_ROLE = 3; // account verified role - uint64 internal constant OPS_ROLE = 4; // operations roles uint64 internal constant CONTENT_COUNCIL_ROLE = 5; // content validation/curation roles - uint64 internal constant NODE_VALIDATOR_ROLE = 6; // nodes validations roles + uint64 internal constant CUSTODY_COUNCIL_ROLE = 6; // nodes validations roles bytes32 internal constant REFERENDUM_SUBMIT_TYPEHASH = keccak256("Submission(uint256 assetId, address initiator, uint256 nonce)"); diff --git a/contracts/core/primitives/Types.sol b/contracts/core/primitives/Types.sol index 6b82cbe..78e9432 100644 --- a/contracts/core/primitives/Types.sol +++ b/contracts/core/primitives/Types.sol @@ -36,17 +36,30 @@ library T { } /// @title Agreement - /// @dev Represents an agreement between multiple parties regarding the distribution and management of asset. - /// @notice This struct captures the total amount involved, net amount after deductions, distribution fees, - /// and the relevant addresses involved in the agreement. + /// @dev Represents an escrow-backed agreement involving payment, distribution or access rights. + /// @notice This struct supports flexible interaction models, including 1:1 and 1:N transfers, + /// purchases, access control, and delegated rights via arbitration. struct Agreement { - address arbiter; // the designated escrow agent enforcing the agreement. - address currency; // the currency used in transaction - address initiator; // the initiator of the transaction - uint256 total; // the transaction total amount - uint256 fees; // the agreement protocol fees - address[] parties; // the accounts or beneficiaries bounded to the agreement - bytes payload; // any additional data needed during agreement execution + /// @notice The authorized arbiter that enforces the agreement logic (e.g., asset transfer or access). + address arbiter; + /// @notice The currency used for settlement (e.g., ETH or ERC20 address). + address currency; + /// @notice The address that initiated the agreement and provided the funds. + /// @dev In a purchase scenario, the initiator is the asset buyer and final recipient of the asset. + /// In access-based agreements, the initiator may be the funder but not necessarily the consumer. + address initiator; + /// @notice Total amount involved in the agreement, including fees. + uint256 total; + /// @notice Protocol or arbitration fees deducted from the total. + uint256 fees; + /// @notice Protocol internal property to handle total locked amount during agreement lifecycle + uint256 locked; + /// @notice List of accounts involved as beneficiaries or consumers of rights. + /// @dev In purchase scenarios, this may be empty (use `initiator` as beneficiary). + /// In access-sharing modelsor multiple agreement this may contain multiple users granted access to content or rights. + address[] parties; + /// @notice Arbitrary data passed for context, such as assetId, license type, content hash, etc. + bytes payload; } /// @title TimeFrame diff --git a/contracts/core/primitives/upgradeable/LockOperatorUpgradeable.sol b/contracts/core/primitives/upgradeable/LockOperatorUpgradeable.sol index ce8f021..830da9f 100644 --- a/contracts/core/primitives/upgradeable/LockOperatorUpgradeable.sol +++ b/contracts/core/primitives/upgradeable/LockOperatorUpgradeable.sol @@ -14,13 +14,12 @@ abstract contract LockOperatorUpgradeable is Initializable, LedgerUpgradeable, I struct LockOperatorStorage { /// @dev Holds the relation between approved funds, the currency, and amount /// @dev Holds the registry of locked funds for accounts. - mapping(address => mapping(address => uint256)) _locked; + mapping(address => mapping(address => uint256)) _locked; } /// @dev Storage slot for LockOperatorUpgradeable, calculated using a unique namespace to avoid conflicts. /// The `LOCK_OPERATOR_SLOT` constant is used to point to the location of the storage. - bytes32 private constant LOCK_OPERATOR_SLOT = - 0xece3ff917f3a3127e521e0c3f2f90ff09a3c8199be32f9b40bff79e776960800; + bytes32 private constant LOCK_OPERATOR_SLOT = 0xece3ff917f3a3127e521e0c3f2f90ff09a3c8199be32f9b40bff79e776960800; /// @dev Initializes the contract and ensures it is upgradeable. /// Even if the initialization is harmless, this ensures the contract follows upgradeable contract patterns. diff --git a/contracts/custody/CustodianImpl.sol b/contracts/custody/CustodianImpl.sol index 3f55e7d..c397c98 100644 --- a/contracts/custody/CustodianImpl.sol +++ b/contracts/custody/CustodianImpl.sol @@ -48,7 +48,7 @@ contract CustodianImpl is /// @dev Ensures that the provided endpoint is valid and initializes ERC165 and Ownable contracts. function initialize(string calldata endpoint, address owner) external initializer { if (bytes(endpoint).length == 0) revert InvalidEndpoint(); - + __ERC165_init(); __Ownable_init(owner); _endpoint = endpoint; diff --git a/contracts/financial/AgreementManager.sol b/contracts/financial/AgreementManager.sol index 4c854d1..d6f36ba 100644 --- a/contracts/financial/AgreementManager.sol +++ b/contracts/financial/AgreementManager.sol @@ -2,7 +2,6 @@ // NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html pragma solidity 0.8.26; -import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import { AccessControlledUpgradeable } from "@synaps3/core/primitives/upgradeable/AccessControlledUpgradeable.sol"; @@ -13,8 +12,7 @@ import { ITollgate } from "@synaps3/core/interfaces/economics/ITollgate.sol"; import { FinancialOps } from "@synaps3/core/libraries/FinancialOps.sol"; import { FeesOps } from "@synaps3/core/libraries/FeesOps.sol"; import { T } from "@synaps3/core/primitives/Types.sol"; - -// TODO Doc: Trustless escrow system - modular escrow framework - escrow mechanism (agreement settlement) +import { C } from "@synaps3/core/primitives/Constants.sol"; /// @title AgreementManager /// @notice Manages the lifecycle (trustless escrow system) of agreements, including creation and retrieval. @@ -23,7 +21,6 @@ import { T } from "@synaps3/core/primitives/Types.sol"; contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpgradeable, IAgreementManager { using FeesOps for uint256; using FinancialOps for address; - using EnumerableSet for EnumerableSet.UintSet; /// KIM: any initialization here is ephemeral and not included in bytecode.. /// so the code within a logic contract’s constructor or global declaration @@ -38,6 +35,10 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg ILedgerVault public immutable LEDGER_VAULT; //slither-disable-end naming-convention + uint256 constant MAX_EXCESS = 13; // 1..13=91%, 14=>105% + /// @notice Maximum allowed number of parties per agreement. + /// @dev Can be updated by admin to adapt system limits. + uint256 private _maxParties; /// @dev Holds a bounded key expressing the agreement between the parts. mapping(uint256 => T.Agreement) private _agreementsByProof; @@ -54,10 +55,13 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg /// @notice Error thrown when a currency is not supported by the specified target. /// @param target The address or context for which the currency is unsupported. /// @param currency The address of the unsupported currency. - error UnsupportedAgreementCurrency(address target, address currency); + error UnsupportedAgreementTarget(address target, address currency); + + /// @notice Error thrown when trying to set an invalid maximum number of parties. + error InvalidMaxParties(uint256 value); - /// @notice Error thrown when an agreement includes no parties. - error NoPartiesInAgreement(); + /// @notice Error thrown when the number of parties exceeds the protocol limit. + error ExceedsMaxParties(); /// @notice Ensures that the specified currency is supported for the given target. /// @dev This modifier verifies if the `currency` is accepted under the context of `target`. @@ -66,7 +70,7 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg /// @param currency The address of the currency being checked. modifier onlySupportedCurrency(address target, address currency) { bool isCurrencySupported = TOLLGATE.isSupportedCurrency(target, currency); - if (!isCurrencySupported) revert UnsupportedAgreementCurrency(target, currency); + if (!isCurrencySupported) revert UnsupportedAgreementTarget(target, currency); _; } @@ -84,6 +88,19 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg function initialize(address accessManager) public initializer { __UUPSUpgradeable_init(); __AccessControlled_init(accessManager); + _maxParties = 5; + } + + /// @notice Updates the maximum number of allowed parties. + /// @param newMax The new maximum number of parties. + function setMaxParties(uint256 newMax) external onlyAdmin { + if (newMax == 0) revert InvalidMaxParties(newMax); + _maxParties = newMax; + } + + /// @notice Retrieves the current max number of parties. + function maxParties() external view returns (uint256) { + return _maxParties; } /// @notice Creates and stores a new agreement. @@ -100,12 +117,13 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg bytes calldata payload ) external onlySupportedCurrency(arbiter, currency) returns (uint256) { // IMPORTANT: The process of distributing funds to accounts should be handled within the settlement logic. - uint256 confirmed = LEDGER_VAULT.lock(msg.sender, amount, currency); - T.Agreement memory agreement = previewAgreement(confirmed, currency, arbiter, parties, payload); + T.Agreement memory agreement = previewAgreement(amount, currency, arbiter, parties, payload); + uint256 confirmed = LEDGER_VAULT.lock(msg.sender, agreement.locked, currency); + // only the initiator can operate with this agreement proof, or transfer the proof to the other party.. // each agreement is unique and immutable, ensuring that it cannot be modified or reconstructed. uint256 proof = _createAndStoreProof(agreement); - emit AgreementCreated(msg.sender, proof, amount, currency); + emit AgreementCreated(msg.sender, proof, confirmed, currency); return proof; } @@ -128,14 +146,6 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg address[] calldata parties, bytes calldata payload ) public view onlySupportedCurrency(arbiter, currency) returns (T.Agreement memory) { - if (parties.length == 0) { - revert NoPartiesInAgreement(); - } - - // TODO Even if we are covered by gas fees, during execution a good way to avoid abuse - // is penalize parties after N length eg. The max parties allowed is 5, any extra - // parties are charged with a extra * fee. Denial of Service risk - // IMPORTANT: // Agreements transport value and represent a defined commitment between parties. // Think of an agreement as similar to a bonus, gift card, prepaid card, or check: @@ -148,7 +158,13 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg // By locking in fees during agreement creation, the protocol avoids scenarios // where fee structures change (favorably or unfavorably) after creation, // which could lead to abuse or exploitation. - uint256 deductions = _calcFees(amount, arbiter, currency); + uint256 baseFees = _calcFees(amount, arbiter, currency); + // Even if we are covered by gas fees, during execution a good way to avoid abuse + // is penalize parties after N length eg. The max parties allowed is 5, any extra + // parties are charged with a extra * fee. Denial of Service risk mitigation.. + uint256 penalization = _calculatePenalization(parties.length, amount); + uint256 totalToLock = amount + penalization; + // This design ensures fairness and transparency by preventing any future // adjustments to fees or protocol conditions from affecting the terms of this agreement. return @@ -157,8 +173,9 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg currency: currency, // the currency used in transaction initiator: msg.sender, // the tx initiator total: amount, // the transaction amount - fees: deductions, // the protocol fees of the agreement - parties: parties, // the accounts related to agreement + fees: baseFees, // the protocol fees of the agreement + locked: totalToLock, // the total to lock, may contain penalization + parties: parties, // the additional accounts related to agreement 1:N agreement payload: payload // any additional data needed during agreement execution }); } @@ -177,6 +194,33 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg return proof; } + /// @dev Calculates the penalization based on parties len and total amount + function _calculatePenalization(uint256 partiesLen, uint256 amount) private view returns (uint256 penalization) { + uint256 hardCap = _maxParties + MAX_EXCESS; + if (partiesLen > hardCap) revert ExceedsMaxParties(); + + // soft cap validation, economic penalization + if (partiesLen > _maxParties) { + uint256 excess = partiesLen - _maxParties; + uint256 multiplierBps = _penaltyBps(excess); + penalization = amount.perOf(multiplierBps); + } + } + + /// @dev Computes the penalty BPS as a arithmetic succession. + /// 1st extra = 1%, 2nd extra = +2%, 3rd extra = +3%, ... + /// Formula: (N * (N + 1) / 2) * 100 + /// @param excess Number of parties beyond the allowed max. + /// @return penaltyBps Total penalty in basis points. + function _penaltyBps(uint256 excess) private pure returns (uint256 penaltyBps) { + if (excess == 0) return 0; + // Formula for the sum of an arithmetic succession: S = n(n + 1) / 2 + // Example: excess = 3 -> 1 + 2 + 3 = 6 % + unchecked { + penaltyBps = ((excess * (excess + 1)) / 2) * 100; + } + } + /// @notice Calculates the fee based on the provided total amount, agent, and currency. /// @dev Reverts if the currency is not supported by the Tollgate or if no fee scheme is defined for the agent. /// @param total The total amount from which the fee will be calculated. @@ -185,7 +229,6 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg /// @return The calculated fee amount based on the applicable fee scheme. function _calcFees(uint256 total, address target, address currency) private view returns (uint256) { // !IMPORTANT if fees manager does not support the currency or the target, will revert.. - // TODO avoid revert, just check if the currency is supported and return 0 (uint256 fees, T.Scheme scheme) = TOLLGATE.getFees(target, currency); if (scheme == T.Scheme.BPS) return total.perOf(fees); // bps calc if (scheme == T.Scheme.NOMINAL) return total.perOf(fees.calcBps()); // nominal to bps diff --git a/contracts/financial/AgreementSettler.sol b/contracts/financial/AgreementSettler.sol index 40064c5..cd030b3 100644 --- a/contracts/financial/AgreementSettler.sol +++ b/contracts/financial/AgreementSettler.sol @@ -152,17 +152,26 @@ contract AgreementSettler is // Penalty fees retained here also help maintain the protocol's economic balance // and ensure that the system operates sustainably over time. uint256 fees = agreement.fees; // keep fees as penalty - uint256 available = agreement.total - fees; // initiator rollback address initiator = agreement.initiator; // the original initiator address currency = agreement.currency; + // eg. total = 100; + // locked = 105 (total + penalization) + // penalization = 5 <- paid by initiator during agreement + // fees = 10 <- 10% + // + // available = 90 + // protocolTake = 10 + 5 + uint256 penalization = agreement.locked - agreement.total; + uint256 available = agreement.total - fees; // initiator rollback + uint256 protocolTake = fees + penalization; _setProofAsSettled(proof); // slither-disable-start unused-return - LEDGER_VAULT.claim(initiator, fees, currency); + LEDGER_VAULT.claim(initiator, protocolTake, currency); // part of the agreement locked amount is released to the account if (available > 0) LEDGER_VAULT.release(initiator, available, currency); // slither-disable-end unused-return - emit AgreementCancelled(initiator, proof, fees); + emit AgreementCancelled(initiator, proof, protocolTake); return agreement; } @@ -197,22 +206,27 @@ contract AgreementSettler is T.Agreement memory agreement = AGREEMENT_MANAGER.getAgreement(proof); if (agreement.arbiter != msg.sender) revert UnauthorizedEscrowAgent(); - uint256 total = agreement.total; // protocol - uint256 fees = agreement.fees; // protocol - uint256 available = total - fees; // holder earnings + uint256 total = agreement.total; + uint256 locked = agreement.locked; + uint256 fees = agreement.fees; + uint256 penalization = locked - total; + uint256 available = total - fees; + address initiator = agreement.initiator; address currency = agreement.currency; + uint256 protocolTake = fees + penalization; // TODO: Implement a time window to enforce the validity period for agreement settlement. // Once the window expires, the agreement should be marked as invalid or revert, // then quit is only way to close the agreement. _setProofAsSettled(proof); + // locked may include penalization // move the funds to settler and transfer the available to counterparty - LEDGER_VAULT.claim(initiator, total, currency); + LEDGER_VAULT.claim(initiator, locked, currency); // could exists cases where available become zero when fees are flat if (available > 0) LEDGER_VAULT.transfer(counterparty, available, currency); - emit AgreementSettled(msg.sender, counterparty, proof, fees); + emit AgreementSettled(msg.sender, counterparty, proof, protocolTake); return agreement; } diff --git a/contracts/lifecycle/HookRegistry.sol b/contracts/lifecycle/HookRegistry.sol index bbe9f44..70f23e5 100644 --- a/contracts/lifecycle/HookRegistry.sol +++ b/contracts/lifecycle/HookRegistry.sol @@ -74,8 +74,7 @@ contract HookRegistry is Initializable, UUPSUpgradeable, AccessControlledUpgrade /// @param hook The address of the hook contract to register. /// @param interfaceId The interface ID that this hook implements. /// This allows different kinds of hook logic to be categorized and retrieved by interface ID. - // TODO: restricted to MOD_ROLE - function submit(address hook, bytes4 interfaceId) external onlyValidHook(hook) restricted { + function submit(address hook, bytes4 interfaceId) external onlyValidHook(hook) onlyAdmin { _register(uint160(hook)); _hooks[interfaceId] = hook; emit HookRegistered(hook, interfaceId, msg.sender); @@ -84,7 +83,7 @@ contract HookRegistry is Initializable, UUPSUpgradeable, AccessControlledUpgrade /// @notice Approves a registered hook contract. /// @param hook The address of the hook to be approved. /// Emits a HookApproved event upon success. - function approve(address hook) external restricted { + function approve(address hook) external onlyAdmin { _approve(uint160(hook)); emit HookApproved(hook, msg.sender); } @@ -92,7 +91,7 @@ contract HookRegistry is Initializable, UUPSUpgradeable, AccessControlledUpgrade /// @notice Revokes a previously approved hook contract. /// @param hook The address of the hook to revoke. /// Emits a HookRevoked event upon success. - function reject(address hook) external restricted { + function reject(address hook) external onlyAdmin { _revoke(uint160(hook)); emit HookRevoked(hook, msg.sender); } diff --git a/contracts/policies/PolicyAudit.sol b/contracts/policies/PolicyAudit.sol index a26f250..a936db5 100644 --- a/contracts/policies/PolicyAudit.sol +++ b/contracts/policies/PolicyAudit.sol @@ -75,7 +75,7 @@ contract PolicyAudit is Initializable, UUPSUpgradeable, AccessControlledUpgradea /// @notice Approves the audit of a given policy by a specified auditor. /// @param policy The address of the policy to be audited. /// @dev This function emits the PolicyApproved event upon successful audit approval. - function approve(address policy) external restricted { + function approve(address policy) external onlyAdmin { _approve(uint160(policy)); emit PolicyApproved(policy, msg.sender); } @@ -83,7 +83,7 @@ contract PolicyAudit is Initializable, UUPSUpgradeable, AccessControlledUpgradea /// @notice Revokes the audit of a given policy by a specified auditor. /// @param policy The address of the policy whose audit is to be revoked. /// @dev This function emits the PolicyRevoked event upon successful audit revocation. - function reject(address policy) external restricted { + function reject(address policy) external onlyAdmin { _revoke(uint160(policy)); emit PolicyRevoked(policy, msg.sender); } diff --git a/contracts/rights/RightsPolicyManager.sol b/contracts/rights/RightsPolicyManager.sol index da56958..543a67c 100644 --- a/contracts/rights/RightsPolicyManager.sol +++ b/contracts/rights/RightsPolicyManager.sol @@ -110,6 +110,10 @@ contract RightsPolicyManager is // 1- retrieves the agreement and marks it as settled.. T.Agreement memory agreement = AGREEMENT_SETTLER.settleAgreement(proof, holder); bytes memory callData = abi.encodeCall(IPolicy.enforce, (holder, agreement)); + if (agreement.parties.length == 0) { + revert EnforcementFailed("No parties in agreement: at least one party is required."); + } + /// Type-safe low-level call to policy. The policy is registered to the parties. /// The policy address is already validated during policy audit and authorization. /// During `onlyAuthorizedPolicy`, the policy is verified about safety. diff --git a/foundry.toml b/foundry.toml index 178f1ac..4f8a2af 100644 --- a/foundry.toml +++ b/foundry.toml @@ -31,3 +31,8 @@ polygon-amoy = "${AMOY_RPC_URL}" [etherscan] polygon-amoy = { key = "${AMOY_API_KEY}", url = "https://www.oklink.com/api/explorer/v1/contract/verify/async/api/polygonAmoy" } + +[invariant] +runs = 1000 +depth = 25 +fail_on_revert = true diff --git a/script/orchestration/01_Orchestrate_ProtocolHydration.s.sol b/script/orchestration/01_Orchestrate_ProtocolHydration.s.sol index d211d5d..426a17e 100644 --- a/script/orchestration/01_Orchestrate_ProtocolHydration.s.sol +++ b/script/orchestration/01_Orchestrate_ProtocolHydration.s.sol @@ -47,15 +47,8 @@ contract OrchestrateProtocolHydration is Script { authority.setTargetFunctionRole(tollgateAddress, tollgateAllowed, C.GOV_ROLE); authority.setTargetFunctionRole(treasuryAddress, treasuryAllowed, C.GOV_ROLE); - authority.setTargetFunctionRole(assetReferendum, assetReferendumAllowed, C.GOV_ROLE); - authority.setTargetFunctionRole(custodianReferendum, custodianReferendumAllowed, C.GOV_ROLE); - - // assign moderation permissions - authority.grantRole(C.MOD_ROLE, adminAddress, 0); - // bytes4[] memory hookModAllowed = HooksModPermissions(); - bytes4[] memory auditorAllowed = PolicyAuditorModPermissions(); - authority.setTargetFunctionRole(auditorAddress, auditorAllowed, C.MOD_ROLE); - // authority.setTargetFunctionRole(auditorAddress, hookModAllowed, C.MOD_ROLE); + authority.setTargetFunctionRole(assetReferendum, assetReferendumAllowed, C.CONTENT_COUNCIL_ROLE); + authority.setTargetFunctionRole(custodianReferendum, custodianReferendumAllowed, C.CUSTODY_COUNCIL_ROLE); // assign operations permissions authority.grantRole(C.OPS_ROLE, agreementManager, 0); @@ -63,6 +56,8 @@ contract OrchestrateProtocolHydration is Script { bytes4[] memory vaultAllowed = LedgerVaultOpsPermissions(); authority.setTargetFunctionRole(ledgerVault, vaultAllowed, C.OPS_ROLE); + + // 2 set mmc as the initial currency and fees uint256 agrFee = vm.envUint("AGREEMENT_FEES"); // 5% 500 bps address currency = vm.envAddress("MMC"); diff --git a/test/BaseTest.t.sol b/test/BaseTest.t.sol index a001ee9..6c7ccef 100644 --- a/test/BaseTest.t.sol +++ b/test/BaseTest.t.sol @@ -103,7 +103,7 @@ abstract contract BaseTest is Test { vm.startPrank(governor); // add to councils the corresponding role authority.grantRole(C.CONTENT_COUNCIL_ROLE, contentCouncil, 0); - authority.grantRole(C.NODE_VALIDATOR_ROLE, nodesCouncil, 0); + authority.grantRole(C.CUSTODY_COUNCIL_ROLE, nodesCouncil, 0); vm.stopPrank(); } @@ -223,7 +223,7 @@ abstract contract BaseTest is Test { vm.startPrank(admin); IAccessManager authority = IAccessManager(accessManager); // assign permissions to VAL_ROLE for allowed functions to call in target - authority.setTargetFunctionRole(target, allowed, C.NODE_VALIDATOR_ROLE); + authority.setTargetFunctionRole(target, allowed, C.CUSTODY_COUNCIL_ROLE); vm.stopPrank(); } diff --git a/test/custody/CustodianImpl.t.sol b/test/custody/CustodianImpl.t.sol index 67e7afa..cdc3283 100644 --- a/test/custody/CustodianImpl.t.sol +++ b/test/custody/CustodianImpl.t.sol @@ -67,6 +67,15 @@ contract CustodianImplTest is BaseTest { ICustodian(custodian).setEndpoint("mynew.com"); } + function test_SetEndpoint_RevertWhen_InvalidEndpoint() public { + // created with an initial endpoint + address custodian = deployCustodian("1.1.1.1", user); + + vm.prank(user); + vm.expectRevert(abi.encodeWithSignature("InvalidEndpoint()")); + ICustodian(custodian).setEndpoint(""); + } + function test_GetBalance_ValidBalance() public { // created with an initial endpoint address custodian = deployCustodian("1.1.1.1", user); diff --git a/test/primitives/BalanceOperator.t.sol b/test/primitives/BalanceOperator.t.sol index 541dde8..40ee6ed 100644 --- a/test/primitives/BalanceOperator.t.sol +++ b/test/primitives/BalanceOperator.t.sol @@ -11,7 +11,7 @@ import { IBalanceTransferable } from "contracts/core/interfaces/base/IBalanceTra import { IBalanceWithdrawable } from "contracts/core/interfaces/base/IBalanceWithdrawable.sol"; import { BalanceOperatorUpgradeable } from "contracts/core/primitives/upgradeable/BalanceOperatorUpgradeable.sol"; -contract BalanceOperatorWrapper is BalanceOperatorUpgradeable { +contract BalanceOperator is BalanceOperatorUpgradeable { function deposit(address recipient, uint256 amount, address currency) external returns (uint256) { return _deposit(recipient, amount, currency); } @@ -25,14 +25,107 @@ contract BalanceOperatorWrapper is BalanceOperatorUpgradeable { } } +contract Handler is Test { + IERC20 mmc; + uint256 public total; + address[] public actors; + BalanceOperator operator; + + constructor(BalanceOperator op, address currency) { + operator = op; + mmc = IERC20(currency); + + for (uint256 i = 0; i < 10; i++) { + address a = vm.addr(i + 1); + actors.push(a); // exec as default admin and fund the authors + } + } + + function getActors() external view returns (address[] memory) { + return actors; + } + + function deposit(uint256 actorIndex, uint256 amount) external { + vm.assume(actorIndex < actors.length); + address a = actors[actorIndex]; + vm.assume(amount > 0 && amount < mmc.balanceOf(a)); + + // as author + vm.startPrank(a); + mmc.approve(address(operator), amount); + uint256 confirmed = operator.deposit(a, amount, address(mmc)); + total += confirmed; + vm.stopPrank(); + } + + function withdraw(uint256 actorIndex, uint256 amount) external { + vm.assume(actorIndex < actors.length); + address a = actors[actorIndex]; + vm.assume(amount > 0 && amount < operator.getLedgerBalance(a, address(mmc))); + + // as author + vm.prank(a); + uint256 confirmed = operator.withdraw(a, amount, address(mmc)); + total -= confirmed; + } + + function transfer(uint256 actorIndex, uint256 actorIndexB, uint256 amount) external { + vm.assume(actorIndex < actors.length); + vm.assume(actorIndexB < actors.length); + vm.assume(actorIndex != actorIndexB); + + address a = actors[actorIndex]; + address b = actors[actorIndexB]; + vm.assume(amount > 0 && amount < operator.getLedgerBalance(a, address(mmc))); + + // as author + vm.prank(a); + operator.transfer(b, amount, address(mmc)); + } +} + contract BalanceOperatorTest is BaseTest { - address op; + Handler handler; + BalanceOperator operator; + address opAddress; function setUp() public initialize { deployToken(); - op = address(new BalanceOperatorWrapper()); + operator = new BalanceOperator(); + handler = new Handler(operator, token); + opAddress = address(operator); + + uint256 amount = 100 * 1e18; + address[] memory actors = handler.getActors(); + uint256 actorsLen = actors.length; + + for (uint256 i = 0; i < actorsLen; i++) { + vm.prank(admin); // the funds origin + IERC20(token).transfer(address(actors[i]), amount); + } + + targetContract(address(handler)); } + function invariant_GetBalance() external { + assertEq(handler.total(), IBalanceVerifiable(opAddress).getBalance(token)); + } + + function invariant_BalanceMatchActorsBalance() external { + uint256 totalByActor = 0; + address[] memory actors = handler.getActors(); + uint256 actorsLen = actors.length; + + for (uint256 i = 0; i < actorsLen; i++) { + // each deposit/withdraw move funds internally for each balance in the ledger + totalByActor += ILedgerVerifiable(opAddress).getLedgerBalance(actors[i], token); + } + + // the contract balance must match with the sum of all ledgers + assertEq(totalByActor, IBalanceVerifiable(opAddress).getBalance(token)); + } + + function test_Deposit_ValidDeposit() public { // 100 MMC uint256 amount = 100 * 1e18; @@ -41,8 +134,8 @@ contract BalanceOperatorTest is BaseTest { uint256 confirmed = _validDeposit(admin, amount); uint256 afterBalance = IERC20(token).balanceOf(admin); - uint256 balance = ILedgerVerifiable(op).getLedgerBalance(admin, token); - uint256 contractBalance = IBalanceVerifiable(op).getBalance(token); + uint256 balance = ILedgerVerifiable(opAddress).getLedgerBalance(admin, token); + uint256 contractBalance = IBalanceVerifiable(opAddress).getBalance(token); vm.stopPrank(); assertEq(confirmed, balance, "Confirmed amount should match ledger balance"); @@ -53,16 +146,17 @@ contract BalanceOperatorTest is BaseTest { function test_Deposit_FundsDepositedEventEmitted() public { uint256 amount = 100 * 1e18; vm.startPrank(admin); - IERC20(token).approve(op, amount); - vm.expectEmit(true, true, false, true, address(op)); + IERC20(token).approve(opAddress, amount); + + vm.expectEmit(true, true, false, true, address(opAddress)); emit IBalanceDepositor.FundsDeposited(admin, admin, amount, token); - IBalanceDepositor(op).deposit(admin, amount, token); + IBalanceDepositor(opAddress).deposit(admin, amount, token); vm.stopPrank(); } function test_Deposit_RevertWhen_InvalidApproval() public { vm.expectRevert(abi.encodeWithSignature("FailDuringDeposit(string)", "Amount exceeds allowance.")); - IBalanceDepositor(op).deposit(admin, 100 * 1e18, token); + IBalanceDepositor(opAddress).deposit(admin, 100 * 1e18, token); } function test_Deposit_RevertIf_InvalidParams() public { @@ -71,10 +165,10 @@ contract BalanceOperatorTest is BaseTest { bytes4 err = bytes4(keccak256("InvalidOperationParameters()")); // must fail if account = address(0) or amount == 0 vm.expectRevert(err); - IBalanceDepositor(op).deposit(admin, amount, token); + IBalanceDepositor(opAddress).deposit(admin, amount, token); vm.expectRevert(err); - IBalanceDepositor(op).deposit(account, 1 * 1e18, token); + IBalanceDepositor(opAddress).deposit(account, 1 * 1e18, token); } function test_Withdraw_ValidWithdraw() public { @@ -85,9 +179,9 @@ contract BalanceOperatorTest is BaseTest { uint256 deposited = _validDeposit(admin, amount); uint256 afterBalance = IERC20(token).balanceOf(admin); - uint256 confirmed = IBalanceWithdrawable(op).withdraw(admin, deposited, token); - uint256 balance = ILedgerVerifiable(op).getLedgerBalance(admin, token); - uint256 contractBalance = IBalanceVerifiable(op).getBalance(token); + uint256 confirmed = IBalanceWithdrawable(opAddress).withdraw(admin, deposited, token); + uint256 balance = ILedgerVerifiable(opAddress).getLedgerBalance(admin, token); + uint256 contractBalance = IBalanceVerifiable(opAddress).getBalance(token); vm.stopPrank(); assertEq(confirmed, deposited, "Confirmed amount should match deposited amount"); @@ -101,15 +195,15 @@ contract BalanceOperatorTest is BaseTest { vm.startPrank(admin); _validDeposit(admin, amount); - vm.expectEmit(true, true, false, true, address(op)); + vm.expectEmit(true, true, false, true, address(opAddress)); emit IBalanceWithdrawable.FundsWithdrawn(admin, admin, amount, token); - IBalanceWithdrawable(op).withdraw(admin, amount, token); + IBalanceWithdrawable(opAddress).withdraw(admin, amount, token); vm.stopPrank(); } function test_Withdraw_RevertIf_NoFunds() public { vm.expectRevert(bytes4(keccak256("NoFundsToWithdraw()"))); - IBalanceWithdrawable(op).withdraw(admin, 1 * 1e18, token); + IBalanceWithdrawable(opAddress).withdraw(admin, 1 * 1e18, token); } function test_Withdraw_RevertIf_InvalidParams() public { @@ -118,10 +212,10 @@ contract BalanceOperatorTest is BaseTest { bytes4 err = bytes4(keccak256("InvalidOperationParameters()")); // must fail if account = address(0) or amount == 0 vm.expectRevert(err); - IBalanceWithdrawable(op).withdraw(admin, amount, token); + IBalanceWithdrawable(opAddress).withdraw(admin, amount, token); vm.expectRevert(err); - IBalanceWithdrawable(op).withdraw(account, 1 * 1e18, token); + IBalanceWithdrawable(opAddress).withdraw(account, 1 * 1e18, token); } function test_Transfer_ValidTransfer() public { @@ -133,11 +227,11 @@ contract BalanceOperatorTest is BaseTest { vm.startPrank(admin); _validDeposit(admin, amount); // transfer the haft of the balance to user - uint256 confirmed = IBalanceTransferable(op).transfer(user, expectedAfter, token); - uint256 contractBalance = IBalanceVerifiable(op).getBalance(token); + uint256 confirmed = IBalanceTransferable(opAddress).transfer(user, expectedAfter, token); + uint256 contractBalance = IBalanceVerifiable(opAddress).getBalance(token); vm.stopPrank(); - ILedgerVerifiable verifier = ILedgerVerifiable(op); + ILedgerVerifiable verifier = ILedgerVerifiable(opAddress); uint256 balanceAdmin = verifier.getLedgerBalance(admin, token); uint256 balanceUser = verifier.getLedgerBalance(user, token); @@ -154,15 +248,15 @@ contract BalanceOperatorTest is BaseTest { vm.startPrank(admin); _validDeposit(admin, amount); // transfer the haft of the balance to user - vm.expectEmit(true, true, false, true, address(op)); + vm.expectEmit(true, true, false, true, address(opAddress)); emit IBalanceTransferable.FundsTransferred(user, admin, amount, token); - IBalanceTransferable(op).transfer(user, amount, token); + IBalanceTransferable(opAddress).transfer(user, amount, token); vm.stopPrank(); } function test_Transfer_RevertIf_NoFunds() public { vm.expectRevert(bytes4(keccak256("NoFundsToTransfer()"))); - IBalanceTransferable(op).transfer(vm.addr(7), 1 * 1e18, token); + IBalanceTransferable(opAddress).transfer(vm.addr(7), 1 * 1e18, token); } function test_Transfer_RevertIf_InvalidParams() public { @@ -171,19 +265,19 @@ contract BalanceOperatorTest is BaseTest { bytes4 err = bytes4(keccak256("InvalidOperationParameters()")); // must fail if account = address(0) or amount == 0 vm.expectRevert(err); - IBalanceTransferable(op).transfer(admin, amount, token); + IBalanceTransferable(opAddress).transfer(admin, amount, token); vm.expectRevert(err); - IBalanceTransferable(op).transfer(account, 1 * 1e18, token); + IBalanceTransferable(opAddress).transfer(account, 1 * 1e18, token); vm.prank(admin); vm.expectRevert(err); // sender cannot be the recipient - IBalanceTransferable(op).transfer(admin, 1 * 1e18, token); + IBalanceTransferable(opAddress).transfer(admin, 1 * 1e18, token); } function _validDeposit(address account, uint256 amount) private returns (uint256) { - IERC20(token).approve(op, amount); - return IBalanceDepositor(op).deposit(account, amount, token); + IERC20(token).approve(opAddress, amount); + return IBalanceDepositor(opAddress).deposit(account, amount, token); } } From 223d773ad355cddd5c6c3fe4761413a832427eca Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Wed, 27 Aug 2025 18:21:29 -0600 Subject: [PATCH 06/33] tests: invariant balance operator --- test/finance/TrustlessEscrow.sol | 95 ++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 test/finance/TrustlessEscrow.sol diff --git a/test/finance/TrustlessEscrow.sol b/test/finance/TrustlessEscrow.sol new file mode 100644 index 0000000..ee65812 --- /dev/null +++ b/test/finance/TrustlessEscrow.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import "forge-std/Test.sol"; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { ITollgate } from "@synaps3/core/interfaces/economics/ITollgate.sol"; +import { ILedgerVault } from "@synaps3/core/interfaces/financial/ILedgerVault.sol"; +import { IAgreementManager } from "@synaps3/core/interfaces/financial/IAgreementManager.sol"; +import { IAgreementSettler } from "@synaps3/core/interfaces/financial/IAgreementSettler.sol"; +import { BaseTest } from "test/BaseTest.t.sol"; +import { T } from "contracts/core/primitives/Types.sol"; +import { C } from "contracts/core/primitives/Constants.sol"; + +contract MockArbiter { + IAgreementSettler public immutable AGREEMENT_SETTLER; + + constructor(address agreementSettler) { + AGREEMENT_SETTLER = IAgreementSettler(agreementSettler); + } + + function executeAgreement(uint256 proof, address counterparty) external returns (T.Agreement memory agreement) { + agreement = AGREEMENT_SETTLER.settleAgreement(proof, counterparty); + } +} + +contract TrustlessEscrowTest is BaseTest { + MockArbiter arbiter; + + function setUp() public initialize { + deployAgreementSettler(); + arbiter = MockArbiter(agreementSettler); + + uint256 fees = 500; // 5% + vm.prank(governor); + ITollgate(tollgate).setFees(T.Scheme.BPS, address(arbiter), fees, token); + + vm.startPrank(admin); + + uint256 amount = 100 * 1e18; + IERC20(token).approve(ledger, amount); + ILedgerVault(ledger).deposit(user, amount, token); + vm.stopPrank(); + } + + function test_PreviewAgreement_ReturnExpectedAgreement() public { + uint256 amount = 10 * 1e18; + IAgreementManager manager = IAgreementManager(agreementManager); + (uint256 feesBPS, ) = ITollgate(tollgate).getFees(address(arbiter),token); + + address[] memory parties = new address[](2); + parties[0] = vm.addr(1); + parties[1] = vm.addr(2); + + vm.prank(user); + T.Agreement memory agreement = manager.previewAgreement(amount, token, address(arbiter), parties, ""); + uint256 fees = (feesBPS * amount) / 10_000; // 5% configured + + assertEq(agreement.total, amount); + assertEq(agreement.initiator, user); + assertEq(agreement.fees, fees); + assertEq(agreement.locked, amount); // eq amount if not exceed allowed parties + assertEq(agreement.currency, token); + assertEq(agreement.arbiter, address(arbiter)); + assertEq(agreement.parties, parties); + assertEq(agreement.payload, ""); + } + + function testFuzz_PreviewAgreement_ReturnPenalizedAgreement(uint256 partiesLen) public { + uint256 amount = 100 * 1e18; + // max 18 are allowed with soft cap maxParties = 5 + // force penalization with min 6, maxParties + 13 = 18 + uint256 capped = bound(partiesLen, 6, 18); + IAgreementManager manager = IAgreementManager(agreementManager); + + // max is 5, per each extra 1% in accumulated succession, + // eg: 6, 7, 8 = 1 + 2 + 3 = 6% penalization + address[] memory parties = new address[](capped); + for (uint256 i = 0; i < capped; i++) { + parties[i] = vm.addr(i + 1); + } + + T.Agreement memory agreement = manager.previewAgreement(amount, token, address(arbiter), parties, ""); + + uint256 exceed = capped - 5; // default maxParties = 5; + uint256 expectedPercentage = (exceed * (exceed + 1)) / 2; + uint256 expectedPenalizationBPS = expectedPercentage * 100; + uint256 expectedPenalizationAmount = (amount * expectedPenalizationBPS) / C.BPS_MAX; + uint256 expectedLocked = amount + expectedPenalizationAmount; + + assertEq(agreement.total, amount); + assertEq(agreement.locked, expectedLocked); + assertEq(agreement.parties, parties); + } +} From 846bc014d8e454efcc8cf098085e7151e5a765d8 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Wed, 27 Aug 2025 18:21:34 -0600 Subject: [PATCH 07/33] tests: invariant balance operator --- test/primitives/BalanceOperator.t.sol | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/primitives/BalanceOperator.t.sol b/test/primitives/BalanceOperator.t.sol index 40ee6ed..59ee0e7 100644 --- a/test/primitives/BalanceOperator.t.sol +++ b/test/primitives/BalanceOperator.t.sol @@ -61,7 +61,7 @@ contract Handler is Test { function withdraw(uint256 actorIndex, uint256 amount) external { vm.assume(actorIndex < actors.length); address a = actors[actorIndex]; - vm.assume(amount > 0 && amount < operator.getLedgerBalance(a, address(mmc))); + vm.assume(amount > 0 && amount < operator.getLedgerBalance(a, address(mmc))); // as author vm.prank(a); @@ -121,11 +121,10 @@ contract BalanceOperatorTest is BaseTest { totalByActor += ILedgerVerifiable(opAddress).getLedgerBalance(actors[i], token); } - // the contract balance must match with the sum of all ledgers + // the contract balance must match with the sum of all ledgers assertEq(totalByActor, IBalanceVerifiable(opAddress).getBalance(token)); } - function test_Deposit_ValidDeposit() public { // 100 MMC uint256 amount = 100 * 1e18; From a73c15651efbd3853b0c20f595585e6e65a8627d Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Thu, 25 Sep 2025 08:56:01 -0600 Subject: [PATCH 08/33] removed the uneeded exceed --- .github/workflows/cov-badge.svg | 2 +- contracts/access/AccessManager.sol | 2 - contracts/assets/AssetOwnership.sol | 2 +- contracts/financial/AgreementManager.sol | 23 +- lcov.info | 2181 ++++++++++++---------- 5 files changed, 1168 insertions(+), 1042 deletions(-) diff --git a/.github/workflows/cov-badge.svg b/.github/workflows/cov-badge.svg index 83ae508..4581b89 100644 --- a/.github/workflows/cov-badge.svg +++ b/.github/workflows/cov-badge.svg @@ -1 +1 @@ -coveragecoverage48.91%48.91% \ No newline at end of file +coveragecoverage46.72%46.72% \ No newline at end of file diff --git a/contracts/access/AccessManager.sol b/contracts/access/AccessManager.sol index d33429a..09b4aa0 100644 --- a/contracts/access/AccessManager.sol +++ b/contracts/access/AccessManager.sol @@ -71,8 +71,6 @@ contract AccessManager is Initializable, UUPSUpgradeable, AccessManagerUpgradeab _setRoleAdmin(C.CONTENT_COUNCIL_ROLE, C.GOV_ROLE); } - // TODO pause protocol based on permission and roles - /// @dev Authorizes the upgrade of the contract. /// @notice Only the admin can authorize the upgrade. function _authorizeUpgrade(address) internal view override { diff --git a/contracts/assets/AssetOwnership.sol b/contracts/assets/AssetOwnership.sol index 21298a0..a38462a 100644 --- a/contracts/assets/AssetOwnership.sol +++ b/contracts/assets/AssetOwnership.sol @@ -115,7 +115,7 @@ contract AssetOwnership is // TODO: Transfer Ownership Fee: Introducing a fee for transferring // ownership discourages frequent or unnecessary transfers, // adding an economic cost to any potential abuse of the system. Like bypassing content - // verification by governance using a verified account. + // verification by governance using a verified account. // TODO: approved content get an incentive: a cooling mechanism is needed eg: // log decay, max registered asset rate, etc diff --git a/contracts/financial/AgreementManager.sol b/contracts/financial/AgreementManager.sol index d6f36ba..fb2a450 100644 --- a/contracts/financial/AgreementManager.sol +++ b/contracts/financial/AgreementManager.sol @@ -35,7 +35,6 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg ILedgerVault public immutable LEDGER_VAULT; //slither-disable-end naming-convention - uint256 constant MAX_EXCESS = 13; // 1..13=91%, 14=>105% /// @notice Maximum allowed number of parties per agreement. /// @dev Can be updated by admin to adapt system limits. uint256 private _maxParties; @@ -160,8 +159,8 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg // which could lead to abuse or exploitation. uint256 baseFees = _calcFees(amount, arbiter, currency); // Even if we are covered by gas fees, during execution a good way to avoid abuse - // is penalize parties after N length eg. The max parties allowed is 5, any extra - // parties are charged with a extra * fee. Denial of Service risk mitigation.. + // is penalize parties after N length eg. The initial max parties allowed is 5, any extra + // parties are charged with an extra. Denial of Service risk mitigation.. uint256 penalization = _calculatePenalization(parties.length, amount); uint256 totalToLock = amount + penalization; @@ -196,15 +195,10 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg /// @dev Calculates the penalization based on parties len and total amount function _calculatePenalization(uint256 partiesLen, uint256 amount) private view returns (uint256 penalization) { - uint256 hardCap = _maxParties + MAX_EXCESS; - if (partiesLen > hardCap) revert ExceedsMaxParties(); - - // soft cap validation, economic penalization - if (partiesLen > _maxParties) { - uint256 excess = partiesLen - _maxParties; - uint256 multiplierBps = _penaltyBps(excess); - penalization = amount.perOf(multiplierBps); - } + if (partiesLen <= _maxParties) return 0; + uint256 excess = partiesLen - _maxParties; + uint256 multiplierBps = _penaltyBps(excess); + penalization = amount.perOf(multiplierBps); } /// @dev Computes the penalty BPS as a arithmetic succession. @@ -219,6 +213,11 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg unchecked { penaltyBps = ((excess * (excess + 1)) / 2) * 100; } + + // strict hard cap revert if bps > 10_0000 + if (penaltyBps > C.BPS_MAX) { + revert ExceedsMaxParties(); + } } /// @notice Calculates the fee based on the provided total amount, agent, and currency. diff --git a/lcov.info b/lcov.info index 84c8407..ec35717 100644 --- a/lcov.info +++ b/lcov.info @@ -1,21 +1,21 @@ TN: SF:contracts/access/AccessManager.sol -DA:17,76 +DA:17,75 FN:17,AccessManager.initialize -FNDA:76,AccessManager.initialize +FNDA:75,AccessManager.initialize DA:18,0 -DA:19,76 -DA:68,76 -DA:69,76 -DA:70,76 -DA:71,76 -DA:78,0 -FN:78,AccessManager._authorizeUpgrade +DA:19,75 +DA:68,75 +DA:69,75 +DA:70,75 +DA:71,75 +DA:76,0 +FN:76,AccessManager._authorizeUpgrade FNDA:0,AccessManager._authorizeUpgrade +DA:77,0 DA:79,0 -DA:81,0 -BRDA:81,0,0,- -BRDA:81,0,1,- +BRDA:79,0,0,- +BRDA:79,0,1,- FNF:2 FNH:1 LF:10 @@ -54,50 +54,50 @@ DA:108,0 FN:108,AssetOwnership.supportsInterface FNDA:0,AssetOwnership.supportsInterface DA:111,0 -DA:128,5 -FN:128,AssetOwnership.register +DA:127,5 +FN:127,AssetOwnership.register FNDA:5,AssetOwnership.register +DA:128,5 DA:129,5 DA:130,5 -DA:131,5 -DA:137,0 -FN:137,AssetOwnership.revoke +DA:136,0 +FN:136,AssetOwnership.revoke FNDA:0,AssetOwnership.revoke +DA:137,0 DA:138,0 DA:139,0 -DA:140,0 -DA:146,0 -FN:146,AssetOwnership.transfer +DA:145,0 +FN:145,AssetOwnership.transfer FNDA:0,AssetOwnership.transfer +DA:146,0 DA:147,0 -DA:148,0 -DA:155,0 -FN:155,AssetOwnership.switchState +DA:154,0 +FN:154,AssetOwnership.switchState FNDA:0,AssetOwnership.switchState -DA:156,0 -DA:158,0 -DA:160,0 -DA:164,5 -FN:164,AssetOwnership._update +DA:155,0 +DA:157,0 +DA:159,0 +DA:163,5 +FN:163,AssetOwnership._update FNDA:5,AssetOwnership._update -DA:169,5 -DA:173,0 -FN:173,AssetOwnership._increaseBalance +DA:168,5 +DA:172,0 +FN:172,AssetOwnership._increaseBalance FNDA:0,AssetOwnership._increaseBalance -DA:177,0 -DA:182,0 -FN:182,AssetOwnership._authorizeUpgrade +DA:176,0 +DA:181,0 +FN:181,AssetOwnership._authorizeUpgrade FNDA:0,AssetOwnership._authorizeUpgrade -DA:185,5 -FN:185,AssetOwnership._enableAsset +DA:184,5 +FN:184,AssetOwnership._enableAsset FNDA:5,AssetOwnership._enableAsset +DA:185,5 DA:186,5 -DA:187,5 -DA:191,0 -FN:191,AssetOwnership._disableAsset +DA:190,0 +FN:190,AssetOwnership._disableAsset FNDA:0,AssetOwnership._disableAsset +DA:191,0 DA:192,0 -DA:193,0 FNF:14 FNH:6 LF:43 @@ -226,29 +226,29 @@ BRH:0 end_of_record TN: SF:contracts/core/libraries/FeesOps.sol -DA:12,3 +DA:12,5 FN:12,FeesOps.isBasePoint -FNDA:3,FeesOps.isBasePoint -DA:14,3 +FNDA:5,FeesOps.isBasePoint +DA:14,5 DA:19,2 FN:19,FeesOps.isNominal FNDA:2,FeesOps.isNominal DA:21,2 -DA:27,0 +DA:27,513 FN:27,FeesOps.perOf -FNDA:0,FeesOps.perOf -DA:31,0 +FNDA:513,FeesOps.perOf +DA:31,513 BRDA:31,0,0,- BRDA:31,0,1,- -DA:32,0 +DA:32,513 DA:37,0 FN:37,FeesOps.calcBps FNDA:0,FeesOps.calcBps DA:38,0 FNF:4 -FNH:2 +FNH:3 LF:9 -LH:4 +LH:7 BRF:2 BRH:0 end_of_record @@ -260,22 +260,22 @@ FNDA:0,FinancialOps._nativeTransfer DA:25,0 DA:26,0 BRDA:26,0,0,- -DA:33,4 +DA:33,5311 FN:33,FinancialOps._erc20Transfer -FNDA:4,FinancialOps._erc20Transfer -DA:34,4 +FNDA:5311,FinancialOps._erc20Transfer +DA:34,5311 DA:41,0 FN:41,FinancialOps._nativeDeposit FNDA:0,FinancialOps._nativeDeposit DA:42,0 BRDA:42,1,0,- DA:44,0 -DA:53,39 +DA:53,11346 FN:53,FinancialOps._erc20Deposit -FNDA:39,FinancialOps._erc20Deposit -DA:54,39 +FNDA:11346,FinancialOps._erc20Deposit +DA:54,11346 BRDA:54,2,0,1 -DA:58,38 +DA:58,11345 DA:59,0 DA:68,0 FN:68,FinancialOps.increaseAllowance @@ -283,32 +283,32 @@ FNDA:0,FinancialOps.increaseAllowance DA:69,0 BRDA:69,3,0,- DA:70,0 -DA:79,39 +DA:79,11346 FN:79,FinancialOps.allowance -FNDA:39,FinancialOps.allowance -DA:80,39 -DA:81,39 -DA:90,39 +FNDA:11346,FinancialOps.allowance +DA:80,11346 +DA:81,11346 +DA:90,11346 FN:90,FinancialOps.safeDeposit -FNDA:39,FinancialOps.safeDeposit -DA:91,39 +FNDA:11346,FinancialOps.safeDeposit +DA:91,11346 BRDA:91,5,0,- -DA:92,39 -DA:93,39 -DA:99,19 +DA:92,11346 +DA:93,11346 +DA:99,5326 FN:99,FinancialOps.balanceOf -FNDA:19,FinancialOps.balanceOf -DA:100,19 -DA:101,19 -DA:109,4 +FNDA:5326,FinancialOps.balanceOf +DA:100,5326 +DA:101,5326 +DA:109,5311 FN:109,FinancialOps.transfer -FNDA:4,FinancialOps.transfer -DA:110,4 +FNDA:5311,FinancialOps.transfer +DA:110,5311 BRDA:110,8,0,- -DA:111,4 +DA:111,5311 BRDA:111,9,0,- -DA:112,4 -DA:113,4 +DA:112,5311 +DA:113,5311 FNF:9 FNH:6 LF:30 @@ -434,48 +434,56 @@ BRH:3 end_of_record TN: SF:contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol -DA:28,0 -FN:28,AccessControlledUpgradeable.onlyAdmin +DA:29,0 +FN:29,AccessControlledUpgradeable.onlyAdmin FNDA:0,AccessControlledUpgradeable.onlyAdmin -DA:33,0 -BRDA:33,0,0,- DA:34,0 -DA:44,286 -FN:44,AccessControlledUpgradeable.__AccessControlled_init -FNDA:286,AccessControlledUpgradeable.__AccessControlled_init -DA:45,286 -DA:46,286 -DA:52,286 -FN:52,AccessControlledUpgradeable.__AccessControlled_init_unchained -FNDA:286,AccessControlledUpgradeable.__AccessControlled_init_unchained -DA:53,286 -BRDA:53,1,0,- -DA:54,0 -DA:57,286 -DA:58,286 -DA:65,9 -FN:65,AccessControlledUpgradeable._hasRole +BRDA:34,0,0,- +DA:35,0 +DA:43,0 +FN:43,AccessControlledUpgradeable.pause +FNDA:0,AccessControlledUpgradeable.pause +DA:44,0 +DA:50,0 +FN:50,AccessControlledUpgradeable.unpause +FNDA:0,AccessControlledUpgradeable.unpause +DA:51,0 +DA:59,260 +FN:59,AccessControlledUpgradeable.__AccessControlled_init +FNDA:260,AccessControlledUpgradeable.__AccessControlled_init +DA:60,260 +DA:61,260 +DA:67,260 +FN:67,AccessControlledUpgradeable.__AccessControlled_init_unchained +FNDA:260,AccessControlledUpgradeable.__AccessControlled_init_unchained +DA:68,260 +BRDA:68,1,0,- +DA:69,0 +DA:72,260 +DA:73,260 +DA:80,9 +FN:80,AccessControlledUpgradeable._hasRole FNDA:9,AccessControlledUpgradeable._hasRole -DA:66,9 -DA:67,9 -DA:68,9 -DA:69,9 -DA:73,295 -FN:73,AccessControlledUpgradeable._getAccessControlStorage -FNDA:295,AccessControlledUpgradeable._getAccessControlStorage -DA:75,0 -FNF:5 +DA:81,9 +DA:82,9 +DA:83,9 +DA:84,9 +DA:88,269 +FN:88,AccessControlledUpgradeable._getAccessControlStorage +FNDA:269,AccessControlledUpgradeable._getAccessControlStorage +DA:90,0 +FNF:7 FNH:4 -LF:18 +LF:22 LH:13 BRF:2 BRH:0 end_of_record TN: SF:contracts/core/primitives/upgradeable/AllowanceOperatorUpgradeable.sol -DA:32,41 +DA:32,37 FN:32,AllowanceOperatorUpgradeable.__AllowanceOperator_init -FNDA:41,AllowanceOperatorUpgradeable.__AllowanceOperator_init +FNDA:37,AllowanceOperatorUpgradeable.__AllowanceOperator_init DA:33,0 DA:39,0 FN:39,AllowanceOperatorUpgradeable.__AllowanceOperator_init_unchained @@ -487,24 +495,24 @@ DA:47,0 DA:48,0 DA:49,0 DA:56,0 -FN:56,AllowanceOperatorUpgradeable.approve -FNDA:0,AllowanceOperatorUpgradeable.approve +FN:56,AllowanceOperatorUpgradeable._approve +FNDA:0,AllowanceOperatorUpgradeable._approve DA:61,0 BRDA:61,0,0,- DA:62,0 DA:63,0 DA:64,0 DA:71,0 -FN:71,AllowanceOperatorUpgradeable.revoke -FNDA:0,AllowanceOperatorUpgradeable.revoke +FN:71,AllowanceOperatorUpgradeable._revoke +FNDA:0,AllowanceOperatorUpgradeable._revoke DA:76,0 BRDA:76,1,0,- DA:77,0 DA:78,0 DA:79,0 DA:86,0 -FN:86,AllowanceOperatorUpgradeable.collect -FNDA:0,AllowanceOperatorUpgradeable.collect +FN:86,AllowanceOperatorUpgradeable._collect +FNDA:0,AllowanceOperatorUpgradeable._collect DA:91,0 BRDA:91,2,0,- DA:92,0 @@ -543,52 +551,51 @@ BRH:0 end_of_record TN: SF:contracts/core/primitives/upgradeable/BalanceOperatorUpgradeable.sol -DA:37,82 -FN:37,BalanceOperatorUpgradeable.__BalanceOperator_init -FNDA:82,BalanceOperatorUpgradeable.__BalanceOperator_init -DA:38,0 -DA:39,0 -DA:44,0 -FN:44,BalanceOperatorUpgradeable.__BalanceOperator_init_unchained +DA:31,74 +FN:31,BalanceOperatorUpgradeable.__BalanceOperator_init +FNDA:74,BalanceOperatorUpgradeable.__BalanceOperator_init +DA:32,0 +DA:37,0 +FN:37,BalanceOperatorUpgradeable.__BalanceOperator_init_unchained FNDA:0,BalanceOperatorUpgradeable.__BalanceOperator_init_unchained -DA:49,3 -FN:49,BalanceOperatorUpgradeable.getBalance +DA:42,3 +FN:42,BalanceOperatorUpgradeable.getBalance FNDA:3,BalanceOperatorUpgradeable.getBalance -DA:50,3 -DA:57,39 -FN:57,BalanceOperatorUpgradeable.deposit -FNDA:39,BalanceOperatorUpgradeable.deposit -DA:62,39 -DA:63,38 -DA:64,39 -DA:65,0 -DA:72,3 -FN:72,BalanceOperatorUpgradeable.withdraw -FNDA:3,BalanceOperatorUpgradeable.withdraw -DA:77,3 -BRDA:77,0,0,1 -DA:78,2 -DA:79,2 -DA:80,2 -DA:81,0 -DA:88,4 -FN:88,BalanceOperatorUpgradeable.transfer -FNDA:4,BalanceOperatorUpgradeable.transfer -DA:93,4 -BRDA:93,1,0,1 -DA:94,3 -BRDA:94,2,0,1 -DA:96,2 -DA:97,2 -DA:98,2 -DA:99,0 -DA:104,0 -FN:104,BalanceOperatorUpgradeable._getBalanceOperatorStorage +DA:43,3 +DA:50,11346 +FN:50,BalanceOperatorUpgradeable._deposit +FNDA:11346,BalanceOperatorUpgradeable._deposit +DA:55,11346 +DA:56,11345 +DA:57,11346 +DA:58,0 +DA:65,5310 +FN:65,BalanceOperatorUpgradeable._withdraw +FNDA:5310,BalanceOperatorUpgradeable._withdraw +DA:70,5310 +BRDA:70,0,0,1 +DA:71,5309 +DA:72,5309 +DA:73,5309 +DA:74,0 +DA:81,287 +FN:81,BalanceOperatorUpgradeable._transfer +FNDA:287,BalanceOperatorUpgradeable._transfer +DA:86,287 +BRDA:86,1,0,1 +DA:87,286 +BRDA:87,2,0,1 +DA:89,285 +DA:90,285 +DA:91,285 +DA:92,0 +DA:97,0 +FN:97,BalanceOperatorUpgradeable._getBalanceOperatorStorage FNDA:0,BalanceOperatorUpgradeable._getBalanceOperatorStorage -DA:106,0 +DA:99,0 FNF:7 FNH:5 -LF:26 +LF:25 LH:18 BRF:3 BRH:3 @@ -640,24 +647,24 @@ FN:49,FeesCollectorUpgradeable.getTreasuryAddress FNDA:0,FeesCollectorUpgradeable.getTreasuryAddress DA:50,0 DA:51,0 -DA:58,41 +DA:58,37 FN:58,FeesCollectorUpgradeable.__FeesCollector_init -FNDA:41,FeesCollectorUpgradeable.__FeesCollector_init -DA:59,41 -DA:66,41 +FNDA:37,FeesCollectorUpgradeable.__FeesCollector_init +DA:59,37 +DA:66,37 FN:66,FeesCollectorUpgradeable.__FeesCollector_init_unchained -FNDA:41,FeesCollectorUpgradeable.__FeesCollector_init_unchained -DA:67,41 -DA:73,41 +FNDA:37,FeesCollectorUpgradeable.__FeesCollector_init_unchained +DA:67,37 +DA:73,37 FN:73,FeesCollectorUpgradeable._setTreasuryAddress -FNDA:41,FeesCollectorUpgradeable._setTreasuryAddress -DA:74,41 +FNDA:37,FeesCollectorUpgradeable._setTreasuryAddress +DA:74,37 BRDA:74,1,0,- -DA:75,41 -DA:76,41 -DA:82,41 +DA:75,37 +DA:76,37 +DA:82,37 FN:82,FeesCollectorUpgradeable._getFeesCollectorStorage -FNDA:41,FeesCollectorUpgradeable._getFeesCollectorStorage +FNDA:37,FeesCollectorUpgradeable._getFeesCollectorStorage DA:84,0 FNF:6 FNH:4 @@ -668,19 +675,19 @@ BRH:0 end_of_record TN: SF:contracts/core/primitives/upgradeable/LedgerUpgradeable.sol -DA:28,5 +DA:28,5312 FN:28,LedgerUpgradeable.onlyValidOperation -FNDA:5,LedgerUpgradeable.onlyValidOperation -DA:29,5 +FNDA:5312,LedgerUpgradeable.onlyValidOperation +DA:29,5312 BRDA:29,0,0,2 -DA:36,45 +DA:36,48332 FN:36,LedgerUpgradeable.getLedgerBalance -FNDA:45,LedgerUpgradeable.getLedgerBalance -DA:37,45 -DA:38,45 -DA:45,123 +FNDA:48332,LedgerUpgradeable.getLedgerBalance +DA:37,48332 +DA:38,48332 +DA:45,148 FN:45,LedgerUpgradeable.__Ledger_init -FNDA:123,LedgerUpgradeable.__Ledger_init +FNDA:148,LedgerUpgradeable.__Ledger_init DA:50,0 FN:50,LedgerUpgradeable.__Ledger_init_unchained FNDA:0,LedgerUpgradeable.__Ledger_init_unchained @@ -689,19 +696,19 @@ FN:57,LedgerUpgradeable._setLedgerEntry FNDA:1,LedgerUpgradeable._setLedgerEntry DA:58,1 DA:59,1 -DA:67,76 +DA:67,11634 FN:67,LedgerUpgradeable._sumLedgerEntry -FNDA:76,LedgerUpgradeable._sumLedgerEntry -DA:68,76 -DA:69,76 -DA:77,38 +FNDA:11634,LedgerUpgradeable._sumLedgerEntry +DA:68,11634 +DA:69,11634 +DA:77,5596 FN:77,LedgerUpgradeable._subLedgerEntry -FNDA:38,LedgerUpgradeable._subLedgerEntry -DA:78,38 -DA:79,38 -DA:84,160 +FNDA:5596,LedgerUpgradeable._subLedgerEntry +DA:78,5596 +DA:79,5596 +DA:84,65563 FN:84,LedgerUpgradeable._getLedgerStorage -FNDA:160,LedgerUpgradeable._getLedgerStorage +FNDA:65563,LedgerUpgradeable._getLedgerStorage DA:86,0 FNF:8 FNH:7 @@ -711,18 +718,80 @@ BRF:1 BRH:1 end_of_record TN: +SF:contracts/core/primitives/upgradeable/LockOperatorUpgradeable.sol +DA:28,37 +FN:28,LockOperatorUpgradeable.__LockOperator_init +FNDA:37,LockOperatorUpgradeable.__LockOperator_init +DA:29,0 +DA:35,0 +FN:35,LockOperatorUpgradeable.__LockOperator_init_unchained +FNDA:0,LockOperatorUpgradeable.__LockOperator_init_unchained +DA:44,0 +FN:44,LockOperatorUpgradeable._lock +FNDA:0,LockOperatorUpgradeable._lock +DA:49,0 +BRDA:49,0,0,- +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:60,0 +FN:60,LockOperatorUpgradeable._release +FNDA:0,LockOperatorUpgradeable._release +DA:65,0 +BRDA:65,1,0,- +DA:66,0 +DA:67,0 +DA:68,0 +DA:69,0 +DA:78,0 +FN:78,LockOperatorUpgradeable._claim +FNDA:0,LockOperatorUpgradeable._claim +DA:83,0 +BRDA:83,2,0,- +DA:84,0 +DA:85,0 +DA:86,0 +DA:87,0 +DA:95,0 +FN:95,LockOperatorUpgradeable._subLockedAmount +FNDA:0,LockOperatorUpgradeable._subLockedAmount +DA:96,0 +DA:97,0 +DA:105,0 +FN:105,LockOperatorUpgradeable._sumLockedAmount +FNDA:0,LockOperatorUpgradeable._sumLockedAmount +DA:106,0 +DA:107,0 +DA:115,0 +FN:115,LockOperatorUpgradeable._getLockedAmount +FNDA:0,LockOperatorUpgradeable._getLockedAmount +DA:116,0 +DA:117,0 +DA:122,0 +FN:122,LockOperatorUpgradeable._getLockOperatorStorage +FNDA:0,LockOperatorUpgradeable._getLockOperatorStorage +DA:124,0 +FNF:9 +FNH:1 +LF:32 +LH:1 +BRF:3 +BRH:0 +end_of_record +TN: SF:contracts/core/primitives/upgradeable/QuorumUpgradeable.sol -DA:48,54 +DA:48,48 FN:48,QuorumUpgradeable.__Quorum_init -FNDA:54,QuorumUpgradeable.__Quorum_init +FNDA:48,QuorumUpgradeable.__Quorum_init DA:53,0 FN:53,QuorumUpgradeable.__Quorum_init_unchained FNDA:0,QuorumUpgradeable.__Quorum_init_unchained -DA:57,159 +DA:57,5531 FN:57,QuorumUpgradeable._status -FNDA:159,QuorumUpgradeable._status -DA:58,159 -DA:59,159 +FNDA:5531,QuorumUpgradeable._status +DA:58,5531 +DA:59,5531 DA:65,8 FN:65,QuorumUpgradeable._revoke FNDA:8,QuorumUpgradeable._revoke @@ -737,13 +806,13 @@ DA:75,4 DA:76,4 BRDA:76,1,0,- DA:77,4 -DA:82,41 +DA:82,2728 FN:82,QuorumUpgradeable._approve -FNDA:41,QuorumUpgradeable._approve -DA:83,41 -DA:84,41 +FNDA:2728,QuorumUpgradeable._approve +DA:83,2728 +DA:84,2728 BRDA:84,2,0,1 -DA:85,40 +DA:85,2727 DA:90,3 FN:90,QuorumUpgradeable._quit FNDA:3,QuorumUpgradeable._quit @@ -751,16 +820,16 @@ DA:91,3 DA:92,3 BRDA:92,3,0,2 DA:93,1 -DA:98,54 +DA:98,2740 FN:98,QuorumUpgradeable._register -FNDA:54,QuorumUpgradeable._register -DA:99,54 -DA:100,54 +FNDA:2740,QuorumUpgradeable._register +DA:99,2740 +DA:100,2740 BRDA:100,4,0,1 -DA:101,53 -DA:105,269 +DA:101,2739 +DA:105,11014 FN:105,QuorumUpgradeable._getRegistryStorage -FNDA:269,QuorumUpgradeable._getRegistryStorage +FNDA:11014,QuorumUpgradeable._getRegistryStorage DA:107,0 FNF:9 FNH:8 @@ -775,35 +844,35 @@ DA:50,0 FN:50,CustodianFactory.getCreator FNDA:0,CustodianFactory.getCreator DA:51,0 -DA:58,34 +DA:58,2974 FN:58,CustodianFactory.isRegistered -FNDA:34,CustodianFactory.isRegistered -DA:59,34 -DA:69,48 +FNDA:2974,CustodianFactory.isRegistered +DA:59,2974 +DA:69,3498 FN:69,CustodianFactory.create -FNDA:48,CustodianFactory.create -DA:70,48 -DA:71,48 -DA:72,48 -DA:74,48 +FNDA:3498,CustodianFactory.create +DA:70,3498 +DA:71,3498 +DA:72,3498 +DA:74,3498 DA:75,0 -DA:81,48 +DA:81,3498 FN:81,CustodianFactory._registerEndpoint -FNDA:48,CustodianFactory._registerEndpoint -DA:82,48 -DA:83,48 +FNDA:3498,CustodianFactory._registerEndpoint +DA:82,3498 +DA:83,3498 BRDA:83,0,0,- -DA:84,48 +DA:84,3498 DA:85,0 -DA:91,48 +DA:91,3498 FN:91,CustodianFactory._deployCustodian -FNDA:48,CustodianFactory._deployCustodian -DA:92,48 -DA:93,48 -DA:99,48 +FNDA:3498,CustodianFactory._deployCustodian +DA:92,3498 +DA:93,3498 +DA:99,3498 FN:99,CustodianFactory._registerManager -FNDA:48,CustodianFactory._registerManager -DA:100,48 +FNDA:3498,CustodianFactory._registerManager +DA:100,3498 FNF:6 FNH:5 LF:20 @@ -813,31 +882,31 @@ BRH:0 end_of_record TN: SF:contracts/custody/CustodianImpl.sol -DA:49,48 +DA:49,3498 FN:49,CustodianImpl.initialize -FNDA:48,CustodianImpl.initialize -DA:50,48 +FNDA:3498,CustodianImpl.initialize +DA:50,3498 BRDA:50,0,0,- -DA:51,0 -DA:52,48 -DA:53,48 -DA:58,1 -FN:58,CustodianImpl.supportsInterface -FNDA:1,CustodianImpl.supportsInterface -DA:59,1 -DA:63,1 -FN:63,CustodianImpl.getManager -FNDA:1,CustodianImpl.getManager -DA:64,1 -DA:70,2 +DA:52,0 +DA:53,3498 +DA:54,3498 +DA:59,256 +FN:59,CustodianImpl.supportsInterface +FNDA:256,CustodianImpl.supportsInterface +DA:60,256 +DA:64,256 +FN:64,CustodianImpl.getManager +FNDA:256,CustodianImpl.getManager +DA:65,256 +DA:70,257 FN:70,CustodianImpl.getEndpoint -FNDA:2,CustodianImpl.getEndpoint -DA:71,2 -DA:77,1 +FNDA:257,CustodianImpl.getEndpoint +DA:71,257 +DA:77,2 FN:77,CustodianImpl.setEndpoint -FNDA:1,CustodianImpl.setEndpoint -DA:78,1 -BRDA:78,1,0,- +FNDA:2,CustodianImpl.setEndpoint +DA:78,2 +BRDA:78,1,0,1 DA:79,1 DA:80,1 DA:81,1 @@ -858,101 +927,76 @@ FNH:7 LF:23 LH:21 BRF:3 -BRH:1 +BRH:2 end_of_record TN: SF:contracts/custody/CustodianReferendum.sol -DA:71,34 -FN:71,CustodianReferendum.onlyValidCustodian -FNDA:34,CustodianReferendum.onlyValidCustodian -DA:73,34 -BRDA:73,0,0,1 -DA:74,1 -DA:80,41 -FN:80,CustodianReferendum.constructor -FNDA:41,CustodianReferendum.constructor -DA:83,0 -DA:84,41 -DA:85,41 -DA:89,41 -FN:89,CustodianReferendum.initialize -FNDA:41,CustodianReferendum.initialize -DA:90,0 -DA:91,0 -DA:92,41 -DA:94,41 -DA:100,35 -FN:100,CustodianReferendum.isFeeSchemeSupported -FNDA:35,CustodianReferendum.isFeeSchemeSupported -DA:102,35 -DA:106,3 -FN:106,CustodianReferendum.getExpirationPeriod -FNDA:3,CustodianReferendum.getExpirationPeriod -DA:107,3 -DA:112,1 -FN:112,CustodianReferendum.getEnrollmentDeadline -FNDA:1,CustodianReferendum.getEnrollmentDeadline -DA:113,1 -DA:117,2 -FN:117,CustodianReferendum.getEnrollmentCount -FNDA:2,CustodianReferendum.getEnrollmentCount -DA:118,2 -DA:124,27 -FN:124,CustodianReferendum.isActive -FNDA:27,CustodianReferendum.isActive -DA:139,27 -DA:140,27 -DA:146,1 -FN:146,CustodianReferendum.isWaiting +DA:50,2974 +FN:50,CustodianReferendum.onlyValidCustodian +FNDA:2974,CustodianReferendum.onlyValidCustodian +DA:52,2974 +BRDA:52,0,0,256 +DA:53,256 +DA:59,35 +FN:59,CustodianReferendum.constructor +FNDA:35,CustodianReferendum.constructor +DA:62,0 +DA:63,35 +DA:67,35 +FN:67,CustodianReferendum.initialize +FNDA:35,CustodianReferendum.initialize +DA:68,0 +DA:69,0 +DA:70,35 +DA:76,26 +FN:76,CustodianReferendum.isActive +FNDA:26,CustodianReferendum.isActive +DA:82,26 +DA:88,1 +FN:88,CustodianReferendum.isWaiting FNDA:1,CustodianReferendum.isWaiting -DA:147,1 -DA:153,1 -FN:153,CustodianReferendum.isBlocked +DA:89,1 +DA:95,1 +FN:95,CustodianReferendum.isBlocked FNDA:1,CustodianReferendum.isBlocked -DA:154,1 -DA:160,33 -FN:160,CustodianReferendum.register -FNDA:33,CustodianReferendum.register -DA:173,33 -DA:174,32 -BRDA:174,1,0,- -DA:175,0 -DA:179,32 -DA:182,32 -DA:183,32 -DA:188,29 -FN:188,CustodianReferendum.approve -FNDA:29,CustodianReferendum.approve -DA:189,29 -DA:190,29 -DA:191,29 -DA:196,4 -FN:196,CustodianReferendum.revoke +DA:96,1 +DA:101,2718 +FN:101,CustodianReferendum.register +FNDA:2718,CustodianReferendum.register +DA:103,2718 +DA:105,2718 +DA:110,2716 +FN:110,CustodianReferendum.approve +FNDA:2716,CustodianReferendum.approve +DA:111,2716 +DA:112,2716 +DA:113,2716 +DA:118,4 +FN:118,CustodianReferendum.revoke FNDA:4,CustodianReferendum.revoke -DA:197,4 -DA:198,4 -DA:199,4 -DA:204,2 -FN:204,CustodianReferendum.setExpirationPeriod -FNDA:2,CustodianReferendum.setExpirationPeriod -DA:205,2 -DA:206,2 -DA:212,0 -FN:212,CustodianReferendum._authorizeUpgrade +DA:119,4 +DA:120,4 +DA:121,4 +DA:125,257 +FN:125,CustodianReferendum.getEnrollmentCount +FNDA:257,CustodianReferendum.getEnrollmentCount +DA:126,257 +DA:132,0 +FN:132,CustodianReferendum._authorizeUpgrade FNDA:0,CustodianReferendum._authorizeUpgrade -FNF:15 -FNH:14 -LF:46 -LH:41 -BRF:2 +FNF:11 +FNH:10 +LF:30 +LH:26 +BRF:1 BRH:1 end_of_record TN: SF:contracts/economics/MMC.sol -DA:19,63 +DA:19,62 FN:19,MMC.constructor -FNDA:63,MMC.constructor -DA:23,63 +FNDA:62,MMC.constructor +DA:23,62 DA:26,0 FN:26,MMC.burn FNDA:0,MMC.burn @@ -961,10 +1005,10 @@ DA:31,0 FN:31,MMC.nonces FNDA:0,MMC.nonces DA:32,0 -DA:36,109 +DA:36,16862 FN:36,MMC._update -FNDA:109,MMC._update -DA:37,109 +FNDA:16862,MMC._update +DA:37,16862 FNF:4 FNH:2 LF:8 @@ -974,76 +1018,76 @@ BRH:0 end_of_record TN: SF:contracts/economics/Tollgate.sol -DA:59,43 +DA:59,12 FN:59,Tollgate.onlyValidFeeRepresentation -FNDA:43,Tollgate.onlyValidFeeRepresentation -DA:60,43 +FNDA:12,Tollgate.onlyValidFeeRepresentation +DA:60,12 BRDA:60,0,0,1 -DA:61,42 +DA:61,11 BRDA:61,1,0,1 -DA:72,44 +DA:72,13 FN:72,Tollgate.onlySupportedScheme -FNDA:44,Tollgate.onlySupportedScheme -DA:74,44 +FNDA:13,Tollgate.onlySupportedScheme +DA:74,13 BRDA:74,2,0,- DA:75,0 -DA:78,44 -DA:79,44 -DA:82,36 -BRDA:82,3,0,36 -DA:83,36 -DA:84,36 +DA:78,13 +DA:79,13 +DA:82,1 +BRDA:82,3,0,1 +DA:83,1 +DA:84,1 BRDA:84,4,0,1 -DA:92,41 +DA:92,37 FN:92,Tollgate.constructor -FNDA:41,Tollgate.constructor +FNDA:37,Tollgate.constructor DA:93,0 -DA:98,41 +DA:98,37 FN:98,Tollgate.initialize -FNDA:41,Tollgate.initialize +FNDA:37,Tollgate.initialize DA:99,0 -DA:100,41 -DA:107,64 +DA:100,37 +DA:107,257 FN:107,Tollgate.isSupportedCurrency -FNDA:64,Tollgate.isSupportedCurrency -DA:108,64 +FNDA:257,Tollgate.isSupportedCurrency +DA:108,257 DA:114,1 FN:114,Tollgate.supportedCurrencies FNDA:1,Tollgate.supportedCurrencies DA:115,1 -DA:122,38 +DA:122,264 FN:122,Tollgate.getFees -FNDA:38,Tollgate.getFees -DA:124,38 +FNDA:264,Tollgate.getFees +DA:124,264 BRDA:124,5,0,1 DA:125,1 -DA:128,37 -DA:129,37 -DA:130,37 -DA:131,37 -DA:139,41 +DA:128,263 +DA:129,263 +DA:130,263 +DA:131,263 +DA:139,10 FN:139,Tollgate.setFees -FNDA:41,Tollgate.setFees -DA:152,41 +FNDA:10,Tollgate.setFees +DA:152,10 BRDA:152,6,0,- -DA:153,41 -DA:155,41 -DA:156,41 -DA:157,41 -DA:158,41 +DA:153,10 +DA:155,10 +DA:156,10 +DA:157,10 +DA:158,10 DA:163,0 FN:163,Tollgate._authorizeUpgrade FNDA:0,Tollgate._authorizeUpgrade -DA:169,102 +DA:169,521 FN:169,Tollgate._isSchemeSupported -FNDA:102,Tollgate._isSchemeSupported -DA:170,102 -DA:171,102 -DA:172,102 -DA:180,180 +FNDA:521,Tollgate._isSchemeSupported +DA:170,521 +DA:171,521 +DA:172,521 +DA:180,794 FN:180,Tollgate._computeComposedKey -FNDA:180,Tollgate._computeComposedKey -DA:181,180 +FNDA:794,Tollgate._computeComposedKey +DA:181,794 FNF:11 FNH:10 LF:41 @@ -1053,96 +1097,130 @@ BRH:5 end_of_record TN: SF:contracts/economics/Treasury.sol -DA:35,41 -FN:35,Treasury.constructor -FNDA:41,Treasury.constructor -DA:38,0 -DA:41,41 -FN:41,Treasury.initialize -FNDA:41,Treasury.initialize -DA:42,0 -DA:43,0 -DA:44,41 -DA:59,0 -FN:59,Treasury.deposit +DA:37,37 +FN:37,Treasury.constructor +FNDA:37,Treasury.constructor +DA:40,0 +DA:43,37 +FN:43,Treasury.initialize +FNDA:37,Treasury.initialize +DA:44,0 +DA:45,0 +DA:46,0 +DA:47,37 +DA:65,0 +FN:65,Treasury.deposit FNDA:0,Treasury.deposit -DA:66,0 -DA:75,0 -FN:75,Treasury.collectFees -FNDA:0,Treasury.collectFees +DA:70,0 +DA:80,0 +FN:80,Treasury.withdraw +FNDA:0,Treasury.withdraw DA:85,0 -FN:85,Treasury._authorizeUpgrade +DA:95,0 +FN:95,Treasury.transfer +FNDA:0,Treasury.transfer +DA:100,0 +DA:109,0 +FN:109,Treasury.collectFees +FNDA:0,Treasury.collectFees +DA:120,0 +FN:120,Treasury._authorizeUpgrade FNDA:0,Treasury._authorizeUpgrade -FNF:5 +FNF:7 FNH:2 -LF:10 +LF:15 LH:3 BRF:0 BRH:0 end_of_record TN: SF:contracts/financial/AgreementManager.sol -DA:67,32 -FN:67,AgreementManager.onlySupportedCurrency -FNDA:32,AgreementManager.onlySupportedCurrency -DA:68,32 -DA:69,32 -BRDA:69,0,0,- -DA:74,41 -FN:74,AgreementManager.constructor -FNDA:41,AgreementManager.constructor -DA:77,0 -DA:79,41 -DA:80,41 -DA:84,41 -FN:84,AgreementManager.initialize -FNDA:41,AgreementManager.initialize -DA:85,0 -DA:86,41 -DA:95,32 -FN:95,AgreementManager.createAgreement -FNDA:32,AgreementManager.createAgreement -DA:103,32 -DA:104,32 -DA:107,32 -DA:108,32 -DA:109,0 -DA:114,33 -FN:114,AgreementManager.getAgreement -FNDA:33,AgreementManager.getAgreement -DA:115,33 -DA:124,32 -FN:124,AgreementManager.previewAgreement -FNDA:32,AgreementManager.previewAgreement -DA:131,32 -BRDA:131,1,0,- +DA:70,257 +FN:70,AgreementManager.onlySupportedCurrency +FNDA:257,AgreementManager.onlySupportedCurrency +DA:71,257 +DA:72,257 +BRDA:72,0,0,- +DA:77,37 +FN:77,AgreementManager.constructor +FNDA:37,AgreementManager.constructor +DA:80,0 +DA:82,37 +DA:83,37 +DA:87,37 +FN:87,AgreementManager.initialize +FNDA:37,AgreementManager.initialize +DA:88,0 +DA:89,37 +DA:90,37 +DA:95,0 +FN:95,AgreementManager.setMaxParties +FNDA:0,AgreementManager.setMaxParties +DA:96,0 +BRDA:96,1,0,- +DA:97,0 +DA:101,0 +FN:101,AgreementManager.maxParties +FNDA:0,AgreementManager.maxParties +DA:102,0 +DA:111,0 +FN:111,AgreementManager.createAgreement +FNDA:0,AgreementManager.createAgreement +DA:119,0 +DA:120,0 +DA:124,0 +DA:125,0 +DA:126,0 +DA:131,0 +FN:131,AgreementManager.getAgreement +FNDA:0,AgreementManager.getAgreement DA:132,0 -DA:151,32 -DA:154,32 -DA:169,0 -FN:169,AgreementManager._authorizeUpgrade +DA:141,257 +FN:141,AgreementManager.previewAgreement +FNDA:257,AgreementManager.previewAgreement +DA:160,257 +DA:164,257 +DA:165,257 +DA:169,257 +DA:185,0 +FN:185,AgreementManager._authorizeUpgrade FNDA:0,AgreementManager._authorizeUpgrade -DA:172,32 -FN:172,AgreementManager._createAndStoreProof -FNDA:32,AgreementManager._createAndStoreProof -DA:174,32 -DA:175,32 -DA:176,32 -DA:177,0 -DA:186,32 -FN:186,AgreementManager._calcFees -FNDA:32,AgreementManager._calcFees -DA:188,32 -DA:189,32 -DA:190,32 -DA:191,32 -BRDA:191,4,0,- -DA:192,32 -FNF:9 -FNH:8 -LF:35 -LH:29 -BRF:3 +DA:188,0 +FN:188,AgreementManager._createAndStoreProof +FNDA:0,AgreementManager._createAndStoreProof +DA:190,0 +DA:191,0 +DA:192,0 +DA:193,0 +DA:197,257 +FN:197,AgreementManager._calculatePenalization +FNDA:257,AgreementManager._calculatePenalization +DA:198,257 +DA:199,256 +DA:200,256 +DA:201,256 +DA:209,256 +FN:209,AgreementManager._penaltyBps +FNDA:256,AgreementManager._penaltyBps +DA:210,256 +DA:214,256 +DA:218,256 +BRDA:218,4,0,- +DA:219,0 +DA:229,257 +FN:229,AgreementManager._calcFees +FNDA:257,AgreementManager._calcFees +DA:231,257 +DA:232,257 +DA:233,0 +DA:234,0 +BRDA:234,7,0,- +DA:235,0 +FNF:13 +FNH:7 +LF:51 +LH:26 +BRF:4 BRH:0 end_of_record TN: @@ -1153,19 +1231,19 @@ FNDA:0,AgreementSettler.onlyValidAgreement DA:86,0 BRDA:86,0,0,- DA:87,0 -DA:93,41 +DA:93,37 FN:93,AgreementSettler.constructor -FNDA:41,AgreementSettler.constructor +FNDA:37,AgreementSettler.constructor DA:96,0 -DA:97,41 -DA:98,41 -DA:99,41 -DA:103,41 +DA:97,37 +DA:98,37 +DA:99,37 +DA:103,37 FN:103,AgreementSettler.initialize -FNDA:41,AgreementSettler.initialize +FNDA:37,AgreementSettler.initialize DA:104,0 -DA:105,41 -DA:106,41 +DA:105,37 +DA:106,37 DA:114,0 FN:114,AgreementSettler.disburse FNDA:0,AgreementSettler.disburse @@ -1174,149 +1252,117 @@ DA:117,0 DA:119,0 DA:120,0 DA:121,0 -DA:139,0 -FN:139,AgreementSettler.quitAgreement +DA:138,0 +FN:138,AgreementSettler.quitAgreement FNDA:0,AgreementSettler.quitAgreement +DA:139,0 DA:140,0 -DA:141,0 -BRDA:141,2,0,- +BRDA:140,2,0,- +DA:154,0 DA:155,0 DA:156,0 -DA:157,0 -DA:158,0 -DA:160,0 -DA:162,0 DA:164,0 -BRDA:164,3,0,- +DA:165,0 DA:166,0 -DA:167,0 -DA:173,33 -FN:173,AgreementSettler.settleAgreement -FNDA:33,AgreementSettler.settleAgreement -DA:178,33 -DA:179,33 -BRDA:179,4,0,1 -DA:181,32 -DA:182,32 -DA:183,32 -DA:184,32 -DA:185,32 -DA:190,32 -DA:193,32 -DA:195,32 -BRDA:195,5,0,- -DA:196,32 -DA:197,0 -DA:203,0 -FN:203,AgreementSettler._authorizeUpgrade +DA:168,0 +DA:170,0 +DA:172,0 +BRDA:172,3,0,- +DA:174,0 +DA:175,0 +DA:201,0 +FN:201,AgreementSettler.settleAgreement +FNDA:0,AgreementSettler.settleAgreement +DA:206,0 +DA:207,0 +BRDA:207,4,0,- +DA:209,0 +DA:210,0 +DA:211,0 +DA:212,0 +DA:213,0 +DA:215,0 +DA:216,0 +DA:217,0 +DA:222,0 +DA:226,0 +DA:228,0 +BRDA:228,5,0,- +DA:229,0 +DA:230,0 +DA:236,0 +FN:236,AgreementSettler._authorizeUpgrade FNDA:0,AgreementSettler._authorizeUpgrade -DA:207,32 -FN:207,AgreementSettler._setProofAsSettled -FNDA:32,AgreementSettler._setProofAsSettled -DA:208,32 +DA:240,0 +FN:240,AgreementSettler._setProofAsSettled +FNDA:0,AgreementSettler._setProofAsSettled +DA:241,0 FNF:8 -FNH:4 -LF:46 -LH:21 +FNH:2 +LF:51 +LH:7 BRF:5 -BRH:1 +BRH:0 end_of_record TN: SF:contracts/financial/LedgerVault.sol -DA:65,41 -FN:65,LedgerVault.constructor -FNDA:41,LedgerVault.constructor -DA:68,0 -DA:71,41 -FN:71,LedgerVault.initialize -FNDA:41,LedgerVault.initialize -DA:72,0 -DA:73,0 -DA:74,0 -DA:75,41 -DA:85,32 -FN:85,LedgerVault.lock -FNDA:32,LedgerVault.lock -DA:90,32 -BRDA:90,0,0,- -DA:91,32 -DA:92,32 -DA:93,32 -DA:94,0 -DA:101,0 -FN:101,LedgerVault.release +DA:31,37 +FN:31,LedgerVault.constructor +FNDA:37,LedgerVault.constructor +DA:34,0 +DA:37,37 +FN:37,LedgerVault.initialize +FNDA:37,LedgerVault.initialize +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,37 +DA:54,0 +FN:54,LedgerVault.lock +FNDA:0,LedgerVault.lock +DA:59,0 +DA:66,0 +FN:66,LedgerVault.release FNDA:0,LedgerVault.release -DA:106,0 -BRDA:106,1,0,- -DA:107,0 +DA:71,0 +DA:80,0 +FN:80,LedgerVault.claim +FNDA:0,LedgerVault.claim +DA:85,0 +DA:92,0 +FN:92,LedgerVault.approve +FNDA:0,LedgerVault.approve +DA:93,0 +DA:100,0 +FN:100,LedgerVault.revoke +FNDA:0,LedgerVault.revoke +DA:101,0 DA:108,0 +FN:108,LedgerVault.collect +FNDA:0,LedgerVault.collect DA:109,0 -DA:110,0 -DA:119,32 -FN:119,LedgerVault.claim -FNDA:32,LedgerVault.claim -DA:124,32 -BRDA:124,2,0,- -DA:125,32 -DA:126,32 -DA:127,32 -DA:128,0 -DA:136,32 -FN:136,LedgerVault._subLockedAmount -FNDA:32,LedgerVault._subLockedAmount -DA:137,32 -DA:145,32 -FN:145,LedgerVault._sumLockedAmount -FNDA:32,LedgerVault._sumLockedAmount -DA:146,32 -DA:154,32 -FN:154,LedgerVault._getLockedAmount -FNDA:32,LedgerVault._getLockedAmount -DA:155,32 -DA:161,0 -FN:161,LedgerVault._authorizeUpgrade +DA:116,2 +FN:116,LedgerVault.deposit +FNDA:2,LedgerVault.deposit +DA:117,2 +DA:124,0 +FN:124,LedgerVault.withdraw +FNDA:0,LedgerVault.withdraw +DA:129,0 +DA:136,0 +FN:136,LedgerVault.transfer +FNDA:0,LedgerVault.transfer +DA:137,0 +DA:143,0 +FN:143,LedgerVault._authorizeUpgrade FNDA:0,LedgerVault._authorizeUpgrade -FNF:9 -FNH:7 -LF:32 -LH:19 -BRF:3 -BRH:0 -end_of_record -TN: -SF:contracts/governance/Governance.sol -DA:56,0 -FN:56,Governance.state -FNDA:0,Governance.state -DA:57,0 -DA:62,0 -FN:62,Governance.proposalNeedsQueuing -FNDA:0,Governance.proposalNeedsQueuing -DA:65,0 -DA:77,0 -FN:77,Governance._queueOperations -FNDA:0,Governance._queueOperations -DA:84,0 -DA:95,0 -FN:95,Governance._executeOperations -FNDA:0,Governance._executeOperations -DA:102,0 -DA:113,0 -FN:113,Governance._cancel -FNDA:0,Governance._cancel -DA:119,0 -DA:126,0 -FN:126,Governance._executor -FNDA:0,Governance._executor -DA:127,0 -DA:134,0 -FN:134,Governance.proposalThreshold -FNDA:0,Governance.proposalThreshold -DA:135,0 -FNF:7 -FNH:0 -LF:14 -LH:0 +FNF:12 +FNH:3 +LF:29 +LH:5 BRF:0 BRH:0 end_of_record @@ -1356,34 +1402,34 @@ FNDA:0,HookRegistry.initialize DA:68,0 DA:69,0 DA:70,0 -DA:78,0 -FN:78,HookRegistry.submit +DA:77,0 +FN:77,HookRegistry.submit FNDA:0,HookRegistry.submit +DA:78,0 DA:79,0 DA:80,0 -DA:81,0 -DA:87,0 -FN:87,HookRegistry.approve +DA:86,0 +FN:86,HookRegistry.approve FNDA:0,HookRegistry.approve +DA:87,0 DA:88,0 -DA:89,0 -DA:95,0 -FN:95,HookRegistry.reject +DA:94,0 +FN:94,HookRegistry.reject FNDA:0,HookRegistry.reject +DA:95,0 DA:96,0 -DA:97,0 -DA:103,0 -FN:103,HookRegistry.lookup +DA:102,0 +FN:102,HookRegistry.lookup FNDA:0,HookRegistry.lookup -DA:104,0 -DA:110,0 -FN:110,HookRegistry.isActive +DA:103,0 +DA:109,0 +FN:109,HookRegistry.isActive FNDA:0,HookRegistry.isActive +DA:110,0 DA:111,0 DA:112,0 -DA:113,0 -DA:119,0 -FN:119,HookRegistry._authorizeUpgrade +DA:118,0 +FN:118,HookRegistry._authorizeUpgrade FNDA:0,HookRegistry._authorizeUpgrade FNF:9 FNH:0 @@ -1535,14 +1581,14 @@ DA:120,1 FN:120,RightsAssetCustodian.getMaxAllowedRedundancy FNDA:1,RightsAssetCustodian.getMaxAllowedRedundancy DA:121,1 -DA:126,4 +DA:126,5 FN:126,RightsAssetCustodian.revokeCustody -FNDA:4,RightsAssetCustodian.revokeCustody -DA:128,4 -DA:129,4 +FNDA:5,RightsAssetCustodian.revokeCustody +DA:128,5 +DA:129,5 BRDA:129,2,0,1 -DA:130,3 -DA:131,3 +DA:130,4 +DA:131,4 DA:138,18 FN:138,RightsAssetCustodian.grantCustody FNDA:18,RightsAssetCustodian.grantCustody @@ -1625,13 +1671,13 @@ FN:332,RightsAssetCustodian._incrementDemand FNDA:17,RightsAssetCustodian._incrementDemand DA:333,17 DA:334,17 -DA:340,3 +DA:340,4 FN:340,RightsAssetCustodian._decrementDemand -FNDA:3,RightsAssetCustodian._decrementDemand -DA:341,3 -BRDA:341,7,0,3 -DA:342,3 -DA:345,3 +FNDA:4,RightsAssetCustodian._decrementDemand +DA:341,4 +BRDA:341,7,0,4 +DA:342,4 +DA:345,4 DA:351,13 FN:351,RightsAssetCustodian._getDemand FNDA:13,RightsAssetCustodian._getDemand @@ -1653,10 +1699,10 @@ FNDA:1,RightsAssetCustodian._calcRandomness DA:390,1 DA:391,1 DA:392,1 -DA:398,26 +DA:398,25 FN:398,RightsAssetCustodian._isValidActiveCustodian -FNDA:26,RightsAssetCustodian._isValidActiveCustodian -DA:399,26 +FNDA:25,RightsAssetCustodian._isValidActiveCustodian +DA:399,25 DA:406,29 FN:406,RightsAssetCustodian._computeComposedKey FNDA:29,RightsAssetCustodian._computeComposedKey @@ -1738,105 +1784,111 @@ DA:77,0 FN:77,RightsPolicyManager.onlyAuthorizedPolicy FNDA:0,RightsPolicyManager.onlyAuthorizedPolicy DA:78,0 +BRDA:78,0,0,- +BRDA:78,0,1,- DA:79,0 -BRDA:79,0,0,- -DA:84,0 -FN:84,RightsPolicyManager.constructor +DA:80,0 +BRDA:80,1,0,- +DA:85,0 +FN:85,RightsPolicyManager.constructor FNDA:0,RightsPolicyManager.constructor -DA:87,0 DA:88,0 DA:89,0 -DA:93,0 -FN:93,RightsPolicyManager.initialize -FNDA:0,RightsPolicyManager.initialize +DA:90,0 DA:94,0 +FN:94,RightsPolicyManager.initialize +FNDA:0,RightsPolicyManager.initialize DA:95,0 DA:96,0 -DA:104,0 -FN:104,RightsPolicyManager.registerPolicy +DA:97,0 +DA:105,0 +FN:105,RightsPolicyManager.registerPolicy FNDA:0,RightsPolicyManager.registerPolicy -DA:110,0 DA:111,0 -DA:116,0 -DA:117,0 -BRDA:117,1,0,- -DA:119,0 -DA:120,0 +DA:112,0 +DA:113,0 +BRDA:113,2,0,- +DA:114,0 DA:121,0 -DA:127,0 -FN:127,RightsPolicyManager.getActivePolicy -FNDA:0,RightsPolicyManager.getActivePolicy -DA:128,0 -DA:129,0 +DA:122,0 +BRDA:122,3,0,- +DA:124,0 +DA:125,0 +DA:126,0 DA:132,0 +FN:132,RightsPolicyManager.getActivePolicy +FNDA:0,RightsPolicyManager.getActivePolicy +DA:133,0 DA:134,0 -BRDA:134,2,0,- -DA:135,0 +DA:137,0 DA:139,0 -DA:148,0 -FN:148,RightsPolicyManager.getActivePolicies +BRDA:139,4,0,- +DA:140,0 +DA:144,0 +DA:153,0 +FN:153,RightsPolicyManager.getActivePolicies FNDA:0,RightsPolicyManager.getActivePolicies -DA:149,0 -DA:150,0 -DA:151,0 -DA:152,0 +DA:154,0 DA:155,0 DA:156,0 DA:157,0 +DA:160,0 DA:161,0 -DA:174,0 -DA:176,0 +DA:162,0 +DA:166,0 +DA:179,0 DA:181,0 -FN:181,RightsPolicyManager.getPolicies +DA:186,0 +FN:186,RightsPolicyManager.getPolicies FNDA:0,RightsPolicyManager.getPolicies -DA:188,0 -DA:195,0 -FN:195,RightsPolicyManager.isActivePolicy +DA:193,0 +DA:201,0 +FN:201,RightsPolicyManager.isActivePolicy FNDA:0,RightsPolicyManager.isActivePolicy -DA:196,0 -DA:197,0 -DA:204,0 -FN:204,RightsPolicyManager.isRegisteredPolicy +DA:202,0 +DA:203,0 +DA:210,0 +FN:210,RightsPolicyManager.isRegisteredPolicy FNDA:0,RightsPolicyManager.isRegisteredPolicy -DA:205,0 DA:211,0 -FN:211,RightsPolicyManager._authorizeUpgrade +DA:217,0 +FN:217,RightsPolicyManager._authorizeUpgrade FNDA:0,RightsPolicyManager._authorizeUpgrade -DA:218,0 -FN:218,RightsPolicyManager._verifyPolicyAccess +DA:224,0 +FN:224,RightsPolicyManager._verifyPolicyAccess FNDA:0,RightsPolicyManager._verifyPolicyAccess -DA:219,0 -DA:220,0 -DA:221,0 -DA:222,0 -DA:232,0 -FN:232,RightsPolicyManager._registerBatchPolicies -FNDA:0,RightsPolicyManager._registerBatchPolicies +DA:225,0 +DA:226,0 +DA:227,0 +DA:228,0 DA:238,0 -DA:240,0 -DA:241,0 -DA:242,0 -DA:251,0 -FN:251,RightsPolicyManager._registerPolicy +FN:238,RightsPolicyManager._registerBatchPolicies +FNDA:0,RightsPolicyManager._registerBatchPolicies +DA:244,0 +DA:246,0 +DA:247,0 +DA:248,0 +DA:257,0 +FN:257,RightsPolicyManager._registerPolicy FNDA:0,RightsPolicyManager._registerPolicy -DA:252,0 +DA:258,0 FNF:13 FNH:0 -LF:57 +LF:60 LH:0 -BRF:3 +BRF:6 BRH:0 end_of_record TN: SF:script/create3/CREATE3Factory.sol -DA:10,476 +DA:10,443 FN:10,CREATE3Factory.deploy -FNDA:476,CREATE3Factory.deploy -DA:12,476 -DA:16,1076 +FNDA:443,CREATE3Factory.deploy +DA:12,443 +DA:16,950 FN:16,CREATE3Factory.getDeployed -FNDA:1076,CREATE3Factory.getDeployed -DA:18,1076 +FNDA:950,CREATE3Factory.getDeployed +DA:18,950 FNF:2 FNH:2 LF:4 @@ -1846,47 +1898,47 @@ BRH:0 end_of_record TN: SF:script/deployment/00_Deploy_Base.s.sol -DA:14,1552 +DA:14,1393 FN:14,DeployBase.getCreate3FactoryAddress -FNDA:1552,DeployBase.getCreate3FactoryAddress -DA:15,1552 -DA:18,552 +FNDA:1393,DeployBase.getCreate3FactoryAddress +DA:15,1393 +DA:18,518 FN:18,DeployBase.getAdminPK -FNDA:552,DeployBase.getAdminPK -DA:19,552 -DA:23,1628 +FNDA:518,DeployBase.getAdminPK +DA:19,518 +DA:23,1468 FN:23,DeployBase.getSalt -FNDA:1628,DeployBase.getSalt -DA:24,1628 -DA:27,1076 +FNDA:1468,DeployBase.getSalt +DA:24,1468 +DA:27,950 FN:27,DeployBase.computeCreate3Address -FNDA:1076,DeployBase.computeCreate3Address -DA:32,1076 -DA:43,1076 -DA:46,114 +FNDA:950,DeployBase.computeCreate3Address +DA:32,950 +DA:43,950 +DA:46,108 FN:46,DeployBase.deploy -FNDA:114,DeployBase.deploy -DA:48,114 -DA:49,114 -DA:52,362 +FNDA:108,DeployBase.deploy +DA:48,108 +DA:49,108 +DA:52,335 FN:52,DeployBase.deployUUPS -FNDA:362,DeployBase.deployUUPS -DA:58,362 -DA:62,362 -DA:63,362 -DA:65,362 -DA:85,362 -DA:89,476 +FNDA:335,DeployBase.deployUUPS +DA:58,335 +DA:62,335 +DA:63,335 +DA:65,335 +DA:85,335 +DA:89,443 FN:89,DeployBase._checkExpectedAddress -FNDA:476,DeployBase._checkExpectedAddress -DA:90,476 -DA:91,476 +FNDA:443,DeployBase._checkExpectedAddress +DA:90,443 +DA:91,443 BRDA:91,0,0,- BRDA:91,0,1,- -DA:94,552 +DA:94,518 FN:94,DeployBase._logAddress -FNDA:552,DeployBase._logAddress -DA:95,552 +FNDA:518,DeployBase._logAddress +DA:95,518 DA:96,0 DA:97,0 FNF:8 @@ -1898,18 +1950,18 @@ BRH:0 end_of_record TN: SF:script/deployment/01_Deploy_Base_Create3.s.sol -DA:8,76 +DA:8,75 FN:8,DeployCreate3Factory.run -FNDA:76,DeployCreate3Factory.run -DA:10,76 -DA:11,76 -DA:12,76 +FNDA:75,DeployCreate3Factory.run +DA:10,75 +DA:11,75 +DA:12,75 DA:15,0 DA:16,0 BRDA:16,0,0,- DA:17,0 -DA:21,76 -DA:22,76 +DA:21,75 +DA:22,75 DA:23,0 FNF:1 FNH:1 @@ -1920,18 +1972,18 @@ BRH:0 end_of_record TN: SF:script/deployment/02_Deploy_Access_AccessManager.s.sol -DA:9,76 +DA:9,75 FN:9,DeployAccessManager.run -FNDA:76,DeployAccessManager.run -DA:10,76 -DA:11,76 -DA:13,76 -DA:14,76 -DA:15,76 -DA:16,76 -DA:17,76 -DA:19,76 -DA:20,76 +FNDA:75,DeployAccessManager.run +DA:10,75 +DA:11,75 +DA:13,75 +DA:14,75 +DA:15,75 +DA:16,75 +DA:17,75 +DA:19,75 +DA:20,75 DA:21,0 FNF:1 FNH:1 @@ -1942,18 +1994,18 @@ BRH:0 end_of_record TN: SF:script/deployment/03_Deploy_Economics_Token.s.sol -DA:8,63 +DA:8,62 FN:8,DeployToken.run -FNDA:63,DeployToken.run -DA:9,63 -DA:10,63 -DA:12,63 -DA:13,63 -DA:15,63 -DA:16,63 -DA:17,63 -DA:19,63 -DA:20,63 +FNDA:62,DeployToken.run +DA:9,62 +DA:10,62 +DA:12,62 +DA:13,62 +DA:15,62 +DA:16,62 +DA:17,62 +DA:19,62 +DA:20,62 DA:21,0 FNF:1 FNH:1 @@ -1964,17 +2016,17 @@ BRH:0 end_of_record TN: SF:script/deployment/04_Deploy_Economics_Tollgate.s.sol -DA:10,41 +DA:10,37 FN:10,DeployTollgate.run -FNDA:41,DeployTollgate.run -DA:11,41 -DA:12,41 -DA:13,41 -DA:14,41 -DA:15,41 -DA:16,41 -DA:18,41 -DA:19,41 +FNDA:37,DeployTollgate.run +DA:11,37 +DA:12,37 +DA:13,37 +DA:14,37 +DA:15,37 +DA:16,37 +DA:18,37 +DA:19,37 DA:20,0 FNF:1 FNH:1 @@ -1985,17 +2037,17 @@ BRH:0 end_of_record TN: SF:script/deployment/05_Deploy_Economics_Treasury.s.sol -DA:10,41 +DA:10,37 FN:10,DeployTreasury.run -FNDA:41,DeployTreasury.run -DA:11,41 -DA:12,41 -DA:13,41 -DA:14,41 -DA:15,41 -DA:16,41 -DA:18,41 -DA:19,41 +FNDA:37,DeployTreasury.run +DA:11,37 +DA:12,37 +DA:13,37 +DA:14,37 +DA:15,37 +DA:16,37 +DA:18,37 +DA:19,37 DA:20,0 FNF:1 FNH:1 @@ -2006,17 +2058,17 @@ BRH:0 end_of_record TN: SF:script/deployment/06_Deploy_Financial_LedgerVault.s.sol -DA:8,41 +DA:8,37 FN:8,DeployLedgerVault.run -FNDA:41,DeployLedgerVault.run -DA:10,41 -DA:11,41 -DA:12,41 -DA:13,41 -DA:14,41 -DA:15,41 -DA:17,41 -DA:18,41 +FNDA:37,DeployLedgerVault.run +DA:10,37 +DA:11,37 +DA:12,37 +DA:13,37 +DA:14,37 +DA:15,37 +DA:17,37 +DA:18,37 DA:19,0 FNF:1 FNH:1 @@ -2027,19 +2079,19 @@ BRH:0 end_of_record TN: SF:script/deployment/07_Deploy_Financial_AgreementManager.s.sol -DA:8,41 +DA:8,37 FN:8,DeployAgreementManager.run -FNDA:41,DeployAgreementManager.run -DA:9,41 -DA:10,41 -DA:11,41 -DA:12,41 -DA:13,41 -DA:14,41 -DA:15,41 -DA:16,41 -DA:18,41 -DA:19,41 +FNDA:37,DeployAgreementManager.run +DA:9,37 +DA:10,37 +DA:11,37 +DA:12,37 +DA:13,37 +DA:14,37 +DA:15,37 +DA:16,37 +DA:18,37 +DA:19,37 DA:20,0 FNF:1 FNH:1 @@ -2050,20 +2102,20 @@ BRH:0 end_of_record TN: SF:script/deployment/08_Deploy_Financial_AgreementSettler.s.sol -DA:8,41 +DA:8,37 FN:8,DeployAgreementSettler.run -FNDA:41,DeployAgreementSettler.run -DA:10,41 -DA:11,41 -DA:12,41 -DA:13,41 -DA:14,41 -DA:15,41 -DA:16,41 -DA:17,41 -DA:18,41 -DA:20,41 -DA:21,41 +FNDA:37,DeployAgreementSettler.run +DA:10,37 +DA:11,37 +DA:12,37 +DA:13,37 +DA:14,37 +DA:15,37 +DA:16,37 +DA:17,37 +DA:18,37 +DA:20,37 +DA:21,37 DA:22,0 FNF:1 FNH:1 @@ -2074,17 +2126,17 @@ BRH:0 end_of_record TN: SF:script/deployment/09_Deploy_Custody_CustodianFactory.s.sol -DA:9,51 +DA:9,46 FN:9,DeployCustodianFactory.run -FNDA:51,DeployCustodianFactory.run -DA:11,51 -DA:12,51 -DA:13,51 -DA:14,51 -DA:15,51 -DA:16,51 -DA:18,51 -DA:19,51 +FNDA:46,DeployCustodianFactory.run +DA:11,46 +DA:12,46 +DA:13,46 +DA:14,46 +DA:15,46 +DA:16,46 +DA:18,46 +DA:19,46 DA:20,0 FNF:1 FNH:1 @@ -2095,24 +2147,23 @@ BRH:0 end_of_record TN: SF:script/deployment/10_Deploy_Custody_CustodianReferendum.s.sol -DA:9,41 +DA:9,35 FN:9,DeployCustodianReferendum.run -FNDA:41,DeployCustodianReferendum.run -DA:10,41 -DA:11,41 -DA:12,41 -DA:13,41 -DA:14,41 -DA:15,41 -DA:16,41 -DA:17,41 -DA:19,41 -DA:20,41 -DA:21,0 +FNDA:35,DeployCustodianReferendum.run +DA:10,35 +DA:11,35 +DA:12,35 +DA:13,35 +DA:14,35 +DA:15,35 +DA:16,35 +DA:18,35 +DA:19,35 +DA:20,0 FNF:1 FNH:1 -LF:12 -LH:11 +LF:11 +LH:10 BRF:0 BRH:0 end_of_record @@ -2298,32 +2349,23 @@ DA:49,0 DA:50,0 DA:51,0 DA:54,0 +DA:55,0 DA:56,0 DA:57,0 -DA:61,0 DA:62,0 DA:63,0 -DA:64,0 +DA:65,0 DA:67,0 -DA:68,0 DA:69,0 +DA:70,0 +BRDA:70,0,0,- +BRDA:70,0,1,- DA:71,0 -DA:73,0 -DA:74,0 -DA:76,0 -DA:77,0 -DA:79,0 -BRDA:79,0,0,- -BRDA:79,0,1,- -DA:80,0 -BRDA:80,1,0,- -BRDA:80,1,1,- -DA:82,0 FNF:1 FNH:0 -LF:42 +LF:35 LH:0 -BRF:4 +BRF:2 BRH:0 end_of_record TN: @@ -2337,32 +2379,27 @@ DA:16,0 DA:17,0 DA:18,0 DA:19,0 -DA:20,0 -DA:22,0 +DA:21,0 +DA:23,0 DA:24,0 -DA:25,0 +DA:26,0 DA:27,0 -DA:28,0 +DA:29,0 +BRDA:29,0,0,- +BRDA:29,0,1,- DA:30,0 -BRDA:30,0,0,- -BRDA:30,0,1,- -DA:31,0 -BRDA:31,1,0,- -BRDA:31,1,1,- +BRDA:30,1,0,- +BRDA:30,1,1,- +DA:33,0 DA:34,0 DA:35,0 -DA:36,0 +DA:37,0 DA:38,0 DA:39,0 -DA:40,0 -DA:42,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:54,0 +DA:41,0 FNF:1 FNH:0 -LF:26 +LF:21 LH:0 BRF:4 BRH:0 @@ -2502,13 +2539,12 @@ DA:10,0 DA:11,0 DA:12,0 DA:13,0 -DA:14,0 +DA:17,0 DA:18,0 DA:19,0 -DA:20,0 FNF:1 FNH:0 -LF:9 +LF:8 LH:0 BRF:0 BRH:0 @@ -2609,136 +2645,167 @@ BRH:0 end_of_record TN: SF:test/BaseTest.t.sol -DA:58,76 -FN:58,BaseTest.initialize -FNDA:76,BaseTest.initialize -DA:60,76 -DA:61,76 -DA:62,76 -DA:64,0 -DA:65,0 -DA:71,76 -FN:71,BaseTest.deployCreate3Factory -FNDA:76,BaseTest.deployCreate3Factory -DA:73,76 -DA:74,76 -DA:76,76 -DA:77,76 -DA:78,76 -DA:82,106 -FN:82,BaseTest.deployToken -FNDA:106,BaseTest.deployToken -DA:84,106 -DA:85,106 -DA:89,76 -FN:89,BaseTest.deployAccessManager -FNDA:76,BaseTest.deployAccessManager -DA:91,76 -DA:92,76 -DA:94,76 -DA:96,76 -DA:97,76 -DA:101,67 -FN:101,BaseTest.deployTollgate -FNDA:67,BaseTest.deployTollgate -DA:103,0 -DA:105,67 -DA:106,67 -DA:107,67 -DA:109,41 -DA:113,116 -FN:113,BaseTest.deployLedgerVault -FNDA:116,BaseTest.deployLedgerVault -DA:115,116 -DA:116,116 -DA:117,116 -DA:119,116 -DA:121,116 -DA:122,116 -DA:123,116 -DA:127,58 -FN:127,BaseTest.deployTreasury -FNDA:58,BaseTest.deployTreasury -DA:129,58 -DA:130,58 -DA:131,58 -DA:132,41 -DA:135,58 -FN:135,BaseTest.deployAgreementManager -FNDA:58,BaseTest.deployAgreementManager -DA:136,0 -DA:137,58 -DA:139,58 -DA:140,58 -DA:142,58 -DA:145,58 -FN:145,BaseTest.deployAgreementSettler -FNDA:58,BaseTest.deployAgreementSettler +DA:60,75 +FN:60,BaseTest.initialize +FNDA:75,BaseTest.initialize +DA:62,75 +DA:63,75 +DA:64,75 +DA:65,75 +DA:66,75 +DA:68,0 +DA:69,0 +DA:75,75 +FN:75,BaseTest.deployCreate3Factory +FNDA:75,BaseTest.deployCreate3Factory +DA:77,75 +DA:78,75 +DA:80,75 +DA:81,75 +DA:82,75 +DA:86,105 +FN:86,BaseTest.deployToken +FNDA:105,BaseTest.deployToken +DA:88,105 +DA:89,105 +DA:93,75 +FN:93,BaseTest.deployAccessManager +FNDA:75,BaseTest.deployAccessManager +DA:95,75 +DA:96,75 +DA:98,75 +DA:100,75 +DA:101,75 +DA:103,75 +DA:105,75 +DA:106,75 +DA:107,75 +DA:111,63 +FN:111,BaseTest.deployTollgate +FNDA:63,BaseTest.deployTollgate +DA:113,0 +DA:115,63 +DA:116,63 +DA:117,63 +DA:119,37 +DA:123,108 +FN:123,BaseTest.deployLedgerVault +FNDA:108,BaseTest.deployLedgerVault +DA:125,108 +DA:126,108 +DA:127,108 +DA:129,108 +DA:131,108 +DA:132,108 +DA:133,108 +DA:137,54 +FN:137,BaseTest.deployTreasury +FNDA:54,BaseTest.deployTreasury +DA:139,54 +DA:140,54 +DA:141,54 +DA:142,37 +DA:145,54 +FN:145,BaseTest.deployAgreementManager +FNDA:54,BaseTest.deployAgreementManager DA:146,0 -DA:147,58 -DA:148,0 -DA:150,58 -DA:151,58 -DA:153,58 -DA:157,13 -FN:157,BaseTest.deployAssetReferendum +DA:147,54 +DA:149,54 +DA:150,54 +DA:152,54 +DA:155,54 +FN:155,BaseTest.deployAgreementSettler +FNDA:54,BaseTest.deployAgreementSettler +DA:156,0 +DA:157,54 +DA:158,0 +DA:160,54 +DA:161,54 +DA:163,54 +DA:167,13 +FN:167,BaseTest.deployAssetReferendum FNDA:13,BaseTest.deployAssetReferendum -DA:159,13 -DA:160,13 -DA:161,13 -DA:162,13 -DA:165,5 -FN:165,BaseTest.deployAssetOwnership -FNDA:5,BaseTest.deployAssetOwnership -DA:166,0 -DA:168,5 -DA:169,5 -DA:172,5 -FN:172,BaseTest.deployAssetSafe -FNDA:5,BaseTest.deployAssetSafe -DA:173,0 +DA:169,13 +DA:170,13 +DA:171,13 +DA:172,13 DA:175,5 -DA:176,5 -DA:177,5 +FN:175,BaseTest.deployAssetOwnership +FNDA:5,BaseTest.deployAssetOwnership +DA:176,0 DA:178,5 -DA:182,100 -FN:182,BaseTest.deployCustodianFactory -FNDA:100,BaseTest.deployCustodianFactory -DA:183,100 -DA:184,100 -DA:187,58 -FN:187,BaseTest.deployCustodianReferendum -FNDA:58,BaseTest.deployCustodianReferendum -DA:188,0 -DA:189,0 -DA:192,58 -DA:193,58 -DA:194,58 -DA:196,41 -DA:200,17 -FN:200,BaseTest.deployRightsAssetCustodian +DA:179,5 +DA:182,5 +FN:182,BaseTest.deployAssetSafe +FNDA:5,BaseTest.deployAssetSafe +DA:183,0 +DA:184,5 +DA:185,5 +DA:189,89 +FN:189,BaseTest.deployCustodianFactory +FNDA:89,BaseTest.deployCustodianFactory +DA:190,89 +DA:191,89 +DA:194,52 +FN:194,BaseTest.deployCustodianReferendum +FNDA:52,BaseTest.deployCustodianReferendum +DA:195,0 +DA:196,0 +DA:199,52 +DA:200,52 +DA:201,52 +DA:203,35 +DA:207,17 +FN:207,BaseTest.deployRightsAssetCustodian FNDA:17,BaseTest.deployRightsAssetCustodian -DA:201,0 -DA:203,17 -DA:204,17 -DA:207,201 -FN:207,BaseTest._setGovPermissions -FNDA:201,BaseTest._setGovPermissions -DA:208,201 -DA:209,201 -DA:211,201 -DA:212,201 -DA:215,116 -FN:215,BaseTest._assignOpRole -FNDA:116,BaseTest._assignOpRole -DA:216,116 -DA:217,116 -DA:218,116 -DA:219,116 -FNF:17 -FNH:17 -LF:92 -LH:81 +DA:208,0 +DA:210,17 +DA:211,17 +DA:214,13 +FN:214,BaseTest._setContentCouncilPermissions +FNDA:13,BaseTest._setContentCouncilPermissions +DA:215,13 +DA:216,13 +DA:218,13 +DA:219,13 +DA:222,52 +FN:222,BaseTest._setNodesCouncilPermissions +FNDA:52,BaseTest._setNodesCouncilPermissions +DA:223,52 +DA:224,52 +DA:226,52 +DA:227,52 +DA:230,117 +FN:230,BaseTest._setGovPermissions +FNDA:117,BaseTest._setGovPermissions +DA:231,117 +DA:232,117 +DA:234,117 +DA:235,117 +DA:238,108 +FN:238,BaseTest._assignOpRole +FNDA:108,BaseTest._assignOpRole +DA:239,108 +DA:240,108 +DA:241,108 +DA:242,108 +FNF:19 +FNH:19 +LF:106 +LH:95 +BRF:0 +BRH:0 +end_of_record +TN: +SF:test/assets/AssetOwnership.sol +DA:16,0 +FN:16,AssetOwnershipTest.setUp +FNDA:0,AssetOwnershipTest.setUp +DA:18,0 +FNF:1 +FNH:0 +LF:2 +LH:0 BRF:0 BRH:0 end_of_record @@ -2756,6 +2823,23 @@ BRF:0 BRH:0 end_of_record TN: +SF:test/finance/TrustlessEscrow.sol +DA:18,0 +FN:18,MockArbiter.constructor +FNDA:0,MockArbiter.constructor +DA:19,0 +DA:22,0 +FN:22,MockArbiter.executeAgreement +FNDA:0,MockArbiter.executeAgreement +DA:23,0 +FNF:2 +FNH:0 +LF:4 +LH:0 +BRF:0 +BRH:0 +end_of_record +TN: SF:test/libraries/RollingOps.t.sol DA:17,6 FN:17,RollingOpsWrapper.configureWindow @@ -2793,6 +2877,70 @@ BRF:0 BRH:0 end_of_record TN: +SF:test/primitives/BalanceOperator.t.sol +DA:15,11346 +FN:15,BalanceOperator.deposit +FNDA:11346,BalanceOperator.deposit +DA:16,11346 +DA:19,5312 +FN:19,BalanceOperator.withdraw +FNDA:5312,BalanceOperator.withdraw +DA:20,5312 +DA:23,289 +FN:23,BalanceOperator.transfer +FNDA:289,BalanceOperator.transfer +DA:24,289 +DA:34,14 +FN:34,Handler.constructor +FNDA:14,Handler.constructor +DA:35,14 +DA:36,14 +DA:38,14 +DA:39,140 +DA:40,140 +DA:44,14 +FN:44,Handler.getActors +FNDA:14,Handler.getActors +DA:45,14 +DA:48,1004547 +FN:48,Handler.deposit +FNDA:1004547,Handler.deposit +DA:49,1004547 +DA:50,41764 +DA:51,41764 +DA:54,11337 +DA:55,11337 +DA:56,11337 +DA:57,11337 +DA:58,11337 +DA:61,1002944 +FN:61,Handler.withdraw +FNDA:1002944,Handler.withdraw +DA:62,1002944 +DA:63,41297 +DA:64,41297 +DA:67,5307 +DA:68,5307 +DA:69,5307 +DA:72,1004618 +FN:72,Handler.transfer +FNDA:1004618,Handler.transfer +DA:73,1004618 +DA:74,41444 +DA:75,2844 +DA:77,2233 +DA:78,2233 +DA:79,2233 +DA:82,283 +DA:83,283 +FNF:8 +FNH:8 +LF:39 +LH:39 +BRF:0 +BRH:0 +end_of_record +TN: SF:test/primitives/Quorum.t.sol DA:12,7 FN:12,QuorumWrapper.status @@ -2827,50 +2975,31 @@ BRH:0 end_of_record TN: SF:test/shared/CustodianShared.t.sol -DA:14,32 +DA:14,26 FN:14,CustodianShared.setUp -FNDA:32,CustodianShared.setUp +FNDA:26,CustodianShared.setUp DA:15,0 DA:16,0 -DA:19,38 -FN:19,CustodianShared.deployCustodian -FNDA:38,CustodianShared.deployCustodian -DA:20,38 -DA:21,38 -DA:22,38 -DA:25,33 -FN:25,CustodianShared._setFeesAsGovernor -FNDA:33,CustodianShared._setFeesAsGovernor -DA:26,33 -DA:27,33 -DA:28,33 -DA:31,31 -FN:31,CustodianShared._registerCustodianWithApproval -FNDA:31,CustodianShared._registerCustodianWithApproval -DA:34,31 -DA:36,31 -DA:37,31 -DA:39,31 -DA:41,31 -DA:42,31 -DA:45,32 -FN:45,CustodianShared._createAgreement -FNDA:32,CustodianShared._createAgreement -DA:46,32 -DA:47,32 -DA:49,32 -DA:57,32 -DA:60,28 -FN:60,CustodianShared._registerAndApproveCustodian -FNDA:28,CustodianShared._registerAndApproveCustodian -DA:62,28 -DA:64,28 -DA:65,28 -DA:67,28 -FNF:6 -FNH:6 -LF:28 -LH:26 +DA:19,2722 +FN:19,CustodianShared._deployCustodian +FNDA:2722,CustodianShared._deployCustodian +DA:20,2722 +DA:21,2722 +DA:22,2722 +DA:25,2715 +FN:25,CustodianShared._registerAndApproveCustodian +FNDA:2715,CustodianShared._registerAndApproveCustodian +DA:26,2715 +DA:27,2715 +DA:28,2715 +DA:31,2716 +FN:31,CustodianShared._registerCustodian +FNDA:2716,CustodianShared._registerCustodian +DA:32,2716 +FNF:4 +FNH:4 +LF:13 +LH:11 BRF:0 BRH:0 end_of_record From 22497d39bc9e020457d1e1e291870575cdcf42f5 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Thu, 25 Sep 2025 09:28:17 -0600 Subject: [PATCH 09/33] Cache owner before burning revoked assets --- contracts/assets/AssetOwnership.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/assets/AssetOwnership.sol b/contracts/assets/AssetOwnership.sol index a38462a..74969cb 100644 --- a/contracts/assets/AssetOwnership.sol +++ b/contracts/assets/AssetOwnership.sol @@ -134,9 +134,11 @@ contract AssetOwnership is /// @dev This action is irreversible and restricted to governance control. /// @param assetId The unique identifier of the asset to be revoked. function revoke(uint256 assetId) external restricted { + address previousOwner = ownerOf(assetId); + _burn(assetId); _disableAsset(assetId); - emit RevokedAsset(ownerOf(assetId), assetId); + emit RevokedAsset(previousOwner, assetId); } /// @notice Transfers an asset to a new owner. From 846a6e2fe2e98e1bec1f903b50c26ed6223bfcc7 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Thu, 25 Sep 2025 09:29:06 -0600 Subject: [PATCH 10/33] removed the uneeded exceed --- contracts/core/interfaces/base/IBalanceDepositor.sol | 2 +- contracts/financial/LedgerVault.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/core/interfaces/base/IBalanceDepositor.sol b/contracts/core/interfaces/base/IBalanceDepositor.sol index 1476999..100f97c 100644 --- a/contracts/core/interfaces/base/IBalanceDepositor.sol +++ b/contracts/core/interfaces/base/IBalanceDepositor.sol @@ -16,5 +16,5 @@ interface IBalanceDepositor { /// @param recipient The address of the account to credit with the deposit. /// @param amount The amount of currency to deposit. /// @param currency The address of the ERC20 token to deposit. - function deposit(address recipient, uint256 amount, address currency) external returns (uint256); + function deposit(address recipient, uint256 amount, address currency) external payable returns (uint256); } diff --git a/contracts/financial/LedgerVault.sol b/contracts/financial/LedgerVault.sol index e479280..3cd0a29 100644 --- a/contracts/financial/LedgerVault.sol +++ b/contracts/financial/LedgerVault.sol @@ -113,7 +113,7 @@ contract LedgerVault is /// @param recipient The address of the account to credit with the deposit. /// @param amount The amount of currency to deposit. /// @param currency The address of the ERC20 token to deposit. - function deposit(address recipient, uint256 amount, address currency) external whenNotPaused returns (uint256) { + function deposit(address recipient, uint256 amount, address currency) external payable whenNotPaused returns (uint256) { return _deposit(recipient, amount, currency); } From f75f0faf154d64b1e63c77b57d0ad6c078ba9b70 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Thu, 25 Sep 2025 09:35:28 -0600 Subject: [PATCH 11/33] removed the uneeded exceed --- contracts/economics/Treasury.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/economics/Treasury.sol b/contracts/economics/Treasury.sol index 5b2c1fd..515f89b 100644 --- a/contracts/economics/Treasury.sol +++ b/contracts/economics/Treasury.sol @@ -66,7 +66,7 @@ contract Treasury is address pool, uint256 amount, address currency - ) external whenNotPaused restricted returns (uint256) { + ) external payable whenNotPaused restricted returns (uint256) { return _deposit(pool, amount, currency); } From 169c70ba0842161c7898742f0b0bf8326a576344 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Thu, 25 Sep 2025 10:01:28 -0600 Subject: [PATCH 12/33] removed the uneeded exceed --- contracts/core/libraries/FinancialOps.sol | 4 +++- test/assets/AssetOwnership.sol | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/contracts/core/libraries/FinancialOps.sol b/contracts/core/libraries/FinancialOps.sol index a640c48..ca29a77 100644 --- a/contracts/core/libraries/FinancialOps.sol +++ b/contracts/core/libraries/FinancialOps.sol @@ -22,6 +22,8 @@ library FinancialOps { /// @param to The address to which the native cryptocurrency will be transferred. /// @param amount The amount of native cryptocurrency to transfer. function _nativeTransfer(address to, uint256 amount) internal { + // if address is zero fails + // if empty address contract -> success true = unrecoverable funds (bool success, ) = payable(to).call{ value: amount }(""); if (!success) revert FailDuringTransfer("Transfer failed"); } @@ -39,7 +41,7 @@ library FinancialOps { /// @param amount The amount to deposit. /// @return The deposited amount. function _nativeDeposit(uint256 amount) internal returns (uint256) { - if (amount > msg.value) revert FailDuringDeposit("Amount exceeds balance sent."); + if (amount != msg.value) revert FailDuringDeposit("Amount exceeds balance sent."); // the transfer is not needed since the transfer is implicit here return amount; } diff --git a/test/assets/AssetOwnership.sol b/test/assets/AssetOwnership.sol index 541b861..9055b7b 100644 --- a/test/assets/AssetOwnership.sol +++ b/test/assets/AssetOwnership.sol @@ -18,5 +18,9 @@ contract AssetOwnershipTest is BaseTest { deployAssetOwnership(); } + + + + } From 5af3107d342b38e1f2b22a352a938e7f30a06ace Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Thu, 25 Sep 2025 13:18:03 -0600 Subject: [PATCH 13/33] Rename AssetOwnership to AssetRegistry --- .../{AssetOwnership.sol => AssetRegistry.sol} | 12 +++++----- contracts/assets/AssetSafe.sol | 10 ++++----- ...IAssetOwnership.sol => IAssetRegistry.sol} | 4 ++-- .../interfaces/base/IBalanceDepositor.sol | 2 +- contracts/economics/Treasury.sol | 2 +- contracts/financial/LedgerVault.sol | 6 ++++- contracts/policies/PolicyBase.sol | 10 ++++----- .../12_Deploy_Assets_AssetOwnership.s.sol | 22 ------------------- .../12_Deploy_Assets_AssetRegistry.s.sol | 22 +++++++++++++++++++ .../13_Deploy_Assets_AssetSafe.s.sol | 4 ++-- ... => 12_Upgrade_Assets_AssetRegistry.s.sol} | 12 +++++----- test/BaseTest.t.sol | 12 +++++----- .../{AssetOwnership.sol => AssetRegistry.sol} | 6 ++--- test/assets/AssetSafe.t.sol | 4 ++-- 14 files changed, 67 insertions(+), 61 deletions(-) rename contracts/assets/{AssetOwnership.sol => AssetRegistry.sol} (97%) rename contracts/core/interfaces/assets/{IAssetOwnership.sol => IAssetRegistry.sol} (91%) delete mode 100644 script/deployment/12_Deploy_Assets_AssetOwnership.s.sol create mode 100644 script/deployment/12_Deploy_Assets_AssetRegistry.s.sol rename script/upgrades/{12_Upgrade_Assets_AssetOwnership.s.sol => 12_Upgrade_Assets_AssetRegistry.s.sol} (62%) rename test/assets/{AssetOwnership.sol => AssetRegistry.sol} (90%) diff --git a/contracts/assets/AssetOwnership.sol b/contracts/assets/AssetRegistry.sol similarity index 97% rename from contracts/assets/AssetOwnership.sol rename to contracts/assets/AssetRegistry.sol index a38462a..c58a087 100644 --- a/contracts/assets/AssetOwnership.sol +++ b/contracts/assets/AssetRegistry.sol @@ -11,23 +11,23 @@ import { ERC721EnumerableUpgradeable } from "@openzeppelin/contracts-upgradeable import { ERC721StatefulUpgradeable } from "@synaps3/core/primitives/upgradeable/ERC721StatefulUpgradeable.sol"; import { AccessControlledUpgradeable } from "@synaps3/core/primitives/upgradeable/AccessControlledUpgradeable.sol"; import { IAssetVerifiable } from "@synaps3/core/interfaces/assets/IAssetVerifiable.sol"; -import { IAssetOwnership } from "@synaps3/core/interfaces/assets/IAssetOwnership.sol"; +import { IAssetRegistry } from "@synaps3/core/interfaces/assets/IAssetRegistry.sol"; // TODO: Evaluate ERC-404 for fractionalization support // TODO: Evaluate ERC-2981 for royalty management // TODO: Evaluate ERC-4804 for URL-based on-chain asset references -/// @title AssetOwnership +/// @title AssetRegistry /// @notice This contract manages ownership and lifecycle of digital assets using ERC721. /// @dev Implements UUPS upgradeability, access control, and stateful asset management. -contract AssetOwnership is +contract AssetRegistry is Initializable, UUPSUpgradeable, ERC721Upgradeable, AccessControlledUpgradeable, ERC721EnumerableUpgradeable, ERC721StatefulUpgradeable, - IAssetOwnership + IAssetRegistry { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable /// @notice Reference to the asset verification contract for content approval. @@ -134,9 +134,11 @@ contract AssetOwnership is /// @dev This action is irreversible and restricted to governance control. /// @param assetId The unique identifier of the asset to be revoked. function revoke(uint256 assetId) external restricted { + address previousOwner = ownerOf(assetId); + _burn(assetId); _disableAsset(assetId); - emit RevokedAsset(ownerOf(assetId), assetId); + emit RevokedAsset(previousOwner, assetId); } /// @notice Transfers an asset to a new owner. diff --git a/contracts/assets/AssetSafe.sol b/contracts/assets/AssetSafe.sol index 7cc91d9..5431ce4 100644 --- a/contracts/assets/AssetSafe.sol +++ b/contracts/assets/AssetSafe.sol @@ -5,7 +5,7 @@ import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { AccessControlledUpgradeable } from "@synaps3/core/primitives/upgradeable/AccessControlledUpgradeable.sol"; -import { IAssetOwnership } from "@synaps3/core/interfaces/assets/IAssetOwnership.sol"; +import { IAssetRegistry } from "@synaps3/core/interfaces/assets/IAssetRegistry.sol"; import { IAssetSafe } from "@synaps3/core/interfaces/assets/IAssetSafe.sol"; import { T } from "@synaps3/core/primitives/Types.sol"; @@ -17,7 +17,7 @@ contract AssetSafe is Initializable, UUPSUpgradeable, AccessControlledUpgradeabl /// @custom:oz-upgrades-unsafe-allow state-variable-immutable /// Our immutables behave as constants after deployment /// slither-disable-next-line naming-convention - IAssetOwnership public immutable ASSET_OWNERSHIP; + IAssetRegistry public immutable ASSET_REGISTRY; /// @dev Mapping to securely store encrypted content using a unique key derived from assetId and cipher type. mapping(bytes32 => bytes) private _secured; @@ -38,16 +38,16 @@ contract AssetSafe is Initializable, UUPSUpgradeable, AccessControlledUpgradeabl /// @param assetId The identifier of the asset. /// @dev Reverts if the sender is not the owner of the asset based on the Ownership contract. modifier onlyHolder(uint256 assetId) { - if (ASSET_OWNERSHIP.ownerOf(assetId) != msg.sender) { + if (ASSET_REGISTRY.ownerOf(assetId) != msg.sender) { revert InvalidAssetRightsHolder(); } _; } /// @custom:oz-upgrades-unsafe-allow constructor - constructor(address assetOwnership) { + constructor(address assetRegistry) { _disableInitializers(); - ASSET_OWNERSHIP = IAssetOwnership(assetOwnership); + ASSET_REGISTRY = IAssetRegistry(assetRegistry); } /// @notice Initializes the proxy state. diff --git a/contracts/core/interfaces/assets/IAssetOwnership.sol b/contracts/core/interfaces/assets/IAssetRegistry.sol similarity index 91% rename from contracts/core/interfaces/assets/IAssetOwnership.sol rename to contracts/core/interfaces/assets/IAssetRegistry.sol index 268cf5e..477fa8f 100644 --- a/contracts/core/interfaces/assets/IAssetOwnership.sol +++ b/contracts/core/interfaces/assets/IAssetRegistry.sol @@ -5,11 +5,11 @@ pragma solidity 0.8.26; import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; -/// @title IAssetOwnership +/// @title IAssetRegistry /// @notice Interface for managing asset ownership as ERC721 tokens. /// @dev Extends ERC721 and ERC721Metadata to provide full NFT functionality, /// including ownership tracking and metadata retrieval. -interface IAssetOwnership is IERC721, IERC721Metadata { +interface IAssetRegistry is IERC721, IERC721Metadata { /// @notice Registers a new asset as an NFT. /// @dev The asset must have a unique identifier (`assetId`) that serves as the token ID. /// @param to The address that will own the minted NFT. diff --git a/contracts/core/interfaces/base/IBalanceDepositor.sol b/contracts/core/interfaces/base/IBalanceDepositor.sol index 1476999..100f97c 100644 --- a/contracts/core/interfaces/base/IBalanceDepositor.sol +++ b/contracts/core/interfaces/base/IBalanceDepositor.sol @@ -16,5 +16,5 @@ interface IBalanceDepositor { /// @param recipient The address of the account to credit with the deposit. /// @param amount The amount of currency to deposit. /// @param currency The address of the ERC20 token to deposit. - function deposit(address recipient, uint256 amount, address currency) external returns (uint256); + function deposit(address recipient, uint256 amount, address currency) external payable returns (uint256); } diff --git a/contracts/economics/Treasury.sol b/contracts/economics/Treasury.sol index 5b2c1fd..515f89b 100644 --- a/contracts/economics/Treasury.sol +++ b/contracts/economics/Treasury.sol @@ -66,7 +66,7 @@ contract Treasury is address pool, uint256 amount, address currency - ) external whenNotPaused restricted returns (uint256) { + ) external payable whenNotPaused restricted returns (uint256) { return _deposit(pool, amount, currency); } diff --git a/contracts/financial/LedgerVault.sol b/contracts/financial/LedgerVault.sol index e479280..045b4d4 100644 --- a/contracts/financial/LedgerVault.sol +++ b/contracts/financial/LedgerVault.sol @@ -113,7 +113,11 @@ contract LedgerVault is /// @param recipient The address of the account to credit with the deposit. /// @param amount The amount of currency to deposit. /// @param currency The address of the ERC20 token to deposit. - function deposit(address recipient, uint256 amount, address currency) external whenNotPaused returns (uint256) { + function deposit( + address recipient, + uint256 amount, + address currency + ) external payable whenNotPaused returns (uint256) { return _deposit(recipient, amount, currency); } diff --git a/contracts/policies/PolicyBase.sol b/contracts/policies/PolicyBase.sol index 37a90e3..25d7313 100644 --- a/contracts/policies/PolicyBase.sol +++ b/contracts/policies/PolicyBase.sol @@ -7,7 +7,7 @@ import { IRightsPolicyManagerVerifiable } from "@synaps3/core/interfaces/rights/ // solhint-disable-next-line max-line-length import { IRightsPolicyAuthorizerVerifiable } from "@synaps3/core/interfaces/rights/IRightsPolicyAuthorizerVerifiable.sol"; import { IAttestationProvider } from "@synaps3/core/interfaces/base/IAttestationProvider.sol"; -import { IAssetOwnership } from "@synaps3/core/interfaces/assets/IAssetOwnership.sol"; +import { IAssetRegistry } from "@synaps3/core/interfaces/assets/IAssetRegistry.sol"; import { IPolicy } from "@synaps3/core/interfaces/policies/IPolicy.sol"; import { T } from "@synaps3/core/primitives/Types.sol"; @@ -23,7 +23,7 @@ abstract contract PolicyBase is ERC165, IPolicy { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable IAttestationProvider public immutable ATTESTATION_PROVIDER; /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - IAssetOwnership public immutable ASSET_OWNERSHIP; + IAssetRegistry public immutable ASSET_REGISTRY; /// @dev Registry to store the relation between (context & account) key => attestation mapping(bytes32 => uint256) private _attestations; @@ -87,13 +87,13 @@ abstract contract PolicyBase is ERC165, IPolicy { constructor( address rightsPolicyManager, address rightsAuthorizer, - address assetOwnership, + address assetRegistry, address providerAddress ) { RIGHTS_AUTHORIZER = IRightsPolicyAuthorizerVerifiable(rightsAuthorizer); RIGHTS_POLICY_MANAGER = IRightsPolicyManagerVerifiable(rightsPolicyManager); ATTESTATION_PROVIDER = IAttestationProvider(providerAddress); - ASSET_OWNERSHIP = IAssetOwnership(assetOwnership); + ASSET_REGISTRY = IAssetRegistry(assetRegistry); } /// @notice Retrieves the address of the attestation provider. @@ -122,7 +122,7 @@ abstract contract PolicyBase is ERC165, IPolicy { /// @notice Returns the asset holder registered in the ownership contract. /// @param assetId the asset ID to retrieve the holder. function _getHolder(uint256 assetId) internal view returns (address) { - return ASSET_OWNERSHIP.ownerOf(assetId); // Returns the registered owner. + return ASSET_REGISTRY.ownerOf(assetId); // Returns the registered owner. } /// @dev Internal function to commit an agreement and create an attestation. diff --git a/script/deployment/12_Deploy_Assets_AssetOwnership.s.sol b/script/deployment/12_Deploy_Assets_AssetOwnership.s.sol deleted file mode 100644 index 7a027fb..0000000 --- a/script/deployment/12_Deploy_Assets_AssetOwnership.s.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.26; - -import { DeployBase } from "script/deployment/00_Deploy_Base.s.sol"; -import { AssetOwnership } from "contracts/assets/AssetOwnership.sol"; - -contract DeployAssetOwnership is DeployBase { - function run() external returns (address) { - - vm.startBroadcast(getAdminPK()); - address accessManager = computeCreate3Address("SALT_ACCESS_MANAGER"); - address assetReferendum = computeCreate3Address("SALT_ASSET_REFERENDUM"); - address impl = address(new AssetOwnership(assetReferendum)); - bytes memory init = abi.encodeCall(AssetOwnership.initialize, (accessManager)); - address assetOwnersip = deployUUPS(impl, init, "SALT_ASSET_OWNERSHIP"); - vm.stopBroadcast(); - - _checkExpectedAddress(assetOwnersip, "SALT_ASSET_OWNERSHIP"); - _logAddress("ASSET_OWNERSHIP", assetOwnersip); - return assetOwnersip; - } -} diff --git a/script/deployment/12_Deploy_Assets_AssetRegistry.s.sol b/script/deployment/12_Deploy_Assets_AssetRegistry.s.sol new file mode 100644 index 0000000..e3e8bd0 --- /dev/null +++ b/script/deployment/12_Deploy_Assets_AssetRegistry.s.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import { DeployBase } from "script/deployment/00_Deploy_Base.s.sol"; +import { AssetRegistry } from "contracts/assets/AssetRegistry.sol"; + +contract DeployAssetRegistry is DeployBase { + function run() external returns (address) { + + vm.startBroadcast(getAdminPK()); + address accessManager = computeCreate3Address("SALT_ACCESS_MANAGER"); + address assetReferendum = computeCreate3Address("SALT_ASSET_REFERENDUM"); + address impl = address(new AssetRegistry(assetReferendum)); + bytes memory init = abi.encodeCall(AssetRegistry.initialize, (accessManager)); + address assetRegistry = deployUUPS(impl, init, "SALT_ASSET_REGISTRY"); + vm.stopBroadcast(); + + _checkExpectedAddress(assetRegistry, "SALT_ASSET_REGISTRY"); + _logAddress("ASSET_REGISTRY", assetRegistry); + return assetRegistry; + } +} diff --git a/script/deployment/13_Deploy_Assets_AssetSafe.s.sol b/script/deployment/13_Deploy_Assets_AssetSafe.s.sol index 8dba3a2..062e0ae 100644 --- a/script/deployment/13_Deploy_Assets_AssetSafe.s.sol +++ b/script/deployment/13_Deploy_Assets_AssetSafe.s.sol @@ -9,8 +9,8 @@ contract DeployAssetSafe is DeployBase { vm.startBroadcast(getAdminPK()); address accessManager = computeCreate3Address("SALT_ACCESS_MANAGER"); - address AssetOwnership = computeCreate3Address("SALT_ASSET_OWNERSHIP"); - address impl = address(new AssetSafe(AssetOwnership)); + address assetRegistry = computeCreate3Address("SALT_ASSET_REGISTRY"); + address impl = address(new AssetSafe(assetRegistry)); bytes memory init = abi.encodeCall(AssetSafe.initialize, (accessManager)); address assetVault = deployUUPS(impl, init, "SALT_ASSET_SAFE"); vm.stopBroadcast(); diff --git a/script/upgrades/12_Upgrade_Assets_AssetOwnership.s.sol b/script/upgrades/12_Upgrade_Assets_AssetRegistry.s.sol similarity index 62% rename from script/upgrades/12_Upgrade_Assets_AssetOwnership.s.sol rename to script/upgrades/12_Upgrade_Assets_AssetRegistry.s.sol index 7fd560d..bfa15e6 100644 --- a/script/upgrades/12_Upgrade_Assets_AssetOwnership.s.sol +++ b/script/upgrades/12_Upgrade_Assets_AssetRegistry.s.sol @@ -2,20 +2,20 @@ pragma solidity 0.8.26; import { UpgradeBase } from "script/upgrades/00_Upgrade_Base.s.sol"; -import { AssetOwnership } from "contracts/assets/AssetOwnership.sol"; +import { AssetRegistry } from "contracts/assets/AssetRegistry.sol"; import { C } from "contracts/core/primitives/Constants.sol"; -contract UpgradeAssetOwnership is UpgradeBase { +contract UpgradeAssetRegistry is UpgradeBase { function run() external returns (address) { vm.startBroadcast(getAdminPK()); address assetReferendum = vm.envAddress("ASSET_REFERENDUM"); - address impl = address(new AssetOwnership(assetReferendum)); - address assetOwnershipProxy = vm.envAddress("ASSET_OWNERSHIP"); + address impl = address(new AssetRegistry(assetReferendum)); + address assetRegistryProxy = vm.envAddress("ASSET_REGISTRY"); // address accessManager = vm.envAddress("ACCESS_MANAGER"); //!IMPORTANT: This is not a safe upgrade, take any caution or 2-check needed before run this method // bytes memory init = abi.encodeCall(LedgerVaultV2.initializeV2, (accessManager)); - address assetOwnership = upgradeAndCallUUPS(assetOwnershipProxy, impl, ""); // no initialization + address assetRegistry = upgradeAndCallUUPS(assetRegistryProxy, impl, ""); // no initialization vm.stopBroadcast(); - return assetOwnership; + return assetRegistry; } } diff --git a/test/BaseTest.t.sol b/test/BaseTest.t.sol index 6c7ccef..b29f413 100644 --- a/test/BaseTest.t.sol +++ b/test/BaseTest.t.sol @@ -11,7 +11,7 @@ import { DeployTreasury } from "script/deployment/05_Deploy_Economics_Treasury.s import { DeployLedgerVault } from "script/deployment/06_Deploy_Financial_LedgerVault.s.sol"; import { DeployAssetReferendum } from "script/deployment/11_Deploy_Assets_AssetReferendum.s.sol"; import { DeployAssetSafe } from "script/deployment/13_Deploy_Assets_AssetSafe.s.sol"; -import { DeployAssetOwnership } from "script/deployment/12_Deploy_Assets_AssetOwnership.s.sol"; +import { DeployAssetRegistry } from "script/deployment/12_Deploy_Assets_AssetRegistry.s.sol"; import { DeployCustodianFactory } from "script/deployment/09_Deploy_Custody_CustodianFactory.s.sol"; import { DeployCustodianReferendum } from "script/deployment/10_Deploy_Custody_CustodianReferendum.s.sol"; import { DeployAgreementManager } from "script/deployment/07_Deploy_Financial_AgreementManager.s.sol"; @@ -45,7 +45,7 @@ abstract contract BaseTest is Test { address assetSafe; address assetReferendum; - address assetOwnership; + address assetRegistry; address custodianReferendum; address custodianFactory; @@ -172,15 +172,15 @@ abstract contract BaseTest is Test { _setContentCouncilPermissions(assetReferendum, referendumAllowed); } - function deployAssetOwnership() public { + function deployAssetRegistry() public { deployAssetReferendum(); // set default admin as deployer.. - DeployAssetOwnership assetOwnershipDeployer = new DeployAssetOwnership(); - assetOwnership = assetOwnership == address(0) ? assetOwnershipDeployer.run() : assetOwnership; + DeployAssetRegistry assetRegistryDeployer = new DeployAssetRegistry(); + assetRegistry = assetRegistry == address(0) ? assetRegistryDeployer.run() : assetRegistry; } function deployAssetSafe() public { - deployAssetOwnership(); + deployAssetRegistry(); DeployAssetSafe assetVaultDeployer = new DeployAssetSafe(); assetSafe = assetSafe == address(0) ? assetVaultDeployer.run() : assetSafe; } diff --git a/test/assets/AssetOwnership.sol b/test/assets/AssetRegistry.sol similarity index 90% rename from test/assets/AssetOwnership.sol rename to test/assets/AssetRegistry.sol index 541b861..0b55a99 100644 --- a/test/assets/AssetOwnership.sol +++ b/test/assets/AssetRegistry.sol @@ -12,11 +12,11 @@ import { BaseTest } from "test/BaseTest.t.sol"; import { T } from "contracts/core/primitives/Types.sol"; import { C } from "contracts/core/primitives/Constants.sol"; -contract AssetOwnershipTest is BaseTest { +contract AssetRegistryTest is BaseTest { function setUp() public initialize { // setup the access manager to use during tests.. - deployAssetOwnership(); + deployAssetRegistry(); } - + } diff --git a/test/assets/AssetSafe.t.sol b/test/assets/AssetSafe.t.sol index 6b8c90c..4c3e6de 100644 --- a/test/assets/AssetSafe.t.sol +++ b/test/assets/AssetSafe.t.sol @@ -5,7 +5,7 @@ import "forge-std/Test.sol"; import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; import { IAssetRegistrable } from "contracts/core/interfaces/assets/IAssetRegistrable.sol"; import { IAssetVerifiable } from "contracts/core/interfaces/assets/IAssetVerifiable.sol"; -import { IAssetOwnership } from "contracts/core/interfaces/assets/IAssetOwnership.sol"; +import { IAssetRegistry } from "contracts/core/interfaces/assets/IAssetRegistry.sol"; import { IAssetSafe } from "contracts/core/interfaces/assets/IAssetSafe.sol"; import { AssetSafe } from "contracts/assets/AssetSafe.sol"; @@ -102,6 +102,6 @@ contract AssetSafeTest is BaseTest { IAssetRegistrable(assetReferendum).approve(assetId); vm.prank(to); - IAssetOwnership(assetOwnership).register(to, assetId); + IAssetRegistry(assetRegistry).register(to, assetId); } } From 9b913de2be21dc48a793bfd47d19b8f386b218ab Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Thu, 25 Sep 2025 13:21:39 -0600 Subject: [PATCH 14/33] asset renames --- contracts/assets/AssetOwnership.sol | 6 +- .../interfaces/assets/IAssetOwnership.sol | 10 ++++ .../interfaces/assets/IAssetReferendum.sol | 10 ++-- .../interfaces/assets/IAssetRegistrable.sol | 18 ------ .../interfaces/assets/IAssetRevokable.sol | 18 ------ .../interfaces/assets/IAssetVerifiable.sol | 21 ------- contracts/core/libraries/FinancialOps.sol | 58 ++++++++++++++----- contracts/financial/LedgerVault.sol | 6 +- test/assets/AssetOwnership.sol | 26 --------- test/assets/AssetReferendum.t.sol | 34 +++++------ test/assets/AssetSafe.t.sol | 8 +-- test/primitives/BalanceOperator.t.sol | 2 +- 12 files changed, 90 insertions(+), 127 deletions(-) delete mode 100644 contracts/core/interfaces/assets/IAssetRegistrable.sol delete mode 100644 contracts/core/interfaces/assets/IAssetRevokable.sol delete mode 100644 contracts/core/interfaces/assets/IAssetVerifiable.sol delete mode 100644 test/assets/AssetOwnership.sol diff --git a/contracts/assets/AssetOwnership.sol b/contracts/assets/AssetOwnership.sol index 74969cb..20e77ed 100644 --- a/contracts/assets/AssetOwnership.sol +++ b/contracts/assets/AssetOwnership.sol @@ -10,7 +10,7 @@ import { ERC721Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC import { ERC721EnumerableUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; import { ERC721StatefulUpgradeable } from "@synaps3/core/primitives/upgradeable/ERC721StatefulUpgradeable.sol"; import { AccessControlledUpgradeable } from "@synaps3/core/primitives/upgradeable/AccessControlledUpgradeable.sol"; -import { IAssetVerifiable } from "@synaps3/core/interfaces/assets/IAssetVerifiable.sol"; +import { IAssetReferendumVerifiable } from "@synaps3/core/interfaces/assets/IAssetReferendumVerifiable.sol"; import { IAssetOwnership } from "@synaps3/core/interfaces/assets/IAssetOwnership.sol"; // TODO: Evaluate ERC-404 for fractionalization support @@ -33,7 +33,7 @@ contract AssetOwnership is /// @notice Reference to the asset verification contract for content approval. /// Our immutables behave as constants after deployment /// slither-disable-next-line naming-convention - IAssetVerifiable public immutable ASSET_REFERENDUM; + IAssetReferendumVerifiable public immutable ASSET_REFERENDUM; /// @dev Emitted when a new asset is registered on the platform. /// @param owner The address of the creator or owner of the registered asset. @@ -89,7 +89,7 @@ contract AssetOwnership is /// https://forum.openzeppelin.com/t/what-does-disableinitializers-function-mean/28730/5 _disableInitializers(); // we need to verify that asset has passed the community approval. - ASSET_REFERENDUM = IAssetVerifiable(assetReferendum); + ASSET_REFERENDUM = IAssetReferendumVerifiable(assetReferendum); } /// @notice Initializes the upgradeable contract. diff --git a/contracts/core/interfaces/assets/IAssetOwnership.sol b/contracts/core/interfaces/assets/IAssetOwnership.sol index 268cf5e..e55804b 100644 --- a/contracts/core/interfaces/assets/IAssetOwnership.sol +++ b/contracts/core/interfaces/assets/IAssetOwnership.sol @@ -15,4 +15,14 @@ interface IAssetOwnership is IERC721, IERC721Metadata { /// @param to The address that will own the minted NFT. /// @param assetId The unique identifier for the asset, serving as the NFT ID. function register(address to, uint256 assetId) external; + + /// @notice Revokes an asset, permanently disabling it within the system. + /// @dev This action is irreversible and restricted to governance control. + /// @param assetId The unique identifier of the asset to be revoked. + function revoke(uint256 assetId) external; + + /// @notice Transfers an asset to a new owner. + /// @param to The address of the new owner. + /// @param assetId The unique identifier of the asset being transferred. + function transfer(address to, uint256 assetId) external; } diff --git a/contracts/core/interfaces/assets/IAssetReferendum.sol b/contracts/core/interfaces/assets/IAssetReferendum.sol index 458fcd9..01fc43c 100644 --- a/contracts/core/interfaces/assets/IAssetReferendum.sol +++ b/contracts/core/interfaces/assets/IAssetReferendum.sol @@ -2,12 +2,12 @@ // NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html pragma solidity 0.8.26; -import { IAssetRegistrable } from "@synaps3/core/interfaces/assets/IAssetRegistrable.sol"; -import { IAssetVerifiable } from "@synaps3/core/interfaces/assets/IAssetVerifiable.sol"; -import { IAssetRevokable } from "@synaps3/core/interfaces/assets/IAssetRevokable.sol"; +import { IAssetReferendumRegistrable } from "@synaps3/core/interfaces/assets/IAssetReferendumRegistrable.sol"; +import { IAssetReferendumVerifiable } from "@synaps3/core/interfaces/assets/IAssetReferendumVerifiable.sol"; +import { IAssetReferendumRevokable } from "@synaps3/core/interfaces/assets/IAssetReferendumRevokable.sol"; /// @title IAssetReferendum /// @notice Unified interface for managing content registration and verifications within a referendum-based system. -/// @dev This interface extends both IAssetRegistrable and IAssetVerifiable to provide a single entry point for +/// @dev This interface extends both IAssetReferendumRegistrable and IAssetReferendumVerifiable to provide a single entry point for /// handling asset registration and verification processes. -interface IAssetReferendum is IAssetRegistrable, IAssetVerifiable, IAssetRevokable {} +interface IAssetReferendum is IAssetReferendumRegistrable, IAssetReferendumVerifiable, IAssetReferendumRevokable {} diff --git a/contracts/core/interfaces/assets/IAssetRegistrable.sol b/contracts/core/interfaces/assets/IAssetRegistrable.sol deleted file mode 100644 index 94ad016..0000000 --- a/contracts/core/interfaces/assets/IAssetRegistrable.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -// NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html -pragma solidity 0.8.26; - -/// @title IAssetRegistrable Interface -/// @notice Defines the essential functions for managing asset registration and governance through a referendum process. -/// @dev This interface mirrors the FSM behavior from `IQuorum`, but scoped to asset governance. -interface IAssetRegistrable { - /// @notice Submits a new asset proposition for a referendum. - /// @dev This function should allow entities to propose an asset for approval. - /// @param assetId The unique identifier of the asset being submitted. - function submit(uint256 assetId) external; - - /// @notice Approves an asset proposition in the referendum. - /// @dev Once approved, the asset is considered verified and usable within the system. - /// @param assetId The unique identifier of the asset to be approved. - function approve(uint256 assetId) external; -} diff --git a/contracts/core/interfaces/assets/IAssetRevokable.sol b/contracts/core/interfaces/assets/IAssetRevokable.sol deleted file mode 100644 index c7eed24..0000000 --- a/contracts/core/interfaces/assets/IAssetRevokable.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -// NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html -pragma solidity 0.8.26; - -/// @title IAssetRevokable Interface -/// @notice Defines the functions for invalidating or withdrawing assets from the system. -/// @dev This interface focuses on asset rejection and revocation, used in the governance lifecycle. -interface IAssetRevokable { - /// @notice Rejects an asset proposition in the referendum. - /// @dev If rejected, the asset cannot be used in the system unless resubmitted. - /// @param assetId The unique identifier of the asset to be rejected. - function reject(uint256 assetId) external; - - /// @notice Revokes a previously approved asset. - /// @dev This function allows the system to remove approval from an asset, disabling its functionality. - /// @param assetId The unique identifier of the asset to be revoked. - function revoke(uint256 assetId) external; -} diff --git a/contracts/core/interfaces/assets/IAssetVerifiable.sol b/contracts/core/interfaces/assets/IAssetVerifiable.sol deleted file mode 100644 index 4a518e0..0000000 --- a/contracts/core/interfaces/assets/IAssetVerifiable.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -// NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html -pragma solidity 0.8.26; - -/// @title IAssetVerifiable -/// @notice Interface for verifying the approval and active status of assets. -/// @dev This interface is used to check whether an asset has been approved and whether it is currently active. -interface IAssetVerifiable { - /// @notice Checks if a given asset has been approved. - /// @dev This function verifies if the asset has passed the necessary approval process. - /// @param initiator The address that submitted the asset for approval. - /// @param assetId The unique identifier of the asset. - /// @return A boolean indicating whether the asset is approved (`true`) or not (`false`). - function isApproved(address initiator, uint256 assetId) external view returns (bool); - - /// @notice Checks if a given asset is active and not blocked. - /// @dev Ensures that the asset is currently in use and has not been disabled or blacklisted. - /// @param assetId The unique identifier of the asset. - /// @return A boolean indicating whether the asset is active (`true`) or inactive/blocked (`false`). - function isActive(uint256 assetId) external view returns (bool); -} diff --git a/contracts/core/libraries/FinancialOps.sol b/contracts/core/libraries/FinancialOps.sol index ca29a77..4fcdbd0 100644 --- a/contracts/core/libraries/FinancialOps.sol +++ b/contracts/core/libraries/FinancialOps.sol @@ -22,10 +22,12 @@ library FinancialOps { /// @param to The address to which the native cryptocurrency will be transferred. /// @param amount The amount of native cryptocurrency to transfer. function _nativeTransfer(address to, uint256 amount) internal { - // if address is zero fails + // if address is zero fails // if empty address contract -> success true = unrecoverable funds (bool success, ) = payable(to).call{ value: amount }(""); - if (!success) revert FailDuringTransfer("Transfer failed"); + if (!success) { + revert FailDuringTransfer("Transfer failed"); + } } /// @notice Handles the transfer of ERC20 tokens. @@ -41,9 +43,12 @@ library FinancialOps { /// @param amount The amount to deposit. /// @return The deposited amount. function _nativeDeposit(uint256 amount) internal returns (uint256) { - if (amount != msg.value) revert FailDuringDeposit("Amount exceeds balance sent."); + if (amount != msg.value) { + revert FailDuringDeposit("Amount exceeds balance sent."); + } + // the transfer is not needed since the transfer is implicit here - return amount; + return msg.value; } /// @notice Deposits ERC20 tokens from a specified address. @@ -53,7 +58,10 @@ library FinancialOps { /// @param token The address of the ERC20 token contract. /// @return The deposited amount. function _erc20Deposit(address from, uint256 amount, address token) internal returns (uint256) { - if (amount > allowance(from, token)) revert FailDuringDeposit("Amount exceeds allowance."); + if (amount > allowance(from, token)) { + revert FailDuringDeposit("Amount exceeds allowance."); + } + // disable slitter use 'arbitrary transfer form' since the use of `safeDeposit` is handled in a safe manner. // eg. msg.sender.safeDeposit(total, currency); <- Use msg.sender as from in transferFrom. // slither-disable-next-line arbitrary-send-erc20 @@ -68,7 +76,10 @@ library FinancialOps { /// @param token The address of the ERC20 token contract for which the allowance is increased. /// Use `address(0)` for native tokens, where this function will have no effect. function increaseAllowance(address spender, uint256 amount, address token) internal { - if (token == address(0) || amount == 0) revert FailDuringDeposit("Invalid spender or allowance attempt"); + if (token == address(0) || amount == 0) { + revert FailDuringDeposit("Invalid spender or allowance attempt"); + } + IERC20(token).safeIncreaseAllowance(spender, amount); } @@ -79,7 +90,10 @@ library FinancialOps { /// @param token The address of the ERC20 token contract or `address(0)` for native tokens. /// @return The allowance amount for ERC20 tokens, or `msg.value` if it’s a native token. function allowance(address owner, address token) internal view returns (uint256) { - if (token == address(0)) return msg.value; + if (token == address(0)) { + return msg.value; + } + return IERC20(token).allowance(owner, address(this)); } @@ -90,8 +104,14 @@ library FinancialOps { /// @param amount The amount of tokens to deposit. /// @param token The address of the token to deposit. function safeDeposit(address from, uint256 amount, address token) internal returns (uint256) { - if (amount == 0) revert FailDuringDeposit("Invalid zero amount."); - if (token == address(0)) return _nativeDeposit(amount); + if (amount == 0) { + revert FailDuringDeposit("Invalid zero amount."); + } + + if (token == address(0)) { + return _nativeDeposit(amount); + } + return _erc20Deposit(from, amount, token); } @@ -99,7 +119,10 @@ library FinancialOps { /// @param target The address whose balance will be retrieved. /// @param token The address of the token to check. Use address(0) for native tokens. function balanceOf(address target, address token) internal view returns (uint256) { - if (token == address(0)) return target.balance; + if (token == address(0)) { + return target.balance; + } + return IERC20(token).balanceOf(target); } @@ -109,9 +132,18 @@ library FinancialOps { /// @param amount The amount of tokens to transfer. /// @param token The address of the ERC20 token to transfer or address(0) for native token. function transfer(address to, uint256 amount, address token) internal { - if (amount == 0) revert FailDuringTransfer("Invalid zero amount to transfer."); - if (balanceOf(address(this), token) < amount) revert FailDuringTransfer("Insufficient balance."); - if (token == address(0)) return _nativeTransfer(to, amount); + if (amount == 0) { + revert FailDuringTransfer("Invalid zero amount to transfer."); + } + + if (balanceOf(address(this), token) < amount) { + revert FailDuringTransfer("Insufficient balance."); + } + + if (token == address(0)) { + return _nativeTransfer(to, amount); + } + _erc20Transfer(to, amount, token); } } diff --git a/contracts/financial/LedgerVault.sol b/contracts/financial/LedgerVault.sol index 3cd0a29..045b4d4 100644 --- a/contracts/financial/LedgerVault.sol +++ b/contracts/financial/LedgerVault.sol @@ -113,7 +113,11 @@ contract LedgerVault is /// @param recipient The address of the account to credit with the deposit. /// @param amount The amount of currency to deposit. /// @param currency The address of the ERC20 token to deposit. - function deposit(address recipient, uint256 amount, address currency) external payable whenNotPaused returns (uint256) { + function deposit( + address recipient, + uint256 amount, + address currency + ) external payable whenNotPaused returns (uint256) { return _deposit(recipient, amount, currency); } diff --git a/test/assets/AssetOwnership.sol b/test/assets/AssetOwnership.sol deleted file mode 100644 index 9055b7b..0000000 --- a/test/assets/AssetOwnership.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.26; - -import "forge-std/Test.sol"; -import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; -import { IAssetRegistrable } from "contracts/core/interfaces/assets/IAssetRegistrable.sol"; -import { IAssetRevokable } from "contracts/core/interfaces/assets/IAssetRevokable.sol"; -import { IAssetVerifiable } from "contracts/core/interfaces/assets/IAssetVerifiable.sol"; -import { AssetReferendum } from "contracts/assets/AssetReferendum.sol"; - -import { BaseTest } from "test/BaseTest.t.sol"; -import { T } from "contracts/core/primitives/Types.sol"; -import { C } from "contracts/core/primitives/Constants.sol"; - -contract AssetOwnershipTest is BaseTest { - function setUp() public initialize { - // setup the access manager to use during tests.. - deployAssetOwnership(); - } - - - - - - -} diff --git a/test/assets/AssetReferendum.t.sol b/test/assets/AssetReferendum.t.sol index 3f25700..d7856de 100644 --- a/test/assets/AssetReferendum.t.sol +++ b/test/assets/AssetReferendum.t.sol @@ -3,9 +3,9 @@ pragma solidity 0.8.26; import "forge-std/Test.sol"; import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; -import { IAssetRegistrable } from "contracts/core/interfaces/assets/IAssetRegistrable.sol"; -import { IAssetRevokable } from "contracts/core/interfaces/assets/IAssetRevokable.sol"; -import { IAssetVerifiable } from "contracts/core/interfaces/assets/IAssetVerifiable.sol"; +import { IAssetReferendumRegistrable } from "contracts/core/interfaces/assets/IAssetReferendumRegistrable.sol"; +import { IAssetReferendumRevokable } from "contracts/core/interfaces/assets/IAssetReferendumRevokable.sol"; +import { IAssetReferendumVerifiable } from "contracts/core/interfaces/assets/IAssetReferendumVerifiable.sol"; import { AssetReferendum } from "contracts/assets/AssetReferendum.sol"; import { BaseTest } from "test/BaseTest.t.sol"; @@ -23,12 +23,12 @@ contract AssetReferendumTest is BaseTest { vm.prank(user); vm.expectEmit(true, true, false, true, address(assetReferendum)); emit AssetReferendum.Submitted(user, 1); - IAssetRegistrable(assetReferendum).submit(1); + IAssetReferendumRegistrable(assetReferendum).submit(1); } function test_Submit_SubmittedValidStates() public { _submitContentAsUser(1); - IAssetVerifiable referendum = IAssetVerifiable(assetReferendum); + IAssetReferendumVerifiable referendum = IAssetReferendumVerifiable(assetReferendum); assertFalse(referendum.isActive(1), "Asset should not be active yet"); assertFalse(referendum.isApproved(user, 1), "Asset should not be approved yet"); } @@ -40,7 +40,7 @@ contract AssetReferendumTest is BaseTest { vm.startPrank(contentCouncil); // approve by council.. vm.expectEmit(true, false, false, true, address(assetReferendum)); emit AssetReferendum.Approved(assetId); - IAssetRegistrable(assetReferendum).approve(assetId); + IAssetReferendumRegistrable(assetReferendum).approve(assetId); vm.stopPrank(); } @@ -50,9 +50,9 @@ contract AssetReferendumTest is BaseTest { _submitContentAsUser(assetId); vm.prank(contentCouncil); // approve by council.. - IAssetRegistrable(assetReferendum).approve(assetId); + IAssetReferendumRegistrable(assetReferendum).approve(assetId); - IAssetVerifiable referendum = IAssetVerifiable(assetReferendum); + IAssetReferendumVerifiable referendum = IAssetReferendumVerifiable(assetReferendum); assertTrue(referendum.isActive(assetId), "Asset should be active"); assertTrue(referendum.isApproved(user, assetId), "Asset should be approved"); } @@ -65,7 +65,7 @@ contract AssetReferendumTest is BaseTest { vm.expectEmit(true, false, false, true, address(assetReferendum)); emit AssetReferendum.Rejected(assetId); - IAssetRevokable(assetReferendum).reject(assetId); + IAssetReferendumRevokable(assetReferendum).reject(assetId); } function test_Reject_RejectedValidStates() public { @@ -73,9 +73,9 @@ contract AssetReferendumTest is BaseTest { _submitContentAsUser(assetId); vm.prank(contentCouncil); // approve by council.. - IAssetRevokable(assetReferendum).reject(assetId); + IAssetReferendumRevokable(assetReferendum).reject(assetId); - IAssetVerifiable referendum = IAssetVerifiable(assetReferendum); + IAssetReferendumVerifiable referendum = IAssetReferendumVerifiable(assetReferendum); assertFalse(referendum.isActive(assetId), "Asset should not be active"); assertFalse(referendum.isApproved(user, assetId), "Asset should not be approved"); } @@ -88,11 +88,11 @@ contract AssetReferendumTest is BaseTest { vm.startPrank(contentCouncil); // approve by council.. // first an approval should ve done // then a revoke - IAssetRegistrable(assetReferendum).approve(assetId); + IAssetReferendumRegistrable(assetReferendum).approve(assetId); vm.expectEmit(true, false, false, true, address(assetReferendum)); emit AssetReferendum.Revoked(assetId); - IAssetRevokable(assetReferendum).revoke(assetId); + IAssetReferendumRevokable(assetReferendum).revoke(assetId); vm.stopPrank(); // reject by governance.. } @@ -100,9 +100,9 @@ contract AssetReferendumTest is BaseTest { uint256 assetId = 1; _submitAndApproveContent(assetId); vm.prank(contentCouncil); // approve by council.. - IAssetRevokable(assetReferendum).revoke(assetId); + IAssetReferendumRevokable(assetReferendum).revoke(assetId); - IAssetVerifiable referendum = IAssetVerifiable(assetReferendum); + IAssetReferendumVerifiable referendum = IAssetReferendumVerifiable(assetReferendum); assertFalse(referendum.isActive(assetId), "Asset should not be active"); assertFalse(referendum.isApproved(user, assetId), "Asset should not be approved"); } @@ -111,12 +111,12 @@ contract AssetReferendumTest is BaseTest { _submitContentAsUser(assetId); vm.warp(1641070805); vm.prank(contentCouncil); // approve by council.. - IAssetRegistrable(assetReferendum).approve(assetId); + IAssetReferendumRegistrable(assetReferendum).approve(assetId); vm.stopPrank(); // approve by governance.. } function _submitContentAsUser(uint256 assetId) internal { vm.prank(user); // the default user submitting content.. - IAssetRegistrable(assetReferendum).submit(assetId); + IAssetReferendumRegistrable(assetReferendum).submit(assetId); } } diff --git a/test/assets/AssetSafe.t.sol b/test/assets/AssetSafe.t.sol index 6b8c90c..8237ad7 100644 --- a/test/assets/AssetSafe.t.sol +++ b/test/assets/AssetSafe.t.sol @@ -3,8 +3,8 @@ pragma solidity 0.8.26; import "forge-std/Test.sol"; import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; -import { IAssetRegistrable } from "contracts/core/interfaces/assets/IAssetRegistrable.sol"; -import { IAssetVerifiable } from "contracts/core/interfaces/assets/IAssetVerifiable.sol"; +import { IAssetReferendumRegistrable } from "contracts/core/interfaces/assets/IAssetReferendumRegistrable.sol"; +import { IAssetReferendumVerifiable } from "contracts/core/interfaces/assets/IAssetReferendumVerifiable.sol"; import { IAssetOwnership } from "contracts/core/interfaces/assets/IAssetOwnership.sol"; import { IAssetSafe } from "contracts/core/interfaces/assets/IAssetSafe.sol"; import { AssetSafe } from "contracts/assets/AssetSafe.sol"; @@ -96,10 +96,10 @@ contract AssetSafeTest is BaseTest { function _registerAndApproveAsset(address to, uint256 assetId) private { vm.prank(to); - IAssetRegistrable(assetReferendum).submit(assetId); + IAssetReferendumRegistrable(assetReferendum).submit(assetId); vm.prank(contentCouncil); - IAssetRegistrable(assetReferendum).approve(assetId); + IAssetReferendumRegistrable(assetReferendum).approve(assetId); vm.prank(to); IAssetOwnership(assetOwnership).register(to, assetId); diff --git a/test/primitives/BalanceOperator.t.sol b/test/primitives/BalanceOperator.t.sol index 59ee0e7..8a48b49 100644 --- a/test/primitives/BalanceOperator.t.sol +++ b/test/primitives/BalanceOperator.t.sol @@ -12,7 +12,7 @@ import { IBalanceWithdrawable } from "contracts/core/interfaces/base/IBalanceWit import { BalanceOperatorUpgradeable } from "contracts/core/primitives/upgradeable/BalanceOperatorUpgradeable.sol"; contract BalanceOperator is BalanceOperatorUpgradeable { - function deposit(address recipient, uint256 amount, address currency) external returns (uint256) { + function deposit(address recipient, uint256 amount, address currency) external payable returns (uint256) { return _deposit(recipient, amount, currency); } From 44a546b70f50c0745163fbd97e6e07cd9aababc8 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Thu, 25 Sep 2025 13:21:44 -0600 Subject: [PATCH 15/33] asset renames --- .../assets/IAssetReferendumRegistrable.sol | 18 +++++++++ .../assets/IAssetReferendumRevokable.sol | 18 +++++++++ .../assets/IAssetReferendumVerifiable.sol | 21 +++++++++++ test/assets/AssetOwnership.t.sol | 37 +++++++++++++++++++ 4 files changed, 94 insertions(+) create mode 100644 contracts/core/interfaces/assets/IAssetReferendumRegistrable.sol create mode 100644 contracts/core/interfaces/assets/IAssetReferendumRevokable.sol create mode 100644 contracts/core/interfaces/assets/IAssetReferendumVerifiable.sol create mode 100644 test/assets/AssetOwnership.t.sol diff --git a/contracts/core/interfaces/assets/IAssetReferendumRegistrable.sol b/contracts/core/interfaces/assets/IAssetReferendumRegistrable.sol new file mode 100644 index 0000000..16467bb --- /dev/null +++ b/contracts/core/interfaces/assets/IAssetReferendumRegistrable.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: BUSL-1.1 +// NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html +pragma solidity 0.8.26; + +/// @title IAssetReferendumRegistrable Interface +/// @notice Defines the essential functions for managing asset registration and governance through a referendum process. +/// @dev This interface mirrors the FSM behavior from `IQuorum`, but scoped to asset governance. +interface IAssetReferendumRegistrable { + /// @notice Submits a new asset proposition for a referendum. + /// @dev This function should allow entities to propose an asset for approval. + /// @param assetId The unique identifier of the asset being submitted. + function submit(uint256 assetId) external; + + /// @notice Approves an asset proposition in the referendum. + /// @dev Once approved, the asset is considered verified and usable within the system. + /// @param assetId The unique identifier of the asset to be approved. + function approve(uint256 assetId) external; +} diff --git a/contracts/core/interfaces/assets/IAssetReferendumRevokable.sol b/contracts/core/interfaces/assets/IAssetReferendumRevokable.sol new file mode 100644 index 0000000..d2005d6 --- /dev/null +++ b/contracts/core/interfaces/assets/IAssetReferendumRevokable.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: BUSL-1.1 +// NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html +pragma solidity 0.8.26; + +/// @title IAssetReferendumRevokable Interface +/// @notice Defines the functions for invalidating or withdrawing assets from the system. +/// @dev This interface focuses on asset rejection and revocation, used in the governance lifecycle. +interface IAssetReferendumRevokable { + /// @notice Rejects an asset proposition in the referendum. + /// @dev If rejected, the asset cannot be used in the system unless resubmitted. + /// @param assetId The unique identifier of the asset to be rejected. + function reject(uint256 assetId) external; + + /// @notice Revokes a previously approved asset. + /// @dev This function allows the system to remove approval from an asset, disabling its functionality. + /// @param assetId The unique identifier of the asset to be revoked. + function revoke(uint256 assetId) external; +} diff --git a/contracts/core/interfaces/assets/IAssetReferendumVerifiable.sol b/contracts/core/interfaces/assets/IAssetReferendumVerifiable.sol new file mode 100644 index 0000000..42a4d9c --- /dev/null +++ b/contracts/core/interfaces/assets/IAssetReferendumVerifiable.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: BUSL-1.1 +// NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html +pragma solidity 0.8.26; + +/// @title IAssetReferendumVerifiable +/// @notice Interface for verifying the approval and active status of assets. +/// @dev This interface is used to check whether an asset has been approved and whether it is currently active. +interface IAssetReferendumVerifiable { + /// @notice Checks if a given asset has been approved. + /// @dev This function verifies if the asset has passed the necessary approval process. + /// @param initiator The address that submitted the asset for approval. + /// @param assetId The unique identifier of the asset. + /// @return A boolean indicating whether the asset is approved (`true`) or not (`false`). + function isApproved(address initiator, uint256 assetId) external view returns (bool); + + /// @notice Checks if a given asset is active and not blocked. + /// @dev Ensures that the asset is currently in use and has not been disabled or blacklisted. + /// @param assetId The unique identifier of the asset. + /// @return A boolean indicating whether the asset is active (`true`) or inactive/blocked (`false`). + function isActive(uint256 assetId) external view returns (bool); +} diff --git a/test/assets/AssetOwnership.t.sol b/test/assets/AssetOwnership.t.sol new file mode 100644 index 0000000..f3b133d --- /dev/null +++ b/test/assets/AssetOwnership.t.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import "forge-std/Test.sol"; +import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; +import { IAssetOwnership } from "contracts/core/interfaces/assets/IAssetOwnership.sol"; +import { IAssetReferendumRegistrable } from "contracts/core/interfaces/assets/IAssetReferendumRegistrable.sol"; + +import { BaseTest } from "test/BaseTest.t.sol"; +import { T } from "contracts/core/primitives/Types.sol"; +import { C } from "contracts/core/primitives/Constants.sol"; + +contract AssetOwnershipTest is BaseTest { + function setUp() public initialize { + // setup the access manager to use during tests.. + deployAssetOwnership(); + } + + + function test_Register_ValidRegistration() public { + uint256 assetId = 1; + + vm.prank(user); + IAssetReferendumRegistrable(assetReferendum).submit(assetId); + + vm.prank(contentCouncil); + IAssetReferendumRegistrable(assetReferendum).approve(assetId); + + vm.prank(user); + IAssetOwnership(assetOwnership).register(user, assetId); + assertEq(IAssetOwnership(assetOwnership).ownerOf(assetId), user, "Invalid unexpected owner"); + + } + + + +} From 8ef0990e73f2e3fcd5814400d0f2ce7f9a5bd979 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Fri, 26 Sep 2025 12:22:05 -0600 Subject: [PATCH 16/33] test: coverage upgrade --- Makefile | 2 +- .../core/interfaces/economics/ITreasury.sol | 5 +- contracts/core/libraries/FinancialOps.sol | 2 +- contracts/economics/Treasury.sol | 20 +- contracts/policies/PolicyBase.sol | 7 +- test/assets/AssetOwnership.t.sol | 37 -- test/assets/AssetReferendum.t.sol | 211 ++++++++- test/assets/AssetRegistry.t.sol | 327 ++++++++++++++ test/assets/AssetSafe.t.sol | 258 ++++++++++- test/custody/CustodianImpl.t.sol | 143 ------ test/custody/CustodianReferendum.t.sol | 111 ----- test/economics/Tollgate.t.sol | 211 +++++++++ test/finance/AgreementManager.t.sol | 375 +++++++++++++++ test/finance/AgreementSettler.t.sol | 408 +++++++++++++++++ test/finance/TrustlessEscrow.sol | 95 ---- test/libraries/FinancialOps.t.sol | 427 +++++++++++++++++- .../AccessControlledUpgradeable.t.sol | 311 +++++++++++++ .../AllowanceOperatorUpgradeable.t.sol | 305 +++++++++++++ ...t.sol => BalanceOperatorUpgradeable.t.sol} | 254 +++++++---- test/primitives/Ledger.t.sol | 29 -- test/primitives/LedgerUpgradeable.t.sol | 175 +++++++ test/primitives/LockOperatorUpgradeable.t.sol | 384 ++++++++++++++++ test/primitives/Quorum.t.sol | 135 ------ test/primitives/QuorumUpgradeable.t.sol | 236 ++++++++++ test/rights/RightAssetCustodian.t.sol | 307 ------------- test/shared/CustodianShared.t.sol | 35 -- 26 files changed, 3786 insertions(+), 1024 deletions(-) delete mode 100644 test/assets/AssetOwnership.t.sol create mode 100644 test/assets/AssetRegistry.t.sol delete mode 100644 test/custody/CustodianImpl.t.sol delete mode 100644 test/custody/CustodianReferendum.t.sol create mode 100644 test/finance/AgreementManager.t.sol create mode 100644 test/finance/AgreementSettler.t.sol delete mode 100644 test/finance/TrustlessEscrow.sol create mode 100644 test/primitives/AccessControlledUpgradeable.t.sol create mode 100644 test/primitives/AllowanceOperatorUpgradeable.t.sol rename test/primitives/{BalanceOperator.t.sol => BalanceOperatorUpgradeable.t.sol} (63%) delete mode 100644 test/primitives/Ledger.t.sol create mode 100644 test/primitives/LedgerUpgradeable.t.sol create mode 100644 test/primitives/LockOperatorUpgradeable.t.sol delete mode 100644 test/primitives/Quorum.t.sol create mode 100644 test/primitives/QuorumUpgradeable.t.sol delete mode 100644 test/rights/RightAssetCustodian.t.sol delete mode 100644 test/shared/CustodianShared.t.sol diff --git a/Makefile b/Makefile index 0a6493a..03ebd29 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ force-compile: .PHONY: test ## run tests test: - @export CI=true && forge test --show-progress --gas-report -vvvv + @export CI=true && forge test --show-progress --gas-report -vvv .PHONY: coverage ## run tests coverage report coverage: diff --git a/contracts/core/interfaces/economics/ITreasury.sol b/contracts/core/interfaces/economics/ITreasury.sol index eeab4f5..ebd97cc 100644 --- a/contracts/core/interfaces/economics/ITreasury.sol +++ b/contracts/core/interfaces/economics/ITreasury.sol @@ -7,7 +7,8 @@ import { IBalanceOperator } from "@synaps3/core/interfaces/base/IBalanceOperator /// @notice Defines the standard functions for a Treasury contract. interface ITreasury is IBalanceOperator { /// @notice Collects accrued fees for a specified currency from an authorized fee collector. - /// @param collector The address of an authorized fee collector. + /// @param amount The amount to collect from fee collector. /// @param currency The address of the currency for which fees are being collected. - function collectFees(address collector, address currency) external; + /// @param collector The address of an authorized fee collector. + function collectFees(uint256 amount, address currency, address collector) external; } diff --git a/contracts/core/libraries/FinancialOps.sol b/contracts/core/libraries/FinancialOps.sol index 4fcdbd0..3328381 100644 --- a/contracts/core/libraries/FinancialOps.sol +++ b/contracts/core/libraries/FinancialOps.sol @@ -111,7 +111,7 @@ library FinancialOps { if (token == address(0)) { return _nativeDeposit(amount); } - + return _erc20Deposit(from, amount, token); } diff --git a/contracts/economics/Treasury.sol b/contracts/economics/Treasury.sol index 515f89b..e785bf3 100644 --- a/contracts/economics/Treasury.sol +++ b/contracts/economics/Treasury.sol @@ -9,7 +9,7 @@ import { ReentrancyGuardTransientUpgradeable } from "@openzeppelin/contracts-upg import { BalanceOperatorUpgradeable } from "@synaps3/core/primitives/upgradeable/BalanceOperatorUpgradeable.sol"; import { ITreasury } from "@synaps3/core/interfaces/economics/ITreasury.sol"; -// import { IFeesCollector } from "@synaps3/core/interfaces/economics/IFeesCollector.sol"; +import { IFeesCollector } from "@synaps3/core/interfaces/economics/IFeesCollector.sol"; import { FinancialOps } from "@synaps3/core/libraries/FinancialOps.sol"; import { LoopOps } from "@synaps3/core/libraries/LoopOps.sol"; @@ -104,14 +104,18 @@ contract Treasury is /// @dev This function requests the given collector to disburse its collected fees /// for the specified currency. The collected funds are then credited to the treasury pool. /// Only the governor can execute this function, ensuring controlled fee collection. - /// @param collector The address of an authorized fee collector. + /// @param amount The amount to collect from fee collector. /// @param currency The address of the ERC20 token for which fees are being collected. - function collectFees(address collector, address currency) external restricted whenNotPaused nonReentrant { - // TODO update adding amount param on disburse call - // IFeesCollector feesCollector = IFeesCollector(collector); - // uint256 collected = feesCollector.disburse(currency); - // _sumLedgerEntry(address(this), collected, currency); - // emit FeesCollected(collector, collected, currency); + /// @param collector The address of an authorized fee collector. + function collectFees( + uint256 amount, + address currency, + address collector + ) external restricted whenNotPaused nonReentrant { + IFeesCollector feesCollector = IFeesCollector(collector); + uint256 collected = feesCollector.disburse(amount, currency); + _sumLedgerEntry(address(this), collected, currency); + emit FeesCollected(collector, collected, currency); } /// @notice Function that should revert when msg.sender is not authorized to upgrade the contract. diff --git a/contracts/policies/PolicyBase.sol b/contracts/policies/PolicyBase.sol index 25d7313..25cc6e2 100644 --- a/contracts/policies/PolicyBase.sol +++ b/contracts/policies/PolicyBase.sol @@ -84,12 +84,7 @@ abstract contract PolicyBase is ERC165, IPolicy { _; } - constructor( - address rightsPolicyManager, - address rightsAuthorizer, - address assetRegistry, - address providerAddress - ) { + constructor(address rightsPolicyManager, address rightsAuthorizer, address assetRegistry, address providerAddress) { RIGHTS_AUTHORIZER = IRightsPolicyAuthorizerVerifiable(rightsAuthorizer); RIGHTS_POLICY_MANAGER = IRightsPolicyManagerVerifiable(rightsPolicyManager); ATTESTATION_PROVIDER = IAttestationProvider(providerAddress); diff --git a/test/assets/AssetOwnership.t.sol b/test/assets/AssetOwnership.t.sol deleted file mode 100644 index f3b133d..0000000 --- a/test/assets/AssetOwnership.t.sol +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.26; - -import "forge-std/Test.sol"; -import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; -import { IAssetOwnership } from "contracts/core/interfaces/assets/IAssetOwnership.sol"; -import { IAssetReferendumRegistrable } from "contracts/core/interfaces/assets/IAssetReferendumRegistrable.sol"; - -import { BaseTest } from "test/BaseTest.t.sol"; -import { T } from "contracts/core/primitives/Types.sol"; -import { C } from "contracts/core/primitives/Constants.sol"; - -contract AssetOwnershipTest is BaseTest { - function setUp() public initialize { - // setup the access manager to use during tests.. - deployAssetOwnership(); - } - - - function test_Register_ValidRegistration() public { - uint256 assetId = 1; - - vm.prank(user); - IAssetReferendumRegistrable(assetReferendum).submit(assetId); - - vm.prank(contentCouncil); - IAssetReferendumRegistrable(assetReferendum).approve(assetId); - - vm.prank(user); - IAssetOwnership(assetOwnership).register(user, assetId); - assertEq(IAssetOwnership(assetOwnership).ownerOf(assetId), user, "Invalid unexpected owner"); - - } - - - -} diff --git a/test/assets/AssetReferendum.t.sol b/test/assets/AssetReferendum.t.sol index d7856de..6b900f3 100644 --- a/test/assets/AssetReferendum.t.sol +++ b/test/assets/AssetReferendum.t.sol @@ -2,15 +2,112 @@ pragma solidity 0.8.26; import "forge-std/Test.sol"; -import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; import { IAssetReferendumRegistrable } from "contracts/core/interfaces/assets/IAssetReferendumRegistrable.sol"; import { IAssetReferendumRevokable } from "contracts/core/interfaces/assets/IAssetReferendumRevokable.sol"; import { IAssetReferendumVerifiable } from "contracts/core/interfaces/assets/IAssetReferendumVerifiable.sol"; import { AssetReferendum } from "contracts/assets/AssetReferendum.sol"; import { BaseTest } from "test/BaseTest.t.sol"; -import { T } from "contracts/core/primitives/Types.sol"; -import { C } from "contracts/core/primitives/Constants.sol"; + +contract AssetReferendumHandler is Test { + enum Status { + None, + Submitted, + Approved, + Rejected, + Revoked + } + + struct AssetState { + Status status; + address submitter; + } + + address public immutable referendum; + address public immutable council; + + address[] public actors; + + uint256[] private _trackedAssets; + mapping(uint256 => AssetState) private _assets; + + constructor(address referendum_, address council_) { + referendum = referendum_; + council = council_; + + for (uint256 i = 0; i < 6; i++) { + actors.push(vm.addr(i + 111)); + } + } + + function submit(uint256 assetSeed, uint256 actorSeed) external { + if (actors.length == 0) return; + + uint256 assetId = bound(assetSeed, 1, type(uint128).max); + AssetState storage state = _assets[assetId]; + if (state.status != Status.None) return; + + address submitter = actors[actorSeed % actors.length]; + + vm.prank(submitter); + IAssetReferendumRegistrable(referendum).submit(assetId); + + state.status = Status.Submitted; + state.submitter = submitter; + _trackedAssets.push(assetId); + } + + function approve(uint256 assetSeed) external { + if (_trackedAssets.length == 0) return; + + uint256 assetId = _trackedAssets[assetSeed % _trackedAssets.length]; + AssetState storage state = _assets[assetId]; + if (state.status != Status.Submitted) return; + + vm.prank(council); + IAssetReferendumRegistrable(referendum).approve(assetId); + + state.status = Status.Approved; + } + + function reject(uint256 assetSeed) external { + if (_trackedAssets.length == 0) return; + + uint256 assetId = _trackedAssets[assetSeed % _trackedAssets.length]; + AssetState storage state = _assets[assetId]; + if (state.status != Status.Submitted) return; + + vm.prank(council); + IAssetReferendumRevokable(referendum).reject(assetId); + + state.status = Status.Rejected; + } + + function revoke(uint256 assetSeed) external { + if (_trackedAssets.length == 0) return; + + uint256 assetId = _trackedAssets[assetSeed % _trackedAssets.length]; + AssetState storage state = _assets[assetId]; + if (state.status != Status.Approved) return; + + vm.prank(council); + IAssetReferendumRevokable(referendum).revoke(assetId); + + state.status = Status.Revoked; + } + + function trackedLength() external view returns (uint256) { + return _trackedAssets.length; + } + + function trackedAt(uint256 index) external view returns (uint256) { + return _trackedAssets[index]; + } + + function stateOf(uint256 assetId) external view returns (AssetState memory) { + return _assets[assetId]; + } +} contract AssetReferendumTest is BaseTest { function setUp() public initialize { @@ -107,6 +204,57 @@ contract AssetReferendumTest is BaseTest { assertFalse(referendum.isApproved(user, assetId), "Asset should not be approved"); } + function testFuzz_SubmitAndApprove(address submitter, uint256 assetId) public { + vm.assume(submitter != address(0)); + vm.assume(submitter != contentCouncil); + assetId = bound(assetId, 1, type(uint128).max); + + vm.prank(submitter); + IAssetReferendumRegistrable(assetReferendum).submit(assetId); + + vm.prank(contentCouncil); + IAssetReferendumRegistrable(assetReferendum).approve(assetId); + + IAssetReferendumVerifiable referendum = IAssetReferendumVerifiable(assetReferendum); + assertTrue(referendum.isActive(assetId), "Asset should be active after approval"); + assertTrue(referendum.isApproved(submitter, assetId), "Submitter should have approved asset"); + } + + function testFuzz_SubmitAndReject(address submitter, uint256 assetId) public { + vm.assume(submitter != address(0)); + vm.assume(submitter != contentCouncil); + assetId = bound(assetId, 1, type(uint128).max); + + vm.prank(submitter); + IAssetReferendumRegistrable(assetReferendum).submit(assetId); + + vm.prank(contentCouncil); + IAssetReferendumRevokable(assetReferendum).reject(assetId); + + IAssetReferendumVerifiable referendum = IAssetReferendumVerifiable(assetReferendum); + assertFalse(referendum.isActive(assetId), "Rejected asset should be inactive"); + assertFalse(referendum.isApproved(submitter, assetId), "Rejected asset should not be approved"); + } + + function testFuzz_ApproveThenRevoke(address submitter, uint256 assetId) public { + vm.assume(submitter != address(0)); + vm.assume(submitter != contentCouncil); + assetId = bound(assetId, 1, type(uint128).max); + + vm.prank(submitter); + IAssetReferendumRegistrable(assetReferendum).submit(assetId); + + vm.prank(contentCouncil); + IAssetReferendumRegistrable(assetReferendum).approve(assetId); + + vm.prank(contentCouncil); + IAssetReferendumRevokable(assetReferendum).revoke(assetId); + + IAssetReferendumVerifiable referendum = IAssetReferendumVerifiable(assetReferendum); + assertFalse(referendum.isActive(assetId), "Revoked asset should not be active"); + assertFalse(referendum.isApproved(submitter, assetId), "Revoked asset should not be approved"); + } + function _submitAndApproveContent(uint256 assetId) internal { _submitContentAsUser(assetId); vm.warp(1641070805); @@ -120,3 +268,60 @@ contract AssetReferendumTest is BaseTest { IAssetReferendumRegistrable(assetReferendum).submit(assetId); } } + +contract AssetReferendumInvariantTest is BaseTest { + AssetReferendumHandler handler; + + function setUp() public initialize { + deployAssetReferendum(); + + handler = new AssetReferendumHandler(assetReferendum, contentCouncil); + targetContract(address(handler)); + } + + function invariant_StateAlignment() external view { + IAssetReferendumVerifiable referendum = IAssetReferendumVerifiable(assetReferendum); + uint256 len = handler.trackedLength(); + + for (uint256 i = 0; i < len; i++) { + uint256 assetId = handler.trackedAt(i); + AssetReferendumHandler.AssetState memory state = handler.stateOf(assetId); + + if (state.status == AssetReferendumHandler.Status.None) { + continue; + } + + bool isActive = referendum.isActive(assetId); + bool isApproved = referendum.isApproved(state.submitter, assetId); + + if (state.status == AssetReferendumHandler.Status.Submitted) { + assertFalse(isActive, "Submitted asset should be inactive"); + assertFalse(isApproved, "Submitted asset should not be approved"); + } else if (state.status == AssetReferendumHandler.Status.Approved) { + assertTrue(isActive, "Approved asset should be active"); + assertTrue(isApproved, "Approved asset should be approved for submitter"); + } else if (state.status == AssetReferendumHandler.Status.Rejected) { + assertFalse(isActive, "Rejected asset should be inactive"); + assertFalse(isApproved, "Rejected asset should not be approved"); + } else if (state.status == AssetReferendumHandler.Status.Revoked) { + assertFalse(isActive, "Revoked asset should be inactive"); + assertFalse(isApproved, "Revoked asset should not be approved"); + } + } + } + + function invariant_NoApprovedWithoutSubmitter() external view { + IAssetReferendumVerifiable referendum = IAssetReferendumVerifiable(assetReferendum); + uint256 len = handler.trackedLength(); + + for (uint256 i = 0; i < len; i++) { + uint256 assetId = handler.trackedAt(i); + AssetReferendumHandler.AssetState memory state = handler.stateOf(assetId); + + if (state.status == AssetReferendumHandler.Status.Approved) { + assertTrue(state.submitter != address(0), "Approved asset must track submitter"); + assertTrue(referendum.isApproved(state.submitter, assetId), "Approved asset must stay approved"); + } + } + } +} diff --git a/test/assets/AssetRegistry.t.sol b/test/assets/AssetRegistry.t.sol new file mode 100644 index 0000000..6d084d0 --- /dev/null +++ b/test/assets/AssetRegistry.t.sol @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import "forge-std/Test.sol"; +import { AssetRegistry } from "contracts/assets/AssetRegistry.sol"; +import { IAssetRegistry } from "contracts/core/interfaces/assets/IAssetRegistry.sol"; +import { IAssetReferendumRegistrable } from "contracts/core/interfaces/assets/IAssetReferendumRegistrable.sol"; +import { IERC721StatefulVerifiable } from "contracts/core/interfaces/token/erc721/IERC721StatefulVerifiable.sol"; + +import { BaseTest } from "test/BaseTest.t.sol"; + +contract AssetRegistryHandler is Test { + struct AssetInfo { + bool exists; + bool revoked; + bool active; + address owner; + } + + AssetRegistry public registry; + address public referendum; + address public contentCouncil; + address public admin; + address[] public actors; + + uint256[] private _assetIds; + mapping(uint256 => AssetInfo) private _assets; + + constructor(address registry_, address referendum_, address contentCouncil_, address admin_) { + registry = AssetRegistry(registry_); + referendum = referendum_; + contentCouncil = contentCouncil_; + admin = admin_; + + actors.push(contentCouncil_); + for (uint256 i = 0; i < 5; i++) { + actors.push(vm.addr(i + 100)); + } + } + + function register(uint256 assetSeed, uint256 actorSeed) external { + if (actors.length == 0) return; + + uint256 assetId = bound(assetSeed, 1, type(uint128).max); + AssetInfo storage info = _assets[assetId]; + if (info.exists) return; + + address submitter = actors[actorSeed % actors.length]; + + vm.prank(submitter); + IAssetReferendumRegistrable(referendum).submit(assetId); + + vm.prank(contentCouncil); + IAssetReferendumRegistrable(referendum).approve(assetId); + + vm.prank(submitter); + registry.register(submitter, assetId); + + info.exists = true; + info.revoked = false; + info.active = true; + info.owner = submitter; + _assetIds.push(assetId); + } + + function transfer(uint256 tokenSeed, uint256 targetSeed) external { + if (_assetIds.length == 0) return; + + uint256 assetId = _assetIds[tokenSeed % _assetIds.length]; + AssetInfo storage info = _assets[assetId]; + if (!info.exists || info.revoked) return; + + address newOwner = actors[targetSeed % actors.length]; + if (newOwner == address(0) || newOwner == info.owner) return; + + vm.prank(info.owner); + registry.transfer(newOwner, assetId); + + info.owner = newOwner; + } + + function switchState(uint256 tokenSeed) external { + if (_assetIds.length == 0) return; + + uint256 assetId = _assetIds[tokenSeed % _assetIds.length]; + AssetInfo storage info = _assets[assetId]; + if (!info.exists || info.revoked) return; + + vm.prank(info.owner); + bool newState = registry.switchState(assetId); + info.active = newState; + } + + function revoke(uint256 tokenSeed) external { + if (_assetIds.length == 0) return; + + uint256 assetId = _assetIds[tokenSeed % _assetIds.length]; + AssetInfo storage info = _assets[assetId]; + if (!info.exists || info.revoked) return; + + vm.prank(admin); + registry.revoke(assetId); + + info.revoked = true; + info.active = false; + info.owner = address(0); + } + + function assetIdsLength() external view returns (uint256) { + return _assetIds.length; + } + + function assetIdAt(uint256 index) external view returns (uint256) { + return _assetIds[index]; + } + + function getAssetInfo(uint256 assetId) external view returns (AssetInfo memory) { + return _assets[assetId]; + } +} + +contract AssetRegistryTest is BaseTest { + function setUp() public initialize { + // setup the access manager to use during tests.. + deployAssetRegistry(); + } + + function test_Register_ValidRegistration() public { + uint256 assetId = 1; + + _submitAndApproveAsset(user, assetId); + + vm.expectEmit(false, false, false, true, assetRegistry); + emit AssetRegistry.AssetEnabled(assetId); + + vm.expectEmit(true, true, false, true, assetRegistry); + emit AssetRegistry.RegisteredAsset(user, assetId); + + vm.prank(user); + IAssetRegistry(assetRegistry).register(user, assetId); + + assertEq(IAssetRegistry(assetRegistry).ownerOf(assetId), user, "Invalid unexpected owner"); + assertEq(IERC721StatefulVerifiable(assetRegistry).isActive(assetId), true, "Asset must be active"); + } + + function test_Register_RevertWhen_NotApproved() public { + uint256 assetId = 11; + + vm.expectRevert(AssetRegistry.InvalidNotApprovedAsset.selector); + vm.prank(user); + IAssetRegistry(assetRegistry).register(user, assetId); + } + + function testFuzz_Register_SetsOwnerAndActivates(address to, uint256 assetId) public { + vm.assume(to != address(0)); + assetId = bound(assetId, 1, type(uint128).max); + + _submitAndApproveAsset(to, assetId); + + vm.prank(to); + IAssetRegistry(assetRegistry).register(to, assetId); + + assertEq(IAssetRegistry(assetRegistry).ownerOf(assetId), to, "Unexpected owner after register"); + assertTrue(IERC721StatefulVerifiable(assetRegistry).isActive(assetId), "Asset should be active"); + assertEq(IAssetRegistry(assetRegistry).balanceOf(to), 1, "Balance should account for minted asset"); + assertEq(AssetRegistry(assetRegistry).totalSupply(), 1, "Total supply should match minted assets"); + } + + function test_Register_RevertWhen_DuplicateAsset() public { + uint256 assetId = 21; + _submitAndApproveAsset(user, assetId); + + vm.prank(user); + IAssetRegistry(assetRegistry).register(user, assetId); + + vm.expectRevert(); + vm.prank(user); + IAssetRegistry(assetRegistry).register(user, assetId); + } + + function test_Transfer_ValidOwner() public { + uint256 assetId = 31; + address recipient = vm.addr(33); + + _submitAndApproveAsset(user, assetId); + + vm.prank(user); + IAssetRegistry(assetRegistry).register(user, assetId); + + vm.expectEmit(true, true, false, true, assetRegistry); + emit AssetRegistry.TransferredAsset(user, recipient, assetId); + + vm.prank(user); + IAssetRegistry(assetRegistry).transfer(recipient, assetId); + + assertEq(IAssetRegistry(assetRegistry).ownerOf(assetId), recipient, "Recipient must own the asset"); + } + + function test_Transfer_RevertWhen_NotOwner() public { + uint256 assetId = 41; + address recipient = vm.addr(34); + + _submitAndApproveAsset(user, assetId); + + vm.prank(user); + IAssetRegistry(assetRegistry).register(user, assetId); + + vm.expectRevert(abi.encodeWithSignature("InvalidUnauthorizedOperation(string)", "Only the asset owner can modify its state.")); + vm.prank(recipient); + IAssetRegistry(assetRegistry).transfer(recipient, assetId); + } + + function test_SwitchState_Toggles() public { + uint256 assetId = 51; + _submitAndApproveAsset(user, assetId); + + vm.prank(user); + IAssetRegistry(assetRegistry).register(user, assetId); + + vm.expectEmit(false, false, false, true, assetRegistry); + emit AssetRegistry.AssetDisabled(assetId); + + vm.prank(user); + bool newState = AssetRegistry(assetRegistry).switchState(assetId); + assertFalse(newState, "Asset should be disabled after first toggle"); + assertFalse(IERC721StatefulVerifiable(assetRegistry).isActive(assetId), "Asset should be inactive"); + + vm.expectEmit(false, false, false, true, assetRegistry); + emit AssetRegistry.AssetEnabled(assetId); + + vm.prank(user); + bool backToActive = AssetRegistry(assetRegistry).switchState(assetId); + assertTrue(backToActive, "Asset should be active after second toggle"); + assertTrue(IERC721StatefulVerifiable(assetRegistry).isActive(assetId), "Asset should be active again"); + } + + function test_Revoke_DisablesAndBurns() public { + uint256 assetId = 61; + _submitAndApproveAsset(user, assetId); + + vm.prank(user); + IAssetRegistry(assetRegistry).register(user, assetId); + + vm.expectEmit(true, true, false, true, assetRegistry); + emit AssetRegistry.RevokedAsset(user, assetId); + + vm.prank(admin); + AssetRegistry(assetRegistry).revoke(assetId); + + assertFalse(IERC721StatefulVerifiable(assetRegistry).isActive(assetId), "Revoked asset should be inactive"); + assertEq(AssetRegistry(assetRegistry).totalSupply(), 0, "Total supply should decrease after burn"); + + vm.expectRevert(); + IAssetRegistry(assetRegistry).ownerOf(assetId); + } + + function _submitAndApproveAsset(address submitter, uint256 assetId) private { + vm.prank(submitter); + IAssetReferendumRegistrable(assetReferendum).submit(assetId); + + vm.prank(contentCouncil); + IAssetReferendumRegistrable(assetReferendum).approve(assetId); + } +} + +contract AssetRegistryInvariantTest is BaseTest { + AssetRegistryHandler handler; + + function setUp() public initialize { + deployAssetRegistry(); + + handler = new AssetRegistryHandler(assetRegistry, assetReferendum, contentCouncil, admin); + targetContract(address(handler)); + } + + function invariant_TotalSupplyMatchesTracked() external view { + uint256 len = handler.assetIdsLength(); + uint256 expectedSupply = 0; + + for (uint256 i = 0; i < len; i++) { + uint256 assetId = handler.assetIdAt(i); + AssetRegistryHandler.AssetInfo memory info = handler.getAssetInfo(assetId); + if (info.exists && !info.revoked) { + expectedSupply++; + } + } + + assertEq(AssetRegistry(assetRegistry).totalSupply(), expectedSupply, "Total supply mismatch"); + } + + function invariant_TrackedOwnerMatchesRegistry() external view { + uint256 len = handler.assetIdsLength(); + + for (uint256 i = 0; i < len; i++) { + uint256 assetId = handler.assetIdAt(i); + AssetRegistryHandler.AssetInfo memory info = handler.getAssetInfo(assetId); + + if (!info.exists || info.revoked) { + continue; + } + + assertEq(info.owner, IAssetRegistry(assetRegistry).ownerOf(assetId), "Tracked owner mismatch"); + assertTrue(info.owner != address(0), "Active asset cannot have zero owner"); + } + } + + function invariant_ActiveFlagMatchesRegistryState() external view { + uint256 len = handler.assetIdsLength(); + + for (uint256 i = 0; i < len; i++) { + uint256 assetId = handler.assetIdAt(i); + AssetRegistryHandler.AssetInfo memory info = handler.getAssetInfo(assetId); + + if (!info.exists) { + continue; + } + + bool isActiveOnChain = IERC721StatefulVerifiable(assetRegistry).isActive(assetId); + + if (info.revoked) { + assertFalse(isActiveOnChain, "Revoked asset should be inactive on chain"); + } else { + assertEq(isActiveOnChain, info.active, "Active flag mismatch"); + } + } + } +} diff --git a/test/assets/AssetSafe.t.sol b/test/assets/AssetSafe.t.sol index 3751b2d..ae166cf 100644 --- a/test/assets/AssetSafe.t.sol +++ b/test/assets/AssetSafe.t.sol @@ -2,16 +2,136 @@ pragma solidity 0.8.26; import "forge-std/Test.sol"; -import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; import { IAssetReferendumRegistrable } from "contracts/core/interfaces/assets/IAssetReferendumRegistrable.sol"; -import { IAssetReferendumVerifiable } from "contracts/core/interfaces/assets/IAssetReferendumVerifiable.sol"; import { IAssetRegistry } from "contracts/core/interfaces/assets/IAssetRegistry.sol"; import { IAssetSafe } from "contracts/core/interfaces/assets/IAssetSafe.sol"; import { AssetSafe } from "contracts/assets/AssetSafe.sol"; import { BaseTest } from "test/BaseTest.t.sol"; import { T } from "contracts/core/primitives/Types.sol"; -import { C } from "contracts/core/primitives/Constants.sol"; + +contract AssetSafeHandler is Test { + address public immutable safe; + address public immutable registry; + address public immutable referendum; + address public immutable contentCouncil; + + address[] public actors; + + uint256[] private _assetIds; + mapping(uint256 => bool) private _isTracked; + mapping(uint256 => address) private _owners; + mapping(uint256 => mapping(uint8 => bytes)) private _content; + mapping(uint256 => mapping(uint8 => bool)) private _hasContent; + mapping(uint256 => uint8) private _latestCipher; + mapping(uint256 => bool) private _hasLatestCipher; + + constructor(address safe_, address registry_, address referendum_, address contentCouncil_) { + safe = safe_; + registry = registry_; + referendum = referendum_; + contentCouncil = contentCouncil_; + + for (uint256 i = 0; i < 6; i++) { + actors.push(vm.addr(i + 501)); + } + } + + function registerAsset(uint256 assetSeed, uint256 actorSeed) external { + if (actors.length == 0) return; + + uint256 assetId = bound(assetSeed, 1, type(uint128).max); + if (_isTracked[assetId]) return; + + address owner = actors[actorSeed % actors.length]; + if (owner == address(0)) return; + + vm.prank(owner); + IAssetReferendumRegistrable(referendum).submit(assetId); + + vm.prank(contentCouncil); + IAssetReferendumRegistrable(referendum).approve(assetId); + + vm.prank(owner); + IAssetRegistry(registry).register(owner, assetId); + + _isTracked[assetId] = true; + _owners[assetId] = owner; + _assetIds.push(assetId); + } + + function transferAsset(uint256 assetSeed, uint256 actorSeed) external { + if (_assetIds.length == 0) return; + + uint256 assetId = _assetIds[assetSeed % _assetIds.length]; + if (!_isTracked[assetId]) return; + + address currentOwner = _owners[assetId]; + if (currentOwner == address(0)) return; + + address newOwner = actors[actorSeed % actors.length]; + if (newOwner == address(0) || newOwner == currentOwner) return; + + vm.prank(currentOwner); + IAssetRegistry(registry).transfer(newOwner, assetId); + + _owners[assetId] = newOwner; + } + + function setContent(uint256 assetSeed, uint8 cipherSeed, uint256 dataSeed) external { + if (_assetIds.length == 0) return; + + uint256 assetId = _assetIds[assetSeed % _assetIds.length]; + if (!_isTracked[assetId]) return; + + address owner = _owners[assetId]; + if (owner == address(0)) return; + + uint8 cipherIndex = uint8(bound(cipherSeed, 1, uint8(T.Cipher.EC))); + T.Cipher cipher = T.Cipher(cipherIndex); + bytes memory data = abi.encode(dataSeed); + + vm.prank(owner); + IAssetSafe(safe).setContent(assetId, cipher, data); + + _content[assetId][cipherIndex] = data; + _hasContent[assetId][cipherIndex] = true; + _latestCipher[assetId] = cipherIndex; + _hasLatestCipher[assetId] = true; + } + + function trackedLength() external view returns (uint256) { + return _assetIds.length; + } + + function trackedAt(uint256 index) external view returns (uint256) { + return _assetIds[index]; + } + + function ownerOf(uint256 assetId) external view returns (address) { + return _owners[assetId]; + } + + function isTracked(uint256 assetId) external view returns (bool) { + return _isTracked[assetId]; + } + + function hasContent(uint256 assetId, uint8 cipherIndex) external view returns (bool) { + return _hasContent[assetId][cipherIndex]; + } + + function contentOf(uint256 assetId, uint8 cipherIndex) external view returns (bytes memory) { + return _content[assetId][cipherIndex]; + } + + function hasLatestCipher(uint256 assetId) external view returns (bool) { + return _hasLatestCipher[assetId]; + } + + function latestCipher(uint256 assetId) external view returns (uint8) { + return _latestCipher[assetId]; + } +} contract AssetSafeTest is BaseTest { @@ -28,9 +148,9 @@ contract AssetSafeTest is BaseTest { _registerAndApproveAsset(user, assetId); vm.prank(user); - IAssetSafe assetSafe = IAssetSafe(assetSafe); - assetSafe.setContent(assetId, T.Cipher.LIT, ""); - assertEq(assetSafe.getContent(assetId, T.Cipher.LIT), "", "Content should be set to empty string"); + IAssetSafe safe = IAssetSafe(assetSafe); + safe.setContent(assetId, T.Cipher.LIT, ""); + assertEq(safe.getContent(assetId, T.Cipher.LIT), "", "Content should be set to empty string"); } function test_SetContent_RevertIf_InvalidOwner() public { @@ -40,8 +160,8 @@ contract AssetSafeTest is BaseTest { vm.prank(user); vm.expectRevert(abi.encodeWithSignature("InvalidAssetRightsHolder()")); - IAssetSafe assetSafe = IAssetSafe(assetSafe); - assetSafe.setContent(assetId, T.Cipher.LIT, ""); + IAssetSafe safe = IAssetSafe(assetSafe); + safe.setContent(assetId, T.Cipher.LIT, ""); } function test_SetContent_ContentEventEmitted() public { @@ -51,8 +171,8 @@ contract AssetSafeTest is BaseTest { vm.prank(user); vm.expectEmit(true, true, false, true, address(assetSafe)); emit AssetSafe.ContentStored(assetId, user, T.Cipher.LIT); - IAssetSafe assetSafe = IAssetSafe(assetSafe); - assetSafe.setContent(assetId, T.Cipher.LIT, ""); + IAssetSafe safe = IAssetSafe(assetSafe); + safe.setContent(assetId, T.Cipher.LIT, ""); } function test_SetContent_ValidScheme() public { @@ -61,10 +181,10 @@ contract AssetSafeTest is BaseTest { _registerAndApproveAsset(user, assetId); vm.prank(user); - IAssetSafe assetSafe = IAssetSafe(assetSafe); - assetSafe.setContent(assetId, T.Cipher.LIT, ""); + IAssetSafe safe = IAssetSafe(assetSafe); + safe.setContent(assetId, T.Cipher.LIT, ""); - T.Cipher safeType = assetSafe.getType(assetId); + T.Cipher safeType = safe.getType(assetId); assertEq(uint256(safeType), uint256(T.Cipher.LIT), "Safe type should be LIT"); } @@ -85,15 +205,56 @@ contract AssetSafeTest is BaseTest { bytes memory data = abi.encode(b64); vm.prank(user); - IAssetSafe assetSafe = IAssetSafe(assetSafe); - assetSafe.setContent(assetId, T.Cipher.LIT, data); + IAssetSafe safe = IAssetSafe(assetSafe); + safe.setContent(assetId, T.Cipher.LIT, data); vm.prank(admin); - bytes memory got = assetSafe.getContent(assetId, T.Cipher.LIT); + bytes memory got = safe.getContent(assetId, T.Cipher.LIT); string memory expected = abi.decode(got, (string)); assertEq(keccak256(abi.encodePacked(expected)), keccak256(abi.encodePacked(b64)), "Content should match the expected data"); } + function testFuzz_SetContent_StoresData( + address owner, + uint256 assetId, + uint8 cipherSeed, + uint256 dataSeed + ) public { + vm.assume(owner != address(0)); + assetId = bound(assetId, 1, type(uint128).max); + + _registerAndApproveAsset(owner, assetId); + + T.Cipher cipher = T.Cipher(uint8(bound(cipherSeed, 1, uint8(T.Cipher.EC)))); + bytes memory data = abi.encode(dataSeed); + + IAssetSafe safeContract = IAssetSafe(assetSafe); + + vm.prank(owner); + safeContract.setContent(assetId, cipher, data); + + assertEq(uint8(safeContract.getType(assetId)), uint8(cipher), "Cipher type should match stored value"); + bytes memory stored = safeContract.getContent(assetId, cipher); + assertEq(keccak256(stored), keccak256(data), "Stored content should match provided data"); + } + + function testFuzz_SetContent_RevertsForNonOwner( + address owner, + address attacker, + uint256 assetId + ) public { + vm.assume(owner != address(0)); + vm.assume(attacker != address(0)); + vm.assume(attacker != owner); + assetId = bound(assetId, 1, type(uint128).max); + + _registerAndApproveAsset(owner, assetId); + + vm.expectRevert(AssetSafe.InvalidAssetRightsHolder.selector); + vm.prank(attacker); + IAssetSafe(assetSafe).setContent(assetId, T.Cipher.LIT, ""); + } + function _registerAndApproveAsset(address to, uint256 assetId) private { vm.prank(to); IAssetReferendumRegistrable(assetReferendum).submit(assetId); @@ -105,3 +266,68 @@ contract AssetSafeTest is BaseTest { IAssetRegistry(assetRegistry).register(to, assetId); } } + +contract AssetSafeInvariantTest is BaseTest { + AssetSafeHandler handler; + uint8 private constant MAX_CIPHER = uint8(T.Cipher.EC); + + function setUp() public initialize { + deployAssetSafe(); + + handler = new AssetSafeHandler(assetSafe, assetRegistry, assetReferendum, contentCouncil); + targetContract(address(handler)); + } + + function invariant_OwnerMatchesRegistry() external view { + IAssetRegistry registryContract = IAssetRegistry(assetRegistry); + uint256 len = handler.trackedLength(); + + for (uint256 i = 0; i < len; i++) { + uint256 assetId = handler.trackedAt(i); + if (!handler.isTracked(assetId)) { + continue; + } + + address expectedOwner = handler.ownerOf(assetId); + if (expectedOwner == address(0)) { + continue; + } + + assertEq(registryContract.ownerOf(assetId), expectedOwner, "Handler owner should match registry owner"); + } + } + + function invariant_ContentMatchesStored() external view { + IAssetSafe safeContract = IAssetSafe(assetSafe); + uint256 len = handler.trackedLength(); + + for (uint256 i = 0; i < len; i++) { + uint256 assetId = handler.trackedAt(i); + + for (uint8 cipherIndex = 1; cipherIndex <= MAX_CIPHER; cipherIndex++) { + if (!handler.hasContent(assetId, cipherIndex)) { + continue; + } + + bytes memory expected = handler.contentOf(assetId, cipherIndex); + bytes memory actual = safeContract.getContent(assetId, T.Cipher(cipherIndex)); + assertEq(keccak256(actual), keccak256(expected), "Stored content should match handler state"); + } + } + } + + function invariant_LatestCipherMatchesType() external view { + IAssetSafe safeContract = IAssetSafe(assetSafe); + uint256 len = handler.trackedLength(); + + for (uint256 i = 0; i < len; i++) { + uint256 assetId = handler.trackedAt(i); + if (!handler.hasLatestCipher(assetId)) { + continue; + } + + uint8 expected = handler.latestCipher(assetId); + assertEq(uint8(safeContract.getType(assetId)), expected, "Latest cipher should match stored type"); + } + } +} diff --git a/test/custody/CustodianImpl.t.sol b/test/custody/CustodianImpl.t.sol deleted file mode 100644 index cdc3283..0000000 --- a/test/custody/CustodianImpl.t.sol +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.26; - -import "forge-std/Test.sol"; -import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol"; -import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; -import { ICustodian } from "contracts/core/interfaces/custody/ICustodian.sol"; -import { IBalanceVerifiable } from "contracts/core/interfaces/base/IBalanceVerifiable.sol"; -import { IBalanceWithdrawable } from "contracts/core/interfaces/base/IBalanceWithdrawable.sol"; -import { ICustodianFactory } from "contracts/core/interfaces/custody/ICustodianFactory.sol"; -import { BaseTest } from "test/BaseTest.t.sol"; - -contract CustodianImplTest is BaseTest { - function setUp() public initialize { - deployToken(); - deployCustodianFactory(); - } - - function deployCustodian(string memory endpoint, address owner) public returns (address) { - vm.prank(owner); - ICustodianFactory factory = ICustodianFactory(custodianFactory); - return factory.create(endpoint); - } - - function testFuzz_Create_ValidCustodian(string memory endpoint) public { - vm.assume(bytes(endpoint).length > 0); - - address custodian = deployCustodian(endpoint, user); - bool supportedInterface = IERC165(custodian).supportsInterface(type(ICustodian).interfaceId); - assertEq(supportedInterface, true, "Custodian should support ICustodian interface"); - } - - function testFuzz_GetOwner_ExpectedDeployer(address manager, string memory endpoint) public { - vm.assume(manager != address(0)); - vm.assume(bytes(endpoint).length > 0); - vm.assume(manager.code.length == 0); - - address custodian = deployCustodian(endpoint, manager); - address currentManager = ICustodian(custodian).getManager(); - assertEq(currentManager, manager, "Expected owner should be the deployer"); - } - - function testFuzz_GetEndpoint_ExpectedEndpoint(string memory endpoint) public { - vm.assume(bytes(endpoint).length > 0); - - address custodian = deployCustodian(endpoint, user); - string memory got = ICustodian(custodian).getEndpoint(); - assertEq(endpoint, got, "Expected endpoint should match"); - } - - function test_SetEndpoint_ValidEndpoint() public { - // created with an initial endpoint - address custodian = deployCustodian("1.1.1.1", user); - vm.prank(user); // only owner can do this - ICustodian(custodian).setEndpoint("mynew.com"); - string memory endpoint = ICustodian(custodian).getEndpoint(); - assertEq(endpoint, "mynew.com", "Expected endpoint should be updated"); - } - - function test_SetEndpoint_RevertWhen_InvalidOwner() public { - // created with an initial endpoint - address custodian = deployCustodian("1.1.1.1", user); - address invalidOwner = vm.addr(10); - - vm.prank(invalidOwner); - vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", invalidOwner)); - ICustodian(custodian).setEndpoint("mynew.com"); - } - - function test_SetEndpoint_RevertWhen_InvalidEndpoint() public { - // created with an initial endpoint - address custodian = deployCustodian("1.1.1.1", user); - - vm.prank(user); - vm.expectRevert(abi.encodeWithSignature("InvalidEndpoint()")); - ICustodian(custodian).setEndpoint(""); - } - - function test_GetBalance_ValidBalance() public { - // created with an initial endpoint - address custodian = deployCustodian("1.1.1.1", user); - uint256 expected = 100 * 1e18; - // admin acting as reward system to transfer funds - // here the expected is that rewards system do it. - vm.startPrank(admin); // only owner can get balance by default deployer - IERC20(token).transfer(custodian, expected); - uint256 currentBalance = IBalanceVerifiable(custodian).getBalance(token); - assertEq(currentBalance, expected, "Expected balance should match"); - vm.stopPrank(); - } - - function test_Withdraw_ValidFundsWithdrawn() public { - // created with an initial endpoint - uint256 expected = 100 * 1e18; - address custodian = deployCustodian("1.1.1.1", admin); - - vm.startPrank(admin); // only owner can get balance by default deployer - IERC20(token).transfer(custodian, expected); - // only owner can withdraw funds by default deployer - IBalanceWithdrawable(custodian).withdraw(user, expected, token); - vm.stopPrank(); - - uint256 userBalance = IERC20(token).balanceOf(user); - assertEq(userBalance, expected, "User should receive the withdrawn funds"); - } - - function test_Withdraw_EmitFundsWithdrawn() public { - // created with an initial endpoint - uint256 expected = 100 * 1e18; - address custodian = deployCustodian("1.1.1.1", admin); - - vm.startPrank(admin); // only owner can get balance by default deployer - IERC20(token).transfer(custodian, expected); - // only owner can withdraw funds by default deployer - vm.expectEmit(true, true, false, true, address(custodian)); - emit IBalanceWithdrawable.FundsWithdrawn(user, admin, expected, token); - IBalanceWithdrawable(custodian).withdraw(user, expected, token); - vm.stopPrank(); - - assertEq(IERC20(token).balanceOf(user), expected, "user with funds"); - assertEq(IERC20(token).balanceOf(custodian), 0, "custodian must be zero"); - } - - function test_Withdraw_RevertWhen_NoBalance() public { - // created with an initial endpoint - uint256 expected = 100 * 1e18; - address custodian = deployCustodian("1.1.1.1", user); - - vm.prank(user); // only owner can get balance by default deployer - vm.expectRevert(abi.encodeWithSignature("NoFundsToWithdraw()")); - IBalanceWithdrawable(custodian).withdraw(user, expected, token); - } - - function test_Withdraw_RevertWhen_InvalidOwner() public { - // created with an initial endpoint - uint256 expected = 100 * 1e18; - address custodian = deployCustodian("1.1.1.1", user); - - vm.prank(admin); - vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", admin)); - IBalanceWithdrawable(custodian).withdraw(user, expected, token); - } -} diff --git a/test/custody/CustodianReferendum.t.sol b/test/custody/CustodianReferendum.t.sol deleted file mode 100644 index d992aa8..0000000 --- a/test/custody/CustodianReferendum.t.sol +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.26; - -import "forge-std/Test.sol"; - -import { ICustodianVerifiable } from "contracts/core/interfaces/custody/ICustodianVerifiable.sol"; -import { ICustodianRegistrable } from "contracts/core/interfaces/custody/ICustodianRegistrable.sol"; -import { ICustodianInspectable } from "contracts/core/interfaces/custody/ICustodianInspectable.sol"; -import { ICustodianRevokable } from "contracts/core/interfaces/custody/ICustodianRevokable.sol"; -import { ICustodianFactory } from "contracts/core/interfaces/custody/ICustodianFactory.sol"; - -import { CustodianShared } from "test/shared/CustodianShared.t.sol"; -import { CustodianReferendum } from "contracts/custody/CustodianReferendum.sol"; -import { CustodianImpl } from "contracts/custody/CustodianImpl.sol"; - -contract CustodianReferendumTest is CustodianShared { - /// ---------------------------------------------------------------- - - function test_Register_RegisteredEventEmitted() public { - address custodian = _deployCustodian("contentrider.com", user); - // after register a custodian a Registered event is expected - vm.warp(1641070803); - vm.startPrank(admin); - - vm.expectEmit(true, false, false, true, address(custodianReferendum)); - emit CustodianReferendum.Registered(custodian); - ICustodianRegistrable(custodianReferendum).register(custodian); - vm.stopPrank(); - } - - function test_Register_SetWaitingState() public { - address custodian = _deployCustodian("contentrider.com", user); - // register the custodian expecting the right status. - ICustodianRegistrable(custodianReferendum).register(custodian); - bool isWaiting = ICustodianVerifiable(custodianReferendum).isWaiting(custodian); - assertTrue(isWaiting, "Custodian should be in waiting state"); - } - - function testFuzz_Register_RevertIf_InvalidCustodian(address custodian) public { - vm.prank(admin); // - vm.expectRevert(abi.encodeWithSignature("UnregisteredCustodian(address)", custodian)); - ICustodianRegistrable(custodianReferendum).register(custodian); - } - - function test_Approve_ApprovedEventEmitted() public { - address custodian = _deployCustodian("contentrider.com", user); - _registerCustodian(custodian); - - vm.prank(nodesCouncil); // as governor. - vm.warp(1641070802); - // after register a custodian a Registered event is expected - vm.expectEmit(true, false, false, true, address(custodianReferendum)); - emit CustodianReferendum.Approved(custodian); - ICustodianRegistrable(custodianReferendum).approve(custodian); - } - - function test_Approve_SetActiveState() public { - address custodian = _deployCustodian("contentrider.com", user); - - _registerAndApproveCustodian(custodian); - bool isActive = ICustodianVerifiable(custodianReferendum).isActive(custodian); - assertTrue(isActive, "Custodian should be active after approval"); - } - - function testFuzz_Approve_IncrementEnrollmentCount(uint256 rawN) public { - uint256 n = bound(rawN, 1, 20); - - for (uint256 i = 0; i < n; i++) { - address custodian = _deployCustodian(string.concat("content", vm.toString(i), ".com"), user); - _registerAndApproveCustodian(custodian); - } - - // valid approvals, increments the total of enrollments - uint256 enrollment = ICustodianInspectable(custodianReferendum).getEnrollmentCount(); - assertEq(enrollment, n, "Enrollment count should be 3"); - } - - function test_Revoke_RevokedEventEmitted() public { - address custodian = _deployCustodian("contentrider.com", user); - _registerAndApproveCustodian(custodian); // still governor prank - - vm.prank(nodesCouncil); - vm.warp(1641070801); - // after register a custodian a Registered event is expected - vm.expectEmit(true, false, false, true, address(custodianReferendum)); - emit CustodianReferendum.Revoked(custodian); - ICustodianRevokable(custodianReferendum).revoke(custodian); - } - - function test_Revoke_DecrementEnrollmentCount() public { - address custodian = _deployCustodian("contentrider.com", user); - _registerAndApproveCustodian(custodian); // still governor prank - - // valid approvals, increments the total of enrollments - vm.prank(nodesCouncil); - ICustodianRevokable(custodianReferendum).revoke(custodian); - uint256 enrollment = ICustodianInspectable(custodianReferendum).getEnrollmentCount(); - assertEq(enrollment, 0, "Enrollment count should be 0 after revocation"); - } - - function test_Revoke_SetBlockedState() public { - address custodian = _deployCustodian("contentrider.com", user); - _registerAndApproveCustodian(custodian); // still governor prank - - // custodian get revoked by governance.. - vm.prank(nodesCouncil); - ICustodianRevokable(custodianReferendum).revoke(custodian); - bool isBlocked = ICustodianVerifiable(custodianReferendum).isBlocked(custodian); - assertTrue(isBlocked, "Custodian should be blocked after revocation"); - } -} diff --git a/test/economics/Tollgate.t.sol b/test/economics/Tollgate.t.sol index cccc29d..be04601 100644 --- a/test/economics/Tollgate.t.sol +++ b/test/economics/Tollgate.t.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.26; +import "forge-std/Test.sol"; import { BaseTest } from "test/BaseTest.t.sol"; import { Tollgate } from "contracts/economics/Tollgate.sol"; import { ITollgate } from "contracts/core/interfaces/economics/ITollgate.sol"; @@ -22,6 +23,90 @@ contract TargetD { } } +contract TollgateHandler is Test { + struct FeeState { + bool exists; + uint256 fee; + } + + address public immutable tollgate; + address public immutable governor; + address[] public targets; + address[] public currencies; + + mapping(address => T.Scheme) private _schemes; + mapping(address => mapping(address => FeeState)) private _fees; + mapping(address => address[]) private _targetCurrencies; + mapping(address => mapping(address => bool)) private _currencyTracked; + + constructor(address tollgate_, address governor_, address token_) { + tollgate = tollgate_; + governor = governor_; + + targets.push(address(new TargetA())); + targets.push(address(new TargetB())); + targets.push(address(new TargetC())); + targets.push(address(new TargetD())); + + _schemes[targets[0]] = T.Scheme.FLAT; + _schemes[targets[1]] = T.Scheme.NOMINAL; + _schemes[targets[2]] = T.Scheme.BPS; + _schemes[targets[3]] = T.Scheme.FLAT; + + currencies.push(token_); + currencies.push(vm.addr(910)); + currencies.push(vm.addr(911)); + } + + function setFees(uint256 targetSeed, uint256 currencySeed, uint256 feeSeed) external { + if (targets.length == 0) return; + address target = targets[targetSeed % targets.length]; + address currency = currencies[currencySeed % currencies.length]; + T.Scheme scheme = _schemes[target]; + + uint256 fee; + if (scheme == T.Scheme.FLAT) { + fee = bound(feeSeed, 1, type(uint96).max); + } else if (scheme == T.Scheme.NOMINAL) { + fee = bound(feeSeed, 1, 100); + } else { + fee = bound(feeSeed, 1, 10_000); + } + + vm.prank(governor); + ITollgate(tollgate).setFees(scheme, target, fee, currency); + + FeeState storage state = _fees[target][currency]; + state.exists = true; + state.fee = fee; + + if (!_currencyTracked[target][currency]) { + _currencyTracked[target][currency] = true; + _targetCurrencies[target].push(currency); + } + } + + function targetsLength() external view returns (uint256) { + return targets.length; + } + + function targetAt(uint256 index) external view returns (address) { + return targets[index]; + } + + function schemeOf(address target) external view returns (T.Scheme) { + return _schemes[target]; + } + + function currenciesFor(address target) external view returns (address[] memory) { + return _targetCurrencies[target]; + } + + function feeState(address target, address currency) external view returns (FeeState memory) { + return _fees[target][currency]; + } +} + contract TollgateTest is BaseTest { function setUp() public initialize { deployTollgate(); @@ -132,4 +217,130 @@ contract TollgateTest is BaseTest { // only one expected since the set avoid dupes.. assertEq(got, expected, "Expected supported currencies should match"); } + + function testFuzz_SetFees_Flat(uint256 fee, address currency) public { + vm.assume(currency != address(0)); + address target = address(new TargetA()); + fee = bound(fee, 1, type(uint96).max); + + vm.prank(governor); + ITollgate(tollgate).setFees(T.Scheme.FLAT, target, fee, currency); + + (uint256 stored, T.Scheme scheme) = ITollgate(tollgate).getFees(target, currency); + assertEq(stored, fee, "Flat fee should match"); + assertEq(uint256(scheme), uint256(T.Scheme.FLAT), "Scheme should be FLAT"); + } + + function testFuzz_SetFees_Nominal(uint256 fee, address currency) public { + vm.assume(currency != address(0)); + address target = address(new TargetB()); + fee = bound(fee, 1, 100); + + vm.prank(governor); + ITollgate(tollgate).setFees(T.Scheme.NOMINAL, target, fee, currency); + + (uint256 stored, T.Scheme scheme) = ITollgate(tollgate).getFees(target, currency); + assertEq(stored, fee, "Nominal fee should match"); + assertEq(uint256(scheme), uint256(T.Scheme.NOMINAL), "Scheme should be NOMINAL"); + } + + function testFuzz_SetFees_Bps(uint256 fee, address currency) public { + vm.assume(currency != address(0)); + address target = address(new TargetC()); + fee = bound(fee, 1, 10_000); + + vm.prank(governor); + ITollgate(tollgate).setFees(T.Scheme.BPS, target, fee, currency); + + (uint256 stored, T.Scheme scheme) = ITollgate(tollgate).getFees(target, currency); + assertEq(stored, fee, "BPS fee should match"); + assertEq(uint256(scheme), uint256(T.Scheme.BPS), "Scheme should be BPS"); + } + + function testFuzz_SupportedCurrencies_NoDuplicates( + uint256 feeA, + uint256 feeB, + address currency + ) public { + vm.assume(currency != address(0)); + address target = address(new TargetA()); + feeA = bound(feeA, 1, type(uint96).max); + feeB = bound(feeB, 1, type(uint96).max); + + vm.prank(governor); + ITollgate(tollgate).setFees(T.Scheme.FLAT, target, feeA, currency); + + vm.prank(governor); + ITollgate(tollgate).setFees(T.Scheme.FLAT, target, feeB, currency); + + address[] memory supported = ITollgate(tollgate).supportedCurrencies(target); + assertEq(supported.length, 1, "Supported currencies should not duplicate entries"); + assertEq(supported[0], currency, "Supported currency should match input"); + } +} + +contract TollgateInvariantTest is BaseTest { + TollgateHandler handler; + + function setUp() public initialize { + deployTollgate(); + + handler = new TollgateHandler(tollgate, governor, token); + targetContract(address(handler)); + } + + function invariant_FeesMatchHandlerState() external view { + ITollgate tollgateContract = ITollgate(tollgate); + uint256 len = handler.targetsLength(); + + for (uint256 i = 0; i < len; i++) { + address target = handler.targetAt(i); + address[] memory currenciesList = handler.currenciesFor(target); + T.Scheme scheme = handler.schemeOf(target); + + for (uint256 j = 0; j < currenciesList.length; j++) { + address currency = currenciesList[j]; + TollgateHandler.FeeState memory state = handler.feeState(target, currency); + if (!state.exists) continue; + + (uint256 fee, T.Scheme storedScheme) = tollgateContract.getFees(target, currency); + assertEq(fee, state.fee, "Fee must align with handler state"); + assertEq(uint256(storedScheme), uint256(scheme), "Scheme must align with handler state"); + } + } + } + + function invariant_SupportedCurrenciesAligned() external view { + ITollgate tollgateContract = ITollgate(tollgate); + uint256 len = handler.targetsLength(); + + for (uint256 i = 0; i < len; i++) { + address target = handler.targetAt(i); + address[] memory handlerCurrencies = handler.currenciesFor(target); + address[] memory supported = tollgateContract.supportedCurrencies(target); + + uint256 expectedCount = 0; + for (uint256 j = 0; j < handlerCurrencies.length; j++) { + TollgateHandler.FeeState memory state = handler.feeState(target, handlerCurrencies[j]); + if (state.exists) expectedCount++; + } + + assertEq(supported.length, expectedCount, "Supported currency count mismatch"); + + for (uint256 j = 0; j < handlerCurrencies.length; j++) { + address currency = handlerCurrencies[j]; + TollgateHandler.FeeState memory state = handler.feeState(target, currency); + if (!state.exists) continue; + + bool found = false; + for (uint256 k = 0; k < supported.length; k++) { + if (supported[k] == currency) { + found = true; + break; + } + } + assertTrue(found, "Supported currency missing from Tollgate state"); + } + } + } } diff --git a/test/finance/AgreementManager.t.sol b/test/finance/AgreementManager.t.sol new file mode 100644 index 0000000..14711c6 --- /dev/null +++ b/test/finance/AgreementManager.t.sol @@ -0,0 +1,375 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import "forge-std/Test.sol"; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { ITollgate } from "contracts/core/interfaces/economics/ITollgate.sol"; +import { ILedgerVault } from "contracts/core/interfaces/financial/ILedgerVault.sol"; +import { ILedgerVerifiable } from "@synaps3/core/interfaces/base/ILedgerVerifiable.sol"; +import { IAgreementManager } from "contracts/core/interfaces/financial/IAgreementManager.sol"; +import { AgreementManager } from "contracts/financial/AgreementManager.sol"; +import { BaseTest } from "test/BaseTest.t.sol"; +import { T } from "contracts/core/primitives/Types.sol"; +import { C } from "contracts/core/primitives/Constants.sol"; + +interface IAgreementManagerExtended is IAgreementManager { + function maxParties() external view returns (uint256); + function setMaxParties(uint256 newMax) external; +} + +contract AgreementManagerMockArbiter {} + +contract AgreementManagerTest is BaseTest { + uint256 internal constant INITIAL_DEPOSIT = 1_000 * 1e18; + address internal arbiter; + + function setUp() public initialize { + deployAgreementManager(); + arbiter = address(new AgreementManagerMockArbiter()); + + vm.prank(governor); + ITollgate(tollgate).setFees(T.Scheme.BPS, arbiter, 500, token); + + vm.startPrank(admin); + IERC20(token).approve(ledger, INITIAL_DEPOSIT); + ILedgerVault(ledger).deposit(user, INITIAL_DEPOSIT, token); + vm.stopPrank(); + } + + function _buildParties(uint256 len) private view returns (address[] memory parties) { + parties = new address[](len); + for (uint256 i = 0; i < len; i++) { + parties[i] = vm.addr(100 + i); + } + } + + function _penaltyBps(uint256 partiesLen, uint256 maxParties) private pure returns (uint256) { + if (partiesLen <= maxParties) return 0; + uint256 excess = partiesLen - maxParties; + return ((excess * (excess + 1)) / 2) * 100; + } + + function test_SetMaxParties_UpdatesValue() public { + vm.prank(admin); + IAgreementManagerExtended(agreementManager).setMaxParties(8); + assertEq(IAgreementManagerExtended(agreementManager).maxParties(), 8, "maxParties should update"); + } + + function test_SetMaxParties_RevertWhen_Zero() public { + vm.prank(admin); + vm.expectRevert(abi.encodeWithSelector(AgreementManager.InvalidMaxParties.selector, 0)); + IAgreementManagerExtended(agreementManager).setMaxParties(0); + } + + function test_SetMaxParties_RevertWhen_NotAdmin() public { + vm.prank(user); + vm.expectRevert(abi.encodeWithSignature("InvalidUnauthorizedOperation(string)", "Only admin can perform this action.")); + IAgreementManagerExtended(agreementManager).setMaxParties(6); + } + + function test_CreateAgreement_StoresAgreement() public { + uint256 amount = 50 * 1e18; + address[] memory parties = _buildParties(2); + bytes memory payload = abi.encode("agreement"); + + vm.expectEmit(true, false, false, true, agreementManager); + emit AgreementManager.AgreementCreated(user, 0, amount, token); + + vm.prank(user); + uint256 proof = IAgreementManager(agreementManager).createAgreement(amount, token, arbiter, parties, payload); + + T.Agreement memory stored = IAgreementManager(agreementManager).getAgreement(proof); + assertEq(stored.total, amount, "Total mismatch"); + assertEq(stored.initiator, user, "Initiator mismatch"); + assertEq(stored.arbiter, arbiter, "Arbiter mismatch"); + assertEq(stored.parties, parties, "Parties mismatch"); + assertEq(stored.payload, payload, "Payload mismatch"); + + uint256 userLedger = ILedgerVerifiable(ledger).getLedgerBalance(user, token); + assertEq(userLedger, INITIAL_DEPOSIT - stored.locked, "Ledger should reflect locked funds"); + } + + function test_CreateAgreement_RevertWhen_UnsupportedCurrency() public { + address unsupportedArbiter = address(new AgreementManagerMockArbiter()); + address[] memory parties; + + vm.prank(user); + vm.expectRevert(abi.encodeWithSelector(AgreementManager.UnsupportedAgreementTarget.selector, unsupportedArbiter, token)); + IAgreementManager(agreementManager).createAgreement(1e18, token, unsupportedArbiter, parties, ""); + } + + function test_CreateAgreement_RevertWhen_FlatFeeExceedsTotal() public { + vm.prank(governor); + ITollgate(tollgate).setFees(T.Scheme.FLAT, arbiter, 20 * 1e18, token); + + address[] memory parties = _buildParties(1); + vm.prank(user); + vm.expectRevert(abi.encodeWithSelector(AgreementManager.FlatFeeExceedsTotal.selector, 10 * 1e18, 20 * 1e18)); + IAgreementManager(agreementManager).createAgreement(10 * 1e18, token, arbiter, parties, ""); + } + + function test_CreateAgreement_RevertWhen_InsufficientBalance() public { + address[] memory parties; + uint256 amount = INITIAL_DEPOSIT + 1; + + vm.prank(user); + vm.expectRevert(bytes4(keccak256("NoFundsToLock()"))); + IAgreementManager(agreementManager).createAgreement(amount, token, arbiter, parties, ""); + } + + function test_CreateAgreement_WithPenalizationLocksAmount() public { + uint256 partiesLen = IAgreementManagerExtended(agreementManager).maxParties() + 2; + address[] memory parties = _buildParties(partiesLen); + uint256 amount = 100 * 1e18; + + vm.prank(user); + uint256 proof = IAgreementManager(agreementManager).createAgreement(amount, token, arbiter, parties, ""); + + T.Agreement memory stored = IAgreementManager(agreementManager).getAgreement(proof); + uint256 penaltyBps = _penaltyBps(partiesLen, IAgreementManagerExtended(agreementManager).maxParties()); + uint256 expectedLocked = amount + ((amount * penaltyBps) / C.BPS_MAX); + + assertEq(stored.locked, expectedLocked, "Locked amount mismatch"); + + uint256 userLedger = ILedgerVerifiable(ledger).getLedgerBalance(user, token); + assertEq(userLedger, INITIAL_DEPOSIT - stored.locked, "Ledger balance should reflect locked amount"); + } + + function test_PreviewAgreement_Penalization() public { + uint256 partiesLen = 9; + address[] memory parties = _buildParties(partiesLen); + uint256 amount = 100 * 1e18; + + vm.prank(user); + T.Agreement memory agreement = IAgreementManager(agreementManager).previewAgreement(amount, token, arbiter, parties, ""); + + uint256 exceed = partiesLen - IAgreementManagerExtended(agreementManager).maxParties(); + uint256 expectedPercentage = (exceed * (exceed + 1)) / 2; + uint256 expectedPenalization = (amount * expectedPercentage * 100) / C.BPS_MAX; + + assertEq(agreement.locked, amount + expectedPenalization, "Penalization mismatch"); + } + + function testFuzz_CreateAgreement_RevertWhen_UnsupportedScheme(uint256 amountSeed) public { + address unsupportedArbiter = address(new AgreementManagerMockArbiter()); + uint256 amount = bound(amountSeed, 1e18, 100 * 1e18); + + vm.prank(user); + vm.expectRevert(abi.encodeWithSelector(AgreementManager.UnsupportedAgreementTarget.selector, unsupportedArbiter, token)); + IAgreementManager(agreementManager).createAgreement(amount, token, unsupportedArbiter, new address[](0), ""); + } + + function testFuzz_PreviewAgreement_MatchesPenalty(uint256 partiesLen) public { + uint256 maxParties = IAgreementManagerExtended(agreementManager).maxParties(); + partiesLen = bound(partiesLen, 0, maxParties + 10); + address[] memory parties = _buildParties(partiesLen); + uint256 amount = 25 * 1e18; + + vm.prank(user); + T.Agreement memory agreement = IAgreementManager(agreementManager).previewAgreement(amount, token, arbiter, parties, ""); + + uint256 penalty = _penaltyBps(partiesLen, maxParties); + uint256 expectedLocked = amount + ((amount * penalty) / C.BPS_MAX); + assertEq(agreement.locked, expectedLocked, "Locked value should include penalty"); + } + + function testFuzz_CreateAgreement_MatchesPreview(uint256 amountSeed, uint8 partiesSeed) public { + uint256 maxParties = IAgreementManagerExtended(agreementManager).maxParties(); + uint256 partiesLen = uint256(partiesSeed) % (maxParties + 6); + address[] memory parties = _buildParties(partiesLen); + uint256 available = ILedgerVerifiable(ledger).getLedgerBalance(user, token); + uint256 penaltyBps = _penaltyBps(partiesLen, maxParties); + + uint256 maxAmount = available; + if (penaltyBps > 0) { + maxAmount = (available * C.BPS_MAX) / (C.BPS_MAX + penaltyBps); + } + if (maxAmount < 1e18) return; + + uint256 amount = bound(amountSeed, 1e18, maxAmount); + bytes memory payload = abi.encode(amountSeed, partiesSeed); + + vm.prank(user); + T.Agreement memory preview = IAgreementManager(agreementManager).previewAgreement(amount, token, arbiter, parties, payload); + + vm.startPrank(user); + uint256 proof = IAgreementManager(agreementManager).createAgreement(amount, token, arbiter, parties, payload); + vm.stopPrank(); + + T.Agreement memory stored = IAgreementManager(agreementManager).getAgreement(proof); + assertEq(stored.total, preview.total, "Total mismatch"); + assertEq(stored.fees, preview.fees, "Fees mismatch"); + assertEq(stored.locked, preview.locked, "Locked mismatch"); + } +} + +contract AgreementManagerHandler is Test { + struct AgreementInfo { + bool exists; + uint256 total; + uint256 fees; + uint256 locked; + } + + IAgreementManagerExtended public immutable manager; + ILedgerVerifiable public immutable vault; + address public immutable token; + address public immutable initiator; + address public immutable arbiter; + address public immutable admin; + uint256 public immutable initialDeposit; + + uint256[] private _proofs; + mapping(uint256 => AgreementInfo) private _agreements; + uint256 private _totalLocked; + + constructor( + address manager_, + address vault_, + address token_, + address initiator_, + address arbiter_, + address admin_, + uint256 initialDeposit_ + ) { + manager = IAgreementManagerExtended(manager_); + vault = ILedgerVerifiable(vault_); + token = token_; + initiator = initiator_; + arbiter = arbiter_; + admin = admin_; + initialDeposit = initialDeposit_; + } + + function createAgreement(uint256 amountSeed, uint8 partiesSeed) external { + uint256 available = vault.getLedgerBalance(initiator, token); + if (available < 1e18) return; + + uint256 maxParties = manager.maxParties(); + uint256 partiesLen = uint256(partiesSeed) % (maxParties + 6); + uint256 penaltyBps = _penaltyBps(partiesLen, maxParties); + if (penaltyBps > C.BPS_MAX) return; + + uint256 maxAmount = available; + if (penaltyBps > 0) { + maxAmount = (available * C.BPS_MAX) / (C.BPS_MAX + penaltyBps); + } + if (maxAmount < 1e18) return; + + uint256 amount = bound(amountSeed, 1e18, maxAmount); + address[] memory parties = _buildParties(partiesLen); + bytes memory payload = abi.encode(amountSeed, partiesSeed); + + vm.prank(initiator); + uint256 proof = manager.createAgreement(amount, token, arbiter, parties, payload); + + if (_agreements[proof].exists) return; + + T.Agreement memory agreement = manager.getAgreement(proof); + _agreements[proof] = AgreementInfo({ exists: true, total: agreement.total, fees: agreement.fees, locked: agreement.locked }); + _totalLocked += agreement.locked; + _proofs.push(proof); + } + + function setMaxParties(uint256 newMax) external { + uint256 value = bound(newMax, 1, 10); + vm.prank(admin); + manager.setMaxParties(value); + } + + function proofsLength() external view returns (uint256) { + return _proofs.length; + } + + function proofAt(uint256 index) external view returns (uint256) { + return _proofs[index]; + } + + function info(uint256 proof) external view returns (AgreementInfo memory) { + return _agreements[proof]; + } + + function totalLocked() external view returns (uint256) { + return _totalLocked; + } + + function recomputeLocked() external view returns (uint256 lockedSum) { + uint256 len = _proofs.length; + for (uint256 i = 0; i < len; i++) { + AgreementInfo memory info = _agreements[_proofs[i]]; + if (!info.exists) continue; + lockedSum += info.locked; + } + } + + function _buildParties(uint256 len) private view returns (address[] memory parties) { + parties = new address[](len); + for (uint256 i = 0; i < len; i++) { + parties[i] = vm.addr(500 + i); + } + } + + function _penaltyBps(uint256 partiesLen, uint256 maxParties) private pure returns (uint256) { + if (partiesLen <= maxParties) return 0; + uint256 excess = partiesLen - maxParties; + return ((excess * (excess + 1)) / 2) * 100; + } +} + +contract AgreementManagerInvariantTest is BaseTest { + AgreementManagerHandler handler; + address internal arbiter; + uint256 internal constant INITIAL_DEPOSIT = 5_000 * 1e18; + + function setUp() public initialize { + deployAgreementManager(); + arbiter = address(new AgreementManagerMockArbiter()); + + vm.prank(governor); + ITollgate(tollgate).setFees(T.Scheme.BPS, arbiter, 400, token); + + vm.startPrank(admin); + IERC20(token).approve(ledger, INITIAL_DEPOSIT); + ILedgerVault(ledger).deposit(user, INITIAL_DEPOSIT, token); + vm.stopPrank(); + + handler = new AgreementManagerHandler( + agreementManager, + ledger, + token, + user, + arbiter, + admin, + INITIAL_DEPOSIT + ); + + targetContract(address(handler)); + } + + function invariant_AgreementsStoredMatchHandler() external view { + uint256 len = handler.proofsLength(); + for (uint256 i = 0; i < len; i++) { + uint256 proof = handler.proofAt(i); + AgreementManagerHandler.AgreementInfo memory info = handler.info(proof); + if (!info.exists) continue; + + T.Agreement memory agreement = IAgreementManager(agreementManager).getAgreement(proof); + assertEq(agreement.total, info.total, "Total mismatch"); + assertEq(agreement.fees, info.fees, "Fees mismatch"); + assertEq(agreement.locked, info.locked, "Locked mismatch"); + assertEq(agreement.arbiter, arbiter, "Arbiter mismatch"); + assertEq(agreement.initiator, user, "Initiator mismatch"); + } + } + + function invariant_UserLedgerPlusLockedEqualsInitial() external view { + uint256 ledgerBalance = ILedgerVerifiable(ledger).getLedgerBalance(user, token); + assertEq(ledgerBalance + handler.totalLocked(), INITIAL_DEPOSIT, "Ledger accounting mismatch"); + } + + function invariant_LockedTotalsConsistent() external view { + assertEq(handler.totalLocked(), handler.recomputeLocked(), "Tracked locked total mismatch"); + } +} + diff --git a/test/finance/AgreementSettler.t.sol b/test/finance/AgreementSettler.t.sol new file mode 100644 index 0000000..1b8e6a2 --- /dev/null +++ b/test/finance/AgreementSettler.t.sol @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import "forge-std/Test.sol"; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { ITollgate } from "contracts/core/interfaces/economics/ITollgate.sol"; +import { ILedgerVault } from "contracts/core/interfaces/financial/ILedgerVault.sol"; +import { ILedgerVerifiable } from "@synaps3/core/interfaces/base/ILedgerVerifiable.sol"; +import { IAgreementManager } from "contracts/core/interfaces/financial/IAgreementManager.sol"; +import { IAgreementSettler } from "contracts/core/interfaces/financial/IAgreementSettler.sol"; +import { AgreementSettler } from "contracts/financial/AgreementSettler.sol"; +import { BaseTest } from "test/BaseTest.t.sol"; +import { T } from "contracts/core/primitives/Types.sol"; +import { C } from "contracts/core/primitives/Constants.sol"; + +interface IAgreementManagerExtended is IAgreementManager { + function maxParties() external view returns (uint256); +} + +interface IAgreementSettlerExtended is IAgreementSettler { + function quitAgreement(uint256 proof) external returns (T.Agreement memory); +} + +contract SettlerMockArbiter { + IAgreementSettler public immutable SETTLER; + + constructor(address settler) { + SETTLER = IAgreementSettler(settler); + } + + function execute(uint256 proof, address counterparty) external returns (T.Agreement memory) { + return SETTLER.settleAgreement(proof, counterparty); + } +} + +contract AgreementSettlerTest is BaseTest { + uint256 internal constant INITIAL_DEPOSIT = 5_000 * 1e18; + SettlerMockArbiter arbiter; + + function setUp() public initialize { + deployAgreementSettler(); + arbiter = new SettlerMockArbiter(agreementSettler); + + vm.prank(governor); + ITollgate(tollgate).setFees(T.Scheme.BPS, address(arbiter), 500, token); + + vm.startPrank(admin); + IERC20(token).approve(ledger, INITIAL_DEPOSIT); + ILedgerVault(ledger).deposit(user, INITIAL_DEPOSIT, token); + vm.stopPrank(); + } + + function _penaltyBps(uint256 partiesLen, uint256 maxParties) private pure returns (uint256) { + if (partiesLen <= maxParties) return 0; + uint256 excess = partiesLen - maxParties; + return ((excess * (excess + 1)) / 2) * 100; + } + + function _buildParties(uint256 len) private view returns (address[] memory parties) { + parties = new address[](len); + for (uint256 i = 0; i < len; i++) { + parties[i] = vm.addr(1_100 + i); + } + } + + function _boundedAmount(uint256 seed, uint256 partiesLen) private view returns (uint256) { + uint256 maxParties = IAgreementManagerExtended(agreementManager).maxParties(); + uint256 penalty = _penaltyBps(partiesLen, maxParties); + uint256 available = ILedgerVerifiable(ledger).getLedgerBalance(user, token); + uint256 maxAmount = available; + if (penalty > 0) { + maxAmount = (available * C.BPS_MAX) / (C.BPS_MAX + penalty); + } + if (maxAmount < 1e18) return 0; + return bound(seed, 1e18, maxAmount); + } + + function _createAgreement(uint256 amount, uint256 partiesLen) private returns (uint256 proof, T.Agreement memory stored) { + address[] memory parties = _buildParties(partiesLen); + vm.prank(user); + proof = IAgreementManager(agreementManager).createAgreement(amount, token, address(arbiter), parties, ""); + stored = IAgreementManager(agreementManager).getAgreement(proof); + } + + function test_SettleAgreement_DistributesFunds() public { + uint256 amount = 150 * 1e18; + (uint256 proof, T.Agreement memory agreement) = _createAgreement(amount, 4); + address counterparty = vm.addr(5555); + + vm.expectEmit(true, true, true, true, agreementSettler); + emit AgreementSettler.AgreementSettled(address(arbiter), counterparty, proof, agreement.fees + (agreement.locked - agreement.total)); + vm.prank(address(arbiter)); + T.Agreement memory settled = IAgreementSettlerExtended(agreementSettler).settleAgreement(proof, counterparty); + + uint256 available = settled.total - settled.fees; + uint256 protocolTake = settled.fees + (settled.locked - settled.total); + + assertEq(ILedgerVerifiable(ledger).getLedgerBalance(counterparty, token), available, "Counterparty payout mismatch"); + assertEq(ILedgerVerifiable(ledger).getLedgerBalance(agreementSettler, token), protocolTake, "Protocol take mismatch"); + + vm.expectRevert(AgreementSettler.AgreementAlreadySettled.selector); + arbiter.execute(proof, counterparty); + } + + function test_SettleAgreement_RevertWhen_NotArbiter() public { + uint256 amount = 10 * 1e18; + (uint256 proof, ) = _createAgreement(amount, 0); + + vm.expectRevert(AgreementSettler.UnauthorizedEscrowAgent.selector); + IAgreementSettler(agreementSettler).settleAgreement(proof, vm.addr(999)); + } + + function test_QuitAgreement_ReleasesFunds() public { + uint256 amount = 75 * 1e18; + (uint256 proof, T.Agreement memory agreement) = _createAgreement(amount, 6); + + uint256 protocolTake = agreement.fees + (agreement.locked - agreement.total); + + vm.prank(user); + vm.expectEmit(true, false, true, true, agreementSettler); + emit AgreementSettler.AgreementCancelled(user, proof, protocolTake); + T.Agreement memory cancelled = IAgreementSettlerExtended(agreementSettler).quitAgreement(proof); + + assertEq(cancelled.total, agreement.total, "Quit agreement mismatch"); + assertEq(ILedgerVerifiable(ledger).getLedgerBalance(agreementSettler, token), protocolTake, "Protocol take mismatch"); + assertEq( + ILedgerVerifiable(ledger).getLedgerBalance(user, token), + INITIAL_DEPOSIT - protocolTake, + "User ledger mismatch" + ); + + vm.expectRevert(AgreementSettler.AgreementAlreadySettled.selector); + vm.prank(user); + IAgreementSettlerExtended(agreementSettler).quitAgreement(proof); + } + + function test_QuitAgreement_RevertWhen_NotInitiator() public { + uint256 amount = 30 * 1e18; + (uint256 proof, ) = _createAgreement(amount, 1); + + vm.expectRevert(AgreementSettler.UnauthorizedInitiator.selector); + vm.prank(vm.addr(3333)); + IAgreementSettlerExtended(agreementSettler).quitAgreement(proof); + } + + function testFuzz_SettleAgreement_LedgerConsistency(uint256 amountSeed, uint8 partiesSeed) public { + uint256 partiesLen = uint256(partiesSeed) % (IAgreementManagerExtended(agreementManager).maxParties() + 5); + uint256 amount = _boundedAmount(amountSeed, partiesLen); + if (amount == 0) return; + + (uint256 proof, ) = _createAgreement(amount, partiesLen); + address counterparty = vm.addr(9000 + partiesLen); + vm.prank(address(arbiter)); + T.Agreement memory settled = IAgreementSettlerExtended(agreementSettler).settleAgreement(proof, counterparty); + + uint256 available = settled.total - settled.fees; + uint256 protocolTake = settled.fees + (settled.locked - settled.total); + + assertEq(ILedgerVerifiable(ledger).getLedgerBalance(counterparty, token), available, "Counterparty ledger mismatch"); + assertEq(ILedgerVerifiable(ledger).getLedgerBalance(agreementSettler, token), protocolTake, "Settler ledger mismatch"); + } + + function testFuzz_QuitAgreement_LedgerConsistency(uint256 amountSeed, uint8 partiesSeed) public { + uint256 partiesLen = uint256(partiesSeed) % (IAgreementManagerExtended(agreementManager).maxParties() + 5); + uint256 amount = _boundedAmount(amountSeed, partiesLen); + if (amount == 0) return; + + (uint256 proof, T.Agreement memory agreement) = _createAgreement(amount, partiesLen); + uint256 protocolTake = agreement.fees + (agreement.locked - agreement.total); + + vm.prank(user); + IAgreementSettlerExtended(agreementSettler).quitAgreement(proof); + + assertEq(ILedgerVerifiable(ledger).getLedgerBalance(agreementSettler, token), protocolTake, "Protocol take ledger mismatch"); + assertEq( + ILedgerVerifiable(ledger).getLedgerBalance(user, token), + INITIAL_DEPOSIT - protocolTake, + "User ledger mismatch after quit" + ); + } +} + +contract AgreementSettlerHandler is Test { + IAgreementSettlerExtended public immutable settler; + IAgreementManagerExtended public immutable manager; + ILedgerVerifiable public immutable vault; + address public immutable token; + address public immutable initiator; + SettlerMockArbiter public immutable arbiter; + + struct ProofState { + bool exists; + bool settled; + bool cancelled; + uint256 total; + uint256 fees; + uint256 locked; + uint256 protocolTake; + uint256 available; + } + + uint256[] private _proofs; + mapping(uint256 => ProofState) private _states; + uint256 private _activeLocked; + uint256 private _protocolTake; + uint256 private _payout; + uint256 private _nonce; + + constructor( + address settler_, + address manager_, + address vault_, + address token_, + address initiator_, + address arbiter_ + ) { + settler = IAgreementSettlerExtended(settler_); + manager = IAgreementManagerExtended(manager_); + vault = ILedgerVerifiable(vault_); + token = token_; + initiator = initiator_; + arbiter = SettlerMockArbiter(arbiter_); + } + + function createAgreement(uint256 amountSeed, uint8 partiesSeed) external { + uint256 partiesLen = uint256(partiesSeed) % (manager.maxParties() + 5); + uint256 penaltyBps = _penaltyBps(partiesLen, manager.maxParties()); + uint256 available = vault.getLedgerBalance(initiator, token); + if (available < 1e18) return; + + uint256 maxAmount = available; + if (penaltyBps > 0) { + maxAmount = (available * C.BPS_MAX) / (C.BPS_MAX + penaltyBps); + } + if (maxAmount < 1e18) return; + + uint256 amount = bound(amountSeed, 1e18, maxAmount); + address[] memory parties = _buildParties(partiesLen); + bytes memory payload = abi.encode(_nonce++); + vm.prank(initiator); + uint256 proof = manager.createAgreement(amount, token, address(arbiter), parties, payload); + if (_states[proof].exists) return; + + T.Agreement memory agreement = manager.getAgreement(proof); + _states[proof] = ProofState({ + exists: true, + settled: false, + cancelled: false, + total: agreement.total, + fees: agreement.fees, + locked: agreement.locked, + protocolTake: 0, + available: agreement.total - agreement.fees + }); + _activeLocked += agreement.locked; + _proofs.push(proof); + } + + function settle(uint256 proofSeed, address counterpartySeed) external { + if (_proofs.length == 0) return; + uint256 proof = _proofs[proofSeed % _proofs.length]; + ProofState storage state = _states[proof]; + if (!state.exists || state.settled || state.cancelled) return; + + address counterParty = counterpartySeed; + while (counterParty == address(0) || counterParty == initiator || counterParty == address(settler)) { + counterParty = vm.addr(uint256(uint160(counterParty)) + 1); + } + + vm.prank(address(arbiter)); + T.Agreement memory settled = settler.settleAgreement(proof, counterParty); + uint256 protocolTake = settled.fees + (settled.locked - settled.total); + uint256 available = settled.total - settled.fees; + + state.settled = true; + state.protocolTake = protocolTake; + state.available = available; + + _activeLocked -= settled.locked; + _protocolTake += protocolTake; + _payout += available; + } + + function quit(uint256 proofSeed) external { + if (_proofs.length == 0) return; + uint256 proof = _proofs[proofSeed % _proofs.length]; + ProofState storage state = _states[proof]; + if (!state.exists || state.settled || state.cancelled) return; + + vm.prank(initiator); + T.Agreement memory cancelled = settler.quitAgreement(proof); + uint256 protocolTake = cancelled.fees + (cancelled.locked - cancelled.total); + + state.cancelled = true; + state.protocolTake = protocolTake; + + _activeLocked -= cancelled.locked; + _protocolTake += protocolTake; + } + + function proofsLength() external view returns (uint256) { + return _proofs.length; + } + + function proofAt(uint256 index) external view returns (uint256) { + return _proofs[index]; + } + + function stateOf(uint256 proof) external view returns (ProofState memory) { + return _states[proof]; + } + + function activeLocked() external view returns (uint256) { + return _activeLocked; + } + + function totalProtocolTake() external view returns (uint256) { + return _protocolTake; + } + + function totalPayout() external view returns (uint256) { + return _payout; + } + + function recomputeActiveLocked() external view returns (uint256 sum) { + uint256 len = _proofs.length; + for (uint256 i = 0; i < len; i++) { + ProofState memory state = _states[_proofs[i]]; + if (!state.exists || state.settled || state.cancelled) continue; + sum += state.locked; + } + } + + function _buildParties(uint256 len) private view returns (address[] memory parties) { + parties = new address[](len); + for (uint256 i = 0; i < len; i++) { + parties[i] = vm.addr(1_500 + i); + } + } + + function _penaltyBps(uint256 partiesLen, uint256 maxParties) private pure returns (uint256) { + if (partiesLen <= maxParties) return 0; + uint256 excess = partiesLen - maxParties; + return ((excess * (excess + 1)) / 2) * 100; + } +} + +contract AgreementSettlerInvariantTest is BaseTest { + AgreementSettlerHandler handler; + SettlerMockArbiter arbiter; + uint256 internal constant INITIAL_DEPOSIT = 8_000 * 1e18; + + function setUp() public initialize { + deployAgreementSettler(); + arbiter = new SettlerMockArbiter(agreementSettler); + + vm.prank(governor); + ITollgate(tollgate).setFees(T.Scheme.BPS, address(arbiter), 350, token); + + vm.startPrank(admin); + IERC20(token).approve(ledger, INITIAL_DEPOSIT); + ILedgerVault(ledger).deposit(user, INITIAL_DEPOSIT, token); + vm.stopPrank(); + + handler = new AgreementSettlerHandler( + agreementSettler, + agreementManager, + ledger, + token, + user, + address(arbiter) + ); + + targetContract(address(handler)); + } + + function invariant_SettlerLedgerMatchesProtocolTake() external view { + uint256 settlerLedger = ILedgerVerifiable(ledger).getLedgerBalance(agreementSettler, token); + assertEq(settlerLedger, handler.totalProtocolTake(), "Settler ledger mismatch"); + } + + function invariant_UserLedgerAccountingHolds() external view { + uint256 userLedger = ILedgerVerifiable(ledger).getLedgerBalance(user, token); + uint256 total = userLedger + handler.activeLocked() + handler.totalProtocolTake() + handler.totalPayout(); + assertEq(total, INITIAL_DEPOSIT, "Ledger accounting must balance"); + } + + function invariant_ActiveLockedConsistency() external view { + assertEq(handler.activeLocked(), handler.recomputeActiveLocked(), "Active locked tracking mismatch"); + } + + function invariant_AgreementStateMatchesManager() external view { + uint256 len = handler.proofsLength(); + for (uint256 i = 0; i < len; i++) { + uint256 proof = handler.proofAt(i); + AgreementSettlerHandler.ProofState memory state = handler.stateOf(proof); + if (!state.exists) continue; + + T.Agreement memory agreement = IAgreementManager(agreementManager).getAgreement(proof); + assertEq(agreement.total, state.total, "Agreement total mismatch"); + assertEq(agreement.fees, state.fees, "Agreement fees mismatch"); + assertEq(agreement.locked, state.locked, "Agreement locked mismatch"); + assertEq(agreement.arbiter, address(arbiter), "Arbiter mismatch"); + assertEq(agreement.initiator, user, "Initiator mismatch"); + } + } +} diff --git a/test/finance/TrustlessEscrow.sol b/test/finance/TrustlessEscrow.sol deleted file mode 100644 index ee65812..0000000 --- a/test/finance/TrustlessEscrow.sol +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.26; - -import "forge-std/Test.sol"; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ITollgate } from "@synaps3/core/interfaces/economics/ITollgate.sol"; -import { ILedgerVault } from "@synaps3/core/interfaces/financial/ILedgerVault.sol"; -import { IAgreementManager } from "@synaps3/core/interfaces/financial/IAgreementManager.sol"; -import { IAgreementSettler } from "@synaps3/core/interfaces/financial/IAgreementSettler.sol"; -import { BaseTest } from "test/BaseTest.t.sol"; -import { T } from "contracts/core/primitives/Types.sol"; -import { C } from "contracts/core/primitives/Constants.sol"; - -contract MockArbiter { - IAgreementSettler public immutable AGREEMENT_SETTLER; - - constructor(address agreementSettler) { - AGREEMENT_SETTLER = IAgreementSettler(agreementSettler); - } - - function executeAgreement(uint256 proof, address counterparty) external returns (T.Agreement memory agreement) { - agreement = AGREEMENT_SETTLER.settleAgreement(proof, counterparty); - } -} - -contract TrustlessEscrowTest is BaseTest { - MockArbiter arbiter; - - function setUp() public initialize { - deployAgreementSettler(); - arbiter = MockArbiter(agreementSettler); - - uint256 fees = 500; // 5% - vm.prank(governor); - ITollgate(tollgate).setFees(T.Scheme.BPS, address(arbiter), fees, token); - - vm.startPrank(admin); - - uint256 amount = 100 * 1e18; - IERC20(token).approve(ledger, amount); - ILedgerVault(ledger).deposit(user, amount, token); - vm.stopPrank(); - } - - function test_PreviewAgreement_ReturnExpectedAgreement() public { - uint256 amount = 10 * 1e18; - IAgreementManager manager = IAgreementManager(agreementManager); - (uint256 feesBPS, ) = ITollgate(tollgate).getFees(address(arbiter),token); - - address[] memory parties = new address[](2); - parties[0] = vm.addr(1); - parties[1] = vm.addr(2); - - vm.prank(user); - T.Agreement memory agreement = manager.previewAgreement(amount, token, address(arbiter), parties, ""); - uint256 fees = (feesBPS * amount) / 10_000; // 5% configured - - assertEq(agreement.total, amount); - assertEq(agreement.initiator, user); - assertEq(agreement.fees, fees); - assertEq(agreement.locked, amount); // eq amount if not exceed allowed parties - assertEq(agreement.currency, token); - assertEq(agreement.arbiter, address(arbiter)); - assertEq(agreement.parties, parties); - assertEq(agreement.payload, ""); - } - - function testFuzz_PreviewAgreement_ReturnPenalizedAgreement(uint256 partiesLen) public { - uint256 amount = 100 * 1e18; - // max 18 are allowed with soft cap maxParties = 5 - // force penalization with min 6, maxParties + 13 = 18 - uint256 capped = bound(partiesLen, 6, 18); - IAgreementManager manager = IAgreementManager(agreementManager); - - // max is 5, per each extra 1% in accumulated succession, - // eg: 6, 7, 8 = 1 + 2 + 3 = 6% penalization - address[] memory parties = new address[](capped); - for (uint256 i = 0; i < capped; i++) { - parties[i] = vm.addr(i + 1); - } - - T.Agreement memory agreement = manager.previewAgreement(amount, token, address(arbiter), parties, ""); - - uint256 exceed = capped - 5; // default maxParties = 5; - uint256 expectedPercentage = (exceed * (exceed + 1)) / 2; - uint256 expectedPenalizationBPS = expectedPercentage * 100; - uint256 expectedPenalizationAmount = (amount * expectedPenalizationBPS) / C.BPS_MAX; - uint256 expectedLocked = amount + expectedPenalizationAmount; - - assertEq(agreement.total, amount); - assertEq(agreement.locked, expectedLocked); - assertEq(agreement.parties, parties); - } -} diff --git a/test/libraries/FinancialOps.t.sol b/test/libraries/FinancialOps.t.sol index 49c96a9..10f4683 100644 --- a/test/libraries/FinancialOps.t.sol +++ b/test/libraries/FinancialOps.t.sol @@ -1 +1,426 @@ -// TODO complete here \ No newline at end of file +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import "forge-std/Test.sol"; + +import { FinancialOps } from "contracts/core/libraries/FinancialOps.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract TestToken is ERC20 { + constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) {} + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } +} + +contract FinancialOpsHarness { + using FinancialOps for address; + + function depositNative(uint256 amount) external payable returns (uint256) { + return FinancialOps.safeDeposit(msg.sender, amount, address(0)); + } + + function depositToken(address from, uint256 amount, address token) external returns (uint256) { + return FinancialOps.safeDeposit(from, amount, token); + } + + function transferFunds(address to, uint256 amount, address token) external { + FinancialOps.transfer(to, amount, token); + } + + function increaseTokenAllowance(address spender, uint256 amount, address token) external { + FinancialOps.increaseAllowance(spender, amount, token); + } + + function queryAllowance(address owner, address token) external view returns (uint256) { + return FinancialOps.allowance(owner, token); + } + + function queryNativeAllowance(address owner) external payable returns (uint256) { + return FinancialOps.allowance(owner, address(0)); + } + + function queryBalance(address target, address token) external view returns (uint256) { + return FinancialOps.balanceOf(target, token); + } + + receive() external payable {} +} + +contract FinancialOpsTest is Test { + FinancialOpsHarness internal harness; + TestToken internal token; + address internal alice; + address internal bob; + address internal carol; + uint256 internal constant INITIAL_TOKEN_ALLOCATION = 1e24; + uint256 internal constant INITIAL_NATIVE_ALLOCATION = 100 ether; + + function setUp() public { + harness = new FinancialOpsHarness(); + token = new TestToken("Mock Token", "MOCK"); + alice = vm.addr(1); + bob = vm.addr(2); + carol = vm.addr(3); + + token.mint(alice, INITIAL_TOKEN_ALLOCATION); + token.mint(bob, INITIAL_TOKEN_ALLOCATION); + vm.deal(alice, INITIAL_NATIVE_ALLOCATION); + vm.deal(bob, INITIAL_NATIVE_ALLOCATION); + } + + function test_SafeDepositNative_Succeeds() public { + uint256 amount = 5 ether; + vm.prank(alice); + uint256 deposited = harness.depositNative{ value: amount }(amount); + assertEq(deposited, amount, "Deposit return mismatch"); + assertEq(address(harness).balance, amount, "Harness native balance mismatch"); + } + + function test_SafeDepositNative_RevertWhen_Mismatch() public { + uint256 amount = 3 ether; + vm.prank(alice); + vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringDeposit.selector, "Amount exceeds balance sent.")); + harness.depositNative{ value: amount - 1 }(amount); + } + + function test_SafeDepositNative_RevertWhen_Zero() public { + vm.prank(alice); + vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringDeposit.selector, "Invalid zero amount.")); + harness.depositNative{ value: 0 }(0); + } + + function test_SafeDepositERC20_Succeeds() public { + uint256 amount = 2e21; + vm.startPrank(alice); + token.approve(address(harness), amount); + uint256 deposited = harness.depositToken(alice, amount, address(token)); + vm.stopPrank(); + + assertEq(deposited, amount, "ERC20 deposit return mismatch"); + assertEq(token.balanceOf(address(harness)), amount, "Harness token balance mismatch"); + assertEq(token.balanceOf(alice), INITIAL_TOKEN_ALLOCATION - amount, "Alice token balance mismatch"); + } + + function test_SafeDepositERC20_RevertWhen_NoAllowance() public { + uint256 amount = 1e18; + vm.prank(alice); + vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringDeposit.selector, "Amount exceeds allowance.")); + harness.depositToken(alice, amount, address(token)); + } + + function test_SafeDepositERC20_RevertWhen_Zero() public { + vm.prank(alice); + vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringDeposit.selector, "Invalid zero amount.")); + harness.depositToken(alice, 0, address(token)); + } + + function test_TransferNative_Succeeds() public { + uint256 amount = 6 ether; + vm.prank(alice); + harness.depositNative{ value: amount }(amount); + + uint256 transferAmount = 2 ether; + uint256 bobBefore = bob.balance; + harness.transferFunds(bob, transferAmount, address(0)); + + assertEq(address(harness).balance, amount - transferAmount, "Harness native after transfer"); + assertEq(bob.balance, bobBefore + transferAmount, "Bob native balance mismatch"); + } + + function test_TransferNative_RevertWhen_Zero() public { + vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringTransfer.selector, "Invalid zero amount to transfer.")); + harness.transferFunds(bob, 0, address(0)); + } + + function test_TransferNative_RevertWhen_InsufficientBalance() public { + uint256 amount = 1 ether; + vm.prank(alice); + harness.depositNative{ value: amount }(amount); + + vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringTransfer.selector, "Insufficient balance.")); + harness.transferFunds(bob, amount + 1 ether, address(0)); + } + + function test_TransferERC20_Succeeds() public { + uint256 amount = 4e21; + vm.startPrank(alice); + token.approve(address(harness), amount); + harness.depositToken(alice, amount, address(token)); + vm.stopPrank(); + + uint256 transferAmount = 1e21; + uint256 bobBefore = token.balanceOf(bob); + harness.transferFunds(bob, transferAmount, address(token)); + + assertEq(token.balanceOf(address(harness)), amount - transferAmount, "Harness token after transfer"); + assertEq(token.balanceOf(bob), bobBefore + transferAmount, "Bob token balance mismatch"); + } + + function test_TransferERC20_RevertWhen_Zero() public { + vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringTransfer.selector, "Invalid zero amount to transfer.")); + harness.transferFunds(bob, 0, address(token)); + } + + function test_TransferERC20_RevertWhen_InsufficientBalance() public { + uint256 amount = 5e21; + vm.startPrank(alice); + token.approve(address(harness), amount); + harness.depositToken(alice, amount, address(token)); + vm.stopPrank(); + + vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringTransfer.selector, "Insufficient balance.")); + harness.transferFunds(bob, amount + 1, address(token)); + } + + function test_IncreaseAllowance_Succeeds() public { + uint256 allowanceAmount = 7e20; + harness.increaseTokenAllowance(carol, allowanceAmount, address(token)); + assertEq(token.allowance(address(harness), carol), allowanceAmount, "Allowance mismatch"); + } + + function test_IncreaseAllowance_RevertWhen_ZeroAmount() public { + vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringDeposit.selector, "Invalid spender or allowance attempt")); + harness.increaseTokenAllowance(carol, 0, address(token)); + } + + function test_IncreaseAllowance_RevertWhen_NativeToken() public { + vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringDeposit.selector, "Invalid spender or allowance attempt")); + harness.increaseTokenAllowance(carol, 1, address(0)); + } + + function test_Allowance_NativeReflectsMsgValue() public { + uint256 amount = 3 ether; + uint256 reported = harness.queryNativeAllowance{ value: amount }(alice); + assertEq(reported, amount, "Native allowance mismatch"); + } + + function test_Allowance_ERC20MatchesApproval() public { + uint256 amount = 9e20; + vm.startPrank(alice); + token.approve(address(harness), amount); + vm.stopPrank(); + + uint256 reported = harness.queryAllowance(alice, address(token)); + assertEq(reported, amount, "Allowance report mismatch"); + } + + function test_BalanceOf_ReturnsBalances() public { + uint256 nativeAmount = 2 ether; + vm.prank(alice); + harness.depositNative{ value: nativeAmount }(nativeAmount); + + uint256 tokenAmount = 3e21; + vm.startPrank(bob); + token.approve(address(harness), tokenAmount); + harness.depositToken(bob, tokenAmount, address(token)); + vm.stopPrank(); + + assertEq(harness.queryBalance(address(harness), address(0)), nativeAmount, "Native balance query mismatch"); + assertEq(harness.queryBalance(address(harness), address(token)), tokenAmount, "Token balance query mismatch"); + } + + function test_Integration_MultiActorFlow() public { + vm.prank(alice); + harness.depositNative{ value: 10 ether }(10 ether); + vm.prank(bob); + harness.depositNative{ value: 4 ether }(4 ether); + + vm.startPrank(alice); + token.approve(address(harness), 5e21); + harness.depositToken(alice, 5e21, address(token)); + vm.stopPrank(); + + vm.startPrank(bob); + token.approve(address(harness), 2e21); + harness.depositToken(bob, 2e21, address(token)); + vm.stopPrank(); + + harness.transferFunds(carol, 6 ether, address(0)); + harness.transferFunds(carol, 3e21, address(token)); + + assertEq(address(harness).balance, 8 ether, "Harness native residual mismatch"); + assertEq(token.balanceOf(address(harness)), 4e21, "Harness token residual mismatch"); + assertEq(carol.balance, 6 ether, "Carol native balance mismatch"); + assertEq(token.balanceOf(carol), 3e21, "Carol token balance mismatch"); + } + + function testFuzz_NativeDepositTransferConservation(uint256 depositAmount, uint256 transferAmount) public { + depositAmount = bound(depositAmount, 1 wei, 50 ether); + transferAmount = bound(transferAmount, 0, depositAmount); + + vm.prank(alice); + harness.depositNative{ value: depositAmount }(depositAmount); + + uint256 bobBefore = bob.balance; + if (transferAmount > 0) { + harness.transferFunds(bob, transferAmount, address(0)); + } + + assertEq(address(harness).balance, depositAmount - transferAmount, "Harness native conservation"); + assertEq(bob.balance, bobBefore + transferAmount, "Bob native gain mismatch"); + } + + function testFuzz_ERC20DepositTransferConservation(uint256 depositAmount, uint256 transferAmount) public { + depositAmount = bound(depositAmount, 1, INITIAL_TOKEN_ALLOCATION); + transferAmount = bound(transferAmount, 0, depositAmount); + + vm.startPrank(alice); + token.approve(address(harness), depositAmount); + harness.depositToken(alice, depositAmount, address(token)); + vm.stopPrank(); + + uint256 bobBefore = token.balanceOf(bob); + if (transferAmount > 0) { + harness.transferFunds(bob, transferAmount, address(token)); + } + + assertEq(token.balanceOf(address(harness)), depositAmount - transferAmount, "Harness token conservation"); + assertEq(token.balanceOf(bob), bobBefore + transferAmount, "Bob token gain mismatch"); + } +} + +contract FinancialOpsHandler is Test { + FinancialOpsHarness public immutable harness; + TestToken public immutable token; + + address[] internal accounts; + uint256 internal constant INITIAL_NATIVE_BALANCE = 80 ether; + uint256 internal constant INITIAL_TOKEN_BALANCE = 5e21; + + uint256 internal expectedHarnessNative; + uint256 internal expectedHarnessToken; + uint256 internal aggregateNativeInitial; + uint256 internal aggregateTokenInitial; + + constructor(FinancialOpsHarness harness_, TestToken token_) { + harness = harness_; + token = token_; + + for (uint256 i = 0; i < 3; i++) { + address account = vm.addr(i + 10); + accounts.push(account); + vm.deal(account, INITIAL_NATIVE_BALANCE); + token.mint(account, INITIAL_TOKEN_BALANCE); + aggregateNativeInitial += INITIAL_NATIVE_BALANCE; + aggregateTokenInitial += INITIAL_TOKEN_BALANCE; + } + } + + function depositNative(uint256 accountIdx, uint256 amount) external { + vm.assume(accountIdx < accounts.length); + address account = accounts[accountIdx]; + uint256 balance = account.balance; + if (balance == 0) return; + amount = bound(amount, 1, balance); + + vm.prank(account); + harness.depositNative{ value: amount }(amount); + expectedHarnessNative += amount; + } + + function transferNative(uint256 accountIdx, uint256 amount) external { + vm.assume(accountIdx < accounts.length); + if (expectedHarnessNative == 0) return; + amount = bound(amount, 1, expectedHarnessNative); + address recipient = accounts[accountIdx]; + + harness.transferFunds(recipient, amount, address(0)); + expectedHarnessNative -= amount; + } + + function depositToken(uint256 accountIdx, uint256 amount) external { + vm.assume(accountIdx < accounts.length); + address account = accounts[accountIdx]; + uint256 balance = token.balanceOf(account); + if (balance == 0) return; + amount = bound(amount, 1, balance); + + vm.startPrank(account); + token.approve(address(harness), amount); + harness.depositToken(account, amount, address(token)); + vm.stopPrank(); + + expectedHarnessToken += amount; + } + + function transferToken(uint256 accountIdx, uint256 amount) external { + vm.assume(accountIdx < accounts.length); + if (expectedHarnessToken == 0) return; + amount = bound(amount, 1, expectedHarnessToken); + address recipient = accounts[accountIdx]; + + harness.transferFunds(recipient, amount, address(token)); + expectedHarnessToken -= amount; + } + + function accountsLength() external view returns (uint256) { + return accounts.length; + } + + function accountAt(uint256 idx) external view returns (address) { + return accounts[idx]; + } + + function expectedHarnessNativeBalance() external view returns (uint256) { + return expectedHarnessNative; + } + + function expectedHarnessTokenBalance() external view returns (uint256) { + return expectedHarnessToken; + } + + function nativeInitialTotal() external view returns (uint256) { + return aggregateNativeInitial; + } + + function tokenInitialTotal() external view returns (uint256) { + return aggregateTokenInitial; + } +} + +contract FinancialOpsInvariantTest is Test { + FinancialOpsHarness internal harness; + TestToken internal token; + FinancialOpsHandler internal handler; + + function setUp() public { + harness = new FinancialOpsHarness(); + token = new TestToken("Mock Token", "MOCK"); + handler = new FinancialOpsHandler(harness, token); + targetContract(address(handler)); + } + + function invariant_HarnessBalancesMatchExpectations() external view { + assertEq( + address(harness).balance, + handler.expectedHarnessNativeBalance(), + "Harness native expectation mismatch" + ); + assertEq( + token.balanceOf(address(harness)), + handler.expectedHarnessTokenBalance(), + "Harness token expectation mismatch" + ); + } + + function invariant_TotalTokenConserved() external view { + uint256 total = token.balanceOf(address(harness)); + uint256 len = handler.accountsLength(); + for (uint256 i = 0; i < len; i++) { + total += token.balanceOf(handler.accountAt(i)); + } + assertEq(total, handler.tokenInitialTotal(), "Token conservation failed"); + } + + function invariant_TotalNativeConserved() external view { + uint256 total = address(harness).balance; + uint256 len = handler.accountsLength(); + for (uint256 i = 0; i < len; i++) { + total += handler.accountAt(i).balance; + } + assertEq(total, handler.nativeInitialTotal(), "Native conservation failed"); + } +} diff --git a/test/primitives/AccessControlledUpgradeable.t.sol b/test/primitives/AccessControlledUpgradeable.t.sol new file mode 100644 index 0000000..a51ddf9 --- /dev/null +++ b/test/primitives/AccessControlledUpgradeable.t.sol @@ -0,0 +1,311 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import "forge-std/Test.sol"; + +import { AccessManager } from "@openzeppelin/contracts/access/manager/AccessManager.sol"; +import { AccessControlledUpgradeable } from "contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol"; +import { IAccessManaged } from "@openzeppelin/contracts/access/manager/IAccessManaged.sol"; +import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; +import { C } from "contracts/core/primitives/Constants.sol"; + +contract AccessControlledHarness is AccessControlledUpgradeable { + uint256 public counter; + + function initialize(address manager) external initializer { + __AccessControlled_init(manager); + } + + function adminAction() external onlyAdmin returns (uint256) { + counter += 1; + return counter; + } + + function opsAction() external restricted whenNotPaused returns (uint256) { + counter += 1; + return counter; + } + + function isPaused() external view returns (bool) { + return paused(); + } + + function hasRoleView(uint64 role, address account) external view returns (bool) { + return _hasRole(role, account); + } +} + +contract AccessControlledUpgradeableTest is Test { + AccessManager internal manager; + AccessControlledHarness internal harness; + + address internal admin = vm.addr(1); + address internal operator = vm.addr(2); + address internal stranger = vm.addr(3); + + function setUp() public { + manager = new AccessManager(admin); + harness = new AccessControlledHarness(); + + vm.prank(admin); + harness.initialize(address(manager)); + + vm.startPrank(admin); + bytes4[] memory adminSelectors = new bytes4[](3); + adminSelectors[0] = AccessControlledUpgradeable.pause.selector; + adminSelectors[1] = AccessControlledUpgradeable.unpause.selector; + adminSelectors[2] = AccessControlledHarness.adminAction.selector; + manager.setTargetFunctionRole(address(harness), adminSelectors, C.ADMIN_ROLE); + + bytes4[] memory opsSelectors = new bytes4[](1); + opsSelectors[0] = AccessControlledHarness.opsAction.selector; + manager.setTargetFunctionRole(address(harness), opsSelectors, C.OPS_ROLE); + manager.setRoleAdmin(C.OPS_ROLE, C.ADMIN_ROLE); + manager.grantRole(C.OPS_ROLE, operator, 0); + vm.stopPrank(); + } + + function test_Initialize_RevertWhen_InvalidManager() public { + AccessControlledHarness fresh = new AccessControlledHarness(); + vm.expectRevert( + abi.encodeWithSelector( + AccessControlledUpgradeable.InvalidUnauthorizedOperation.selector, + "Invalid authority address." + ) + ); + fresh.initialize(address(0)); + } + + function test_AdminAction_AllowsAdmin() public { + vm.prank(admin); + uint256 result = harness.adminAction(); + assertEq(result, 1, "Admin action should increment counter"); + assertEq(harness.counter(), 1, "Counter mismatch after admin action"); + } + + function test_AdminAction_RevertsForNonAdmin() public { + vm.expectRevert( + abi.encodeWithSelector( + AccessControlledUpgradeable.InvalidUnauthorizedOperation.selector, + "Only admin can perform this action." + ) + ); + vm.prank(operator); + harness.adminAction(); + } + + function test_HasRole_ReflectsAssignments() public { + assertTrue(harness.hasRoleView(C.ADMIN_ROLE, admin), "Admin should have admin role"); + assertFalse(harness.hasRoleView(C.ADMIN_ROLE, operator), "Operator should not have admin role"); + + vm.prank(admin); + manager.grantRole(C.ADMIN_ROLE, operator, 0); + + assertTrue(harness.hasRoleView(C.ADMIN_ROLE, operator), "Operator admin role not reflected"); + } + + function test_OpsAction_AllowsOperator() public { + vm.prank(operator); + uint256 result = harness.opsAction(); + assertEq(result, 1, "Ops action should increment counter"); + } + + function test_OpsAction_RevertsForUnauthorized() public { + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, stranger)); + vm.prank(stranger); + harness.opsAction(); + } + + function test_PauseBlocksOpsActionUntilUnpaused() public { + vm.prank(admin); + harness.pause(); + assertTrue(harness.isPaused(), "Contract should be paused"); + + vm.expectRevert(PausableUpgradeable.EnforcedPause.selector); + vm.prank(operator); + harness.opsAction(); + + vm.prank(admin); + harness.unpause(); + assertFalse(harness.isPaused(), "Contract should be unpaused"); + + vm.prank(operator); + uint256 result = harness.opsAction(); + assertEq(result, 1, "Ops action should succeed after unpause"); + } + + function test_Integration_GrantRevokeFlow() public { + vm.prank(operator); + harness.opsAction(); + assertEq(harness.counter(), 1, "Counter should increment after ops action"); + + vm.prank(admin); + manager.revokeRole(C.OPS_ROLE, operator); + assertFalse(harness.hasRoleView(C.OPS_ROLE, operator), "Operator role should be revoked"); + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, operator)); + vm.prank(operator); + harness.opsAction(); + } + + function testFuzz_AdminAction_RevertsForNonAdmin(address caller) public { + vm.assume(caller != admin && caller != address(manager)); + vm.expectRevert( + abi.encodeWithSelector( + AccessControlledUpgradeable.InvalidUnauthorizedOperation.selector, + "Only admin can perform this action." + ) + ); + vm.prank(caller); + harness.adminAction(); + } + + function testFuzz_OpsAction_HonorsPause(bool pauseBeforeCall) public { + if (pauseBeforeCall && !harness.isPaused()) { + vm.prank(admin); + harness.pause(); + } + + if (harness.isPaused()) { + vm.expectRevert(PausableUpgradeable.EnforcedPause.selector); + vm.prank(operator); + harness.opsAction(); + + vm.prank(admin); + harness.unpause(); + } else { + vm.prank(operator); + harness.opsAction(); + } + } +} + +contract AccessControlledHandler is Test { + AccessControlledHarness public immutable harness; + AccessManager public immutable manager; + address public immutable admin; + address[] internal actors; + + uint256 internal expectedCounter; + bool internal expectedPaused; + + constructor(AccessControlledHarness harness_, AccessManager manager_, address admin_, address[] memory actors_) { + harness = harness_; + manager = manager_; + admin = admin_; + + for (uint256 i = 0; i < actors_.length; i++) { + actors.push(actors_[i]); + } + } + + function grantOpsRole(uint256 actorIdx) external { + vm.assume(actorIdx < actors.length); + address actor = actors[actorIdx]; + vm.prank(admin); + manager.grantRole(C.OPS_ROLE, actor, 0); + } + + function revokeOpsRole(uint256 actorIdx) external { + vm.assume(actorIdx < actors.length); + address actor = actors[actorIdx]; + if (!harness.hasRoleView(C.OPS_ROLE, actor)) return; + vm.prank(admin); + manager.revokeRole(C.OPS_ROLE, actor); + } + + function callAdminAction() external { + vm.prank(admin); + harness.adminAction(); + expectedCounter += 1; + } + + function callOpsAction(uint256 actorIdx) external { + vm.assume(actorIdx < actors.length); + address actor = actors[actorIdx]; + if (!harness.hasRoleView(C.OPS_ROLE, actor) || harness.isPaused()) return; + vm.prank(actor); + harness.opsAction(); + expectedCounter += 1; + } + + function pause() external { + if (expectedPaused) return; + vm.prank(admin); + harness.pause(); + expectedPaused = true; + } + + function unpause() external { + if (!expectedPaused) return; + vm.prank(admin); + harness.unpause(); + expectedPaused = false; + } + + function actorsLength() external view returns (uint256) { + return actors.length; + } + + function actorAt(uint256 idx) external view returns (address) { + return actors[idx]; + } + + function expectedCounterValue() external view returns (uint256) { + return expectedCounter; + } + + function expectedPausedState() external view returns (bool) { + return expectedPaused; + } +} + +contract AccessControlledInvariantTest is Test { + AccessManager internal manager; + AccessControlledHarness internal harness; + AccessControlledHandler internal handler; + + address internal admin = vm.addr(11); + address[] internal actors; + + function setUp() public { + manager = new AccessManager(admin); + harness = new AccessControlledHarness(); + + vm.prank(admin); + harness.initialize(address(manager)); + + vm.startPrank(admin); + bytes4[] memory adminSelectors = new bytes4[](3); + adminSelectors[0] = AccessControlledUpgradeable.pause.selector; + adminSelectors[1] = AccessControlledUpgradeable.unpause.selector; + adminSelectors[2] = AccessControlledHarness.adminAction.selector; + manager.setTargetFunctionRole(address(harness), adminSelectors, C.ADMIN_ROLE); + + bytes4[] memory opsSelectors = new bytes4[](1); + opsSelectors[0] = AccessControlledHarness.opsAction.selector; + manager.setTargetFunctionRole(address(harness), opsSelectors, C.OPS_ROLE); + manager.setRoleAdmin(C.OPS_ROLE, C.ADMIN_ROLE); + vm.stopPrank(); + + actors = new address[](3); + for (uint256 i = 0; i < actors.length; i++) { + actors[i] = vm.addr(12 + i); + } + + vm.prank(admin); + manager.grantRole(C.OPS_ROLE, actors[0], 0); + + handler = new AccessControlledHandler(harness, manager, admin, actors); + targetContract(address(handler)); + } + + function invariant_CounterMatchesExpectations() external view { + assertEq(harness.counter(), handler.expectedCounterValue(), "Counter expectation mismatch"); + } + + function invariant_PauseStateMatches() external view { + assertEq(harness.isPaused(), handler.expectedPausedState(), "Pause state mismatch"); + } + +} diff --git a/test/primitives/AllowanceOperatorUpgradeable.t.sol b/test/primitives/AllowanceOperatorUpgradeable.t.sol new file mode 100644 index 0000000..7c9ada7 --- /dev/null +++ b/test/primitives/AllowanceOperatorUpgradeable.t.sol @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import "forge-std/Test.sol"; + +import { AllowanceOperatorUpgradeable } from "contracts/core/primitives/upgradeable/AllowanceOperatorUpgradeable.sol"; +import { ILedgerVerifiable } from "contracts/core/interfaces/base/ILedgerVerifiable.sol"; +import { IAllowanceApprovable } from "contracts/core/interfaces/base/IAllowanceApprovable.sol"; +import { IAllowanceCollectable } from "contracts/core/interfaces/base/IAllowanceCollectable.sol"; + +contract AllowanceOperatorHarness is AllowanceOperatorUpgradeable { + function initialize() external initializer { + __AllowanceOperator_init(); + } + + function boostLedger(address account, uint256 amount, address currency) external { + _sumLedgerEntry(account, amount, currency); + } + + // IAllowanceOperator interface + function approve(address to, uint256 amount, address currency) external override returns (uint256) { + return _approve(to, amount, currency); + } + + function revoke(address to, uint256 amount, address currency) external override returns (uint256) { + return _revoke(to, amount, currency); + } + + function collect(address from, uint256 amount, address currency) external override returns (uint256) { + return _collect(from, amount, currency); + } + + +} + +contract AllowanceOperatorTest is Test { + AllowanceOperatorHarness harness; + address internal constant TOKEN = address(0xC0FFEE); + address alice; + address bob; + address carol; + + function setUp() public { + harness = new AllowanceOperatorHarness(); + harness.initialize(); + alice = vm.addr(1); + bob = vm.addr(2); + carol = vm.addr(3); + } + + function test_Approve_SetsAllowanceAndEmitsEvent() public { + vm.prank(alice); + vm.expectEmit(true, true, false, true, address(harness)); + emit IAllowanceApprovable.FundsApproved(alice, bob, 10, TOKEN); + harness.approve(bob, 10, TOKEN); + + assertEq(harness.getApprovedAmount(alice, bob, TOKEN), 10, "Allowance mismatch"); + } + + function test_Approve_RevertWhen_InvalidParams() public { + vm.prank(alice); + vm.expectRevert(bytes4(keccak256("InvalidOperationParameters()"))); + harness.approve(address(0), 10, TOKEN); + + vm.prank(alice); + vm.expectRevert(bytes4(keccak256("InvalidOperationParameters()"))); + harness.approve(bob, 0, TOKEN); + } + + function test_Approve_RevertWhen_SelfApproval() public { + vm.prank(alice); + vm.expectRevert(bytes4(keccak256("InvalidOperationParameters()"))); + harness.approve(alice, 1, TOKEN); + } + + function test_Revoke_RemovesAllowance() public { + vm.startPrank(alice); + harness.approve(bob, 20, TOKEN); + harness.revoke(bob, 5, TOKEN); + vm.stopPrank(); + + assertEq(harness.getApprovedAmount(alice, bob, TOKEN), 15, "Allowance after revoke mismatch"); + } + + function test_Revoke_RevertWhen_ExceedsAllowance() public { + vm.startPrank(alice); + harness.approve(bob, 5, TOKEN); + vm.expectRevert(bytes4(keccak256("NoFundsToRevoke()"))); + harness.revoke(bob, 6, TOKEN); + vm.stopPrank(); + } + + function test_Collect_TransfersApprovedFunds() public { + vm.prank(alice); + harness.approve(bob, 40, TOKEN); + harness.boostLedger(alice, 40, TOKEN); + + vm.prank(bob); + vm.expectEmit(true, true, false, true, address(harness)); + emit IAllowanceCollectable.FundsCollected(alice, bob, 35, TOKEN); + harness.collect(alice, 35, TOKEN); + + assertEq(harness.getApprovedAmount(alice, bob, TOKEN), 5, "Remaining allowance mismatch"); + assertEq(ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN), 5, "Alice ledger mismatch"); + assertEq(ILedgerVerifiable(address(harness)).getLedgerBalance(bob, TOKEN), 35, "Bob ledger mismatch"); + } + + function test_Collect_RevertWhen_NoApproval() public { + harness.boostLedger(alice, 20, TOKEN); + + vm.prank(bob); + vm.expectRevert(bytes4(keccak256("NoFundsToCollect()"))); + harness.collect(alice, 10, TOKEN); + } + + function test_Collect_RevertWhen_InsufficientBalance() public { + vm.prank(alice); + harness.approve(bob, 10, TOKEN); + + vm.prank(bob); + vm.expectRevert(bytes4(keccak256("NoFundsToCollect()"))); + harness.collect(alice, 5, TOKEN); + } + + function test_Integration_MultiRecipientFlow() public { + vm.prank(alice); + harness.approve(bob, 30, TOKEN); + vm.prank(alice); + harness.approve(carol, 15, TOKEN); + harness.boostLedger(alice, 45, TOKEN); + + vm.prank(bob); + harness.collect(alice, 20, TOKEN); + + vm.prank(carol); + harness.collect(alice, 10, TOKEN); + + assertEq(harness.getApprovedAmount(alice, bob, TOKEN), 10, "Bob remaining allowance"); + assertEq(harness.getApprovedAmount(alice, carol, TOKEN), 5, "Carol remaining allowance"); + assertEq(ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN), 15, "Alice ledger balance"); + assertEq(ILedgerVerifiable(address(harness)).getLedgerBalance(bob, TOKEN), 20, "Bob ledger balance"); + assertEq(ILedgerVerifiable(address(harness)).getLedgerBalance(carol, TOKEN), 10, "Carol ledger balance"); + } + + function testFuzz_ApproveRevokeCycle(uint256 amount, uint256 revokeAmount) public { + amount = bound(amount, 1, 1e24); + revokeAmount = bound(revokeAmount, 1, amount); + + vm.prank(alice); + harness.approve(bob, amount, TOKEN); + + vm.prank(alice); + harness.revoke(bob, revokeAmount, TOKEN); + + assertEq(harness.getApprovedAmount(alice, bob, TOKEN), amount - revokeAmount, "Allowance after fuzz revoke mismatch"); + } + + function testFuzz_CollectMaintainsLedger(uint256 deposit, uint256 collectAmount) public { + deposit = bound(deposit, 1e18, 1e24); + collectAmount = bound(collectAmount, 1e18, deposit); + + vm.prank(alice); + harness.approve(bob, deposit, TOKEN); + harness.boostLedger(alice, deposit, TOKEN); + + vm.prank(bob); + harness.collect(alice, collectAmount, TOKEN); + + uint256 total = + ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN) + + ILedgerVerifiable(address(harness)).getLedgerBalance(bob, TOKEN); + assertEq(total, deposit, "Ledger conservation failed"); + } +} + +contract AllowanceHandler is Test { + AllowanceOperatorHarness public immutable harness; + address[] internal accounts; + address internal constant TOKEN = address(0xC0FFEE); + uint256 internal constant MAX_TEST_AMOUNT = 1e24; + + mapping(address => uint256) internal ledgerExpectation; + mapping(bytes32 => uint256) internal allowanceExpectation; + + constructor(AllowanceOperatorHarness operator) { + harness = operator; + for (uint256 i = 0; i < 3; i++) { + accounts.push(vm.addr(i + 10)); + } + } + + function seedLedger(uint256 index, uint256 amount) external { + vm.assume(index < accounts.length); + address account = accounts[index]; + amount = bound(amount, 1, MAX_TEST_AMOUNT); + harness.boostLedger(account, amount, TOKEN); + ledgerExpectation[account] += amount; + } + + function approve(uint256 fromIdx, uint256 toIdx, uint256 amount) external { + vm.assume(fromIdx < accounts.length && toIdx < accounts.length && fromIdx != toIdx); + address from = accounts[fromIdx]; + address to = accounts[toIdx]; + amount = bound(amount, 1, MAX_TEST_AMOUNT); + + vm.prank(from); + harness.approve(to, amount, TOKEN); + + bytes32 key = keccak256(abi.encode(from, to)); + allowanceExpectation[key] += amount; + } + + function revoke(uint256 fromIdx, uint256 toIdx, uint256 amount) external { + vm.assume(fromIdx < accounts.length && toIdx < accounts.length && fromIdx != toIdx); + address from = accounts[fromIdx]; + address to = accounts[toIdx]; + bytes32 key = keccak256(abi.encode(from, to)); + uint256 expected = allowanceExpectation[key]; + if (expected == 0) return; + amount = bound(amount, 1, expected); + + vm.prank(from); + harness.revoke(to, amount, TOKEN); + allowanceExpectation[key] = expected - amount; + } + + function collect(uint256 fromIdx, uint256 toIdx, uint256 amount) external { + vm.assume(fromIdx < accounts.length && toIdx < accounts.length && fromIdx != toIdx); + address from = accounts[fromIdx]; + address to = accounts[toIdx]; + bytes32 key = keccak256(abi.encode(from, to)); + uint256 allowance = allowanceExpectation[key]; + uint256 availableLedger = ledgerExpectation[from]; + if (allowance == 0 || availableLedger == 0) return; + uint256 maxCollect = allowance < availableLedger ? allowance : availableLedger; + amount = bound(amount, 1, maxCollect); + + vm.prank(to); + harness.collect(from, amount, TOKEN); + + allowanceExpectation[key] = allowance - amount; + ledgerExpectation[from] -= amount; + ledgerExpectation[to] += amount; + } + + function accountsLength() external view returns (uint256) { + return accounts.length; + } + + function accountAt(uint256 idx) external view returns (address) { + return accounts[idx]; + } + + function expectedLedger(address account) external view returns (uint256) { + return ledgerExpectation[account]; + } + + function expectedAllowance(address from, address to) external view returns (uint256) { + return allowanceExpectation[keccak256(abi.encode(from, to))]; + } + + function token() external pure returns (address) { + return TOKEN; + } +} + +contract AllowanceOperatorInvariantTest is Test { + AllowanceOperatorHarness harness; + AllowanceHandler handler; + + function setUp() public { + harness = new AllowanceOperatorHarness(); + harness.initialize(); + handler = new AllowanceHandler(harness); + targetContract(address(handler)); + } + + function invariant_LedgerBalancesMatchExpectation() external view { + uint256 len = handler.accountsLength(); + for (uint256 i = 0; i < len; i++) { + address account = handler.accountAt(i); + assertEq( + ILedgerVerifiable(address(harness)).getLedgerBalance(account, handler.token()), + handler.expectedLedger(account), + "Ledger balance mismatch" + ); + } + } + + function invariant_AllowancesMatchExpectation() external view { + uint256 len = handler.accountsLength(); + for (uint256 i = 0; i < len; i++) { + address from = handler.accountAt(i); + for (uint256 j = 0; j < len; j++) { + address to = handler.accountAt(j); + if (from == to) continue; + assertEq( + harness.getApprovedAmount(from, to, handler.token()), + handler.expectedAllowance(from, to), + "Allowance mismatch" + ); + } + } + } +} diff --git a/test/primitives/BalanceOperator.t.sol b/test/primitives/BalanceOperatorUpgradeable.t.sol similarity index 63% rename from test/primitives/BalanceOperator.t.sol rename to test/primitives/BalanceOperatorUpgradeable.t.sol index 8a48b49..0b8dc5e 100644 --- a/test/primitives/BalanceOperator.t.sol +++ b/test/primitives/BalanceOperatorUpgradeable.t.sol @@ -1,4 +1,4 @@ -// test balanaceoperator here// SPDX-License-Identifier: BUSL-1.1 +// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.26; import "forge-std/Test.sol"; @@ -11,7 +11,8 @@ import { IBalanceTransferable } from "contracts/core/interfaces/base/IBalanceTra import { IBalanceWithdrawable } from "contracts/core/interfaces/base/IBalanceWithdrawable.sol"; import { BalanceOperatorUpgradeable } from "contracts/core/primitives/upgradeable/BalanceOperatorUpgradeable.sol"; -contract BalanceOperator is BalanceOperatorUpgradeable { +/// @notice Thin wrapper to expose BalanceOperatorUpgradeable internal entrypoints for testing. +contract BalanceOperatorHarness is BalanceOperatorUpgradeable { function deposit(address recipient, uint256 amount, address currency) external payable returns (uint256) { return _deposit(recipient, amount, currency); } @@ -25,104 +26,15 @@ contract BalanceOperator is BalanceOperatorUpgradeable { } } -contract Handler is Test { - IERC20 mmc; - uint256 public total; - address[] public actors; - BalanceOperator operator; - - constructor(BalanceOperator op, address currency) { - operator = op; - mmc = IERC20(currency); - - for (uint256 i = 0; i < 10; i++) { - address a = vm.addr(i + 1); - actors.push(a); // exec as default admin and fund the authors - } - } - - function getActors() external view returns (address[] memory) { - return actors; - } - - function deposit(uint256 actorIndex, uint256 amount) external { - vm.assume(actorIndex < actors.length); - address a = actors[actorIndex]; - vm.assume(amount > 0 && amount < mmc.balanceOf(a)); - - // as author - vm.startPrank(a); - mmc.approve(address(operator), amount); - uint256 confirmed = operator.deposit(a, amount, address(mmc)); - total += confirmed; - vm.stopPrank(); - } - - function withdraw(uint256 actorIndex, uint256 amount) external { - vm.assume(actorIndex < actors.length); - address a = actors[actorIndex]; - vm.assume(amount > 0 && amount < operator.getLedgerBalance(a, address(mmc))); - - // as author - vm.prank(a); - uint256 confirmed = operator.withdraw(a, amount, address(mmc)); - total -= confirmed; - } - - function transfer(uint256 actorIndex, uint256 actorIndexB, uint256 amount) external { - vm.assume(actorIndex < actors.length); - vm.assume(actorIndexB < actors.length); - vm.assume(actorIndex != actorIndexB); - - address a = actors[actorIndex]; - address b = actors[actorIndexB]; - vm.assume(amount > 0 && amount < operator.getLedgerBalance(a, address(mmc))); - - // as author - vm.prank(a); - operator.transfer(b, amount, address(mmc)); - } -} -contract BalanceOperatorTest is BaseTest { - Handler handler; - BalanceOperator operator; +contract BalanceOperatorUpgradeableTest is BaseTest { + BalanceOperatorHarness operator; address opAddress; function setUp() public initialize { deployToken(); - operator = new BalanceOperator(); - handler = new Handler(operator, token); + operator = new BalanceOperatorHarness(); opAddress = address(operator); - - uint256 amount = 100 * 1e18; - address[] memory actors = handler.getActors(); - uint256 actorsLen = actors.length; - - for (uint256 i = 0; i < actorsLen; i++) { - vm.prank(admin); // the funds origin - IERC20(token).transfer(address(actors[i]), amount); - } - - targetContract(address(handler)); - } - - function invariant_GetBalance() external { - assertEq(handler.total(), IBalanceVerifiable(opAddress).getBalance(token)); - } - - function invariant_BalanceMatchActorsBalance() external { - uint256 totalByActor = 0; - address[] memory actors = handler.getActors(); - uint256 actorsLen = actors.length; - - for (uint256 i = 0; i < actorsLen; i++) { - // each deposit/withdraw move funds internally for each balance in the ledger - totalByActor += ILedgerVerifiable(opAddress).getLedgerBalance(actors[i], token); - } - - // the contract balance must match with the sum of all ledgers - assertEq(totalByActor, IBalanceVerifiable(opAddress).getBalance(token)); } function test_Deposit_ValidDeposit() public { @@ -275,8 +187,162 @@ contract BalanceOperatorTest is BaseTest { IBalanceTransferable(opAddress).transfer(admin, 1 * 1e18, token); } + function test_Integration_DepositTransferWithdrawFlow() public { + uint256 depositAmount = 250 * 1e18; + address recipient = vm.addr(8); + + vm.startPrank(admin); + _validDeposit(admin, depositAmount); + IBalanceTransferable(opAddress).transfer(recipient, 40 * 1e18, token); + IBalanceTransferable(opAddress).transfer(vm.addr(9), 60 * 1e18, token); + uint256 withdrawn = IBalanceWithdrawable(opAddress).withdraw(admin, 90 * 1e18, token); + vm.stopPrank(); + + ILedgerVerifiable verifier = ILedgerVerifiable(opAddress); + assertEq(withdrawn, 90 * 1e18, "Withdrawn amount mismatch"); + assertEq(verifier.getLedgerBalance(admin, token), 60 * 1e18, "Admin residual ledger mismatch"); + assertEq(verifier.getLedgerBalance(recipient, token), 40 * 1e18, "Recipient ledger mismatch"); + assertEq( + IBalanceVerifiable(opAddress).getBalance(token), + depositAmount - withdrawn, + "Contract balance mismatch" + ); + } + + function testFuzz_DepositWithdrawMaintainsLedger(uint256 amount) public { + amount = bound(amount, 1e18, 1_000 * 1e18); + + vm.startPrank(admin); + uint256 deposited = _validDeposit(admin, amount); + uint256 withdrawn = IBalanceWithdrawable(opAddress).withdraw(admin, deposited, token); + vm.stopPrank(); + + assertEq(deposited, withdrawn, "Mismatch between deposit and withdrawal"); + assertEq(ILedgerVerifiable(opAddress).getLedgerBalance(admin, token), 0, "Admin ledger should be zero"); + assertEq(IBalanceVerifiable(opAddress).getBalance(token), 0, "Contract balance should be zero"); + } + + function testFuzz_TransferDistributesLedger(uint256 depositAmount, uint256 transferAmount) public { + depositAmount = bound(depositAmount, 2e18, 1_000 * 1e18); + transferAmount = bound(transferAmount, 1e18, depositAmount - 1); + address recipient = vm.addr(10); + + vm.startPrank(admin); + _validDeposit(admin, depositAmount); + IBalanceTransferable(opAddress).transfer(recipient, transferAmount, token); + vm.stopPrank(); + + ILedgerVerifiable verifier = ILedgerVerifiable(opAddress); + assertEq( + verifier.getLedgerBalance(admin, token) + verifier.getLedgerBalance(recipient, token), + depositAmount, + "Ledger conservation failed" + ); + } + function _validDeposit(address account, uint256 amount) private returns (uint256) { IERC20(token).approve(opAddress, amount); return IBalanceDepositor(opAddress).deposit(account, amount, token); } } + + +contract BalanceOperatorHandler is Test { + IERC20 internal immutable token; + BalanceOperatorHarness internal immutable operator; + + uint256 public totalDeposited; + address[] public actors; + + constructor(BalanceOperatorHarness op, address currency) { + operator = op; + token = IERC20(currency); + + for (uint256 i = 0; i < 10; i++) { + actors.push(vm.addr(i + 1)); + } + } + + function getActors() external view returns (address[] memory) { + return actors; + } + + function deposit(uint256 actorIndex, uint256 amount) external { + vm.assume(actorIndex < actors.length); + address actor = actors[actorIndex]; + uint256 balance = token.balanceOf(actor); + if (balance == 0) return; + amount = bound(amount, 1, balance); + + vm.startPrank(actor); + token.approve(address(operator), amount); + uint256 confirmed = operator.deposit(actor, amount, address(token)); + vm.stopPrank(); + + totalDeposited += confirmed; + } + + function withdraw(uint256 actorIndex, uint256 amount) external { + vm.assume(actorIndex < actors.length); + address actor = actors[actorIndex]; + uint256 available = operator.getLedgerBalance(actor, address(token)); + if (available == 0) return; + amount = bound(amount, 1, available); + + vm.prank(actor); + uint256 confirmed = operator.withdraw(actor, amount, address(token)); + totalDeposited -= confirmed; + } + + function transfer(uint256 actorIndex, uint256 actorIndexB, uint256 amount) external { + vm.assume(actorIndex < actors.length); + vm.assume(actorIndexB < actors.length); + vm.assume(actorIndex != actorIndexB); + + address from = actors[actorIndex]; + address to = actors[actorIndexB]; + uint256 balance = operator.getLedgerBalance(from, address(token)); + if (balance == 0) return; + amount = bound(amount, 1, balance); + + vm.prank(from); + operator.transfer(to, amount, address(token)); + } +} + +contract BalanceOperatorInvariantTest is BaseTest { + BalanceOperatorHarness internal operator; + BalanceOperatorHandler internal handler; + address internal opAddress; + + function setUp() public initialize { + deployToken(); + operator = new BalanceOperatorHarness(); + handler = new BalanceOperatorHandler(operator, token); + opAddress = address(operator); + + address[] memory actors = handler.getActors(); + uint256 len = actors.length; + for (uint256 i = 0; i < len; i++) { + vm.prank(admin); + IERC20(token).transfer(actors[i], 100 * 1e18); + } + + targetContract(address(handler)); + } + + function invariant_TotalDepositsMatchVault() external { + assertEq(handler.totalDeposited(), IBalanceVerifiable(opAddress).getBalance(token), "Deposit ledger mismatch"); + } + + function invariant_SumOfLedgersEqualsVaultBalance() external { + uint256 aggregate; + address[] memory actors = handler.getActors(); + uint256 len = actors.length; + for (uint256 i = 0; i < len; i++) { + aggregate += ILedgerVerifiable(opAddress).getLedgerBalance(actors[i], token); + } + + assertEq(aggregate, IBalanceVerifiable(opAddress).getBalance(token), "Ledger aggregation mismatch"); + } +} diff --git a/test/primitives/Ledger.t.sol b/test/primitives/Ledger.t.sol deleted file mode 100644 index eebd84d..0000000 --- a/test/primitives/Ledger.t.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.26; - -import "forge-std/Test.sol"; -import { LedgerUpgradeable } from "contracts/core/primitives/upgradeable/LedgerUpgradeable.sol"; - -contract LedgerTest is Test, LedgerUpgradeable { - function test_SetLedgerEntry() public { - address account = vm.addr(1); // example address - _setLedgerEntry(account, 1e18, address(0)); - assertEq(getLedgerBalance(account, address(0)), 1e18, "Expected balance should be 1e18 after setting entry"); - } - - function test_SumLedgerEntry() public { - address account = vm.addr(1); // example address - _sumLedgerEntry(account, 1e18, address(0)); - _sumLedgerEntry(account, 1e18, address(0)); - assertEq(getLedgerBalance(account, address(0)), 2e18, "Expected balance should be 2e18 after summation"); - } - - function test_SubLenderEntry() public { - address account = vm.addr(1); // example address - _sumLedgerEntry(account, 1e18, address(0)); - _sumLedgerEntry(account, 1e18, address(0)); - _subLedgerEntry(account, 1e18, address(0)); - _subLedgerEntry(account, 1e18, address(0)); - assertEq(getLedgerBalance(account, address(0)), 0, "Expected balance should be zero after subtraction"); - } -} diff --git a/test/primitives/LedgerUpgradeable.t.sol b/test/primitives/LedgerUpgradeable.t.sol new file mode 100644 index 0000000..fdec3a0 --- /dev/null +++ b/test/primitives/LedgerUpgradeable.t.sol @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import "forge-std/Test.sol"; + +import { LedgerUpgradeable } from "contracts/core/primitives/upgradeable/LedgerUpgradeable.sol"; + +contract LedgerUpgradeableHarness is LedgerUpgradeable { + function initialize() external initializer { + __Ledger_init(); + } + + function setEntry(address account, uint256 amount, address currency) external { + _setLedgerEntry(account, amount, currency); + } + + function sumEntry(address account, uint256 amount, address currency) external { + _sumLedgerEntry(account, amount, currency); + } + + function subEntry(address account, uint256 amount, address currency) external { + _subLedgerEntry(account, amount, currency); + } +} + +contract LedgerUpgradeableTest is Test { + LedgerUpgradeableHarness harness; + + function setUp() public { + harness = new LedgerUpgradeableHarness(); + harness.initialize(); + } + + function test_SetEntry_SetsBalance() public { + address account = address(0xBEEF); + address currency = address(0xCAFE); + uint256 amount = 123 ether; + + harness.setEntry(account, amount, currency); + + assertEq(harness.getLedgerBalance(account, currency), amount, "Ledger should equal set amount"); + } + + function test_SumEntry_Accumulates() public { + address account = address(0xA11CE); + address currency = address(0xC0FFEE); + + harness.setEntry(account, 10 ether, currency); + harness.sumEntry(account, 5 ether, currency); + + assertEq(harness.getLedgerBalance(account, currency), 15 ether, "Sum should increase balance"); + } + + function test_SubEntry_Decrements() public { + address account = address(0xDEAD); + address currency = address(0xBADDAD); + + harness.setEntry(account, 20 ether, currency); + harness.subEntry(account, 7 ether, currency); + + assertEq(harness.getLedgerBalance(account, currency), 13 ether, "Sub should decrease balance"); + } + + function testFuzz_SetAndAdjust(uint256 amount, uint256 addAmount, uint256 subAmount) public { + amount = bound(amount, 1, type(uint96).max); + addAmount = bound(addAmount, 0, type(uint96).max - amount); + subAmount = bound(subAmount, 0, amount + addAmount); + + address account = vm.addr(111); + address currency = vm.addr(222); + + harness.setEntry(account, amount, currency); + harness.sumEntry(account, addAmount, currency); + harness.subEntry(account, subAmount, currency); + + uint256 expected = amount + addAmount - subAmount; + assertEq(harness.getLedgerBalance(account, currency), expected, "Ledger after adjustments mismatch"); + } +} + +contract LedgerUpgradeableHandler is Test { + LedgerUpgradeableHarness public immutable harness; + + struct Key { + address account; + address currency; + } + + Key[] private _keys; + mapping(bytes32 => bool) private _tracked; + mapping(bytes32 => uint256) private _expected; + + constructor(LedgerUpgradeableHarness harness_) { + harness = harness_; + } + + function setEntry(address account, address currency, uint256 amount) external { + if (account == address(0) || currency == address(0)) return; + harness.setEntry(account, amount, currency); + + bytes32 key = keccak256(abi.encode(account, currency)); + if (!_tracked[key]) { + _tracked[key] = true; + _keys.push(Key({ account: account, currency: currency })); + } + _expected[key] = amount; + } + + function sumEntry(address account, address currency, uint256 amount) external { + if (account == address(0) || currency == address(0)) return; + + bytes32 key = keccak256(abi.encode(account, currency)); + uint256 current = _tracked[key] ? _expected[key] : harness.getLedgerBalance(account, currency); + uint256 newBalance = current + amount; + + harness.sumEntry(account, amount, currency); + + if (!_tracked[key]) { + _tracked[key] = true; + _keys.push(Key({ account: account, currency: currency })); + } + _expected[key] = newBalance; + } + + function subEntry(address account, address currency, uint256 amount) external { + if (account == address(0) || currency == address(0)) return; + + bytes32 key = keccak256(abi.encode(account, currency)); + uint256 current = _tracked[key] ? _expected[key] : harness.getLedgerBalance(account, currency); + if (amount > current) return; // avoid underflow + + harness.subEntry(account, amount, currency); + + if (!_tracked[key]) { + _tracked[key] = true; + _keys.push(Key({ account: account, currency: currency })); + } + _expected[key] = current - amount; + } + + function keysLength() external view returns (uint256) { + return _keys.length; + } + + function keyAt(uint256 index) external view returns (Key memory) { + return _keys[index]; + } + + function expectedBalance(address account, address currency) external view returns (uint256) { + bytes32 key = keccak256(abi.encode(account, currency)); + return _expected[key]; + } +} + +contract LedgerUpgradeableInvariantTest is Test { + LedgerUpgradeableHarness harness; + LedgerUpgradeableHandler handler; + + function setUp() public { + harness = new LedgerUpgradeableHarness(); + harness.initialize(); + handler = new LedgerUpgradeableHandler(harness); + targetContract(address(handler)); + } + + function invariant_LedgerMatchesExpected() external view { + uint256 len = handler.keysLength(); + for (uint256 i = 0; i < len; i++) { + LedgerUpgradeableHandler.Key memory key = handler.keyAt(i); + uint256 expected = handler.expectedBalance(key.account, key.currency); + assertEq(harness.getLedgerBalance(key.account, key.currency), expected, "Ledger mismatch"); + } + } +} + diff --git a/test/primitives/LockOperatorUpgradeable.t.sol b/test/primitives/LockOperatorUpgradeable.t.sol new file mode 100644 index 0000000..ea08e4e --- /dev/null +++ b/test/primitives/LockOperatorUpgradeable.t.sol @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import "forge-std/Test.sol"; + +import { LockOperatorUpgradeable } from "contracts/core/primitives/upgradeable/LockOperatorUpgradeable.sol"; +import { ILedgerVerifiable } from "contracts/core/interfaces/base/ILedgerVerifiable.sol"; +import { ILockLocker } from "contracts/core/interfaces/base/ILockLocker.sol"; +import { ILockReleaser } from "contracts/core/interfaces/base/ILockReleaser.sol"; +import { ILockClaimer } from "contracts/core/interfaces/base/ILockClaimer.sol"; + +contract LockOperatorHarness is LockOperatorUpgradeable { + bytes32 private constant LOCK_SLOT = + 0xece3ff917f3a3127e521e0c3f2f90ff09a3c8199be32f9b40bff79e776960800; + + function initialize() external initializer { + __LockOperator_init(); + } + + function boostLedger(address account, uint256 amount, address currency) external { + _sumLedgerEntry(account, amount, currency); + } + + function lock(address account, uint256 amount, address currency) external override returns (uint256) { + return _lock(account, amount, currency); + } + + function release(address account, uint256 amount, address currency) external override returns (uint256) { + return _release(account, amount, currency); + } + + function claim(address account, uint256 amount, address currency) external override returns (uint256) { + return _claim(account, amount, currency); + } + + function lockedBalance(address account, address currency) external view returns (uint256 balance_) { + bytes32 first; + bytes32 second; + assembly { + mstore(0x00, account) + mstore(0x20, LOCK_SLOT) + first := keccak256(0x00, 0x40) + + mstore(0x00, currency) + mstore(0x20, first) + second := keccak256(0x00, 0x40) + + balance_ := sload(second) + } + } +} + +contract LockOperatorUpgradeableTest is Test { + LockOperatorHarness harness; + address internal constant TOKEN = address(0xC0FFEE); + address operator; + address alice; + address bob; + address claimer; + + function setUp() public { + harness = new LockOperatorHarness(); + harness.initialize(); + operator = vm.addr(1); + alice = vm.addr(2); + bob = vm.addr(3); + claimer = vm.addr(4); + } + + function test_Lock_ReducesLedgerAndTracksLocked() public { + uint256 amount = 50 ether; + harness.boostLedger(alice, 100 ether, TOKEN); + + vm.prank(operator); + vm.expectEmit(true, true, false, true, address(harness)); + emit ILockLocker.FundsLocked(operator, alice, amount, TOKEN); + harness.lock(alice, amount, TOKEN); + + assertEq( + ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN), + 50 ether, + "Ledger should reflect locked deduction" + ); + assertEq(harness.lockedBalance(alice, TOKEN), amount, "Locked balance mismatch"); + } + + function test_Lock_RevertWhen_InvalidParams() public { + harness.boostLedger(alice, 10 ether, TOKEN); + bytes4 err = bytes4(keccak256("InvalidOperationParameters()")); + + vm.prank(operator); + vm.expectRevert(err); + harness.lock(address(0), 1 ether, TOKEN); + + vm.prank(operator); + vm.expectRevert(err); + harness.lock(alice, 0, TOKEN); + } + + function test_Lock_RevertWhen_InsufficientLedgerBalance() public { + vm.prank(operator); + vm.expectRevert(ILockLocker.NoFundsToLock.selector); + harness.lock(alice, 1 ether, TOKEN); + } + + function test_Release_RestoresLedger() public { + harness.boostLedger(alice, 80 ether, TOKEN); + + vm.prank(operator); + harness.lock(alice, 60 ether, TOKEN); + + vm.prank(operator); + vm.expectEmit(true, true, false, true, address(harness)); + emit ILockReleaser.FundsReleased(operator, alice, 20 ether, TOKEN); + harness.release(alice, 20 ether, TOKEN); + + assertEq(harness.lockedBalance(alice, TOKEN), 40 ether, "Locked balance after release"); + assertEq( + ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN), + 40 ether, + "Ledger should regain released amount" + ); + } + + function test_Release_RevertWhen_InsufficientLocked() public { + harness.boostLedger(alice, 40 ether, TOKEN); + vm.prank(operator); + harness.lock(alice, 30 ether, TOKEN); + + vm.prank(operator); + vm.expectRevert(ILockReleaser.NoFundsToRelease.selector); + harness.release(alice, 40 ether, TOKEN); + } + + function test_Claim_MovesLockedToClaimerLedger() public { + harness.boostLedger(alice, 90 ether, TOKEN); + vm.prank(operator); + harness.lock(alice, 60 ether, TOKEN); + + vm.prank(claimer); + vm.expectEmit(true, true, false, true, address(harness)); + emit ILockClaimer.FundsClaimed(claimer, alice, 25 ether, TOKEN); + harness.claim(alice, 25 ether, TOKEN); + + assertEq(harness.lockedBalance(alice, TOKEN), 35 ether, "Locked balance after claim"); + assertEq( + ILedgerVerifiable(address(harness)).getLedgerBalance(claimer, TOKEN), + 25 ether, + "Claimer ledger should increase" + ); + } + + function test_Claim_RevertWhen_InsufficientLocked() public { + vm.prank(claimer); + vm.expectRevert(ILockClaimer.NoFundsToClaim.selector); + harness.claim(alice, 1 ether, TOKEN); + } + + function test_Integration_MultiAccountFlow() public { + harness.boostLedger(alice, 100 ether, TOKEN); + harness.boostLedger(bob, 90 ether, TOKEN); + + vm.prank(operator); + harness.lock(alice, 60 ether, TOKEN); + + vm.prank(operator); + harness.lock(bob, 45 ether, TOKEN); + + vm.prank(operator); + harness.release(alice, 20 ether, TOKEN); + + vm.prank(claimer); + harness.claim(alice, 10 ether, TOKEN); + + vm.prank(claimer); + harness.claim(bob, 15 ether, TOKEN); + + assertEq(harness.lockedBalance(alice, TOKEN), 30 ether, "Alice locked mismatch"); + assertEq(harness.lockedBalance(bob, TOKEN), 30 ether, "Bob locked mismatch"); + assertEq( + ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN), + 60 ether, + "Alice ledger mismatch" + ); + assertEq( + ILedgerVerifiable(address(harness)).getLedgerBalance(bob, TOKEN), + 45 ether, + "Bob ledger mismatch" + ); + assertEq( + ILedgerVerifiable(address(harness)).getLedgerBalance(claimer, TOKEN), + 25 ether, + "Claimer ledger aggregate mismatch" + ); + } + + function testFuzz_LockReleaseCycle(uint256 seedAmount, uint256 lockAmount, uint256 releaseAmount) public { + seedAmount = bound(seedAmount, 1 ether, 1e24); + lockAmount = bound(lockAmount, 1 ether, seedAmount); + releaseAmount = bound(releaseAmount, 0, lockAmount); + + harness.boostLedger(alice, seedAmount, TOKEN); + + vm.prank(operator); + harness.lock(alice, lockAmount, TOKEN); + + if (releaseAmount > 0) { + vm.prank(operator); + harness.release(alice, releaseAmount, TOKEN); + } + + uint256 expectedLocked = lockAmount - releaseAmount; + uint256 expectedLedger = seedAmount - lockAmount + releaseAmount; + + assertEq(harness.lockedBalance(alice, TOKEN), expectedLocked, "Fuzz locked mismatch"); + assertEq( + ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN), + expectedLedger, + "Fuzz ledger mismatch" + ); + assertEq(expectedLocked + expectedLedger, seedAmount, "Conservation after release"); + } + + function testFuzz_ClaimMaintainsConservation(uint256 seedAmount, uint256 lockAmount, uint256 claimAmount) public { + seedAmount = bound(seedAmount, 1 ether, 1e24); + lockAmount = bound(lockAmount, 1 ether, seedAmount); + claimAmount = bound(claimAmount, 1 ether, lockAmount); + + harness.boostLedger(alice, seedAmount, TOKEN); + vm.prank(operator); + harness.lock(alice, lockAmount, TOKEN); + + vm.prank(claimer); + harness.claim(alice, claimAmount, TOKEN); + + uint256 lockedLeft = lockAmount - claimAmount; + uint256 ledgerAlice = ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN); + uint256 ledgerClaimer = ILedgerVerifiable(address(harness)).getLedgerBalance(claimer, TOKEN); + + assertEq(harness.lockedBalance(alice, TOKEN), lockedLeft, "Locked left mismatch"); + assertEq(ledgerAlice + lockedLeft + ledgerClaimer, seedAmount, "Seed conservation broken"); + } +} + +contract LockOperatorHandler is Test { + LockOperatorHarness public immutable harness; + address[] internal accounts; + address internal constant TOKEN = address(0xC0FFEE); + + mapping(address => uint256) internal ledgerExpectation; + mapping(address => uint256) internal lockedExpectation; + + constructor(LockOperatorHarness operator) { + harness = operator; + for (uint256 i = 0; i < 3; i++) { + accounts.push(vm.addr(i + 10)); + } + } + + function seedLedger(uint256 index, uint256 amount) external { + vm.assume(index < accounts.length); + amount = bound(amount, 1, 1e27); + address account = accounts[index]; + harness.boostLedger(account, amount, TOKEN); + ledgerExpectation[account] += amount; + } + + function lock(uint256 index, uint256 amount) external { + vm.assume(index < accounts.length); + address account = accounts[index]; + uint256 available = ledgerExpectation[account]; + vm.assume(amount > 0 && amount <= available); + + vm.prank(account); + harness.lock(account, amount, TOKEN); + + ledgerExpectation[account] = available - amount; + lockedExpectation[account] += amount; + } + + function release(uint256 index, uint256 amount) external { + vm.assume(index < accounts.length); + address account = accounts[index]; + uint256 locked = lockedExpectation[account]; + vm.assume(amount > 0 && amount <= locked); + + vm.prank(account); + harness.release(account, amount, TOKEN); + + lockedExpectation[account] = locked - amount; + ledgerExpectation[account] += amount; + } + + function claim(uint256 lockedIdx, uint256 claimerIdx, uint256 amount) external { + vm.assume(lockedIdx < accounts.length && claimerIdx < accounts.length && lockedIdx != claimerIdx); + address account = accounts[lockedIdx]; + address claimerAccount = accounts[claimerIdx]; + uint256 locked = lockedExpectation[account]; + vm.assume(amount > 0 && amount <= locked); + + vm.prank(claimerAccount); + harness.claim(account, amount, TOKEN); + + lockedExpectation[account] = locked - amount; + ledgerExpectation[claimerAccount] += amount; + } + + function accountsLength() external view returns (uint256) { + return accounts.length; + } + + function accountAt(uint256 idx) external view returns (address) { + return accounts[idx]; + } + + function expectedLedger(address account) external view returns (uint256) { + return ledgerExpectation[account]; + } + + function expectedLocked(address account) external view returns (uint256) { + return lockedExpectation[account]; + } + + function token() external pure returns (address) { + return TOKEN; + } +} + +contract LockOperatorUpgradeableInvariantTest is Test { + LockOperatorHarness harness; + LockOperatorHandler handler; + + function setUp() public { + harness = new LockOperatorHarness(); + harness.initialize(); + handler = new LockOperatorHandler(harness); + targetContract(address(handler)); + } + + function invariant_LedgerBalancesMatchExpectation() external { + uint256 len = handler.accountsLength(); + for (uint256 i = 0; i < len; i++) { + address account = handler.accountAt(i); + assertEq( + ILedgerVerifiable(address(harness)).getLedgerBalance(account, handler.token()), + handler.expectedLedger(account), + "Ledger expectation mismatch" + ); + } + } + + function invariant_LockedBalancesMatchExpectation() external { + uint256 len = handler.accountsLength(); + for (uint256 i = 0; i < len; i++) { + address account = handler.accountAt(i); + assertEq( + harness.lockedBalance(account, handler.token()), + handler.expectedLocked(account), + "Locked expectation mismatch" + ); + } + } + + function invariant_TotalConservationHolds() external { + uint256 len = handler.accountsLength(); + uint256 expectedLedgerSum; + uint256 expectedLockedSum; + uint256 actualLedgerSum; + uint256 actualLockedSum; + address tokenAddress = handler.token(); + + for (uint256 i = 0; i < len; i++) { + address account = handler.accountAt(i); + expectedLedgerSum += handler.expectedLedger(account); + expectedLockedSum += handler.expectedLocked(account); + actualLedgerSum += ILedgerVerifiable(address(harness)).getLedgerBalance(account, tokenAddress); + actualLockedSum += harness.lockedBalance(account, tokenAddress); + } + + assertEq(actualLedgerSum, expectedLedgerSum, "Aggregated ledger mismatch"); + assertEq(actualLockedSum, expectedLockedSum, "Aggregated locked mismatch"); + assertEq(actualLedgerSum + actualLockedSum, expectedLedgerSum + expectedLockedSum, "Total conservation mismatch"); + } +} diff --git a/test/primitives/Quorum.t.sol b/test/primitives/Quorum.t.sol deleted file mode 100644 index f7527ba..0000000 --- a/test/primitives/Quorum.t.sol +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.26; - -import "forge-std/Test.sol"; -import { QuorumUpgradeable } from "contracts/core/primitives/upgradeable/QuorumUpgradeable.sol"; -import { IQuorumInspectable } from "contracts/core/interfaces/base/IQuorumInspectable.sol"; -import { IQuorumRegistrable } from "contracts/core/interfaces/base/IQuorumRegistrable.sol"; -import { IQuorumRevokable } from "contracts/core/interfaces/base/IQuorumRevokable.sol"; -import { T } from "@synaps3/core/primitives/Types.sol"; - -contract QuorumWrapper is QuorumUpgradeable { - function status(uint256 entry) external view returns (uint8) { - return uint8(_status(entry)); - } - - function revoke(uint256 entry) external { - _revoke(entry); - } - - function approve(uint256 entry) external { - _approve(entry); - } - - function quit(uint256 entry) external { - _quit(entry); - } - - function register(uint256 entry) external { - _register(entry); - } - - function reject(uint256 entry) external { - _block(entry); - } -} - -contract QuorumTest is Test { - address quorum; - - function setUp() public { - quorum = address(new QuorumWrapper()); - } - - function test_DefaultStatus() public view { - T.Status status = IQuorumInspectable(quorum).status(1234536789); - assertTrue(status == T.Status.Pending, "Default status should be Pending"); - } - - function test_RegisterStatusFlow() public { - uint256 entry = 1234567189; - // initial pending status - T.Status prevStatus = IQuorumInspectable(quorum).status(entry); - assertTrue(prevStatus == T.Status.Pending, "Initial status should be Pending"); - - // register status - IQuorumRegistrable(quorum).register(entry); - T.Status newStatus = IQuorumInspectable(quorum).status(entry); - assertTrue(newStatus == T.Status.Waiting, "Expected Waiting status after registration"); - } - - function test_ActiveStatusFlow() public { - uint256 entry = 1234526789; - // waiting status -> active status - IQuorumRegistrable(quorum).register(entry); - IQuorumRegistrable(quorum).approve(entry); - T.Status newStatus = IQuorumInspectable(quorum).status(entry); - assertTrue(newStatus == T.Status.Active, "Expected Active status after approval"); - } - - function test_QuitStatusFlow() public { - uint256 entry = 1234256789; - // waiting status -> pending status - IQuorumRegistrable(quorum).register(entry); - IQuorumRegistrable(quorum).quit(entry); - T.Status newStatus = IQuorumInspectable(quorum).status(entry); - assertTrue(newStatus == T.Status.Pending, "Expected Pending status after quitting"); - } - - function test_BlockedStatusFlow() public { - uint256 entry = 123455589; - // waiting status -> blocked - IQuorumRegistrable(quorum).register(entry); - // blocked status happens before active - IQuorumRegistrable(quorum).reject(entry); - T.Status newStatus = IQuorumInspectable(quorum).status(entry); - assertTrue(newStatus == T.Status.Blocked, "Expected Blocked status after rejection"); - } - - function test_RevokeStatusFlow() public { - uint256 entry = 123455589; - // waiting status -> active -> blocked - IQuorumRegistrable(quorum).register(entry); - IQuorumRegistrable(quorum).approve(entry); - // revoked status happens after approved - IQuorumRevokable(quorum).revoke(entry); - T.Status newStatus = IQuorumInspectable(quorum).status(entry); - assertTrue(newStatus == T.Status.Blocked, "Expected Blocked status after revocation"); - } - - function test_Approve_RevertWhen_ApproveNotRegistered() public { - uint256 entry = 123456789; - vm.expectRevert(QuorumUpgradeable.NotWaitingApproval.selector); - IQuorumRegistrable(quorum).approve(entry); - } - - function test_Register_RevertWhen_WaitingApproval() public { - uint256 entry = 123456789; - IQuorumRegistrable(quorum).register(entry); - vm.expectRevert(QuorumUpgradeable.NotPendingApproval.selector); - IQuorumRegistrable(quorum).register(entry); - } - - function test_Revoke_RevertWhen_BlockedNotActive() public { - uint256 entry = 12345677; - IQuorumRegistrable(quorum).register(entry); - vm.expectRevert(QuorumUpgradeable.InvalidInactiveState.selector); - IQuorumRevokable(quorum).revoke(entry); - } - - function test_Quit_RevertWhen_QuitNotWaiting() public { - uint256 entry = 123456459; - // blocked status - vm.expectRevert(QuorumUpgradeable.NotWaitingApproval.selector); - IQuorumRegistrable(quorum).quit(entry); - } - - function test_Quit_RevertWhen_Blocked() public { - uint256 entry = 123456789; - // waiting status - IQuorumRegistrable(quorum).register(entry); - IQuorumRegistrable(quorum).reject(entry); - vm.expectRevert(QuorumUpgradeable.NotWaitingApproval.selector); - IQuorumRegistrable(quorum).quit(entry); - } -} diff --git a/test/primitives/QuorumUpgradeable.t.sol b/test/primitives/QuorumUpgradeable.t.sol new file mode 100644 index 0000000..7b19f41 --- /dev/null +++ b/test/primitives/QuorumUpgradeable.t.sol @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import "forge-std/Test.sol"; + +import { QuorumUpgradeable } from "contracts/core/primitives/upgradeable/QuorumUpgradeable.sol"; +import { T } from "contracts/core/primitives/Types.sol"; + +contract QuorumUpgradeableHarness is QuorumUpgradeable { + function initialize() external initializer { + __Quorum_init(); + } + + function statusOf(uint256 entry) external view returns (T.Status) { + return _status(entry); + } + + function register(uint256 entry) external { + _register(entry); + } + + function approve(uint256 entry) external { + _approve(entry); + } + + function blockEntry(uint256 entry) external { + _block(entry); + } + + function quit(uint256 entry) external { + _quit(entry); + } + + function revoke(uint256 entry) external { + _revoke(entry); + } +} + +contract QuorumUpgradeableTest is Test { + QuorumUpgradeableHarness harness; + + function setUp() public { + harness = new QuorumUpgradeableHarness(); + harness.initialize(); + } + + function test_DefaultStatusIsPending() public { + assertEq(uint256(harness.statusOf(1)), uint256(T.Status.Pending), "Default should be pending"); + } + + function test_Register_FromPendingMovesToWaiting() public { + harness.register(1); + assertEq(uint256(harness.statusOf(1)), uint256(T.Status.Waiting), "Should move to waiting"); + } + + function test_Register_RevertWhen_NotPending() public { + harness.register(1); + vm.expectRevert(QuorumUpgradeable.NotPendingApproval.selector); + harness.register(1); + } + + function test_Approve_FromWaitingMovesToActive() public { + harness.register(1); + harness.approve(1); + assertEq(uint256(harness.statusOf(1)), uint256(T.Status.Active), "Should be active"); + } + + function test_Approve_RevertWhen_NotWaiting() public { + vm.expectRevert(QuorumUpgradeable.NotWaitingApproval.selector); + harness.approve(1); + } + + function test_Block_FromWaitingMovesToBlocked() public { + harness.register(1); + harness.blockEntry(1); + assertEq(uint256(harness.statusOf(1)), uint256(T.Status.Blocked), "Should be blocked"); + } + + function test_Block_RevertWhen_NotWaiting() public { + vm.expectRevert(QuorumUpgradeable.NotWaitingApproval.selector); + harness.blockEntry(1); + } + + function test_Quit_FromWaitingReturnsPending() public { + harness.register(1); + harness.quit(1); + assertEq(uint256(harness.statusOf(1)), uint256(T.Status.Pending), "Should return to pending"); + } + + function test_Quit_RevertWhen_NotWaiting() public { + vm.expectRevert(QuorumUpgradeable.NotWaitingApproval.selector); + harness.quit(1); + } + + function test_Revoke_FromActiveMovesToBlocked() public { + harness.register(1); + harness.approve(1); + harness.revoke(1); + assertEq(uint256(harness.statusOf(1)), uint256(T.Status.Blocked), "Active should move to blocked"); + } + + function test_Revoke_RevertWhen_NotActive() public { + vm.expectRevert(QuorumUpgradeable.InvalidInactiveState.selector); + harness.revoke(1); + } + + function testFuzz_RegisterApproveCycle(uint256 entry) public { + entry = bound(entry, 0, type(uint64).max); + + harness.register(entry); + assertEq(uint256(harness.statusOf(entry)), uint256(T.Status.Waiting)); + + harness.approve(entry); + assertEq(uint256(harness.statusOf(entry)), uint256(T.Status.Active)); + } + + function testFuzz_RegisterQuitKeepsPending(uint256 entry) public { + entry = bound(entry, 0, type(uint64).max); + + harness.register(entry); + harness.quit(entry); + + assertEq(uint256(harness.statusOf(entry)), uint256(T.Status.Pending)); + } +} + +contract QuorumHandler is Test { + QuorumUpgradeableHarness public immutable harness; + + struct EntryState { + bool tracked; + T.Status status; + } + + mapping(uint256 => EntryState) private _entries; + uint256[] private _trackedEntries; + + constructor(QuorumUpgradeableHarness harness_) { + harness = harness_; + } + + function register(uint256 entry) external { + entry = _normalize(entry); + if (harness.statusOf(entry) != T.Status.Pending) return; + harness.register(entry); + _update(entry, T.Status.Waiting); + } + + function approve(uint256 entry) external { + entry = _normalize(entry); + if (harness.statusOf(entry) != T.Status.Waiting) return; + harness.approve(entry); + _update(entry, T.Status.Active); + } + + function quit(uint256 entry) external { + entry = _normalize(entry); + if (harness.statusOf(entry) != T.Status.Waiting) return; + harness.quit(entry); + _update(entry, T.Status.Pending); + } + + function blockEntry(uint256 entry) external { + entry = _normalize(entry); + if (harness.statusOf(entry) != T.Status.Waiting) return; + harness.blockEntry(entry); + _update(entry, T.Status.Blocked); + } + + function revoke(uint256 entry) external { + entry = _normalize(entry); + if (harness.statusOf(entry) != T.Status.Active) return; + harness.revoke(entry); + _update(entry, T.Status.Blocked); + } + + function trackedLength() external view returns (uint256) { + return _trackedEntries.length; + } + + function trackedAt(uint256 index) external view returns (uint256) { + return _trackedEntries[index]; + } + + function expectedStatus(uint256 entry) external view returns (T.Status) { + return _entries[entry].status; + } + + function _update(uint256 entry, T.Status newStatus) private { + if (!_entries[entry].tracked) { + _entries[entry].tracked = true; + _trackedEntries.push(entry); + } + _entries[entry].status = newStatus; + } + + function _normalize(uint256 entry) private pure returns (uint256) { + return entry % 1_000; + } +} + +contract QuorumUpgradeableInvariantTest is Test { + QuorumUpgradeableHarness harness; + QuorumHandler handler; + + function setUp() public { + harness = new QuorumUpgradeableHarness(); + harness.initialize(); + handler = new QuorumHandler(harness); + targetContract(address(handler)); + } + + function invariant_StatusMatchesHandler() external view { + uint256 len = handler.trackedLength(); + for (uint256 i = 0; i < len; i++) { + uint256 entry = handler.trackedAt(i); + assertEq(uint256(harness.statusOf(entry)), uint256(handler.expectedStatus(entry)), "Status mismatch"); + } + } + + function invariant_StatusWithinEnum() external view { + uint256 len = handler.trackedLength(); + for (uint256 i = 0; i < len; i++) { + uint256 entry = handler.trackedAt(i); + T.Status status = harness.statusOf(entry); + assertTrue( + status == T.Status.Pending || + status == T.Status.Waiting || + status == T.Status.Active || + status == T.Status.Blocked, + "Invalid status value" + ); + } + } +} + diff --git a/test/rights/RightAssetCustodian.t.sol b/test/rights/RightAssetCustodian.t.sol deleted file mode 100644 index 499a234..0000000 --- a/test/rights/RightAssetCustodian.t.sol +++ /dev/null @@ -1,307 +0,0 @@ -// calc weight based on expected balance, demand and priority -// get balanced custodian with a expected proba -// - -// SPDX-License-Identifier: MIT -pragma solidity 0.8.26; -import { console } from "forge-std/console.sol"; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; -import { IRightsAssetCustodianManager } from "contracts/core/interfaces/rights/IRightsAssetCustodianManager.sol"; -import { IRightsAssetCustodianVerifiable } from "contracts/core/interfaces/rights/IRightsAssetCustodianVerifiable.sol"; -import { IRightsAssetCustodianRegistrable } from "contracts/core/interfaces/rights/IRightsAssetCustodianRegistrable.sol"; -import { ICustodianVerifiable } from "contracts/core/interfaces/custody/ICustodianVerifiable.sol"; -import { ICustodianRevokable } from "contracts/core/interfaces/custody/ICustodianRevokable.sol"; -import { IBalanceVerifiable } from "contracts/core/interfaces/base/IBalanceVerifiable.sol"; -import { RightsAssetCustodian } from "contracts/rights/RightsAssetCustodian.sol"; -import { CustodianShared } from "test/shared/CustodianShared.t.sol"; - -contract RightAssetCustodianTest is CustodianShared { - using Math for uint256; - address custodian; - - function setUp() public override { - super.setUp(); - custodian = _deployCustodian("weare.com", user); - _registerAndApproveCustodian(custodian); - deployRightsAssetCustodian(); - deployToken(); - } - - function test_SetMaxAllowedRedundancy_ValidValue() public { - vm.startPrank(admin); - uint256 newMaxRedundancy = 5; - IRightsAssetCustodianManager(rightAssetCustodian).setMaxAllowedRedundancy(newMaxRedundancy); - uint256 maxRedundancy = IRightsAssetCustodianManager(rightAssetCustodian).getMaxAllowedRedundancy(); - assertEq(maxRedundancy, newMaxRedundancy, "Max allowed redundancy should be updated"); - vm.stopPrank(); - } - - function test_SetMaxAllowedRedundancy_RevertIf_NotAuthorized() public { - vm.startPrank(user); - uint256 newMaxRedundancy = 5; - vm.expectRevert(abi.encodeWithSignature("AccessManagedUnauthorized(address)", user)); - IRightsAssetCustodianManager(rightAssetCustodian).setMaxAllowedRedundancy(newMaxRedundancy); - vm.stopPrank(); - } - - function test_GrantCustody_ValidCustodian() public { - vm.prank(user); - IRightsAssetCustodianRegistrable(rightAssetCustodian).grantCustody(custodian); - bool isCustodian = IRightsAssetCustodianVerifiable(rightAssetCustodian).isCustodian(custodian, user); - assertTrue(isCustodian, "Custodian should be registered"); - } - - function test_GrantCustody_EmitCustodialGranted() public { - vm.prank(user); - - vm.expectEmit(true, true, false, true, address(rightAssetCustodian)); - emit RightsAssetCustodian.CustodialGranted(custodian, user, 1); - IRightsAssetCustodianRegistrable(rightAssetCustodian).grantCustody(custodian); - } - - function test_GrantCustody_RevertIf_GrantDuplication() public { - vm.startPrank(user); - // registered first time - IRightsAssetCustodianRegistrable(rightAssetCustodian).grantCustody(custodian); - uint256 demand = IRightsAssetCustodianManager(rightAssetCustodian).getDemand(custodian); - assertEq(demand, 1, "Demand should be 1 after granting custody"); - - // second expected failing attempt - vm.expectRevert(abi.encodeWithSignature("GrantCustodyFailed(address,address)", custodian, user)); - IRightsAssetCustodianRegistrable(rightAssetCustodian).grantCustody(custodian); - vm.stopPrank(); - } - - function test_GrantCustody_RevertIf_ExceedAvailableRedundancy() public { - IRightsAssetCustodianRegistrable rightCustody = IRightsAssetCustodianRegistrable(rightAssetCustodian); - - for (uint256 i = 0; i < 3; i++) { - // MAX default = 3 - address custodianN = _deployCustodian(string.concat("weare", vm.toString(i), ".com"), user); - _registerAndApproveCustodian(custodianN); - - vm.prank(user); - // registered first time - rightCustody.grantCustody(custodianN); - } - - // second expected failing attempt - vm.prank(user); - vm.expectRevert(abi.encodeWithSignature("MaxRedundancyAllowedReached()")); - rightCustody.grantCustody(custodian); - vm.stopPrank(); - } - - function test_RevokeCustody_ValidRegisteredCustodian() public { - vm.startPrank(user); - IRightsAssetCustodianRegistrable(rightAssetCustodian).grantCustody(custodian); - IRightsAssetCustodianRegistrable(rightAssetCustodian).revokeCustody(custodian); - vm.stopPrank(); - - bool isCustodian = IRightsAssetCustodianVerifiable(rightAssetCustodian).isCustodian(custodian, user); - assertFalse(isCustodian, "Custodian should be revoked"); - } - - function test_RevokeCustody_EmitCustodialRevoked() public { - vm.startPrank(user); - // first grant the custody - IRightsAssetCustodianRegistrable(rightAssetCustodian).grantCustody(custodian); - - vm.expectEmit(true, true, false, true, address(rightAssetCustodian)); - emit RightsAssetCustodian.CustodialRevoked(custodian, user, 0); - IRightsAssetCustodianRegistrable(rightAssetCustodian).revokeCustody(custodian); - vm.stopPrank(); - } - - function test_RevokeCustody_RevertIf_NotRegisteredCustodian() public { - vm.startPrank(user); - // registered first time - uint256 demand = IRightsAssetCustodianManager(rightAssetCustodian).getDemand(custodian); - assertEq(demand, 0, "Demand should be 0 before granting custody"); - - // second expected failing attempt - vm.expectRevert(abi.encodeWithSignature("RevokeCustodyFailed(address,address)", custodian, user)); - IRightsAssetCustodianRegistrable(rightAssetCustodian).revokeCustody(custodian); - vm.stopPrank(); - } - - function test_SetPriority_EmitPrioritySet() public { - // second expected failing attempt - uint256 designedPriority = 2; - address custodian2 = _deployCustodian("weare1.com", user); - - vm.startPrank(user); - vm.expectEmit(true, true, false, true, address(rightAssetCustodian)); - emit RightsAssetCustodian.PrioritySet(custodian2, user, designedPriority); - IRightsAssetCustodianManager(rightAssetCustodian).setPriority(custodian2, designedPriority); - vm.stopPrank(); - } - - function test_SetPriority_ValidPriority() public { - // second expected failing attempt - uint256 designedPriority = 2; - address custodian2 = _deployCustodian("weare1.com", user); - - vm.prank(user); - IRightsAssetCustodianManager(rightAssetCustodian).setPriority(custodian2, designedPriority); - uint256 got = IRightsAssetCustodianManager(rightAssetCustodian).getPriority(custodian2, user); - assertEq(got, designedPriority, "Priority should be set correctly"); - } - - function test_SetPriority_RevertIf_ValidPriority() public { - // second expected failing attempt - address custodian2 = _deployCustodian("weare1.com", user); - vm.expectRevert(abi.encodeWithSignature("InvalidPriority(uint256)", 0)); - IRightsAssetCustodianManager(rightAssetCustodian).setPriority(custodian2, 0); - } - - function test_GetDemand_ReturnValidDemand() public { - uint256 before = IRightsAssetCustodianManager(rightAssetCustodian).getDemand(custodian); - assertEq(before, 0, "Demand should be 0 before granting custody"); - - vm.prank(user); - IRightsAssetCustodianRegistrable(rightAssetCustodian).grantCustody(custodian); - uint256 after_ = IRightsAssetCustodianManager(rightAssetCustodian).getDemand(custodian); - assertEq(after_, 1, "Demand should be 1 after granting custody"); - - vm.prank(user); - IRightsAssetCustodianRegistrable(rightAssetCustodian).revokeCustody(custodian); - uint256 revoked = IRightsAssetCustodianManager(rightAssetCustodian).getDemand(custodian); - assertEq(revoked, 0, "Demand should be 0 after revoked custody"); - } - - function test_GetWeight_ValidExpectedWeight() public { - address user1 = vm.addr(4); - IRightsAssetCustodianManager rightAssetCustodianMgr = IRightsAssetCustodianManager(rightAssetCustodian); - IRightsAssetCustodianRegistrable rightAssetCustodianReg = IRightsAssetCustodianRegistrable(rightAssetCustodian); - // expected d = 2 - vm.prank(user); // user grant custody - rightAssetCustodianReg.grantCustody(custodian); - vm.prank(user1); - rightAssetCustodianReg.grantCustody(custodian); - - // expected b = log2(10000) - vm.prank(admin); - IERC20(token).transfer(custodian, 10000); - // expected p = 2 - vm.prank(user); - rightAssetCustodianMgr.setPriority(custodian, 2); - - // calc weight for user - uint256 b = IBalanceVerifiable(custodian).getBalance(token); - uint256 p = rightAssetCustodianMgr.getPriority(custodian, user); - uint256 d = rightAssetCustodianMgr.getDemand(custodian); - uint256 expectedWeight = rightAssetCustodianMgr.getWeight(custodian, user, token); - uint256 w = p * (d + 1) * (b.log2() + 1); - - assertEq(w, 84, "Weight should match the expected formula"); - assertEq(w, expectedWeight, "Weight should match the expected formula"); - - // - } - - function test_GetCustodian_ValidGrantedCustodian() public { - address custodian2 = _deployCustodian("weare1.com", user); - address custodian3 = _deployCustodian("weare2.com", user); - - address user1 = vm.addr(4); - IRightsAssetCustodianManager rightAssetCustodianMgr = IRightsAssetCustodianManager(rightAssetCustodian); - IRightsAssetCustodianRegistrable rightAssetCustodianReg = IRightsAssetCustodianRegistrable(rightAssetCustodian); - - // simulate approval process - _registerAndApproveCustodian(custodian2); - _registerAndApproveCustodian(custodian3); - - // expected d = 2 - // higher demand for 'custodian' - vm.prank(user1); - rightAssetCustodianReg.grantCustody(custodian); - - vm.startPrank(user); - // assign custodians to user - rightAssetCustodianReg.grantCustody(custodian); - rightAssetCustodianReg.grantCustody(custodian2); - rightAssetCustodianReg.grantCustody(custodian3); - vm.stopPrank(); - - // 1- sum the weights - uint256 total = 0; - uint256[] memory weights = new uint256[](3); - address[] memory custodians = new address[](3); - custodians[0] = custodian; - custodians[1] = custodian2; - custodians[2] = custodian3; - - for (uint256 i = 0; i < custodians.length; i++) { - uint256 w = rightAssetCustodianMgr.getWeight(custodians[i], user, token); - weights[i] = w; - total += w; - } - - // simulate the internal behavior of getCustodian - // given the block A, the holder X and currency Z - vm.roll(10); // initialize in block 10 - // same block number derive deterministic in the same blockhash - // same hash + user + token derive in the same randomSeed - bytes32 blockHash = blockhash(block.number - 1); - uint256 randomSeed = uint256(keccak256(abi.encodePacked(blockHash, user, token))); - // same modulus with same randomSeed and total derive deterministic in the same randomValue - // the randomValue is in range [0, total] - uint256 randomValue = randomSeed % total; - uint256 acc = 0; - - // the same data is used to derive the custodian in deterministic way - // must match exact the same custodian during categorical selection - address selectedCustodian = rightAssetCustodianMgr.getCustodian(user, token); - // iterate through the weights and custodians to find the selected custodian - for (uint256 i = 0; i < weights.length; i++) { - uint256 weight = weights[i]; - acc += weight; - - // assert the matched in the hit range - if (randomValue < acc) { - assertEq(selectedCustodian, custodians[i], "Selected custodian should match the expected one"); - break; - } - } - } - - function test_IsCustodian_ReturnFalseIfRevokedNorExist() public { - // MAX default = 3 - address custodian2 = _deployCustodian("weare1.com", user); - IRightsAssetCustodianVerifiable rightAssetCustodianVer = IRightsAssetCustodianVerifiable(rightAssetCustodian); - IRightsAssetCustodianRegistrable rightAssetCustodianReg = IRightsAssetCustodianRegistrable(rightAssetCustodian); - - vm.prank(user); - rightAssetCustodianReg.grantCustody(custodian); - bool isCustodian = rightAssetCustodianVer.isCustodian(custodian, user); - bool isFalseCustodian = rightAssetCustodianVer.isCustodian(custodian2, user); - - vm.prank(user); - rightAssetCustodianReg.revokeCustody(custodian); - bool isRevokedCustodian = rightAssetCustodianVer.isCustodian(custodian2, user); - - assertTrue(isCustodian, "Custodian should be registered after grant"); - assertFalse(isFalseCustodian, "Custodian should not be registered"); - assertFalse(isRevokedCustodian, "Custodian should not be registered after revoke"); - } - - function test_IsCustodian_ReturnFalseIfRevokedByGovernance() public { - // MAX default = 3 - IRightsAssetCustodianVerifiable rightAssetCustodianVer = IRightsAssetCustodianVerifiable(rightAssetCustodian); - IRightsAssetCustodianRegistrable rightAssetCustodianReg = IRightsAssetCustodianRegistrable(rightAssetCustodian); - - vm.prank(user); - //custody granted - rightAssetCustodianReg.grantCustody(custodian); - bool isCustodian = rightAssetCustodianVer.isCustodian(custodian, user); - assertTrue(isCustodian, "Custodian should be registered"); - - vm.prank(nodesCouncil); - ICustodianRevokable(custodianReferendum).revoke(custodian); - bool isRevokedCustodian = rightAssetCustodianVer.isCustodian(custodian, user); - assertFalse(isRevokedCustodian, "Custodian should not be registered after revocation by governance"); - } -} diff --git a/test/shared/CustodianShared.t.sol b/test/shared/CustodianShared.t.sol deleted file mode 100644 index 0d251fc..0000000 --- a/test/shared/CustodianShared.t.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.26; - -import { BaseTest } from "test/BaseTest.t.sol"; -import { ICustodianFactory } from "contracts/core/interfaces/custody/ICustodianFactory.sol"; -import { ICustodianRegistrable } from "contracts/core/interfaces/custody/ICustodianRegistrable.sol"; -import { IAgreementManager } from "contracts/core/interfaces/financial/IAgreementManager.sol"; -import { ITollgate } from "contracts/core/interfaces/economics/ITollgate.sol"; -import { ILedgerVault } from "contracts/core/interfaces/financial/ILedgerVault.sol"; -import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; -import { T } from "contracts/core/primitives/Types.sol"; - -contract CustodianShared is BaseTest { - function setUp() public virtual initialize { - deployCustodianReferendum(); - deployCustodianFactory(); - } - - function _deployCustodian(string memory endpoint, address owner) internal returns (address) { - vm.prank(owner); - ICustodianFactory custodianFactory = ICustodianFactory(custodianFactory); - return custodianFactory.create(endpoint); - } - - function _registerAndApproveCustodian(address custodian) internal { - _registerCustodian(custodian); - vm.prank(nodesCouncil); // as governor. - ICustodianRegistrable(custodianReferendum).approve(custodian); - } - - function _registerCustodian(address custodian) internal { - ICustodianRegistrable(custodianReferendum).register(custodian); - } - -} From 257de6f8195cbdff8037906037671b0e736fb46c Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Mon, 29 Sep 2025 07:55:56 -0600 Subject: [PATCH 17/33] test: coverage upgrade --- .github/workflows/cov-badge.svg | 2 +- lcov.info | 3790 ++++++++++++++++++++----------- 2 files changed, 2427 insertions(+), 1365 deletions(-) diff --git a/.github/workflows/cov-badge.svg b/.github/workflows/cov-badge.svg index 4581b89..01d7808 100644 --- a/.github/workflows/cov-badge.svg +++ b/.github/workflows/cov-badge.svg @@ -1 +1 @@ -coveragecoverage46.72%46.72% \ No newline at end of file +coveragecoverage56.47%56.47% \ No newline at end of file diff --git a/lcov.info b/lcov.info index ec35717..8840514 100644 --- a/lcov.info +++ b/lcov.info @@ -1,14 +1,14 @@ TN: SF:contracts/access/AccessManager.sol -DA:17,75 +DA:17,91 FN:17,AccessManager.initialize -FNDA:75,AccessManager.initialize +FNDA:91,AccessManager.initialize DA:18,0 -DA:19,75 -DA:68,75 -DA:69,75 -DA:70,75 -DA:71,75 +DA:19,91 +DA:68,91 +DA:69,91 +DA:70,91 +DA:71,91 DA:76,0 FN:76,AccessManager._authorizeUpgrade FNDA:0,AccessManager._authorizeUpgrade @@ -24,133 +24,51 @@ BRF:2 BRH:0 end_of_record TN: -SF:contracts/assets/AssetOwnership.sol -DA:69,5 -FN:69,AssetOwnership.onlyApprovedAsset -FNDA:5,AssetOwnership.onlyApprovedAsset -DA:70,5 -BRDA:70,0,0,- -DA:71,0 -DA:78,0 -FN:78,AssetOwnership.onlyOwner -FNDA:0,AssetOwnership.onlyOwner -DA:79,0 -BRDA:79,1,0,- -DA:80,0 -DA:87,5 -FN:87,AssetOwnership.constructor -FNDA:5,AssetOwnership.constructor -DA:90,0 -DA:92,5 -DA:97,5 -FN:97,AssetOwnership.initialize -FNDA:5,AssetOwnership.initialize -DA:98,0 -DA:99,0 -DA:100,0 -DA:101,5 -DA:102,5 -DA:108,0 -FN:108,AssetOwnership.supportsInterface -FNDA:0,AssetOwnership.supportsInterface -DA:111,0 -DA:127,5 -FN:127,AssetOwnership.register -FNDA:5,AssetOwnership.register -DA:128,5 -DA:129,5 -DA:130,5 -DA:136,0 -FN:136,AssetOwnership.revoke -FNDA:0,AssetOwnership.revoke -DA:137,0 -DA:138,0 -DA:139,0 -DA:145,0 -FN:145,AssetOwnership.transfer -FNDA:0,AssetOwnership.transfer -DA:146,0 -DA:147,0 -DA:154,0 -FN:154,AssetOwnership.switchState -FNDA:0,AssetOwnership.switchState -DA:155,0 -DA:157,0 -DA:159,0 -DA:163,5 -FN:163,AssetOwnership._update -FNDA:5,AssetOwnership._update -DA:168,5 -DA:172,0 -FN:172,AssetOwnership._increaseBalance -FNDA:0,AssetOwnership._increaseBalance -DA:176,0 -DA:181,0 -FN:181,AssetOwnership._authorizeUpgrade -FNDA:0,AssetOwnership._authorizeUpgrade -DA:184,5 -FN:184,AssetOwnership._enableAsset -FNDA:5,AssetOwnership._enableAsset -DA:185,5 -DA:186,5 -DA:190,0 -FN:190,AssetOwnership._disableAsset -FNDA:0,AssetOwnership._disableAsset -DA:191,0 -DA:192,0 -FNF:14 -FNH:6 -LF:43 -LH:16 -BRF:2 -BRH:0 -end_of_record -TN: SF:contracts/assets/AssetReferendum.sol -DA:58,13 +DA:58,34 FN:58,AssetReferendum.constructor -FNDA:13,AssetReferendum.constructor +FNDA:34,AssetReferendum.constructor DA:59,0 -DA:63,13 +DA:63,34 FN:63,AssetReferendum.initialize -FNDA:13,AssetReferendum.initialize +FNDA:34,AssetReferendum.initialize DA:64,0 DA:65,0 -DA:66,13 -DA:72,13 +DA:66,34 +DA:72,58241 FN:72,AssetReferendum.submit -FNDA:13,AssetReferendum.submit -DA:74,13 -DA:75,13 +FNDA:58241,AssetReferendum.submit +DA:74,58241 +DA:75,58241 BRDA:75,0,0,- -DA:76,13 -DA:77,13 -DA:99,2 +DA:76,58241 +DA:77,58241 +DA:99,2123 FN:99,AssetReferendum.revoke -FNDA:2,AssetReferendum.revoke -DA:100,2 -DA:101,2 -DA:106,2 +FNDA:2123,AssetReferendum.revoke +DA:100,2123 +DA:101,2123 +DA:106,4184 FN:106,AssetReferendum.reject -FNDA:2,AssetReferendum.reject -DA:107,2 -DA:108,2 -DA:113,9 +FNDA:4184,AssetReferendum.reject +DA:107,4184 +DA:108,4184 +DA:113,49380 FN:113,AssetReferendum.approve -FNDA:9,AssetReferendum.approve -DA:114,9 -DA:115,9 -DA:121,9 +FNDA:49380,AssetReferendum.approve +DA:114,49380 +DA:115,49380 +DA:121,45629 FN:121,AssetReferendum.isApproved -FNDA:9,AssetReferendum.isApproved -DA:122,9 -DA:123,9 -DA:124,9 -DA:126,9 -DA:131,13 +FNDA:45629,AssetReferendum.isApproved +DA:122,45629 +DA:123,45629 +DA:124,45629 +DA:126,45629 +DA:131,46401 FN:131,AssetReferendum.isActive -FNDA:13,AssetReferendum.isActive -DA:132,13 +FNDA:46401,AssetReferendum.isActive +DA:132,46401 DA:138,0 FN:138,AssetReferendum._authorizeUpgrade FNDA:0,AssetReferendum._authorizeUpgrade @@ -162,44 +80,127 @@ BRF:1 BRH:0 end_of_record TN: +SF:contracts/assets/AssetRegistry.sol +DA:69,44857 +FN:69,AssetRegistry.onlyApprovedAsset +FNDA:44857,AssetRegistry.onlyApprovedAsset +DA:70,44857 +BRDA:70,0,0,1 +DA:71,1 +DA:78,8920 +FN:78,AssetRegistry.onlyOwner +FNDA:8920,AssetRegistry.onlyOwner +DA:79,8920 +BRDA:79,1,0,- +DA:80,0 +DA:87,21 +FN:87,AssetRegistry.constructor +FNDA:21,AssetRegistry.constructor +DA:90,0 +DA:92,21 +DA:97,21 +FN:97,AssetRegistry.initialize +FNDA:21,AssetRegistry.initialize +DA:98,0 +DA:99,0 +DA:100,0 +DA:101,21 +DA:102,21 +DA:108,0 +FN:108,AssetRegistry.supportsInterface +FNDA:0,AssetRegistry.supportsInterface +DA:111,0 +DA:127,44856 +FN:127,AssetRegistry.register +FNDA:44856,AssetRegistry.register +DA:128,44856 +DA:129,44855 +DA:130,44856 +DA:136,8500 +FN:136,AssetRegistry.revoke +FNDA:8500,AssetRegistry.revoke +DA:137,8500 +DA:139,8500 +DA:140,8500 +DA:141,8500 +DA:147,25783 +FN:147,AssetRegistry.transfer +FNDA:25783,AssetRegistry.transfer +DA:148,25783 +DA:149,25783 +DA:156,8920 +FN:156,AssetRegistry.switchState +FNDA:8920,AssetRegistry.switchState +DA:157,8920 +DA:159,8920 +DA:161,8920 +DA:165,79139 +FN:165,AssetRegistry._update +FNDA:79139,AssetRegistry._update +DA:170,79139 +DA:174,0 +FN:174,AssetRegistry._increaseBalance +FNDA:0,AssetRegistry._increaseBalance +DA:178,0 +DA:183,0 +FN:183,AssetRegistry._authorizeUpgrade +FNDA:0,AssetRegistry._authorizeUpgrade +DA:186,47051 +FN:186,AssetRegistry._enableAsset +FNDA:47051,AssetRegistry._enableAsset +DA:187,47051 +DA:188,47051 +DA:192,15224 +FN:192,AssetRegistry._disableAsset +FNDA:15224,AssetRegistry._disableAsset +DA:193,15224 +DA:194,15224 +FNF:14 +FNH:11 +LF:44 +LH:34 +BRF:2 +BRH:1 +end_of_record +TN: SF:contracts/assets/AssetSafe.sol -DA:40,5 +DA:40,22489 FN:40,AssetSafe.onlyHolder -FNDA:5,AssetSafe.onlyHolder -DA:41,5 -BRDA:41,0,0,1 -DA:42,1 -DA:48,5 +FNDA:22489,AssetSafe.onlyHolder +DA:41,22489 +BRDA:41,0,0,257 +DA:42,257 +DA:48,10 FN:48,AssetSafe.constructor -FNDA:5,AssetSafe.constructor +FNDA:10,AssetSafe.constructor DA:49,0 -DA:50,5 -DA:54,5 +DA:50,10 +DA:54,10 FN:54,AssetSafe.initialize -FNDA:5,AssetSafe.initialize +FNDA:10,AssetSafe.initialize DA:55,0 -DA:56,5 -DA:62,1 +DA:56,10 +DA:62,257 FN:62,AssetSafe.getType -FNDA:1,AssetSafe.getType -DA:63,1 -DA:71,2 +FNDA:257,AssetSafe.getType +DA:63,257 +DA:71,258 FN:71,AssetSafe.getContent -FNDA:2,AssetSafe.getContent -DA:72,2 -DA:80,4 +FNDA:258,AssetSafe.getContent +DA:72,258 +DA:80,22232 FN:80,AssetSafe.setContent -FNDA:4,AssetSafe.setContent -DA:81,4 -DA:82,4 -DA:83,4 +FNDA:22232,AssetSafe.setContent +DA:81,22232 +DA:82,22232 +DA:83,22232 DA:88,0 FN:88,AssetSafe._authorizeUpgrade FNDA:0,AssetSafe._authorizeUpgrade -DA:95,6 +DA:95,22490 FN:95,AssetSafe._computeComposedKey -FNDA:6,AssetSafe._computeComposedKey -DA:96,6 +FNDA:22490,AssetSafe._computeComposedKey +DA:96,22490 FNF:8 FNH:7 LF:20 @@ -226,21 +227,21 @@ BRH:0 end_of_record TN: SF:contracts/core/libraries/FeesOps.sol -DA:12,5 +DA:12,12654 FN:12,FeesOps.isBasePoint -FNDA:5,FeesOps.isBasePoint -DA:14,5 -DA:19,2 +FNDA:12654,FeesOps.isBasePoint +DA:14,12654 +DA:19,12639 FN:19,FeesOps.isNominal -FNDA:2,FeesOps.isNominal -DA:21,2 -DA:27,513 +FNDA:12639,FeesOps.isNominal +DA:21,12639 +DA:27,29688 FN:27,FeesOps.perOf -FNDA:513,FeesOps.perOf -DA:31,513 +FNDA:29688,FeesOps.perOf +DA:31,29688 BRDA:31,0,0,- BRDA:31,0,1,- -DA:32,513 +DA:32,29688 DA:37,0 FN:37,FeesOps.calcBps FNDA:0,FeesOps.calcBps @@ -254,82 +255,97 @@ BRH:0 end_of_record TN: SF:contracts/core/libraries/FinancialOps.sol -DA:24,0 +DA:24,15750 FN:24,FinancialOps._nativeTransfer -FNDA:0,FinancialOps._nativeTransfer -DA:25,0 -DA:26,0 -BRDA:26,0,0,- -DA:33,5311 -FN:33,FinancialOps._erc20Transfer -FNDA:5311,FinancialOps._erc20Transfer -DA:34,5311 -DA:41,0 -FN:41,FinancialOps._nativeDeposit -FNDA:0,FinancialOps._nativeDeposit -DA:42,0 -BRDA:42,1,0,- -DA:44,0 -DA:53,11346 -FN:53,FinancialOps._erc20Deposit -FNDA:11346,FinancialOps._erc20Deposit -DA:54,11346 -BRDA:54,2,0,1 -DA:58,11345 -DA:59,0 -DA:68,0 -FN:68,FinancialOps.increaseAllowance -FNDA:0,FinancialOps.increaseAllowance +FNDA:15750,FinancialOps._nativeTransfer +DA:27,15750 +DA:28,15750 +BRDA:28,0,0,- +DA:29,0 +DA:37,30938 +FN:37,FinancialOps._erc20Transfer +FNDA:30938,FinancialOps._erc20Transfer +DA:38,30938 +DA:45,18856 +FN:45,FinancialOps._nativeDeposit +FNDA:18856,FinancialOps._nativeDeposit +DA:46,18856 +BRDA:46,1,0,1 +DA:47,1 +DA:51,0 +DA:60,43439 +FN:60,FinancialOps._erc20Deposit +FNDA:43439,FinancialOps._erc20Deposit +DA:61,43439 +BRDA:61,2,0,2 +DA:62,2 +DA:68,43437 DA:69,0 -BRDA:69,3,0,- -DA:70,0 -DA:79,11346 -FN:79,FinancialOps.allowance -FNDA:11346,FinancialOps.allowance -DA:80,11346 -DA:81,11346 -DA:90,11346 -FN:90,FinancialOps.safeDeposit -FNDA:11346,FinancialOps.safeDeposit -DA:91,11346 -BRDA:91,5,0,- -DA:92,11346 -DA:93,11346 -DA:99,5326 -FN:99,FinancialOps.balanceOf -FNDA:5326,FinancialOps.balanceOf -DA:100,5326 -DA:101,5326 -DA:109,5311 -FN:109,FinancialOps.transfer -FNDA:5311,FinancialOps.transfer -DA:110,5311 -BRDA:110,8,0,- -DA:111,5311 -BRDA:111,9,0,- -DA:112,5311 -DA:113,5311 +DA:78,3 +FN:78,FinancialOps.increaseAllowance +FNDA:3,FinancialOps.increaseAllowance +DA:79,3 +BRDA:79,3,0,2 +DA:80,2 +DA:83,1 +DA:92,43441 +FN:92,FinancialOps.allowance +FNDA:43441,FinancialOps.allowance +DA:93,43441 +BRDA:93,4,0,1 +DA:94,1 +DA:97,43440 +DA:106,62297 +FN:106,FinancialOps.safeDeposit +FNDA:62297,FinancialOps.safeDeposit +DA:107,62297 +BRDA:107,5,0,2 +DA:108,2 +DA:111,62295 +BRDA:111,6,0,18856 +DA:112,18856 +DA:115,43439 +DA:121,46952 +FN:121,FinancialOps.balanceOf +FNDA:46952,FinancialOps.balanceOf +DA:122,46952 +BRDA:122,7,0,15752 +DA:123,15752 +DA:126,31200 +DA:134,46692 +FN:134,FinancialOps.transfer +FNDA:46692,FinancialOps.transfer +DA:135,46692 +BRDA:135,8,0,2 +DA:136,2 +DA:139,46690 +BRDA:139,9,0,2 +DA:140,2 +DA:143,46688 +BRDA:143,10,0,15750 +DA:144,15750 +DA:147,30938 FNF:9 -FNH:6 -LF:30 -LH:20 -BRF:7 -BRH:1 +FNH:9 +LF:41 +LH:38 +BRF:11 +BRH:10 end_of_record TN: SF:contracts/core/libraries/LoopOps.sol -DA:15,9 +DA:15,0 FN:15,LoopOps.uncheckedInc -FNDA:9,LoopOps.uncheckedInc -DA:17,9 +FNDA:0,LoopOps.uncheckedInc +DA:17,0 DA:26,0 FN:26,LoopOps.uncheckedDec FNDA:0,LoopOps.uncheckedDec DA:28,0 FNF:2 -FNH:1 +FNH:0 LF:4 -LH:2 +LH:0 BRF:0 BRH:0 end_of_record @@ -434,160 +450,160 @@ BRH:3 end_of_record TN: SF:contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol -DA:29,0 +DA:29,54226 FN:29,AccessControlledUpgradeable.onlyAdmin -FNDA:0,AccessControlledUpgradeable.onlyAdmin -DA:34,0 -BRDA:34,0,0,- -DA:35,0 -DA:43,0 +FNDA:54226,AccessControlledUpgradeable.onlyAdmin +DA:34,54226 +BRDA:34,0,0,258 +DA:35,258 +DA:43,8830 FN:43,AccessControlledUpgradeable.pause -FNDA:0,AccessControlledUpgradeable.pause +FNDA:8830,AccessControlledUpgradeable.pause DA:44,0 -DA:50,0 +DA:50,7834 FN:50,AccessControlledUpgradeable.unpause -FNDA:0,AccessControlledUpgradeable.unpause +FNDA:7834,AccessControlledUpgradeable.unpause DA:51,0 -DA:59,260 +DA:59,253 FN:59,AccessControlledUpgradeable.__AccessControlled_init -FNDA:260,AccessControlledUpgradeable.__AccessControlled_init -DA:60,260 -DA:61,260 -DA:67,260 +FNDA:253,AccessControlledUpgradeable.__AccessControlled_init +DA:60,253 +DA:61,253 +DA:67,253 FN:67,AccessControlledUpgradeable.__AccessControlled_init_unchained -FNDA:260,AccessControlledUpgradeable.__AccessControlled_init_unchained -DA:68,260 -BRDA:68,1,0,- -DA:69,0 -DA:72,260 -DA:73,260 -DA:80,9 +FNDA:253,AccessControlledUpgradeable.__AccessControlled_init_unchained +DA:68,253 +BRDA:68,1,0,1 +DA:69,1 +DA:72,252 +DA:73,252 +DA:80,100771 FN:80,AccessControlledUpgradeable._hasRole -FNDA:9,AccessControlledUpgradeable._hasRole -DA:81,9 -DA:82,9 -DA:83,9 -DA:84,9 -DA:88,269 +FNDA:100771,AccessControlledUpgradeable._hasRole +DA:81,100771 +DA:82,100771 +DA:83,100771 +DA:84,100771 +DA:88,101023 FN:88,AccessControlledUpgradeable._getAccessControlStorage -FNDA:269,AccessControlledUpgradeable._getAccessControlStorage +FNDA:101023,AccessControlledUpgradeable._getAccessControlStorage DA:90,0 FNF:7 -FNH:4 +FNH:7 LF:22 -LH:13 +LH:19 BRF:2 -BRH:0 +BRH:2 end_of_record TN: SF:contracts/core/primitives/upgradeable/AllowanceOperatorUpgradeable.sol -DA:32,37 +DA:32,51 FN:32,AllowanceOperatorUpgradeable.__AllowanceOperator_init -FNDA:37,AllowanceOperatorUpgradeable.__AllowanceOperator_init +FNDA:51,AllowanceOperatorUpgradeable.__AllowanceOperator_init DA:33,0 DA:39,0 FN:39,AllowanceOperatorUpgradeable.__AllowanceOperator_init_unchained FNDA:0,AllowanceOperatorUpgradeable.__AllowanceOperator_init_unchained -DA:46,0 +DA:46,899 FN:46,AllowanceOperatorUpgradeable.getApprovedAmount -FNDA:0,AllowanceOperatorUpgradeable.getApprovedAmount -DA:47,0 -DA:48,0 -DA:49,0 -DA:56,0 +FNDA:899,AllowanceOperatorUpgradeable.getApprovedAmount +DA:47,899 +DA:48,899 +DA:49,899 +DA:56,1607 FN:56,AllowanceOperatorUpgradeable._approve -FNDA:0,AllowanceOperatorUpgradeable._approve -DA:61,0 -BRDA:61,0,0,- -DA:62,0 -DA:63,0 +FNDA:1607,AllowanceOperatorUpgradeable._approve +DA:61,1607 +BRDA:61,0,0,1 +DA:62,1606 +DA:63,1606 DA:64,0 -DA:71,0 +DA:71,320 FN:71,AllowanceOperatorUpgradeable._revoke -FNDA:0,AllowanceOperatorUpgradeable._revoke -DA:76,0 -BRDA:76,1,0,- -DA:77,0 -DA:78,0 +FNDA:320,AllowanceOperatorUpgradeable._revoke +DA:76,320 +BRDA:76,1,0,1 +DA:77,319 +DA:78,319 DA:79,0 -DA:86,0 +DA:86,318 FN:86,AllowanceOperatorUpgradeable._collect -FNDA:0,AllowanceOperatorUpgradeable._collect -DA:91,0 -BRDA:91,2,0,- -DA:92,0 -BRDA:92,3,0,- -DA:94,0 -DA:95,0 -DA:96,0 -DA:97,0 +FNDA:318,AllowanceOperatorUpgradeable._collect +DA:91,318 +BRDA:91,2,0,1 +DA:92,317 +BRDA:92,3,0,1 +DA:94,316 +DA:95,316 +DA:96,316 +DA:97,316 DA:98,0 -DA:107,0 +DA:107,635 FN:107,AllowanceOperatorUpgradeable._subApprovedAmount -FNDA:0,AllowanceOperatorUpgradeable._subApprovedAmount -DA:108,0 -DA:109,0 -DA:110,0 -DA:119,0 +FNDA:635,AllowanceOperatorUpgradeable._subApprovedAmount +DA:108,635 +DA:109,635 +DA:110,635 +DA:119,1606 FN:119,AllowanceOperatorUpgradeable._sumApprovedAmount -FNDA:0,AllowanceOperatorUpgradeable._sumApprovedAmount -DA:120,0 -DA:121,0 -DA:122,0 -DA:130,0 +FNDA:1606,AllowanceOperatorUpgradeable._sumApprovedAmount +DA:120,1606 +DA:121,1606 +DA:122,1606 +DA:130,3140 FN:130,AllowanceOperatorUpgradeable._computeComposedKey -FNDA:0,AllowanceOperatorUpgradeable._computeComposedKey -DA:131,0 -DA:136,0 +FNDA:3140,AllowanceOperatorUpgradeable._computeComposedKey +DA:131,3140 +DA:136,3140 FN:136,AllowanceOperatorUpgradeable._getAllowanceOperatorStorage -FNDA:0,AllowanceOperatorUpgradeable._getAllowanceOperatorStorage +FNDA:3140,AllowanceOperatorUpgradeable._getAllowanceOperatorStorage DA:138,0 FNF:10 -FNH:1 +FNH:9 LF:37 -LH:1 +LH:31 BRF:4 -BRH:0 +BRH:4 end_of_record TN: SF:contracts/core/primitives/upgradeable/BalanceOperatorUpgradeable.sol -DA:31,74 +DA:31,61 FN:31,BalanceOperatorUpgradeable.__BalanceOperator_init -FNDA:74,BalanceOperatorUpgradeable.__BalanceOperator_init +FNDA:61,BalanceOperatorUpgradeable.__BalanceOperator_init DA:32,0 DA:37,0 FN:37,BalanceOperatorUpgradeable.__BalanceOperator_init_unchained FNDA:0,BalanceOperatorUpgradeable.__BalanceOperator_init_unchained -DA:42,3 +DA:42,260 FN:42,BalanceOperatorUpgradeable.getBalance -FNDA:3,BalanceOperatorUpgradeable.getBalance -DA:43,3 -DA:50,11346 +FNDA:260,BalanceOperatorUpgradeable.getBalance +DA:43,260 +DA:50,24731 FN:50,BalanceOperatorUpgradeable._deposit -FNDA:11346,BalanceOperatorUpgradeable._deposit -DA:55,11346 -DA:56,11345 -DA:57,11346 +FNDA:24731,BalanceOperatorUpgradeable._deposit +DA:55,24731 +DA:56,24730 +DA:57,24731 DA:58,0 -DA:65,5310 +DA:65,15368 FN:65,BalanceOperatorUpgradeable._withdraw -FNDA:5310,BalanceOperatorUpgradeable._withdraw -DA:70,5310 +FNDA:15368,BalanceOperatorUpgradeable._withdraw +DA:70,15368 BRDA:70,0,0,1 -DA:71,5309 -DA:72,5309 -DA:73,5309 +DA:71,15367 +DA:72,15367 +DA:73,15367 DA:74,0 -DA:81,287 +DA:81,7504 FN:81,BalanceOperatorUpgradeable._transfer -FNDA:287,BalanceOperatorUpgradeable._transfer -DA:86,287 +FNDA:7504,BalanceOperatorUpgradeable._transfer +DA:86,7504 BRDA:86,1,0,1 -DA:87,286 +DA:87,7503 BRDA:87,2,0,1 -DA:89,285 -DA:90,285 -DA:91,285 +DA:89,7502 +DA:90,7502 +DA:91,7502 DA:92,0 DA:97,0 FN:97,BalanceOperatorUpgradeable._getBalanceOperatorStorage @@ -602,35 +618,35 @@ BRH:3 end_of_record TN: SF:contracts/core/primitives/upgradeable/ERC721StatefulUpgradeable.sol -DA:26,5 +DA:26,21 FN:26,ERC721StatefulUpgradeable.__ERC721Stateful_init -FNDA:5,ERC721StatefulUpgradeable.__ERC721Stateful_init +FNDA:21,ERC721StatefulUpgradeable.__ERC721Stateful_init DA:31,0 FN:31,ERC721StatefulUpgradeable.__ERC721Stateful_init_unchained FNDA:0,ERC721StatefulUpgradeable.__ERC721Stateful_init_unchained -DA:35,5 +DA:35,47051 FN:35,ERC721StatefulUpgradeable._activate -FNDA:5,ERC721StatefulUpgradeable._activate -DA:36,5 -DA:37,5 -DA:42,0 +FNDA:47051,ERC721StatefulUpgradeable._activate +DA:36,47051 +DA:37,47051 +DA:42,15224 FN:42,ERC721StatefulUpgradeable._deactivate -FNDA:0,ERC721StatefulUpgradeable._deactivate -DA:43,0 -DA:44,0 -DA:50,0 +FNDA:15224,ERC721StatefulUpgradeable._deactivate +DA:43,15224 +DA:44,15224 +DA:50,9180 FN:50,ERC721StatefulUpgradeable.isActive -FNDA:0,ERC721StatefulUpgradeable.isActive -DA:51,0 -DA:52,0 -DA:56,5 +FNDA:9180,ERC721StatefulUpgradeable.isActive +DA:51,9180 +DA:52,9180 +DA:56,71455 FN:56,ERC721StatefulUpgradeable._getERC721StateStorage -FNDA:5,ERC721StatefulUpgradeable._getERC721StateStorage +FNDA:71455,ERC721StatefulUpgradeable._getERC721StateStorage DA:58,0 FNF:6 -FNH:3 +FNH:5 LF:13 -LH:5 +LH:11 BRF:0 BRH:0 end_of_record @@ -647,24 +663,24 @@ FN:49,FeesCollectorUpgradeable.getTreasuryAddress FNDA:0,FeesCollectorUpgradeable.getTreasuryAddress DA:50,0 DA:51,0 -DA:58,37 +DA:58,23 FN:58,FeesCollectorUpgradeable.__FeesCollector_init -FNDA:37,FeesCollectorUpgradeable.__FeesCollector_init -DA:59,37 -DA:66,37 +FNDA:23,FeesCollectorUpgradeable.__FeesCollector_init +DA:59,23 +DA:66,23 FN:66,FeesCollectorUpgradeable.__FeesCollector_init_unchained -FNDA:37,FeesCollectorUpgradeable.__FeesCollector_init_unchained -DA:67,37 -DA:73,37 +FNDA:23,FeesCollectorUpgradeable.__FeesCollector_init_unchained +DA:67,23 +DA:73,23 FN:73,FeesCollectorUpgradeable._setTreasuryAddress -FNDA:37,FeesCollectorUpgradeable._setTreasuryAddress -DA:74,37 +FNDA:23,FeesCollectorUpgradeable._setTreasuryAddress +DA:74,23 BRDA:74,1,0,- -DA:75,37 -DA:76,37 -DA:82,37 +DA:75,23 +DA:76,23 +DA:82,23 FN:82,FeesCollectorUpgradeable._getFeesCollectorStorage -FNDA:37,FeesCollectorUpgradeable._getFeesCollectorStorage +FNDA:23,FeesCollectorUpgradeable._getFeesCollectorStorage DA:84,0 FNF:6 FNH:4 @@ -675,40 +691,40 @@ BRH:0 end_of_record TN: SF:contracts/core/primitives/upgradeable/LedgerUpgradeable.sol -DA:28,5312 +DA:28,25694 FN:28,LedgerUpgradeable.onlyValidOperation -FNDA:5312,LedgerUpgradeable.onlyValidOperation -DA:29,5312 -BRDA:29,0,0,2 -DA:36,48332 +FNDA:25694,LedgerUpgradeable.onlyValidOperation +DA:29,25694 +BRDA:29,0,0,4 +DA:36,168827 FN:36,LedgerUpgradeable.getLedgerBalance -FNDA:48332,LedgerUpgradeable.getLedgerBalance -DA:37,48332 -DA:38,48332 -DA:45,148 +FNDA:168827,LedgerUpgradeable.getLedgerBalance +DA:37,168827 +DA:38,168827 +DA:45,168 FN:45,LedgerUpgradeable.__Ledger_init -FNDA:148,LedgerUpgradeable.__Ledger_init +FNDA:168,LedgerUpgradeable.__Ledger_init DA:50,0 FN:50,LedgerUpgradeable.__Ledger_init_unchained FNDA:0,LedgerUpgradeable.__Ledger_init_unchained -DA:57,1 +DA:57,8745 FN:57,LedgerUpgradeable._setLedgerEntry -FNDA:1,LedgerUpgradeable._setLedgerEntry -DA:58,1 -DA:59,1 -DA:67,11634 +FNDA:8745,LedgerUpgradeable._setLedgerEntry +DA:58,8745 +DA:59,8745 +DA:67,116782 FN:67,LedgerUpgradeable._sumLedgerEntry -FNDA:11634,LedgerUpgradeable._sumLedgerEntry -DA:68,11634 -DA:69,11634 -DA:77,5596 +FNDA:116782,LedgerUpgradeable._sumLedgerEntry +DA:68,116782 +DA:69,116782 +DA:77,52428 FN:77,LedgerUpgradeable._subLedgerEntry -FNDA:5596,LedgerUpgradeable._subLedgerEntry -DA:78,5596 -DA:79,5596 -DA:84,65563 +FNDA:52428,LedgerUpgradeable._subLedgerEntry +DA:78,52428 +DA:79,52428 +DA:84,346782 FN:84,LedgerUpgradeable._getLedgerStorage -FNDA:65563,LedgerUpgradeable._getLedgerStorage +FNDA:346782,LedgerUpgradeable._getLedgerStorage DA:86,0 FNF:8 FNH:7 @@ -719,124 +735,124 @@ BRH:1 end_of_record TN: SF:contracts/core/primitives/upgradeable/LockOperatorUpgradeable.sol -DA:28,37 +DA:28,51 FN:28,LockOperatorUpgradeable.__LockOperator_init -FNDA:37,LockOperatorUpgradeable.__LockOperator_init +FNDA:51,LockOperatorUpgradeable.__LockOperator_init DA:29,0 DA:35,0 FN:35,LockOperatorUpgradeable.__LockOperator_init_unchained FNDA:0,LockOperatorUpgradeable.__LockOperator_init_unchained -DA:44,0 +DA:44,28881 FN:44,LockOperatorUpgradeable._lock -FNDA:0,LockOperatorUpgradeable._lock -DA:49,0 -BRDA:49,0,0,- -DA:50,0 -DA:51,0 -DA:52,0 +FNDA:28881,LockOperatorUpgradeable._lock +DA:49,28881 +BRDA:49,0,0,2 +DA:50,28879 +DA:51,28879 +DA:52,28879 DA:53,0 -DA:60,0 +DA:60,8715 FN:60,LockOperatorUpgradeable._release -FNDA:0,LockOperatorUpgradeable._release -DA:65,0 -BRDA:65,1,0,- -DA:66,0 -DA:67,0 -DA:68,0 +FNDA:8715,LockOperatorUpgradeable._release +DA:65,8715 +BRDA:65,1,0,1 +DA:66,8714 +DA:67,8714 +DA:68,8714 DA:69,0 -DA:78,0 +DA:78,13535 FN:78,LockOperatorUpgradeable._claim -FNDA:0,LockOperatorUpgradeable._claim -DA:83,0 -BRDA:83,2,0,- -DA:84,0 -DA:85,0 -DA:86,0 +FNDA:13535,LockOperatorUpgradeable._claim +DA:83,13535 +BRDA:83,2,0,1 +DA:84,13534 +DA:85,13534 +DA:86,13534 DA:87,0 -DA:95,0 +DA:95,22248 FN:95,LockOperatorUpgradeable._subLockedAmount -FNDA:0,LockOperatorUpgradeable._subLockedAmount -DA:96,0 -DA:97,0 -DA:105,0 +FNDA:22248,LockOperatorUpgradeable._subLockedAmount +DA:96,22248 +DA:97,22248 +DA:105,28879 FN:105,LockOperatorUpgradeable._sumLockedAmount -FNDA:0,LockOperatorUpgradeable._sumLockedAmount -DA:106,0 -DA:107,0 -DA:115,0 +FNDA:28879,LockOperatorUpgradeable._sumLockedAmount +DA:106,28879 +DA:107,28879 +DA:115,22250 FN:115,LockOperatorUpgradeable._getLockedAmount -FNDA:0,LockOperatorUpgradeable._getLockedAmount -DA:116,0 -DA:117,0 -DA:122,0 +FNDA:22250,LockOperatorUpgradeable._getLockedAmount +DA:116,22250 +DA:117,22250 +DA:122,73377 FN:122,LockOperatorUpgradeable._getLockOperatorStorage -FNDA:0,LockOperatorUpgradeable._getLockOperatorStorage +FNDA:73377,LockOperatorUpgradeable._getLockOperatorStorage DA:124,0 FNF:9 -FNH:1 +FNH:8 LF:32 -LH:1 +LH:26 BRF:3 -BRH:0 +BRH:3 end_of_record TN: SF:contracts/core/primitives/upgradeable/QuorumUpgradeable.sol -DA:48,48 +DA:48,62 FN:48,QuorumUpgradeable.__Quorum_init -FNDA:48,QuorumUpgradeable.__Quorum_init +FNDA:62,QuorumUpgradeable.__Quorum_init DA:53,0 FN:53,QuorumUpgradeable.__Quorum_init_unchained FNDA:0,QuorumUpgradeable.__Quorum_init_unchained -DA:57,5531 +DA:57,222415 FN:57,QuorumUpgradeable._status -FNDA:5531,QuorumUpgradeable._status -DA:58,5531 -DA:59,5531 -DA:65,8 +FNDA:222415,QuorumUpgradeable._status +DA:58,222415 +DA:59,222415 +DA:65,2125 FN:65,QuorumUpgradeable._revoke -FNDA:8,QuorumUpgradeable._revoke -DA:66,8 -DA:67,8 +FNDA:2125,QuorumUpgradeable._revoke +DA:66,2125 +DA:67,2125 BRDA:67,0,0,1 -DA:68,7 -DA:74,4 +DA:68,2124 +DA:74,4218 FN:74,QuorumUpgradeable._block -FNDA:4,QuorumUpgradeable._block -DA:75,4 -DA:76,4 -BRDA:76,1,0,- -DA:77,4 -DA:82,2728 +FNDA:4218,QuorumUpgradeable._block +DA:75,4218 +DA:76,4218 +BRDA:76,1,0,1 +DA:77,4217 +DA:82,49687 FN:82,QuorumUpgradeable._approve -FNDA:2728,QuorumUpgradeable._approve -DA:83,2728 -DA:84,2728 +FNDA:49687,QuorumUpgradeable._approve +DA:83,49687 +DA:84,49687 BRDA:84,2,0,1 -DA:85,2727 -DA:90,3 +DA:85,49686 +DA:90,295 FN:90,QuorumUpgradeable._quit -FNDA:3,QuorumUpgradeable._quit -DA:91,3 -DA:92,3 -BRDA:92,3,0,2 -DA:93,1 -DA:98,2740 +FNDA:295,QuorumUpgradeable._quit +DA:91,295 +DA:92,295 +BRDA:92,3,0,1 +DA:93,294 +DA:98,68865 FN:98,QuorumUpgradeable._register -FNDA:2740,QuorumUpgradeable._register -DA:99,2740 -DA:100,2740 +FNDA:68865,QuorumUpgradeable._register +DA:99,68865 +DA:100,68865 BRDA:100,4,0,1 -DA:101,2739 -DA:105,11014 +DA:101,68864 +DA:105,347605 FN:105,QuorumUpgradeable._getRegistryStorage -FNDA:11014,QuorumUpgradeable._getRegistryStorage +FNDA:347605,QuorumUpgradeable._getRegistryStorage DA:107,0 FNF:9 FNH:8 LF:27 LH:25 BRF:5 -BRH:4 +BRH:5 end_of_record TN: SF:contracts/custody/CustodianFactory.sol @@ -844,159 +860,159 @@ DA:50,0 FN:50,CustodianFactory.getCreator FNDA:0,CustodianFactory.getCreator DA:51,0 -DA:58,2974 +DA:58,0 FN:58,CustodianFactory.isRegistered -FNDA:2974,CustodianFactory.isRegistered -DA:59,2974 -DA:69,3498 +FNDA:0,CustodianFactory.isRegistered +DA:59,0 +DA:69,0 FN:69,CustodianFactory.create -FNDA:3498,CustodianFactory.create -DA:70,3498 -DA:71,3498 -DA:72,3498 -DA:74,3498 +FNDA:0,CustodianFactory.create +DA:70,0 +DA:71,0 +DA:72,0 +DA:74,0 DA:75,0 -DA:81,3498 +DA:81,0 FN:81,CustodianFactory._registerEndpoint -FNDA:3498,CustodianFactory._registerEndpoint -DA:82,3498 -DA:83,3498 +FNDA:0,CustodianFactory._registerEndpoint +DA:82,0 +DA:83,0 BRDA:83,0,0,- -DA:84,3498 +DA:84,0 DA:85,0 -DA:91,3498 +DA:91,0 FN:91,CustodianFactory._deployCustodian -FNDA:3498,CustodianFactory._deployCustodian -DA:92,3498 -DA:93,3498 -DA:99,3498 +FNDA:0,CustodianFactory._deployCustodian +DA:92,0 +DA:93,0 +DA:99,0 FN:99,CustodianFactory._registerManager -FNDA:3498,CustodianFactory._registerManager -DA:100,3498 +FNDA:0,CustodianFactory._registerManager +DA:100,0 FNF:6 -FNH:5 +FNH:0 LF:20 -LH:16 +LH:0 BRF:1 BRH:0 end_of_record TN: SF:contracts/custody/CustodianImpl.sol -DA:49,3498 +DA:49,0 FN:49,CustodianImpl.initialize -FNDA:3498,CustodianImpl.initialize -DA:50,3498 +FNDA:0,CustodianImpl.initialize +DA:50,0 BRDA:50,0,0,- DA:52,0 -DA:53,3498 -DA:54,3498 -DA:59,256 +DA:53,0 +DA:54,0 +DA:59,0 FN:59,CustodianImpl.supportsInterface -FNDA:256,CustodianImpl.supportsInterface -DA:60,256 -DA:64,256 +FNDA:0,CustodianImpl.supportsInterface +DA:60,0 +DA:64,0 FN:64,CustodianImpl.getManager -FNDA:256,CustodianImpl.getManager -DA:65,256 -DA:70,257 +FNDA:0,CustodianImpl.getManager +DA:65,0 +DA:70,0 FN:70,CustodianImpl.getEndpoint -FNDA:257,CustodianImpl.getEndpoint -DA:71,257 -DA:77,2 +FNDA:0,CustodianImpl.getEndpoint +DA:71,0 +DA:77,0 FN:77,CustodianImpl.setEndpoint -FNDA:2,CustodianImpl.setEndpoint -DA:78,2 -BRDA:78,1,0,1 -DA:79,1 -DA:80,1 -DA:81,1 -DA:90,3 +FNDA:0,CustodianImpl.setEndpoint +DA:78,0 +BRDA:78,1,0,- +DA:79,0 +DA:80,0 +DA:81,0 +DA:90,0 FN:90,CustodianImpl.withdraw -FNDA:3,CustodianImpl.withdraw -DA:91,3 -BRDA:91,2,0,1 -DA:92,2 -DA:93,2 +FNDA:0,CustodianImpl.withdraw +DA:91,0 +BRDA:91,2,0,- +DA:92,0 +DA:93,0 DA:94,0 -DA:102,12 +DA:102,0 FN:102,CustodianImpl.getBalance -FNDA:12,CustodianImpl.getBalance -DA:103,12 +FNDA:0,CustodianImpl.getBalance +DA:103,0 FNF:7 -FNH:7 +FNH:0 LF:23 -LH:21 +LH:0 BRF:3 -BRH:2 +BRH:0 end_of_record TN: SF:contracts/custody/CustodianReferendum.sol -DA:50,2974 +DA:50,0 FN:50,CustodianReferendum.onlyValidCustodian -FNDA:2974,CustodianReferendum.onlyValidCustodian -DA:52,2974 -BRDA:52,0,0,256 -DA:53,256 -DA:59,35 +FNDA:0,CustodianReferendum.onlyValidCustodian +DA:52,0 +BRDA:52,0,0,- +DA:53,0 +DA:59,13 FN:59,CustodianReferendum.constructor -FNDA:35,CustodianReferendum.constructor +FNDA:13,CustodianReferendum.constructor DA:62,0 -DA:63,35 -DA:67,35 +DA:63,13 +DA:67,13 FN:67,CustodianReferendum.initialize -FNDA:35,CustodianReferendum.initialize +FNDA:13,CustodianReferendum.initialize DA:68,0 DA:69,0 -DA:70,35 -DA:76,26 +DA:70,13 +DA:76,0 FN:76,CustodianReferendum.isActive -FNDA:26,CustodianReferendum.isActive -DA:82,26 -DA:88,1 +FNDA:0,CustodianReferendum.isActive +DA:82,0 +DA:88,0 FN:88,CustodianReferendum.isWaiting -FNDA:1,CustodianReferendum.isWaiting -DA:89,1 -DA:95,1 +FNDA:0,CustodianReferendum.isWaiting +DA:89,0 +DA:95,0 FN:95,CustodianReferendum.isBlocked -FNDA:1,CustodianReferendum.isBlocked -DA:96,1 -DA:101,2718 +FNDA:0,CustodianReferendum.isBlocked +DA:96,0 +DA:101,0 FN:101,CustodianReferendum.register -FNDA:2718,CustodianReferendum.register -DA:103,2718 -DA:105,2718 -DA:110,2716 +FNDA:0,CustodianReferendum.register +DA:103,0 +DA:105,0 +DA:110,0 FN:110,CustodianReferendum.approve -FNDA:2716,CustodianReferendum.approve -DA:111,2716 -DA:112,2716 -DA:113,2716 -DA:118,4 +FNDA:0,CustodianReferendum.approve +DA:111,0 +DA:112,0 +DA:113,0 +DA:118,0 FN:118,CustodianReferendum.revoke -FNDA:4,CustodianReferendum.revoke -DA:119,4 -DA:120,4 -DA:121,4 -DA:125,257 +FNDA:0,CustodianReferendum.revoke +DA:119,0 +DA:120,0 +DA:121,0 +DA:125,0 FN:125,CustodianReferendum.getEnrollmentCount -FNDA:257,CustodianReferendum.getEnrollmentCount -DA:126,257 +FNDA:0,CustodianReferendum.getEnrollmentCount +DA:126,0 DA:132,0 FN:132,CustodianReferendum._authorizeUpgrade FNDA:0,CustodianReferendum._authorizeUpgrade FNF:11 -FNH:10 +FNH:2 LF:30 -LH:26 +LH:4 BRF:1 -BRH:1 +BRH:0 end_of_record TN: SF:contracts/economics/MMC.sol -DA:19,62 +DA:19,57 FN:19,MMC.constructor -FNDA:62,MMC.constructor -DA:23,62 +FNDA:57,MMC.constructor +DA:23,57 DA:26,0 FN:26,MMC.burn FNDA:0,MMC.burn @@ -1005,10 +1021,10 @@ DA:31,0 FN:31,MMC.nonces FNDA:0,MMC.nonces DA:32,0 -DA:36,16862 +DA:36,40174 FN:36,MMC._update -FNDA:16862,MMC._update -DA:37,16862 +FNDA:40174,MMC._update +DA:37,40174 FNF:4 FNH:2 LF:8 @@ -1018,76 +1034,76 @@ BRH:0 end_of_record TN: SF:contracts/economics/Tollgate.sol -DA:59,12 +DA:59,51366 FN:59,Tollgate.onlyValidFeeRepresentation -FNDA:12,Tollgate.onlyValidFeeRepresentation -DA:60,12 +FNDA:51366,Tollgate.onlyValidFeeRepresentation +DA:60,51366 BRDA:60,0,0,1 -DA:61,11 +DA:61,51365 BRDA:61,1,0,1 -DA:72,13 +DA:72,51367 FN:72,Tollgate.onlySupportedScheme -FNDA:13,Tollgate.onlySupportedScheme -DA:74,13 +FNDA:51367,Tollgate.onlySupportedScheme +DA:74,51367 BRDA:74,2,0,- DA:75,0 -DA:78,13 -DA:79,13 -DA:82,1 -BRDA:82,3,0,1 -DA:83,1 -DA:84,1 +DA:78,51367 +DA:79,51367 +DA:82,12417 +BRDA:82,3,0,12417 +DA:83,12417 +DA:84,12417 BRDA:84,4,0,1 -DA:92,37 +DA:92,40 FN:92,Tollgate.constructor -FNDA:37,Tollgate.constructor +FNDA:40,Tollgate.constructor DA:93,0 -DA:98,37 +DA:98,40 FN:98,Tollgate.initialize -FNDA:37,Tollgate.initialize +FNDA:40,Tollgate.initialize DA:99,0 -DA:100,37 -DA:107,257 +DA:100,40 +DA:107,46040 FN:107,Tollgate.isSupportedCurrency -FNDA:257,Tollgate.isSupportedCurrency -DA:108,257 -DA:114,1 +FNDA:46040,Tollgate.isSupportedCurrency +DA:108,46040 +DA:114,257 FN:114,Tollgate.supportedCurrencies -FNDA:1,Tollgate.supportedCurrencies -DA:115,1 -DA:122,264 +FNDA:257,Tollgate.supportedCurrencies +DA:115,257 +DA:122,23922 FN:122,Tollgate.getFees -FNDA:264,Tollgate.getFees -DA:124,264 +FNDA:23922,Tollgate.getFees +DA:124,23922 BRDA:124,5,0,1 DA:125,1 -DA:128,263 -DA:129,263 -DA:130,263 -DA:131,263 -DA:139,10 +DA:128,23921 +DA:129,23921 +DA:130,23921 +DA:131,23921 +DA:139,51364 FN:139,Tollgate.setFees -FNDA:10,Tollgate.setFees -DA:152,10 +FNDA:51364,Tollgate.setFees +DA:152,51364 BRDA:152,6,0,- -DA:153,10 -DA:155,10 -DA:156,10 -DA:157,10 -DA:158,10 +DA:153,51364 +DA:155,51364 +DA:156,51364 +DA:157,51364 +DA:158,51364 DA:163,0 FN:163,Tollgate._authorizeUpgrade FNDA:0,Tollgate._authorizeUpgrade -DA:169,521 +DA:169,69962 FN:169,Tollgate._isSchemeSupported -FNDA:521,Tollgate._isSchemeSupported -DA:170,521 -DA:171,521 -DA:172,521 -DA:180,794 +FNDA:69962,Tollgate._isSchemeSupported +DA:170,69962 +DA:171,69962 +DA:172,69962 +DA:180,145247 FN:180,Tollgate._computeComposedKey -FNDA:794,Tollgate._computeComposedKey -DA:181,794 +FNDA:145247,Tollgate._computeComposedKey +DA:181,145247 FNF:11 FNH:10 LF:41 @@ -1097,17 +1113,17 @@ BRH:5 end_of_record TN: SF:contracts/economics/Treasury.sol -DA:37,37 +DA:37,23 FN:37,Treasury.constructor -FNDA:37,Treasury.constructor +FNDA:23,Treasury.constructor DA:40,0 -DA:43,37 +DA:43,23 FN:43,Treasury.initialize -FNDA:37,Treasury.initialize +FNDA:23,Treasury.initialize DA:44,0 DA:45,0 DA:46,0 -DA:47,37 +DA:47,23 DA:65,0 FN:65,Treasury.deposit FNDA:0,Treasury.deposit @@ -1120,130 +1136,134 @@ DA:95,0 FN:95,Treasury.transfer FNDA:0,Treasury.transfer DA:100,0 -DA:109,0 -FN:109,Treasury.collectFees +DA:110,0 +FN:110,Treasury.collectFees FNDA:0,Treasury.collectFees -DA:120,0 -FN:120,Treasury._authorizeUpgrade +DA:115,0 +DA:116,0 +DA:117,0 +DA:118,0 +DA:124,0 +FN:124,Treasury._authorizeUpgrade FNDA:0,Treasury._authorizeUpgrade FNF:7 FNH:2 -LF:15 +LF:19 LH:3 BRF:0 BRH:0 end_of_record TN: SF:contracts/financial/AgreementManager.sol -DA:70,257 +DA:70,23148 FN:70,AgreementManager.onlySupportedCurrency -FNDA:257,AgreementManager.onlySupportedCurrency -DA:71,257 -DA:72,257 +FNDA:23148,AgreementManager.onlySupportedCurrency +DA:71,23148 +DA:72,23148 BRDA:72,0,0,- -DA:77,37 +DA:77,38 FN:77,AgreementManager.constructor -FNDA:37,AgreementManager.constructor +FNDA:38,AgreementManager.constructor DA:80,0 -DA:82,37 -DA:83,37 -DA:87,37 +DA:82,38 +DA:83,38 +DA:87,38 FN:87,AgreementManager.initialize -FNDA:37,AgreementManager.initialize +FNDA:38,AgreementManager.initialize DA:88,0 -DA:89,37 -DA:90,37 -DA:95,0 +DA:89,38 +DA:90,38 +DA:95,37889 FN:95,AgreementManager.setMaxParties -FNDA:0,AgreementManager.setMaxParties -DA:96,0 -BRDA:96,1,0,- -DA:97,0 -DA:101,0 +FNDA:37889,AgreementManager.setMaxParties +DA:96,37889 +BRDA:96,1,0,1 +DA:97,37888 +DA:101,75249 FN:101,AgreementManager.maxParties -FNDA:0,AgreementManager.maxParties -DA:102,0 -DA:111,0 +FNDA:75249,AgreementManager.maxParties +DA:102,75249 +DA:111,22635 FN:111,AgreementManager.createAgreement -FNDA:0,AgreementManager.createAgreement -DA:119,0 -DA:120,0 -DA:124,0 -DA:125,0 +FNDA:22635,AgreementManager.createAgreement +DA:119,22635 +DA:120,22635 +DA:124,22633 +DA:125,22633 DA:126,0 -DA:131,0 +DA:131,35860 FN:131,AgreementManager.getAgreement -FNDA:0,AgreementManager.getAgreement -DA:132,0 -DA:141,257 +FNDA:35860,AgreementManager.getAgreement +DA:132,35860 +DA:141,23148 FN:141,AgreementManager.previewAgreement -FNDA:257,AgreementManager.previewAgreement -DA:160,257 -DA:164,257 -DA:165,257 -DA:169,257 +FNDA:23148,AgreementManager.previewAgreement +DA:160,23148 +DA:164,23147 +DA:165,23147 +DA:169,23147 DA:185,0 FN:185,AgreementManager._authorizeUpgrade FNDA:0,AgreementManager._authorizeUpgrade -DA:188,0 +DA:188,22633 FN:188,AgreementManager._createAndStoreProof -FNDA:0,AgreementManager._createAndStoreProof -DA:190,0 -DA:191,0 -DA:192,0 +FNDA:22633,AgreementManager._createAndStoreProof +DA:190,22633 +DA:191,22633 +DA:192,22633 DA:193,0 -DA:197,257 +DA:197,23147 FN:197,AgreementManager._calculatePenalization -FNDA:257,AgreementManager._calculatePenalization -DA:198,257 -DA:199,256 -DA:200,256 -DA:201,256 -DA:209,256 +FNDA:23147,AgreementManager._calculatePenalization +DA:198,23147 +DA:199,6541 +DA:200,6541 +DA:201,6541 +DA:209,6541 FN:209,AgreementManager._penaltyBps -FNDA:256,AgreementManager._penaltyBps -DA:210,256 -DA:214,256 -DA:218,256 +FNDA:6541,AgreementManager._penaltyBps +DA:210,6541 +DA:214,6541 +DA:218,6541 BRDA:218,4,0,- DA:219,0 -DA:229,257 +DA:229,23148 FN:229,AgreementManager._calcFees -FNDA:257,AgreementManager._calcFees -DA:231,257 -DA:232,257 -DA:233,0 -DA:234,0 -BRDA:234,7,0,- +FNDA:23148,AgreementManager._calcFees +DA:231,23148 +DA:232,23148 +DA:233,1 +DA:234,1 +BRDA:234,7,0,1 DA:235,0 FNF:13 -FNH:7 +FNH:12 LF:51 -LH:26 +LH:44 BRF:4 -BRH:0 +BRH:2 end_of_record TN: SF:contracts/financial/AgreementSettler.sol -DA:85,0 +DA:85,6783 FN:85,AgreementSettler.onlyValidAgreement -FNDA:0,AgreementSettler.onlyValidAgreement -DA:86,0 -BRDA:86,0,0,- -DA:87,0 -DA:93,37 +FNDA:6783,AgreementSettler.onlyValidAgreement +DA:86,6783 +BRDA:86,0,0,1 +DA:87,1 +DA:93,23 FN:93,AgreementSettler.constructor -FNDA:37,AgreementSettler.constructor +FNDA:23,AgreementSettler.constructor DA:96,0 -DA:97,37 -DA:98,37 -DA:99,37 -DA:103,37 +DA:97,23 +DA:98,23 +DA:99,23 +DA:103,23 FN:103,AgreementSettler.initialize -FNDA:37,AgreementSettler.initialize +FNDA:23,AgreementSettler.initialize DA:104,0 -DA:105,37 -DA:106,37 +DA:105,23 +DA:106,23 DA:114,0 FN:114,AgreementSettler.disburse FNDA:0,AgreementSettler.disburse @@ -1252,86 +1272,86 @@ DA:117,0 DA:119,0 DA:120,0 DA:121,0 -DA:138,0 +DA:138,6782 FN:138,AgreementSettler.quitAgreement -FNDA:0,AgreementSettler.quitAgreement -DA:139,0 -DA:140,0 -BRDA:140,2,0,- -DA:154,0 -DA:155,0 -DA:156,0 -DA:164,0 -DA:165,0 -DA:166,0 -DA:168,0 -DA:170,0 -DA:172,0 -BRDA:172,3,0,- -DA:174,0 +FNDA:6782,AgreementSettler.quitAgreement +DA:139,6782 +DA:140,6782 +BRDA:140,2,0,1 +DA:154,6781 +DA:155,6781 +DA:156,6781 +DA:164,6781 +DA:165,6781 +DA:166,6781 +DA:168,6781 +DA:170,6781 +DA:172,6781 +BRDA:172,3,0,6781 +DA:174,6781 DA:175,0 -DA:201,0 +DA:201,6445 FN:201,AgreementSettler.settleAgreement -FNDA:0,AgreementSettler.settleAgreement -DA:206,0 -DA:207,0 -BRDA:207,4,0,- -DA:209,0 -DA:210,0 -DA:211,0 -DA:212,0 -DA:213,0 -DA:215,0 -DA:216,0 -DA:217,0 -DA:222,0 -DA:226,0 -DA:228,0 -BRDA:228,5,0,- -DA:229,0 +FNDA:6445,AgreementSettler.settleAgreement +DA:206,6445 +DA:207,6445 +BRDA:207,4,0,1 +DA:209,6444 +DA:210,6444 +DA:211,6444 +DA:212,6444 +DA:213,6444 +DA:215,6444 +DA:216,6444 +DA:217,6444 +DA:222,6444 +DA:226,6444 +DA:228,6444 +BRDA:228,5,0,6444 +DA:229,6444 DA:230,0 DA:236,0 FN:236,AgreementSettler._authorizeUpgrade FNDA:0,AgreementSettler._authorizeUpgrade -DA:240,0 +DA:240,13225 FN:240,AgreementSettler._setProofAsSettled -FNDA:0,AgreementSettler._setProofAsSettled -DA:241,0 +FNDA:13225,AgreementSettler._setProofAsSettled +DA:241,13225 FNF:8 -FNH:2 +FNH:6 LF:51 -LH:7 +LH:40 BRF:5 -BRH:0 +BRH:5 end_of_record TN: SF:contracts/financial/LedgerVault.sol -DA:31,37 +DA:31,38 FN:31,LedgerVault.constructor -FNDA:37,LedgerVault.constructor +FNDA:38,LedgerVault.constructor DA:34,0 -DA:37,37 +DA:37,38 FN:37,LedgerVault.initialize -FNDA:37,LedgerVault.initialize +FNDA:38,LedgerVault.initialize DA:38,0 DA:39,0 DA:40,0 DA:41,0 DA:42,0 DA:43,0 -DA:44,37 -DA:54,0 +DA:44,38 +DA:54,22634 FN:54,LedgerVault.lock -FNDA:0,LedgerVault.lock -DA:59,0 -DA:66,0 +FNDA:22634,LedgerVault.lock +DA:59,22634 +DA:66,6781 FN:66,LedgerVault.release -FNDA:0,LedgerVault.release -DA:71,0 -DA:80,0 +FNDA:6781,LedgerVault.release +DA:71,6781 +DA:80,13225 FN:80,LedgerVault.claim -FNDA:0,LedgerVault.claim -DA:85,0 +FNDA:13225,LedgerVault.claim +DA:85,13225 DA:92,0 FN:92,LedgerVault.approve FNDA:0,LedgerVault.approve @@ -1344,25 +1364,25 @@ DA:108,0 FN:108,LedgerVault.collect FNDA:0,LedgerVault.collect DA:109,0 -DA:116,2 +DA:116,25 FN:116,LedgerVault.deposit -FNDA:2,LedgerVault.deposit -DA:117,2 -DA:124,0 -FN:124,LedgerVault.withdraw +FNDA:25,LedgerVault.deposit +DA:121,25 +DA:128,0 +FN:128,LedgerVault.withdraw FNDA:0,LedgerVault.withdraw -DA:129,0 -DA:136,0 -FN:136,LedgerVault.transfer -FNDA:0,LedgerVault.transfer -DA:137,0 -DA:143,0 -FN:143,LedgerVault._authorizeUpgrade +DA:133,0 +DA:140,6444 +FN:140,LedgerVault.transfer +FNDA:6444,LedgerVault.transfer +DA:141,6444 +DA:147,0 +FN:147,LedgerVault._authorizeUpgrade FNDA:0,LedgerVault._authorizeUpgrade FNF:12 -FNH:3 +FNH:7 LF:29 -LH:5 +LH:13 BRF:0 BRH:0 end_of_record @@ -1502,44 +1522,44 @@ DA:82,0 DA:87,0 FN:87,PolicyBase.constructor FNDA:0,PolicyBase.constructor -DA:93,0 -DA:94,0 -DA:95,0 +DA:88,0 +DA:89,0 +DA:90,0 +DA:91,0 DA:96,0 -DA:101,0 -FN:101,PolicyBase.getAttestationProvider +FN:96,PolicyBase.getAttestationProvider FNDA:0,PolicyBase.getAttestationProvider -DA:102,0 -DA:108,0 -FN:108,PolicyBase.supportsInterface +DA:97,0 +DA:103,0 +FN:103,PolicyBase.supportsInterface FNDA:0,PolicyBase.supportsInterface -DA:109,0 -DA:116,0 -FN:116,PolicyBase.getLicense +DA:104,0 +DA:111,0 +FN:111,PolicyBase.getLicense FNDA:0,PolicyBase.getLicense -DA:118,0 +DA:113,0 +DA:114,0 DA:119,0 -DA:124,0 -FN:124,PolicyBase._getHolder -FNDA:0,PolicyBase._getHolder -DA:125,0 -DA:132,0 -FN:132,PolicyBase._commit +FN:119,PolicyBase._getHolder +FNDA:0,PolicyBase._getHolder +DA:120,0 +DA:127,0 +FN:127,PolicyBase._commit FNDA:0,PolicyBase._commit -DA:137,0 -DA:138,0 -DA:139,0 -DA:140,0 -DA:148,0 -FN:148,PolicyBase._setAttestation +DA:132,0 +DA:133,0 +DA:134,0 +DA:135,0 +DA:143,0 +FN:143,PolicyBase._setAttestation FNDA:0,PolicyBase._setAttestation -DA:150,0 -DA:151,0 -DA:152,0 -DA:160,0 -FN:160,PolicyBase._computeComposedKey +DA:145,0 +DA:146,0 +DA:147,0 +DA:155,0 +FN:155,PolicyBase._computeComposedKey FNDA:0,PolicyBase._computeComposedKey -DA:167,0 +DA:162,0 FNF:10 FNH:0 LF:31 @@ -1549,170 +1569,170 @@ BRH:0 end_of_record TN: SF:contracts/rights/RightsAssetCustodian.sol -DA:74,18 +DA:74,0 FN:74,RightsAssetCustodian.onlyActiveCustodian -FNDA:18,RightsAssetCustodian.onlyActiveCustodian -DA:75,18 +FNDA:0,RightsAssetCustodian.onlyActiveCustodian +DA:75,0 BRDA:75,0,0,- DA:76,0 -DA:82,19 +DA:82,0 FN:82,RightsAssetCustodian.onlyAvailableRedundancy -FNDA:19,RightsAssetCustodian.onlyAvailableRedundancy -DA:84,19 -DA:85,19 -BRDA:85,1,0,1 -DA:86,1 -DA:92,17 +FNDA:0,RightsAssetCustodian.onlyAvailableRedundancy +DA:84,0 +DA:85,0 +BRDA:85,1,0,- +DA:86,0 +DA:92,0 FN:92,RightsAssetCustodian.constructor -FNDA:17,RightsAssetCustodian.constructor +FNDA:0,RightsAssetCustodian.constructor DA:95,0 -DA:97,17 -DA:101,17 +DA:97,0 +DA:101,0 FN:101,RightsAssetCustodian.initialize -FNDA:17,RightsAssetCustodian.initialize +FNDA:0,RightsAssetCustodian.initialize DA:102,0 -DA:103,17 -DA:108,17 -DA:115,1 +DA:103,0 +DA:108,0 +DA:115,0 FN:115,RightsAssetCustodian.setMaxAllowedRedundancy -FNDA:1,RightsAssetCustodian.setMaxAllowedRedundancy -DA:116,1 -DA:120,1 +FNDA:0,RightsAssetCustodian.setMaxAllowedRedundancy +DA:116,0 +DA:120,0 FN:120,RightsAssetCustodian.getMaxAllowedRedundancy -FNDA:1,RightsAssetCustodian.getMaxAllowedRedundancy -DA:121,1 -DA:126,5 +FNDA:0,RightsAssetCustodian.getMaxAllowedRedundancy +DA:121,0 +DA:126,0 FN:126,RightsAssetCustodian.revokeCustody -FNDA:5,RightsAssetCustodian.revokeCustody -DA:128,5 -DA:129,5 -BRDA:129,2,0,1 -DA:130,4 -DA:131,4 -DA:138,18 +FNDA:0,RightsAssetCustodian.revokeCustody +DA:128,0 +DA:129,0 +BRDA:129,2,0,- +DA:130,0 +DA:131,0 +DA:138,0 FN:138,RightsAssetCustodian.grantCustody -FNDA:18,RightsAssetCustodian.grantCustody -DA:144,18 -DA:145,18 -BRDA:145,3,0,1 -DA:148,17 -DA:149,17 -DA:150,17 -DA:156,4 +FNDA:0,RightsAssetCustodian.grantCustody +DA:144,0 +DA:145,0 +BRDA:145,3,0,- +DA:148,0 +DA:149,0 +DA:150,0 +DA:156,0 FN:156,RightsAssetCustodian.setPriority -FNDA:4,RightsAssetCustodian.setPriority -DA:157,4 -DA:166,2 +FNDA:0,RightsAssetCustodian.setPriority +DA:157,0 +DA:166,0 FN:166,RightsAssetCustodian.getPriority -FNDA:2,RightsAssetCustodian.getPriority -DA:167,2 -DA:175,6 +FNDA:0,RightsAssetCustodian.getPriority +DA:167,0 +DA:175,0 FN:175,RightsAssetCustodian.getDemand -FNDA:6,RightsAssetCustodian.getDemand -DA:176,6 -DA:185,4 +FNDA:0,RightsAssetCustodian.getDemand +DA:176,0 +DA:185,0 FN:185,RightsAssetCustodian.getWeight -FNDA:4,RightsAssetCustodian.getWeight -DA:186,4 -DA:192,7 +FNDA:0,RightsAssetCustodian.getWeight +DA:186,0 +DA:192,0 FN:192,RightsAssetCustodian.isCustodian -FNDA:7,RightsAssetCustodian.isCustodian -DA:193,7 -DA:202,1 +FNDA:0,RightsAssetCustodian.isCustodian +DA:193,0 +DA:202,0 FN:202,RightsAssetCustodian.getCustodian -FNDA:1,RightsAssetCustodian.getCustodian -DA:203,1 -DA:204,1 -DA:209,1 -DA:210,1 +FNDA:0,RightsAssetCustodian.getCustodian +DA:203,0 +DA:204,0 +DA:209,0 +DA:210,0 DA:211,0 -DA:213,1 -DA:214,1 -DA:222,2 -DA:229,2 -DA:230,2 -BRDA:230,5,0,1 -DA:231,1 -DA:232,1 -DA:237,1 +DA:213,0 +DA:214,0 +DA:222,0 +DA:229,0 +DA:230,0 +BRDA:230,5,0,- +DA:231,0 +DA:232,0 +DA:237,0 DA:245,0 FN:245,RightsAssetCustodian._authorizeUpgrade FNDA:0,RightsAssetCustodian._authorizeUpgrade -DA:262,7 +DA:262,0 FN:262,RightsAssetCustodian._calcWeight -FNDA:7,RightsAssetCustodian._calcWeight -DA:263,7 -DA:264,7 -DA:265,7 -DA:270,7 -DA:280,1 +FNDA:0,RightsAssetCustodian._calcWeight +DA:263,0 +DA:264,0 +DA:265,0 +DA:270,0 +DA:280,0 FN:280,RightsAssetCustodian._calcWeights -FNDA:1,RightsAssetCustodian._calcWeights -DA:286,1 -DA:287,1 -DA:288,3 -DA:291,3 -DA:292,3 -DA:299,1 +FNDA:0,RightsAssetCustodian._calcWeights +DA:286,0 +DA:287,0 +DA:288,0 +DA:291,0 +DA:292,0 +DA:299,0 FN:299,RightsAssetCustodian._getCustodians -FNDA:1,RightsAssetCustodian._getCustodians -DA:300,1 -DA:301,1 -DA:302,1 -DA:303,1 -DA:305,1 -DA:306,3 -DA:307,3 -DA:310,3 +FNDA:0,RightsAssetCustodian._getCustodians +DA:300,0 +DA:301,0 +DA:302,0 +DA:303,0 +DA:305,0 +DA:306,0 +DA:307,0 +DA:310,0 DA:323,0 DA:326,0 -DA:332,17 +DA:332,0 FN:332,RightsAssetCustodian._incrementDemand -FNDA:17,RightsAssetCustodian._incrementDemand -DA:333,17 -DA:334,17 -DA:340,4 +FNDA:0,RightsAssetCustodian._incrementDemand +DA:333,0 +DA:334,0 +DA:340,0 FN:340,RightsAssetCustodian._decrementDemand -FNDA:4,RightsAssetCustodian._decrementDemand -DA:341,4 -BRDA:341,7,0,4 -DA:342,4 -DA:345,4 -DA:351,13 +FNDA:0,RightsAssetCustodian._decrementDemand +DA:341,0 +BRDA:341,7,0,- +DA:342,0 +DA:345,0 +DA:351,0 FN:351,RightsAssetCustodian._getDemand -FNDA:13,RightsAssetCustodian._getDemand -DA:352,13 -DA:360,21 +FNDA:0,RightsAssetCustodian._getDemand +DA:352,0 +DA:360,0 FN:360,RightsAssetCustodian._setPriority -FNDA:21,RightsAssetCustodian._setPriority -DA:361,21 -BRDA:361,8,0,1 -DA:362,20 -DA:363,20 -DA:372,9 +FNDA:0,RightsAssetCustodian._setPriority +DA:361,0 +BRDA:361,8,0,- +DA:362,0 +DA:363,0 +DA:372,0 FN:372,RightsAssetCustodian._getPriority -FNDA:9,RightsAssetCustodian._getPriority -DA:373,9 -DA:384,1 +FNDA:0,RightsAssetCustodian._getPriority +DA:373,0 +DA:384,0 FN:384,RightsAssetCustodian._calcRandomness -FNDA:1,RightsAssetCustodian._calcRandomness -DA:390,1 -DA:391,1 -DA:392,1 -DA:398,25 +FNDA:0,RightsAssetCustodian._calcRandomness +DA:390,0 +DA:391,0 +DA:392,0 +DA:398,0 FN:398,RightsAssetCustodian._isValidActiveCustodian -FNDA:25,RightsAssetCustodian._isValidActiveCustodian -DA:399,25 -DA:406,29 +FNDA:0,RightsAssetCustodian._isValidActiveCustodian +DA:399,0 +DA:406,0 FN:406,RightsAssetCustodian._computeComposedKey -FNDA:29,RightsAssetCustodian._computeComposedKey -DA:407,29 +FNDA:0,RightsAssetCustodian._computeComposedKey +DA:407,0 FNF:26 -FNH:25 +FNH:0 LF:99 -LH:92 +LH:0 BRF:7 -BRH:6 +BRH:0 end_of_record TN: SF:contracts/rights/RightsPolicyAuthorizer.sol @@ -1881,14 +1901,14 @@ BRH:0 end_of_record TN: SF:script/create3/CREATE3Factory.sol -DA:10,443 +DA:10,401 FN:10,CREATE3Factory.deploy -FNDA:443,CREATE3Factory.deploy -DA:12,443 -DA:16,950 +FNDA:401,CREATE3Factory.deploy +DA:12,401 +DA:16,830 FN:16,CREATE3Factory.getDeployed -FNDA:950,CREATE3Factory.getDeployed -DA:18,950 +FNDA:830,CREATE3Factory.getDeployed +DA:18,830 FNF:2 FNH:2 LF:4 @@ -1898,47 +1918,47 @@ BRH:0 end_of_record TN: SF:script/deployment/00_Deploy_Base.s.sol -DA:14,1393 +DA:14,1231 FN:14,DeployBase.getCreate3FactoryAddress -FNDA:1393,DeployBase.getCreate3FactoryAddress -DA:15,1393 -DA:18,518 +FNDA:1231,DeployBase.getCreate3FactoryAddress +DA:15,1231 +DA:18,492 FN:18,DeployBase.getAdminPK -FNDA:518,DeployBase.getAdminPK -DA:19,518 -DA:23,1468 +FNDA:492,DeployBase.getAdminPK +DA:19,492 +DA:23,1322 FN:23,DeployBase.getSalt -FNDA:1468,DeployBase.getSalt -DA:24,1468 -DA:27,950 +FNDA:1322,DeployBase.getSalt +DA:24,1322 +DA:27,830 FN:27,DeployBase.computeCreate3Address -FNDA:950,DeployBase.computeCreate3Address -DA:32,950 -DA:43,950 -DA:46,108 +FNDA:830,DeployBase.computeCreate3Address +DA:32,830 +DA:43,830 +DA:46,70 FN:46,DeployBase.deploy -FNDA:108,DeployBase.deploy -DA:48,108 -DA:49,108 -DA:52,335 +FNDA:70,DeployBase.deploy +DA:48,70 +DA:49,70 +DA:52,331 FN:52,DeployBase.deployUUPS -FNDA:335,DeployBase.deployUUPS -DA:58,335 -DA:62,335 -DA:63,335 -DA:65,335 -DA:85,335 -DA:89,443 +FNDA:331,DeployBase.deployUUPS +DA:58,331 +DA:62,331 +DA:63,331 +DA:65,331 +DA:85,331 +DA:89,401 FN:89,DeployBase._checkExpectedAddress -FNDA:443,DeployBase._checkExpectedAddress -DA:90,443 -DA:91,443 +FNDA:401,DeployBase._checkExpectedAddress +DA:90,401 +DA:91,401 BRDA:91,0,0,- BRDA:91,0,1,- -DA:94,518 +DA:94,492 FN:94,DeployBase._logAddress -FNDA:518,DeployBase._logAddress -DA:95,518 +FNDA:492,DeployBase._logAddress +DA:95,492 DA:96,0 DA:97,0 FNF:8 @@ -1950,18 +1970,18 @@ BRH:0 end_of_record TN: SF:script/deployment/01_Deploy_Base_Create3.s.sol -DA:8,75 +DA:8,91 FN:8,DeployCreate3Factory.run -FNDA:75,DeployCreate3Factory.run -DA:10,75 -DA:11,75 -DA:12,75 +FNDA:91,DeployCreate3Factory.run +DA:10,91 +DA:11,91 +DA:12,91 DA:15,0 DA:16,0 BRDA:16,0,0,- DA:17,0 -DA:21,75 -DA:22,75 +DA:21,91 +DA:22,91 DA:23,0 FNF:1 FNH:1 @@ -1972,18 +1992,18 @@ BRH:0 end_of_record TN: SF:script/deployment/02_Deploy_Access_AccessManager.s.sol -DA:9,75 +DA:9,91 FN:9,DeployAccessManager.run -FNDA:75,DeployAccessManager.run -DA:10,75 -DA:11,75 -DA:13,75 -DA:14,75 -DA:15,75 -DA:16,75 -DA:17,75 -DA:19,75 -DA:20,75 +FNDA:91,DeployAccessManager.run +DA:10,91 +DA:11,91 +DA:13,91 +DA:14,91 +DA:15,91 +DA:16,91 +DA:17,91 +DA:19,91 +DA:20,91 DA:21,0 FNF:1 FNH:1 @@ -1994,18 +2014,18 @@ BRH:0 end_of_record TN: SF:script/deployment/03_Deploy_Economics_Token.s.sol -DA:8,62 +DA:8,57 FN:8,DeployToken.run -FNDA:62,DeployToken.run -DA:9,62 -DA:10,62 -DA:12,62 -DA:13,62 -DA:15,62 -DA:16,62 -DA:17,62 -DA:19,62 -DA:20,62 +FNDA:57,DeployToken.run +DA:9,57 +DA:10,57 +DA:12,57 +DA:13,57 +DA:15,57 +DA:16,57 +DA:17,57 +DA:19,57 +DA:20,57 DA:21,0 FNF:1 FNH:1 @@ -2016,17 +2036,17 @@ BRH:0 end_of_record TN: SF:script/deployment/04_Deploy_Economics_Tollgate.s.sol -DA:10,37 +DA:10,40 FN:10,DeployTollgate.run -FNDA:37,DeployTollgate.run -DA:11,37 -DA:12,37 -DA:13,37 -DA:14,37 -DA:15,37 -DA:16,37 -DA:18,37 -DA:19,37 +FNDA:40,DeployTollgate.run +DA:11,40 +DA:12,40 +DA:13,40 +DA:14,40 +DA:15,40 +DA:16,40 +DA:18,40 +DA:19,40 DA:20,0 FNF:1 FNH:1 @@ -2037,17 +2057,17 @@ BRH:0 end_of_record TN: SF:script/deployment/05_Deploy_Economics_Treasury.s.sol -DA:10,37 +DA:10,23 FN:10,DeployTreasury.run -FNDA:37,DeployTreasury.run -DA:11,37 -DA:12,37 -DA:13,37 -DA:14,37 -DA:15,37 -DA:16,37 -DA:18,37 -DA:19,37 +FNDA:23,DeployTreasury.run +DA:11,23 +DA:12,23 +DA:13,23 +DA:14,23 +DA:15,23 +DA:16,23 +DA:18,23 +DA:19,23 DA:20,0 FNF:1 FNH:1 @@ -2058,17 +2078,17 @@ BRH:0 end_of_record TN: SF:script/deployment/06_Deploy_Financial_LedgerVault.s.sol -DA:8,37 +DA:8,38 FN:8,DeployLedgerVault.run -FNDA:37,DeployLedgerVault.run -DA:10,37 -DA:11,37 -DA:12,37 -DA:13,37 -DA:14,37 -DA:15,37 -DA:17,37 -DA:18,37 +FNDA:38,DeployLedgerVault.run +DA:10,38 +DA:11,38 +DA:12,38 +DA:13,38 +DA:14,38 +DA:15,38 +DA:17,38 +DA:18,38 DA:19,0 FNF:1 FNH:1 @@ -2079,19 +2099,19 @@ BRH:0 end_of_record TN: SF:script/deployment/07_Deploy_Financial_AgreementManager.s.sol -DA:8,37 +DA:8,38 FN:8,DeployAgreementManager.run -FNDA:37,DeployAgreementManager.run -DA:9,37 -DA:10,37 -DA:11,37 -DA:12,37 -DA:13,37 -DA:14,37 -DA:15,37 -DA:16,37 -DA:18,37 -DA:19,37 +FNDA:38,DeployAgreementManager.run +DA:9,38 +DA:10,38 +DA:11,38 +DA:12,38 +DA:13,38 +DA:14,38 +DA:15,38 +DA:16,38 +DA:18,38 +DA:19,38 DA:20,0 FNF:1 FNH:1 @@ -2102,20 +2122,20 @@ BRH:0 end_of_record TN: SF:script/deployment/08_Deploy_Financial_AgreementSettler.s.sol -DA:8,37 +DA:8,23 FN:8,DeployAgreementSettler.run -FNDA:37,DeployAgreementSettler.run -DA:10,37 -DA:11,37 -DA:12,37 -DA:13,37 -DA:14,37 -DA:15,37 -DA:16,37 -DA:17,37 -DA:18,37 -DA:20,37 -DA:21,37 +FNDA:23,DeployAgreementSettler.run +DA:10,23 +DA:11,23 +DA:12,23 +DA:13,23 +DA:14,23 +DA:15,23 +DA:16,23 +DA:17,23 +DA:18,23 +DA:20,23 +DA:21,23 DA:22,0 FNF:1 FNH:1 @@ -2126,17 +2146,17 @@ BRH:0 end_of_record TN: SF:script/deployment/09_Deploy_Custody_CustodianFactory.s.sol -DA:9,46 +DA:9,13 FN:9,DeployCustodianFactory.run -FNDA:46,DeployCustodianFactory.run -DA:11,46 -DA:12,46 -DA:13,46 -DA:14,46 -DA:15,46 -DA:16,46 -DA:18,46 -DA:19,46 +FNDA:13,DeployCustodianFactory.run +DA:11,13 +DA:12,13 +DA:13,13 +DA:14,13 +DA:15,13 +DA:16,13 +DA:18,13 +DA:19,13 DA:20,0 FNF:1 FNH:1 @@ -2147,18 +2167,18 @@ BRH:0 end_of_record TN: SF:script/deployment/10_Deploy_Custody_CustodianReferendum.s.sol -DA:9,35 +DA:9,13 FN:9,DeployCustodianReferendum.run -FNDA:35,DeployCustodianReferendum.run -DA:10,35 -DA:11,35 -DA:12,35 -DA:13,35 -DA:14,35 -DA:15,35 -DA:16,35 -DA:18,35 -DA:19,35 +FNDA:13,DeployCustodianReferendum.run +DA:10,13 +DA:11,13 +DA:12,13 +DA:13,13 +DA:14,13 +DA:15,13 +DA:16,13 +DA:18,13 +DA:19,13 DA:20,0 FNF:1 FNH:1 @@ -2169,17 +2189,17 @@ BRH:0 end_of_record TN: SF:script/deployment/11_Deploy_Assets_AssetReferendum.s.sol -DA:8,13 +DA:8,34 FN:8,DeployAssetReferendum.run -FNDA:13,DeployAssetReferendum.run -DA:9,13 -DA:10,13 -DA:11,13 -DA:12,13 -DA:13,13 -DA:14,13 -DA:16,13 -DA:17,13 +FNDA:34,DeployAssetReferendum.run +DA:9,34 +DA:10,34 +DA:11,34 +DA:12,34 +DA:13,34 +DA:14,34 +DA:16,34 +DA:17,34 DA:18,0 FNF:1 FNH:1 @@ -2189,19 +2209,19 @@ BRF:0 BRH:0 end_of_record TN: -SF:script/deployment/12_Deploy_Assets_AssetOwnership.s.sol -DA:8,5 -FN:8,DeployAssetOwnership.run -FNDA:5,DeployAssetOwnership.run -DA:10,5 -DA:11,5 -DA:12,5 -DA:13,5 -DA:14,5 -DA:15,5 -DA:16,5 -DA:18,5 -DA:19,5 +SF:script/deployment/12_Deploy_Assets_AssetRegistry.s.sol +DA:8,21 +FN:8,DeployAssetRegistry.run +FNDA:21,DeployAssetRegistry.run +DA:10,21 +DA:11,21 +DA:12,21 +DA:13,21 +DA:14,21 +DA:15,21 +DA:16,21 +DA:18,21 +DA:19,21 DA:20,0 FNF:1 FNH:1 @@ -2212,18 +2232,18 @@ BRH:0 end_of_record TN: SF:script/deployment/13_Deploy_Assets_AssetSafe.s.sol -DA:8,5 +DA:8,10 FN:8,DeployAssetSafe.run -FNDA:5,DeployAssetSafe.run -DA:10,5 -DA:11,5 -DA:12,5 -DA:13,5 -DA:14,5 -DA:15,5 -DA:16,5 -DA:18,5 -DA:19,5 +FNDA:10,DeployAssetSafe.run +DA:10,10 +DA:11,10 +DA:12,10 +DA:13,10 +DA:14,10 +DA:15,10 +DA:16,10 +DA:18,10 +DA:19,10 DA:20,0 FNF:1 FNH:1 @@ -2255,23 +2275,23 @@ BRH:0 end_of_record TN: SF:script/deployment/15_Deploy_RightsManager_AssetCustodian.s.sol -DA:8,17 +DA:8,0 FN:8,DeployRightsAssetCustodian.run -FNDA:17,DeployRightsAssetCustodian.run -DA:10,17 -DA:11,17 -DA:12,17 -DA:13,17 -DA:14,17 -DA:15,17 -DA:16,17 -DA:18,17 -DA:19,17 +FNDA:0,DeployRightsAssetCustodian.run +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:18,0 +DA:19,0 DA:20,0 FNF:1 -FNH:1 +FNH:0 LF:11 -LH:10 +LH:0 BRF:0 BRH:0 end_of_record @@ -2568,10 +2588,10 @@ BRF:0 BRH:0 end_of_record TN: -SF:script/upgrades/12_Upgrade_Assets_AssetOwnership.s.sol +SF:script/upgrades/12_Upgrade_Assets_AssetRegistry.s.sol DA:9,0 -FN:9,UpgradeAssetOwnership.run -FNDA:0,UpgradeAssetOwnership.run +FN:9,UpgradeAssetRegistry.run +FNDA:0,UpgradeAssetRegistry.run DA:10,0 DA:11,0 DA:12,0 @@ -2645,197 +2665,807 @@ BRH:0 end_of_record TN: SF:test/BaseTest.t.sol -DA:60,75 +DA:60,91 FN:60,BaseTest.initialize -FNDA:75,BaseTest.initialize -DA:62,75 -DA:63,75 -DA:64,75 -DA:65,75 -DA:66,75 +FNDA:91,BaseTest.initialize +DA:62,91 +DA:63,91 +DA:64,91 +DA:65,91 +DA:66,91 DA:68,0 DA:69,0 -DA:75,75 +DA:75,91 FN:75,BaseTest.deployCreate3Factory -FNDA:75,BaseTest.deployCreate3Factory -DA:77,75 -DA:78,75 -DA:80,75 -DA:81,75 -DA:82,75 -DA:86,105 +FNDA:91,BaseTest.deployCreate3Factory +DA:77,91 +DA:78,91 +DA:80,91 +DA:81,91 +DA:82,91 +DA:86,70 FN:86,BaseTest.deployToken -FNDA:105,BaseTest.deployToken -DA:88,105 -DA:89,105 -DA:93,75 +FNDA:70,BaseTest.deployToken +DA:88,70 +DA:89,70 +DA:93,91 FN:93,BaseTest.deployAccessManager -FNDA:75,BaseTest.deployAccessManager -DA:95,75 -DA:96,75 -DA:98,75 -DA:100,75 -DA:101,75 -DA:103,75 -DA:105,75 -DA:106,75 -DA:107,75 -DA:111,63 +FNDA:91,BaseTest.deployAccessManager +DA:95,91 +DA:96,91 +DA:98,91 +DA:100,91 +DA:101,91 +DA:103,91 +DA:105,91 +DA:106,91 +DA:107,91 +DA:111,53 FN:111,BaseTest.deployTollgate -FNDA:63,BaseTest.deployTollgate +FNDA:53,BaseTest.deployTollgate DA:113,0 -DA:115,63 -DA:116,63 -DA:117,63 -DA:119,37 -DA:123,108 +DA:115,53 +DA:116,53 +DA:117,53 +DA:119,40 +DA:123,61 FN:123,BaseTest.deployLedgerVault -FNDA:108,BaseTest.deployLedgerVault -DA:125,108 -DA:126,108 -DA:127,108 -DA:129,108 -DA:131,108 -DA:132,108 -DA:133,108 -DA:137,54 +FNDA:61,BaseTest.deployLedgerVault +DA:125,61 +DA:126,61 +DA:127,61 +DA:129,61 +DA:131,61 +DA:132,61 +DA:133,61 +DA:137,23 FN:137,BaseTest.deployTreasury -FNDA:54,BaseTest.deployTreasury -DA:139,54 -DA:140,54 -DA:141,54 -DA:142,37 -DA:145,54 +FNDA:23,BaseTest.deployTreasury +DA:139,23 +DA:140,23 +DA:141,23 +DA:142,23 +DA:145,38 FN:145,BaseTest.deployAgreementManager -FNDA:54,BaseTest.deployAgreementManager +FNDA:38,BaseTest.deployAgreementManager DA:146,0 -DA:147,54 -DA:149,54 -DA:150,54 -DA:152,54 -DA:155,54 +DA:147,38 +DA:149,38 +DA:150,38 +DA:152,38 +DA:155,23 FN:155,BaseTest.deployAgreementSettler -FNDA:54,BaseTest.deployAgreementSettler +FNDA:23,BaseTest.deployAgreementSettler DA:156,0 -DA:157,54 +DA:157,23 DA:158,0 -DA:160,54 -DA:161,54 -DA:163,54 -DA:167,13 +DA:160,23 +DA:161,23 +DA:163,23 +DA:167,34 FN:167,BaseTest.deployAssetReferendum -FNDA:13,BaseTest.deployAssetReferendum -DA:169,13 -DA:170,13 -DA:171,13 -DA:172,13 -DA:175,5 -FN:175,BaseTest.deployAssetOwnership -FNDA:5,BaseTest.deployAssetOwnership +FNDA:34,BaseTest.deployAssetReferendum +DA:169,34 +DA:170,34 +DA:171,34 +DA:172,34 +DA:175,21 +FN:175,BaseTest.deployAssetRegistry +FNDA:21,BaseTest.deployAssetRegistry DA:176,0 -DA:178,5 -DA:179,5 -DA:182,5 +DA:178,21 +DA:179,21 +DA:182,10 FN:182,BaseTest.deployAssetSafe -FNDA:5,BaseTest.deployAssetSafe +FNDA:10,BaseTest.deployAssetSafe DA:183,0 -DA:184,5 -DA:185,5 -DA:189,89 +DA:184,10 +DA:185,10 +DA:189,13 FN:189,BaseTest.deployCustodianFactory -FNDA:89,BaseTest.deployCustodianFactory -DA:190,89 -DA:191,89 -DA:194,52 +FNDA:13,BaseTest.deployCustodianFactory +DA:190,13 +DA:191,13 +DA:194,13 FN:194,BaseTest.deployCustodianReferendum -FNDA:52,BaseTest.deployCustodianReferendum +FNDA:13,BaseTest.deployCustodianReferendum DA:195,0 DA:196,0 -DA:199,52 -DA:200,52 -DA:201,52 -DA:203,35 -DA:207,17 +DA:199,13 +DA:200,13 +DA:201,13 +DA:203,13 +DA:207,0 FN:207,BaseTest.deployRightsAssetCustodian -FNDA:17,BaseTest.deployRightsAssetCustodian +FNDA:0,BaseTest.deployRightsAssetCustodian DA:208,0 -DA:210,17 -DA:211,17 -DA:214,13 +DA:210,0 +DA:211,0 +DA:214,34 FN:214,BaseTest._setContentCouncilPermissions -FNDA:13,BaseTest._setContentCouncilPermissions -DA:215,13 -DA:216,13 -DA:218,13 -DA:219,13 -DA:222,52 +FNDA:34,BaseTest._setContentCouncilPermissions +DA:215,34 +DA:216,34 +DA:218,34 +DA:219,34 +DA:222,13 FN:222,BaseTest._setNodesCouncilPermissions -FNDA:52,BaseTest._setNodesCouncilPermissions -DA:223,52 -DA:224,52 -DA:226,52 -DA:227,52 -DA:230,117 +FNDA:13,BaseTest._setNodesCouncilPermissions +DA:223,13 +DA:224,13 +DA:226,13 +DA:227,13 +DA:230,76 FN:230,BaseTest._setGovPermissions -FNDA:117,BaseTest._setGovPermissions -DA:231,117 -DA:232,117 -DA:234,117 -DA:235,117 -DA:238,108 +FNDA:76,BaseTest._setGovPermissions +DA:231,76 +DA:232,76 +DA:234,76 +DA:235,76 +DA:238,61 FN:238,BaseTest._assignOpRole -FNDA:108,BaseTest._assignOpRole -DA:239,108 -DA:240,108 -DA:241,108 -DA:242,108 +FNDA:61,BaseTest._assignOpRole +DA:239,61 +DA:240,61 +DA:241,61 +DA:242,61 FNF:19 -FNH:19 +FNH:18 LF:106 -LH:95 +LH:92 BRF:0 BRH:0 end_of_record TN: -SF:test/assets/AssetOwnership.sol -DA:16,0 -FN:16,AssetOwnershipTest.setUp -FNDA:0,AssetOwnershipTest.setUp -DA:18,0 -FNF:1 -FNH:0 -LF:2 -LH:0 +SF:test/assets/AssetReferendum.t.sol +DA:34,2 +FN:34,AssetReferendumHandler.constructor +FNDA:2,AssetReferendumHandler.constructor +DA:35,2 +DA:36,2 +DA:38,2 +DA:39,12 +DA:43,12648 +FN:43,AssetReferendumHandler.submit +FNDA:12648,AssetReferendumHandler.submit +DA:44,12648 +DA:46,12648 +DA:47,12648 +DA:48,12648 +DA:50,12610 +DA:52,12610 +DA:53,12610 +DA:55,12610 +DA:56,12610 +DA:57,12610 +DA:60,12509 +FN:60,AssetReferendumHandler.approve +FNDA:12509,AssetReferendumHandler.approve +DA:61,12509 +DA:63,10604 +DA:64,10604 +DA:65,10604 +DA:67,4009 +DA:68,4009 +DA:70,4009 +DA:73,12461 +FN:73,AssetReferendumHandler.reject +FNDA:12461,AssetReferendumHandler.reject +DA:74,12461 +DA:76,10572 +DA:77,10572 +DA:78,10572 +DA:80,3926 +DA:81,3926 +DA:83,3926 +DA:86,12432 +FN:86,AssetReferendumHandler.revoke +FNDA:12432,AssetReferendumHandler.revoke +DA:87,12432 +DA:89,10484 +DA:90,10484 +DA:91,10484 +DA:93,1865 +DA:94,1865 +DA:96,1865 +DA:99,0 +FN:99,AssetReferendumHandler.trackedLength +FNDA:0,AssetReferendumHandler.trackedLength +DA:100,0 +DA:103,0 +FN:103,AssetReferendumHandler.trackedAt +FNDA:0,AssetReferendumHandler.trackedAt +DA:104,0 +DA:107,0 +FN:107,AssetReferendumHandler.stateOf +FNDA:0,AssetReferendumHandler.stateOf +DA:108,0 +FNF:8 +FNH:5 +LF:46 +LH:40 BRF:0 BRH:0 end_of_record TN: -SF:test/economics/Tollgate.t.sol -DA:19,1 -FN:19,TargetD.isFeeSchemeSupported -FNDA:1,TargetD.isFeeSchemeSupported -DA:21,1 -FNF:1 -FNH:1 -LF:2 -LH:2 +SF:test/assets/AssetRegistry.t.sol +DA:29,3 +FN:29,AssetRegistryHandler.constructor +FNDA:3,AssetRegistryHandler.constructor +DA:30,3 +DA:31,3 +DA:32,3 +DA:33,3 +DA:35,3 +DA:36,3 +DA:37,15 +DA:41,19036 +FN:41,AssetRegistryHandler.register +FNDA:19036,AssetRegistryHandler.register +DA:42,19036 +DA:44,19036 +DA:45,19036 +DA:48,18992 +DA:50,18992 +DA:51,18992 +DA:53,18992 +DA:54,18992 +DA:56,18992 +DA:57,18992 +DA:59,18992 +DA:60,18992 +DA:61,18992 +DA:62,18992 +DA:63,18992 +DA:66,18770 +FN:66,AssetRegistryHandler.transfer +FNDA:18770,AssetRegistryHandler.transfer +DA:67,18770 +DA:69,15880 +DA:70,15880 +DA:71,15880 +DA:73,8839 +DA:74,8839 +DA:76,7380 +DA:77,7380 +DA:79,7380 +DA:82,18815 +FN:82,AssetRegistryHandler.switchState +FNDA:18815,AssetRegistryHandler.switchState +DA:83,18815 +DA:85,15889 +DA:86,15889 +DA:87,15889 +DA:89,8918 +DA:90,8918 +DA:91,8918 +DA:94,18454 +FN:94,AssetRegistryHandler.revoke +FNDA:18454,AssetRegistryHandler.revoke +DA:95,18454 +DA:97,15555 +DA:98,15555 +DA:99,15555 +DA:101,8499 +DA:102,8499 +DA:104,8499 +DA:105,8499 +DA:106,8499 +DA:109,0 +FN:109,AssetRegistryHandler.assetIdsLength +FNDA:0,AssetRegistryHandler.assetIdsLength +DA:110,0 +DA:113,0 +FN:113,AssetRegistryHandler.assetIdAt +FNDA:0,AssetRegistryHandler.assetIdAt +DA:114,0 +DA:117,0 +FN:117,AssetRegistryHandler.getAssetInfo +FNDA:0,AssetRegistryHandler.getAssetInfo +DA:118,0 +FNF:8 +FNH:5 +LF:58 +LH:52 BRF:0 BRH:0 end_of_record TN: -SF:test/finance/TrustlessEscrow.sol -DA:18,0 -FN:18,MockArbiter.constructor -FNDA:0,MockArbiter.constructor -DA:19,0 -DA:22,0 -FN:22,MockArbiter.executeAgreement -FNDA:0,MockArbiter.executeAgreement -DA:23,0 -FNF:2 -FNH:0 -LF:4 -LH:0 +SF:test/assets/AssetSafe.t.sol +DA:29,3 +FN:29,AssetSafeHandler.constructor +FNDA:3,AssetSafeHandler.constructor +DA:30,3 +DA:31,3 +DA:32,3 +DA:33,3 +DA:35,3 +DA:36,18 +DA:40,25187 +FN:40,AssetSafeHandler.registerAsset +FNDA:25187,AssetSafeHandler.registerAsset +DA:41,25187 +DA:43,25187 +DA:46,25084 +DA:47,25084 +DA:49,25084 +DA:50,25084 +DA:52,25084 +DA:53,25084 +DA:55,25084 +DA:56,25084 +DA:58,25084 +DA:59,25084 +DA:60,25084 +DA:63,25042 +FN:63,AssetSafeHandler.transferAsset +FNDA:25042,AssetSafeHandler.transferAsset +DA:64,25042 +DA:66,22046 +DA:67,22046 +DA:69,22046 +DA:70,22046 +DA:72,22046 +DA:73,22046 +DA:75,18402 +DA:76,18402 +DA:78,18402 +DA:81,24846 +FN:81,AssetSafeHandler.setContent +FNDA:24846,AssetSafeHandler.setContent +DA:82,24846 +DA:84,21972 +DA:85,21972 +DA:87,21972 +DA:88,21972 +DA:90,21972 +DA:91,21972 +DA:92,21972 +DA:94,21972 +DA:95,21972 +DA:97,21972 +DA:98,21972 +DA:99,21972 +DA:100,21972 +DA:103,0 +FN:103,AssetSafeHandler.trackedLength +FNDA:0,AssetSafeHandler.trackedLength +DA:104,0 +DA:107,0 +FN:107,AssetSafeHandler.trackedAt +FNDA:0,AssetSafeHandler.trackedAt +DA:108,0 +DA:111,0 +FN:111,AssetSafeHandler.ownerOf +FNDA:0,AssetSafeHandler.ownerOf +DA:112,0 +DA:115,0 +FN:115,AssetSafeHandler.isTracked +FNDA:0,AssetSafeHandler.isTracked +DA:116,0 +DA:119,0 +FN:119,AssetSafeHandler.hasContent +FNDA:0,AssetSafeHandler.hasContent +DA:120,0 +DA:123,0 +FN:123,AssetSafeHandler.contentOf +FNDA:0,AssetSafeHandler.contentOf +DA:124,0 +DA:127,0 +FN:127,AssetSafeHandler.hasLatestCipher +FNDA:0,AssetSafeHandler.hasLatestCipher +DA:128,0 +DA:131,0 +FN:131,AssetSafeHandler.latestCipher +FNDA:0,AssetSafeHandler.latestCipher +DA:132,0 +FNF:12 +FNH:4 +LF:63 +LH:47 +BRF:0 +BRH:0 +end_of_record +TN: +SF:test/economics/Tollgate.t.sol +DA:20,12417 +FN:20,TargetD.isFeeSchemeSupported +FNDA:12417,TargetD.isFeeSchemeSupported +DA:22,12417 +DA:42,2 +FN:42,TollgateHandler.constructor +FNDA:2,TollgateHandler.constructor +DA:43,2 +DA:44,2 +DA:46,2 +DA:47,2 +DA:48,2 +DA:49,2 +DA:51,2 +DA:52,2 +DA:53,2 +DA:54,2 +DA:56,2 +DA:57,2 +DA:58,2 +DA:61,50050 +FN:61,TollgateHandler.setFees +FNDA:50050,TollgateHandler.setFees +DA:62,50050 +DA:63,50050 +DA:64,50050 +DA:65,50050 +DA:67,50050 +DA:68,50050 +BRDA:68,1,0,25299 +BRDA:68,1,1,12370 +DA:69,25299 +DA:70,24751 +BRDA:70,2,0,12381 +BRDA:70,2,1,12370 +DA:71,12381 +DA:73,12370 +DA:76,50050 +DA:77,50050 +DA:79,50050 +DA:80,50050 +DA:81,50050 +DA:83,50050 +BRDA:83,3,0,21293 +DA:84,21293 +DA:85,21293 +DA:89,0 +FN:89,TollgateHandler.targetsLength +FNDA:0,TollgateHandler.targetsLength +DA:90,0 +DA:93,0 +FN:93,TollgateHandler.targetAt +FNDA:0,TollgateHandler.targetAt +DA:94,0 +DA:97,0 +FN:97,TollgateHandler.schemeOf +FNDA:0,TollgateHandler.schemeOf +DA:98,0 +DA:101,0 +FN:101,TollgateHandler.currenciesFor +FNDA:0,TollgateHandler.currenciesFor +DA:102,0 +DA:105,0 +FN:105,TollgateHandler.feeState +FNDA:0,TollgateHandler.feeState +DA:106,0 +FNF:8 +FNH:3 +LF:45 +LH:35 +BRF:5 +BRH:5 +end_of_record +TN: +SF:test/finance/AgreementManager.t.sol +DA:227,3 +FN:227,AgreementManagerHandler.constructor +FNDA:3,AgreementManagerHandler.constructor +DA:236,3 +DA:237,3 +DA:238,3 +DA:239,3 +DA:240,3 +DA:241,3 +DA:242,3 +DA:245,37188 +FN:245,AgreementManagerHandler.createAgreement +FNDA:37188,AgreementManagerHandler.createAgreement +DA:246,37188 +DA:247,37188 +DA:249,6961 +DA:250,6961 +DA:251,6961 +DA:252,6961 +DA:254,6961 +DA:255,6961 +BRDA:255,2,0,2349 +DA:256,2349 +DA:258,6961 +DA:260,6684 +DA:261,6684 +DA:262,6684 +DA:264,6684 +DA:265,6684 +DA:269,6684 +DA:270,6684 +DA:271,6684 +DA:272,6684 +DA:275,37887 +FN:275,AgreementManagerHandler.setMaxParties +FNDA:37887,AgreementManagerHandler.setMaxParties +DA:276,37887 +DA:277,37887 +DA:278,37887 +DA:281,0 +FN:281,AgreementManagerHandler.proofsLength +FNDA:0,AgreementManagerHandler.proofsLength +DA:282,0 +DA:285,0 +FN:285,AgreementManagerHandler.proofAt +FNDA:0,AgreementManagerHandler.proofAt +DA:286,0 +DA:289,0 +FN:289,AgreementManagerHandler.info +FNDA:0,AgreementManagerHandler.info +DA:290,0 +DA:293,0 +FN:293,AgreementManagerHandler.totalLocked +FNDA:0,AgreementManagerHandler.totalLocked +DA:294,0 +DA:297,0 +FN:297,AgreementManagerHandler.recomputeLocked +FNDA:0,AgreementManagerHandler.recomputeLocked +DA:298,0 +DA:299,0 +DA:300,0 +DA:301,0 +DA:302,0 +DA:306,6684 +FN:306,AgreementManagerHandler._buildParties +FNDA:6684,AgreementManagerHandler._buildParties +DA:307,6684 +DA:308,6684 +DA:309,26000 +DA:313,6961 +FN:313,AgreementManagerHandler._penaltyBps +FNDA:6961,AgreementManagerHandler._penaltyBps +DA:314,6961 +DA:315,2349 +DA:316,2349 +FNF:10 +FNH:5 +LF:54 +LH:40 +BRF:1 +BRH:1 +end_of_record +TN: +SF:test/finance/AgreementSettler.t.sol +DA:28,10 +FN:28,SettlerMockArbiter.constructor +FNDA:10,SettlerMockArbiter.constructor +DA:29,10 +DA:32,1 +FN:32,SettlerMockArbiter.execute +FNDA:1,SettlerMockArbiter.execute +DA:33,1 +DA:210,4 +FN:210,AgreementSettlerHandler.constructor +FNDA:4,AgreementSettlerHandler.constructor +DA:218,4 +DA:219,4 +DA:220,4 +DA:221,4 +DA:222,4 +DA:223,4 +DA:226,33374 +FN:226,AgreementSettlerHandler.createAgreement +FNDA:33374,AgreementSettlerHandler.createAgreement +DA:227,33374 +DA:228,33374 +DA:229,33374 +DA:230,33374 +DA:232,15566 +DA:233,15566 +BRDA:233,1,0,4391 +DA:234,4391 +DA:236,15566 +DA:238,15175 +DA:239,15175 +DA:240,15175 +DA:241,15175 +DA:242,15175 +DA:245,15175 +DA:246,15175 +DA:256,15175 +DA:257,15175 +DA:260,33050 +FN:260,AgreementSettlerHandler.settle +FNDA:33050,AgreementSettlerHandler.settle +DA:261,33050 +DA:262,29331 +DA:263,29331 +DA:264,29331 +DA:266,0 +DA:267,6190 +DA:268,3 +DA:271,6187 +DA:272,6187 +DA:273,6187 +DA:274,6187 +DA:276,6187 +DA:277,6187 +DA:278,6187 +DA:280,6187 +DA:281,6187 +DA:282,6187 +DA:285,33676 +FN:285,AgreementSettlerHandler.quit +FNDA:33676,AgreementSettlerHandler.quit +DA:286,33676 +DA:287,29658 +DA:288,29658 +DA:289,29658 +DA:291,6524 +DA:292,6524 +DA:293,6524 +DA:295,6524 +DA:296,6524 +DA:298,6524 +DA:299,6524 +DA:302,0 +FN:302,AgreementSettlerHandler.proofsLength +FNDA:0,AgreementSettlerHandler.proofsLength +DA:303,0 +DA:306,0 +FN:306,AgreementSettlerHandler.proofAt +FNDA:0,AgreementSettlerHandler.proofAt +DA:307,0 +DA:310,0 +FN:310,AgreementSettlerHandler.stateOf +FNDA:0,AgreementSettlerHandler.stateOf +DA:311,0 +DA:314,0 +FN:314,AgreementSettlerHandler.activeLocked +FNDA:0,AgreementSettlerHandler.activeLocked +DA:315,0 +DA:318,0 +FN:318,AgreementSettlerHandler.totalProtocolTake +FNDA:0,AgreementSettlerHandler.totalProtocolTake +DA:319,0 +DA:322,0 +FN:322,AgreementSettlerHandler.totalPayout +FNDA:0,AgreementSettlerHandler.totalPayout +DA:323,0 +DA:326,0 +FN:326,AgreementSettlerHandler.recomputeActiveLocked +FNDA:0,AgreementSettlerHandler.recomputeActiveLocked +DA:327,0 +DA:328,0 +DA:329,0 +DA:330,0 +DA:331,0 +DA:335,15175 +FN:335,AgreementSettlerHandler._buildParties +FNDA:15175,AgreementSettlerHandler._buildParties +DA:336,15175 +DA:337,15175 +DA:338,52225 +DA:342,33374 +FN:342,AgreementSettlerHandler._penaltyBps +FNDA:33374,AgreementSettlerHandler._penaltyBps +DA:343,33374 +DA:344,9396 +DA:345,9396 +FNF:15 +FNH:8 +LF:85 +LH:66 +BRF:1 +BRH:1 +end_of_record +TN: +SF:test/libraries/FinancialOps.t.sol +DA:13,51 +FN:13,TestToken.mint +FNDA:51,TestToken.mint +DA:14,51 +DA:21,18857 +FN:21,FinancialOpsHarness.depositNative +FNDA:18857,FinancialOpsHarness.depositNative +DA:22,18857 +DA:25,18709 +FN:25,FinancialOpsHarness.depositToken +FNDA:18709,FinancialOpsHarness.depositToken +DA:26,18709 +DA:29,31325 +FN:29,FinancialOpsHarness.transferFunds +FNDA:31325,FinancialOpsHarness.transferFunds +DA:30,31325 +DA:33,3 +FN:33,FinancialOpsHarness.increaseTokenAllowance +FNDA:3,FinancialOpsHarness.increaseTokenAllowance +DA:34,3 +DA:37,1 +FN:37,FinancialOpsHarness.queryAllowance +FNDA:1,FinancialOpsHarness.queryAllowance +DA:38,1 +DA:41,1 +FN:41,FinancialOpsHarness.queryNativeAllowance +FNDA:1,FinancialOpsHarness.queryNativeAllowance +DA:42,1 +DA:45,2 +FN:45,FinancialOpsHarness.queryBalance +FNDA:2,FinancialOpsHarness.queryBalance +DA:46,2 +DA:298,3 +FN:298,FinancialOpsHandler.constructor +FNDA:3,FinancialOpsHandler.constructor +DA:299,3 +DA:300,3 +DA:302,3 +DA:303,9 +DA:304,9 +DA:305,9 +DA:306,9 +DA:307,9 +DA:308,9 +DA:312,624792 +FN:312,FinancialOpsHandler.depositNative +FNDA:624792,FinancialOpsHandler.depositNative +DA:313,624792 +DA:314,18831 +DA:315,18831 +DA:316,18831 +DA:317,18593 +DA:319,18593 +DA:320,18593 +DA:321,18593 +DA:324,626054 +FN:324,FinancialOpsHandler.transferNative +FNDA:626054,FinancialOpsHandler.transferNative +DA:325,626054 +DA:326,18863 +DA:327,15501 +DA:328,15501 +DA:330,15501 +DA:331,15501 +DA:334,626151 +FN:334,FinancialOpsHandler.depositToken +FNDA:626151,FinancialOpsHandler.depositToken +DA:335,626151 +DA:336,18693 +DA:337,18693 +DA:338,18693 +DA:339,18445 +DA:341,18445 +DA:342,18445 +DA:343,18445 +DA:344,18445 +DA:346,18445 +DA:349,625150 +FN:349,FinancialOpsHandler.transferToken +FNDA:625150,FinancialOpsHandler.transferToken +DA:350,625150 +DA:351,18688 +DA:352,15322 +DA:353,15322 +DA:355,15322 +DA:356,15322 +DA:359,0 +FN:359,FinancialOpsHandler.accountsLength +FNDA:0,FinancialOpsHandler.accountsLength +DA:360,0 +DA:363,0 +FN:363,FinancialOpsHandler.accountAt +FNDA:0,FinancialOpsHandler.accountAt +DA:364,0 +DA:367,0 +FN:367,FinancialOpsHandler.expectedHarnessNativeBalance +FNDA:0,FinancialOpsHandler.expectedHarnessNativeBalance +DA:368,0 +DA:371,0 +FN:371,FinancialOpsHandler.expectedHarnessTokenBalance +FNDA:0,FinancialOpsHandler.expectedHarnessTokenBalance +DA:372,0 +DA:375,0 +FN:375,FinancialOpsHandler.nativeInitialTotal +FNDA:0,FinancialOpsHandler.nativeInitialTotal +DA:376,0 +DA:379,0 +FN:379,FinancialOpsHandler.tokenInitialTotal +FNDA:0,FinancialOpsHandler.tokenInitialTotal +DA:380,0 +FNF:19 +FNH:13 +LF:72 +LH:60 BRF:0 BRH:0 end_of_record @@ -2877,129 +3507,561 @@ BRF:0 BRH:0 end_of_record TN: -SF:test/primitives/BalanceOperator.t.sol -DA:15,11346 -FN:15,BalanceOperator.deposit -FNDA:11346,BalanceOperator.deposit -DA:16,11346 -DA:19,5312 -FN:19,BalanceOperator.withdraw -FNDA:5312,BalanceOperator.withdraw -DA:20,5312 -DA:23,289 -FN:23,BalanceOperator.transfer -FNDA:289,BalanceOperator.transfer -DA:24,289 -DA:34,14 -FN:34,Handler.constructor -FNDA:14,Handler.constructor -DA:35,14 -DA:36,14 -DA:38,14 -DA:39,140 -DA:40,140 -DA:44,14 -FN:44,Handler.getActors -FNDA:14,Handler.getActors -DA:45,14 -DA:48,1004547 -FN:48,Handler.deposit -FNDA:1004547,Handler.deposit -DA:49,1004547 -DA:50,41764 -DA:51,41764 -DA:54,11337 -DA:55,11337 -DA:56,11337 -DA:57,11337 -DA:58,11337 -DA:61,1002944 -FN:61,Handler.withdraw -FNDA:1002944,Handler.withdraw -DA:62,1002944 -DA:63,41297 -DA:64,41297 -DA:67,5307 -DA:68,5307 -DA:69,5307 -DA:72,1004618 -FN:72,Handler.transfer -FNDA:1004618,Handler.transfer -DA:73,1004618 -DA:74,41444 -DA:75,2844 -DA:77,2233 -DA:78,2233 -DA:79,2233 -DA:82,283 -DA:83,283 -FNF:8 -FNH:8 -LF:39 -LH:39 +SF:test/primitives/AccessControlledUpgradeable.t.sol +DA:15,13 +FN:15,AccessControlledHarness.initialize +FNDA:13,AccessControlledHarness.initialize +DA:16,13 +DA:19,16079 +FN:19,AccessControlledHarness.adminAction +FNDA:16079,AccessControlledHarness.adminAction +DA:20,16079 +DA:21,16079 +DA:24,252 +FN:24,AccessControlledHarness.opsAction +FNDA:252,AccessControlledHarness.opsAction +DA:25,252 +DA:26,252 +DA:29,601 +FN:29,AccessControlledHarness.isPaused +FNDA:601,AccessControlledHarness.isPaused +DA:30,601 +DA:33,916 +FN:33,AccessControlledHarness.hasRoleView +FNDA:916,AccessControlledHarness.hasRoleView +DA:34,916 +DA:192,2 +FN:192,AccessControlledHandler.constructor +FNDA:2,AccessControlledHandler.constructor +DA:193,2 +DA:194,2 +DA:195,2 +DA:197,2 +DA:198,6 +DA:202,15928 +FN:202,AccessControlledHandler.grantOpsRole +FNDA:15928,AccessControlledHandler.grantOpsRole +DA:203,15928 +DA:204,500 +DA:205,500 +DA:206,500 +DA:209,15740 +FN:209,AccessControlledHandler.revokeOpsRole +FNDA:15740,AccessControlledHandler.revokeOpsRole +DA:210,15740 +DA:211,422 +DA:212,422 +DA:213,152 +DA:214,152 +DA:217,16078 +FN:217,AccessControlledHandler.callAdminAction +FNDA:16078,AccessControlledHandler.callAdminAction +DA:218,16078 +DA:219,16078 +DA:220,16078 +DA:223,16076 +FN:223,AccessControlledHandler.callOpsAction +FNDA:16076,AccessControlledHandler.callOpsAction +DA:224,16076 +DA:225,490 +DA:226,490 +DA:227,112 +DA:228,112 +DA:229,112 +DA:232,16174 +FN:232,AccessControlledHandler.pause +FNDA:16174,AccessControlledHandler.pause +DA:234,8710 +DA:235,8710 +DA:236,8710 +DA:239,16386 +FN:239,AccessControlledHandler.unpause +FNDA:16386,AccessControlledHandler.unpause +DA:240,16386 +DA:241,7714 +DA:242,7714 +DA:243,7714 +DA:246,0 +FN:246,AccessControlledHandler.actorsLength +FNDA:0,AccessControlledHandler.actorsLength +DA:247,0 +DA:250,0 +FN:250,AccessControlledHandler.actorAt +FNDA:0,AccessControlledHandler.actorAt +DA:251,0 +DA:254,0 +FN:254,AccessControlledHandler.expectedCounterValue +FNDA:0,AccessControlledHandler.expectedCounterValue +DA:255,0 +DA:258,0 +FN:258,AccessControlledHandler.expectedPausedState +FNDA:0,AccessControlledHandler.expectedPausedState +DA:259,0 +FNF:16 +FNH:12 +LF:57 +LH:49 BRF:0 BRH:0 end_of_record TN: -SF:test/primitives/Quorum.t.sol -DA:12,7 -FN:12,QuorumWrapper.status -FNDA:7,QuorumWrapper.status -DA:13,7 -DA:16,2 -FN:16,QuorumWrapper.revoke -FNDA:2,QuorumWrapper.revoke -DA:17,2 -DA:20,3 -FN:20,QuorumWrapper.approve -FNDA:3,QuorumWrapper.approve -DA:21,3 -DA:24,3 -FN:24,QuorumWrapper.quit -FNDA:3,QuorumWrapper.quit -DA:25,3 -DA:28,9 -FN:28,QuorumWrapper.register -FNDA:9,QuorumWrapper.register -DA:29,9 -DA:32,2 -FN:32,QuorumWrapper.reject -FNDA:2,QuorumWrapper.reject -DA:33,2 -FNF:6 -FNH:6 -LF:12 -LH:12 +SF:test/primitives/AllowanceOperatorUpgradeable.t.sol +DA:12,13 +FN:12,AllowanceOperatorHarness.initialize +FNDA:13,AllowanceOperatorHarness.initialize +DA:13,0 +DA:16,32067 +FN:16,AllowanceOperatorHarness.boostLedger +FNDA:32067,AllowanceOperatorHarness.boostLedger +DA:17,32067 +DA:21,1609 +FN:21,AllowanceOperatorHarness.approve +FNDA:1609,AllowanceOperatorHarness.approve +DA:22,1609 +DA:25,320 +FN:25,AllowanceOperatorHarness.revoke +FNDA:320,AllowanceOperatorHarness.revoke +DA:26,320 +DA:29,318 +FN:29,AllowanceOperatorHarness.collect +FNDA:318,AllowanceOperatorHarness.collect +DA:30,318 +DA:185,2 +FN:185,AllowanceHandler.constructor +FNDA:2,AllowanceHandler.constructor +DA:186,2 +DA:187,2 +DA:188,6 +DA:192,1052233 +FN:192,AllowanceHandler.seedLedger +FNDA:1052233,AllowanceHandler.seedLedger +DA:193,1052233 +DA:194,31808 +DA:195,31808 +DA:196,31808 +DA:197,31808 +DA:200,1051770 +FN:200,AllowanceHandler.approve +FNDA:1051770,AllowanceHandler.approve +DA:201,1051770 +DA:202,1087 +DA:203,1087 +DA:204,1087 +DA:206,1087 +DA:207,1087 +DA:209,1087 +DA:210,1087 +DA:213,1053095 +FN:213,AllowanceHandler.revoke +FNDA:1053095,AllowanceHandler.revoke +DA:214,1053095 +DA:215,1107 +DA:216,1107 +DA:217,1107 +DA:218,1107 +DA:219,1107 +DA:220,62 +DA:222,62 +DA:223,62 +DA:224,62 +DA:227,1054374 +FN:227,AllowanceHandler.collect +FNDA:1054374,AllowanceHandler.collect +DA:228,1054374 +DA:229,1029 +DA:230,1029 +DA:231,1029 +DA:232,1029 +DA:233,1029 +DA:234,1029 +DA:235,57 +DA:236,57 +DA:238,57 +DA:239,57 +DA:241,57 +DA:242,57 +DA:243,57 +DA:246,0 +FN:246,AllowanceHandler.accountsLength +FNDA:0,AllowanceHandler.accountsLength +DA:247,0 +DA:250,0 +FN:250,AllowanceHandler.accountAt +FNDA:0,AllowanceHandler.accountAt +DA:251,0 +DA:254,0 +FN:254,AllowanceHandler.expectedLedger +FNDA:0,AllowanceHandler.expectedLedger +DA:255,0 +DA:258,0 +FN:258,AllowanceHandler.expectedAllowance +FNDA:0,AllowanceHandler.expectedAllowance +DA:259,0 +DA:262,0 +FN:262,AllowanceHandler.token +FNDA:0,AllowanceHandler.token +DA:263,0 +FNF:15 +FNH:10 +LF:65 +LH:54 BRF:0 BRH:0 end_of_record TN: -SF:test/shared/CustodianShared.t.sol -DA:14,26 -FN:14,CustodianShared.setUp -FNDA:26,CustodianShared.setUp -DA:15,0 -DA:16,0 -DA:19,2722 -FN:19,CustodianShared._deployCustodian -FNDA:2722,CustodianShared._deployCustodian -DA:20,2722 -DA:21,2722 -DA:22,2722 -DA:25,2715 -FN:25,CustodianShared._registerAndApproveCustodian -FNDA:2715,CustodianShared._registerAndApproveCustodian -DA:26,2715 -DA:27,2715 -DA:28,2715 -DA:31,2716 -FN:31,CustodianShared._registerCustodian -FNDA:2716,CustodianShared._registerCustodian -DA:32,2716 -FNF:4 -FNH:4 -LF:13 -LH:11 +SF:test/primitives/BalanceOperatorUpgradeable.t.sol +DA:16,24708 +FN:16,BalanceOperatorHarness.deposit +FNDA:24708,BalanceOperatorHarness.deposit +DA:17,24708 +DA:20,15370 +FN:20,BalanceOperatorHarness.withdraw +FNDA:15370,BalanceOperatorHarness.withdraw +DA:21,15370 +DA:24,1062 +FN:24,BalanceOperatorHarness.transfer +FNDA:1062,BalanceOperatorHarness.transfer +DA:25,1062 +DA:257,2 +FN:257,BalanceOperatorHandler.constructor +FNDA:2,BalanceOperatorHandler.constructor +DA:258,2 +DA:259,2 +DA:261,2 +DA:262,20 +DA:266,2 +FN:266,BalanceOperatorHandler.getActors +FNDA:2,BalanceOperatorHandler.getActors +DA:267,2 +DA:270,593058 +FN:270,BalanceOperatorHandler.deposit +FNDA:593058,BalanceOperatorHandler.deposit +DA:271,593058 +DA:272,24483 +DA:273,24483 +DA:274,24483 +DA:275,24186 +DA:277,24186 +DA:278,24186 +DA:279,24186 +DA:280,24186 +DA:282,24186 +DA:285,590617 +FN:285,BalanceOperatorHandler.withdraw +FNDA:590617,BalanceOperatorHandler.withdraw +DA:286,590617 +DA:287,24300 +DA:288,24300 +DA:289,24300 +DA:290,15108 +DA:292,15108 +DA:293,15108 +DA:294,15108 +DA:297,592494 +FN:297,BalanceOperatorHandler.transfer +FNDA:592494,BalanceOperatorHandler.transfer +DA:298,592494 +DA:299,24405 +DA:300,1630 +DA:302,1267 +DA:303,1267 +DA:304,1267 +DA:305,1267 +DA:306,798 +DA:308,798 +DA:309,798 +FNF:8 +FNH:8 +LF:44 +LH:44 +BRF:0 +BRH:0 +end_of_record +TN: +SF:test/primitives/LedgerUpgradeable.t.sol +DA:9,5 +FN:9,LedgerUpgradeableHarness.initialize +FNDA:5,LedgerUpgradeableHarness.initialize +DA:10,0 +DA:13,8745 +FN:13,LedgerUpgradeableHarness.setEntry +FNDA:8745,LedgerUpgradeableHarness.setEntry +DA:14,8745 +DA:17,8583 +FN:17,LedgerUpgradeableHarness.sumEntry +FNDA:8583,LedgerUpgradeableHarness.sumEntry +DA:18,8583 +DA:21,364 +FN:21,LedgerUpgradeableHarness.subEntry +FNDA:364,LedgerUpgradeableHarness.subEntry +DA:22,364 +DA:93,1 +FN:93,LedgerUpgradeableHandler.constructor +FNDA:1,LedgerUpgradeableHandler.constructor +DA:94,1 +DA:97,8491 +FN:97,LedgerUpgradeableHandler.setEntry +FNDA:8491,LedgerUpgradeableHandler.setEntry +DA:98,8491 +DA:99,8486 +DA:101,8486 +DA:102,8486 +BRDA:102,1,0,8486 +DA:103,8486 +DA:104,8486 +DA:106,8486 +DA:109,8340 +FN:109,LedgerUpgradeableHandler.sumEntry +FNDA:8340,LedgerUpgradeableHandler.sumEntry +DA:110,8340 +DA:112,8326 +DA:113,8326 +DA:114,0 +DA:116,8326 +DA:118,8326 +BRDA:118,3,0,8326 +DA:119,8326 +DA:120,8326 +DA:122,8326 +DA:125,8194 +FN:125,LedgerUpgradeableHandler.subEntry +FNDA:8194,LedgerUpgradeableHandler.subEntry +DA:126,8194 +DA:128,8181 +DA:129,8181 +DA:130,8181 +DA:132,107 +DA:134,107 +BRDA:134,6,0,107 +DA:135,107 +DA:136,107 +DA:138,107 +DA:141,0 +FN:141,LedgerUpgradeableHandler.keysLength +FNDA:0,LedgerUpgradeableHandler.keysLength +DA:142,0 +DA:145,0 +FN:145,LedgerUpgradeableHandler.keyAt +FNDA:0,LedgerUpgradeableHandler.keyAt +DA:146,0 +DA:149,0 +FN:149,LedgerUpgradeableHandler.expectedBalance +FNDA:0,LedgerUpgradeableHandler.expectedBalance +DA:150,0 +DA:151,0 +FNF:11 +FNH:8 +LF:45 +LH:36 +BRF:3 +BRH:3 +end_of_record +TN: +SF:test/primitives/LockOperatorUpgradeable.t.sol +DA:16,13 +FN:16,LockOperatorHarness.initialize +FNDA:13,LockOperatorHarness.initialize +DA:17,0 +DA:20,21336 +FN:20,LockOperatorHarness.boostLedger +FNDA:21336,LockOperatorHarness.boostLedger +DA:21,21336 +DA:24,6249 +FN:24,LockOperatorHarness.lock +FNDA:6249,LockOperatorHarness.lock +DA:25,6249 +DA:28,1934 +FN:28,LockOperatorHarness.release +FNDA:1934,LockOperatorHarness.release +DA:29,1934 +DA:32,310 +FN:32,LockOperatorHarness.claim +FNDA:310,LockOperatorHarness.claim +DA:33,310 +DA:36,517 +FN:36,LockOperatorHarness.lockedBalance +FNDA:517,LockOperatorHarness.lockedBalance +DA:37,517 +DA:38,517 +DA:40,0 +DA:41,0 +DA:42,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:48,0 +DA:253,3 +FN:253,LockOperatorHandler.constructor +FNDA:3,LockOperatorHandler.constructor +DA:254,3 +DA:255,3 +DA:256,9 +DA:260,692242 +FN:260,LockOperatorHandler.seedLedger +FNDA:692242,LockOperatorHandler.seedLedger +DA:261,692242 +DA:262,20817 +DA:263,20817 +DA:264,20817 +DA:265,20817 +DA:268,692334 +FN:268,LockOperatorHandler.lock +FNDA:692334,LockOperatorHandler.lock +DA:269,692334 +DA:270,20769 +DA:271,20769 +DA:272,20769 +DA:274,5728 +DA:275,5728 +DA:277,5728 +DA:278,5728 +DA:281,692567 +FN:281,LockOperatorHandler.release +FNDA:692567,LockOperatorHandler.release +DA:282,692567 +DA:283,20848 +DA:284,20848 +DA:285,20848 +DA:287,1677 +DA:288,1677 +DA:290,1677 +DA:291,1677 +DA:294,692932 +FN:294,LockOperatorHandler.claim +FNDA:692932,LockOperatorHandler.claim +DA:295,692932 +DA:296,611 +DA:297,611 +DA:298,611 +DA:299,611 +DA:301,50 +DA:302,50 +DA:304,50 +DA:305,50 +DA:308,0 +FN:308,LockOperatorHandler.accountsLength +FNDA:0,LockOperatorHandler.accountsLength +DA:309,0 +DA:312,0 +FN:312,LockOperatorHandler.accountAt +FNDA:0,LockOperatorHandler.accountAt +DA:313,0 +DA:316,0 +FN:316,LockOperatorHandler.expectedLedger +FNDA:0,LockOperatorHandler.expectedLedger +DA:317,0 +DA:320,0 +FN:320,LockOperatorHandler.expectedLocked +FNDA:0,LockOperatorHandler.expectedLocked +DA:321,0 +DA:324,0 +FN:324,LockOperatorHandler.token +FNDA:0,LockOperatorHandler.token +DA:325,0 +FNF:16 +FNH:11 +LF:68 +LH:50 BRF:0 BRH:0 end_of_record +TN: +SF:test/primitives/QuorumUpgradeable.t.sol +DA:10,15 +FN:10,QuorumUpgradeableHarness.initialize +FNDA:15,QuorumUpgradeableHarness.initialize +DA:11,0 +DA:14,50824 +FN:14,QuorumUpgradeableHarness.statusOf +FNDA:50824,QuorumUpgradeableHarness.statusOf +DA:15,50824 +DA:18,10624 +FN:18,QuorumUpgradeableHarness.register +FNDA:10624,QuorumUpgradeableHarness.register +DA:19,10624 +DA:22,307 +FN:22,QuorumUpgradeableHarness.approve +FNDA:307,QuorumUpgradeableHarness.approve +DA:23,307 +DA:26,34 +FN:26,QuorumUpgradeableHarness.blockEntry +FNDA:34,QuorumUpgradeableHarness.blockEntry +DA:27,34 +DA:30,295 +FN:30,QuorumUpgradeableHarness.quit +FNDA:295,QuorumUpgradeableHarness.quit +DA:31,295 +DA:34,2 +FN:34,QuorumUpgradeableHarness.revoke +FNDA:2,QuorumUpgradeableHarness.revoke +DA:35,2 +DA:138,2 +FN:138,QuorumHandler.constructor +FNDA:2,QuorumHandler.constructor +DA:139,2 +DA:142,10145 +FN:142,QuorumHandler.register +FNDA:10145,QuorumHandler.register +DA:143,10145 +DA:144,10145 +DA:145,10105 +DA:146,10105 +DA:149,9755 +FN:149,QuorumHandler.approve +FNDA:9755,QuorumHandler.approve +DA:150,9755 +DA:151,9755 +DA:152,48 +DA:153,48 +DA:156,10174 +FN:156,QuorumHandler.quit +FNDA:10174,QuorumHandler.quit +DA:157,10174 +DA:158,10174 +DA:159,37 +DA:160,37 +DA:163,10068 +FN:163,QuorumHandler.blockEntry +FNDA:10068,QuorumHandler.blockEntry +DA:164,10068 +DA:165,10068 +DA:166,32 +DA:167,32 +DA:170,9908 +FN:170,QuorumHandler.revoke +FNDA:9908,QuorumHandler.revoke +DA:171,9908 +DA:172,9908 +DA:173,0 +DA:174,0 +DA:177,0 +FN:177,QuorumHandler.trackedLength +FNDA:0,QuorumHandler.trackedLength +DA:178,0 +DA:181,0 +FN:181,QuorumHandler.trackedAt +FNDA:0,QuorumHandler.trackedAt +DA:182,0 +DA:185,0 +FN:185,QuorumHandler.expectedStatus +FNDA:0,QuorumHandler.expectedStatus +DA:186,0 +DA:189,10222 +FN:189,QuorumHandler._update +FNDA:10222,QuorumHandler._update +DA:190,10222 +BRDA:190,5,0,10105 +DA:191,10105 +DA:192,10105 +DA:194,10222 +DA:197,50050 +FN:197,QuorumHandler._normalize +FNDA:50050,QuorumHandler._normalize +DA:198,50050 +FNF:18 +FNH:15 +LF:54 +LH:45 +BRF:1 +BRH:1 +end_of_record From cb1c7e79a2656d48cb12cbdd0c19a1d16d42af82 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Mon, 29 Sep 2025 08:16:39 -0600 Subject: [PATCH 18/33] test: coverage upgrade --- lcov.info | 1306 +++++++++++++++++----------------- test/libraries/FeesOps.t.sol | 129 ++++ 2 files changed, 782 insertions(+), 653 deletions(-) create mode 100644 test/libraries/FeesOps.t.sol diff --git a/lcov.info b/lcov.info index 8840514..850f63b 100644 --- a/lcov.info +++ b/lcov.info @@ -35,40 +35,40 @@ FNDA:34,AssetReferendum.initialize DA:64,0 DA:65,0 DA:66,34 -DA:72,58241 +DA:72,58261 FN:72,AssetReferendum.submit -FNDA:58241,AssetReferendum.submit -DA:74,58241 -DA:75,58241 +FNDA:58261,AssetReferendum.submit +DA:74,58261 +DA:75,58261 BRDA:75,0,0,- -DA:76,58241 -DA:77,58241 -DA:99,2123 +DA:76,58261 +DA:77,58261 +DA:99,2127 FN:99,AssetReferendum.revoke -FNDA:2123,AssetReferendum.revoke -DA:100,2123 -DA:101,2123 -DA:106,4184 +FNDA:2127,AssetReferendum.revoke +DA:100,2127 +DA:101,2127 +DA:106,4178 FN:106,AssetReferendum.reject -FNDA:4184,AssetReferendum.reject -DA:107,4184 -DA:108,4184 -DA:113,49380 +FNDA:4178,AssetReferendum.reject +DA:107,4178 +DA:108,4178 +DA:113,49404 FN:113,AssetReferendum.approve -FNDA:49380,AssetReferendum.approve -DA:114,49380 -DA:115,49380 -DA:121,45629 +FNDA:49404,AssetReferendum.approve +DA:114,49404 +DA:115,49404 +DA:121,45649 FN:121,AssetReferendum.isApproved -FNDA:45629,AssetReferendum.isApproved -DA:122,45629 -DA:123,45629 -DA:124,45629 -DA:126,45629 -DA:131,46401 +FNDA:45649,AssetReferendum.isApproved +DA:122,45649 +DA:123,45649 +DA:124,45649 +DA:126,45649 +DA:131,46421 FN:131,AssetReferendum.isActive -FNDA:46401,AssetReferendum.isActive -DA:132,46401 +FNDA:46421,AssetReferendum.isActive +DA:132,46421 DA:138,0 FN:138,AssetReferendum._authorizeUpgrade FNDA:0,AssetReferendum._authorizeUpgrade @@ -81,16 +81,16 @@ BRH:0 end_of_record TN: SF:contracts/assets/AssetRegistry.sol -DA:69,44857 +DA:69,44877 FN:69,AssetRegistry.onlyApprovedAsset -FNDA:44857,AssetRegistry.onlyApprovedAsset -DA:70,44857 +FNDA:44877,AssetRegistry.onlyApprovedAsset +DA:70,44877 BRDA:70,0,0,1 DA:71,1 -DA:78,8920 +DA:78,8914 FN:78,AssetRegistry.onlyOwner -FNDA:8920,AssetRegistry.onlyOwner -DA:79,8920 +FNDA:8914,AssetRegistry.onlyOwner +DA:79,8914 BRDA:79,1,0,- DA:80,0 DA:87,21 @@ -110,34 +110,34 @@ DA:108,0 FN:108,AssetRegistry.supportsInterface FNDA:0,AssetRegistry.supportsInterface DA:111,0 -DA:127,44856 +DA:127,44876 FN:127,AssetRegistry.register -FNDA:44856,AssetRegistry.register -DA:128,44856 -DA:129,44855 -DA:130,44856 -DA:136,8500 +FNDA:44876,AssetRegistry.register +DA:128,44876 +DA:129,44875 +DA:130,44876 +DA:136,8504 FN:136,AssetRegistry.revoke -FNDA:8500,AssetRegistry.revoke -DA:137,8500 -DA:139,8500 -DA:140,8500 -DA:141,8500 -DA:147,25783 +FNDA:8504,AssetRegistry.revoke +DA:137,8504 +DA:139,8504 +DA:140,8504 +DA:141,8504 +DA:147,25773 FN:147,AssetRegistry.transfer -FNDA:25783,AssetRegistry.transfer -DA:148,25783 -DA:149,25783 -DA:156,8920 +FNDA:25773,AssetRegistry.transfer +DA:148,25773 +DA:149,25773 +DA:156,8914 FN:156,AssetRegistry.switchState -FNDA:8920,AssetRegistry.switchState -DA:157,8920 -DA:159,8920 -DA:161,8920 -DA:165,79139 +FNDA:8914,AssetRegistry.switchState +DA:157,8914 +DA:159,8914 +DA:161,8914 +DA:165,79153 FN:165,AssetRegistry._update -FNDA:79139,AssetRegistry._update -DA:170,79139 +FNDA:79153,AssetRegistry._update +DA:170,79153 DA:174,0 FN:174,AssetRegistry._increaseBalance FNDA:0,AssetRegistry._increaseBalance @@ -145,16 +145,16 @@ DA:178,0 DA:183,0 FN:183,AssetRegistry._authorizeUpgrade FNDA:0,AssetRegistry._authorizeUpgrade -DA:186,47051 +DA:186,47073 FN:186,AssetRegistry._enableAsset -FNDA:47051,AssetRegistry._enableAsset -DA:187,47051 -DA:188,47051 -DA:192,15224 +FNDA:47073,AssetRegistry._enableAsset +DA:187,47073 +DA:188,47073 +DA:192,15220 FN:192,AssetRegistry._disableAsset -FNDA:15224,AssetRegistry._disableAsset -DA:193,15224 -DA:194,15224 +FNDA:15220,AssetRegistry._disableAsset +DA:193,15220 +DA:194,15220 FNF:14 FNH:11 LF:44 @@ -164,10 +164,10 @@ BRH:1 end_of_record TN: SF:contracts/assets/AssetSafe.sol -DA:40,22489 +DA:40,22522 FN:40,AssetSafe.onlyHolder -FNDA:22489,AssetSafe.onlyHolder -DA:41,22489 +FNDA:22522,AssetSafe.onlyHolder +DA:41,22522 BRDA:41,0,0,257 DA:42,257 DA:48,10 @@ -188,19 +188,19 @@ DA:71,258 FN:71,AssetSafe.getContent FNDA:258,AssetSafe.getContent DA:72,258 -DA:80,22232 +DA:80,22265 FN:80,AssetSafe.setContent -FNDA:22232,AssetSafe.setContent -DA:81,22232 -DA:82,22232 -DA:83,22232 +FNDA:22265,AssetSafe.setContent +DA:81,22265 +DA:82,22265 +DA:83,22265 DA:88,0 FN:88,AssetSafe._authorizeUpgrade FNDA:0,AssetSafe._authorizeUpgrade -DA:95,22490 +DA:95,22523 FN:95,AssetSafe._computeComposedKey -FNDA:22490,AssetSafe._computeComposedKey -DA:96,22490 +FNDA:22523,AssetSafe._computeComposedKey +DA:96,22523 FNF:8 FNH:7 LF:20 @@ -231,17 +231,17 @@ DA:12,12654 FN:12,FeesOps.isBasePoint FNDA:12654,FeesOps.isBasePoint DA:14,12654 -DA:19,12639 +DA:19,12650 FN:19,FeesOps.isNominal -FNDA:12639,FeesOps.isNominal -DA:21,12639 -DA:27,29688 +FNDA:12650,FeesOps.isNominal +DA:21,12650 +DA:27,29714 FN:27,FeesOps.perOf -FNDA:29688,FeesOps.perOf -DA:31,29688 +FNDA:29714,FeesOps.perOf +DA:31,29714 BRDA:31,0,0,- BRDA:31,0,1,- -DA:32,29688 +DA:32,29714 DA:37,0 FN:37,FeesOps.calcBps FNDA:0,FeesOps.calcBps @@ -450,10 +450,10 @@ BRH:3 end_of_record TN: SF:contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol -DA:29,54226 +DA:29,54213 FN:29,AccessControlledUpgradeable.onlyAdmin -FNDA:54226,AccessControlledUpgradeable.onlyAdmin -DA:34,54226 +FNDA:54213,AccessControlledUpgradeable.onlyAdmin +DA:34,54213 BRDA:34,0,0,258 DA:35,258 DA:43,8830 @@ -477,16 +477,16 @@ BRDA:68,1,0,1 DA:69,1 DA:72,252 DA:73,252 -DA:80,100771 +DA:80,100778 FN:80,AccessControlledUpgradeable._hasRole -FNDA:100771,AccessControlledUpgradeable._hasRole -DA:81,100771 -DA:82,100771 -DA:83,100771 -DA:84,100771 -DA:88,101023 +FNDA:100778,AccessControlledUpgradeable._hasRole +DA:81,100778 +DA:82,100778 +DA:83,100778 +DA:84,100778 +DA:88,101030 FN:88,AccessControlledUpgradeable._getAccessControlStorage -FNDA:101023,AccessControlledUpgradeable._getAccessControlStorage +FNDA:101030,AccessControlledUpgradeable._getAccessControlStorage DA:90,0 FNF:7 FNH:7 @@ -594,16 +594,16 @@ DA:71,15367 DA:72,15367 DA:73,15367 DA:74,0 -DA:81,7504 +DA:81,7494 FN:81,BalanceOperatorUpgradeable._transfer -FNDA:7504,BalanceOperatorUpgradeable._transfer -DA:86,7504 +FNDA:7494,BalanceOperatorUpgradeable._transfer +DA:86,7494 BRDA:86,1,0,1 -DA:87,7503 +DA:87,7493 BRDA:87,2,0,1 -DA:89,7502 -DA:90,7502 -DA:91,7502 +DA:89,7492 +DA:90,7492 +DA:91,7492 DA:92,0 DA:97,0 FN:97,BalanceOperatorUpgradeable._getBalanceOperatorStorage @@ -624,24 +624,24 @@ FNDA:21,ERC721StatefulUpgradeable.__ERC721Stateful_init DA:31,0 FN:31,ERC721StatefulUpgradeable.__ERC721Stateful_init_unchained FNDA:0,ERC721StatefulUpgradeable.__ERC721Stateful_init_unchained -DA:35,47051 +DA:35,47073 FN:35,ERC721StatefulUpgradeable._activate -FNDA:47051,ERC721StatefulUpgradeable._activate -DA:36,47051 -DA:37,47051 -DA:42,15224 +FNDA:47073,ERC721StatefulUpgradeable._activate +DA:36,47073 +DA:37,47073 +DA:42,15220 FN:42,ERC721StatefulUpgradeable._deactivate -FNDA:15224,ERC721StatefulUpgradeable._deactivate -DA:43,15224 -DA:44,15224 -DA:50,9180 +FNDA:15220,ERC721StatefulUpgradeable._deactivate +DA:43,15220 +DA:44,15220 +DA:50,9174 FN:50,ERC721StatefulUpgradeable.isActive -FNDA:9180,ERC721StatefulUpgradeable.isActive -DA:51,9180 -DA:52,9180 -DA:56,71455 +FNDA:9174,ERC721StatefulUpgradeable.isActive +DA:51,9174 +DA:52,9174 +DA:56,71467 FN:56,ERC721StatefulUpgradeable._getERC721StateStorage -FNDA:71455,ERC721StatefulUpgradeable._getERC721StateStorage +FNDA:71467,ERC721StatefulUpgradeable._getERC721StateStorage DA:58,0 FNF:6 FNH:5 @@ -691,40 +691,40 @@ BRH:0 end_of_record TN: SF:contracts/core/primitives/upgradeable/LedgerUpgradeable.sol -DA:28,25694 +DA:28,25705 FN:28,LedgerUpgradeable.onlyValidOperation -FNDA:25694,LedgerUpgradeable.onlyValidOperation -DA:29,25694 +FNDA:25705,LedgerUpgradeable.onlyValidOperation +DA:29,25705 BRDA:29,0,0,4 -DA:36,168827 +DA:36,168867 FN:36,LedgerUpgradeable.getLedgerBalance -FNDA:168827,LedgerUpgradeable.getLedgerBalance -DA:37,168827 -DA:38,168827 +FNDA:168867,LedgerUpgradeable.getLedgerBalance +DA:37,168867 +DA:38,168867 DA:45,168 FN:45,LedgerUpgradeable.__Ledger_init FNDA:168,LedgerUpgradeable.__Ledger_init DA:50,0 FN:50,LedgerUpgradeable.__Ledger_init_unchained FNDA:0,LedgerUpgradeable.__Ledger_init_unchained -DA:57,8745 +DA:57,8729 FN:57,LedgerUpgradeable._setLedgerEntry -FNDA:8745,LedgerUpgradeable._setLedgerEntry -DA:58,8745 -DA:59,8745 -DA:67,116782 +FNDA:8729,LedgerUpgradeable._setLedgerEntry +DA:58,8729 +DA:59,8729 +DA:67,116792 FN:67,LedgerUpgradeable._sumLedgerEntry -FNDA:116782,LedgerUpgradeable._sumLedgerEntry -DA:68,116782 -DA:69,116782 -DA:77,52428 +FNDA:116792,LedgerUpgradeable._sumLedgerEntry +DA:68,116792 +DA:69,116792 +DA:77,52449 FN:77,LedgerUpgradeable._subLedgerEntry -FNDA:52428,LedgerUpgradeable._subLedgerEntry -DA:78,52428 -DA:79,52428 -DA:84,346782 +FNDA:52449,LedgerUpgradeable._subLedgerEntry +DA:78,52449 +DA:79,52449 +DA:84,346837 FN:84,LedgerUpgradeable._getLedgerStorage -FNDA:346782,LedgerUpgradeable._getLedgerStorage +FNDA:346837,LedgerUpgradeable._getLedgerStorage DA:86,0 FNF:8 FNH:7 @@ -742,51 +742,51 @@ DA:29,0 DA:35,0 FN:35,LockOperatorUpgradeable.__LockOperator_init_unchained FNDA:0,LockOperatorUpgradeable.__LockOperator_init_unchained -DA:44,28881 +DA:44,28912 FN:44,LockOperatorUpgradeable._lock -FNDA:28881,LockOperatorUpgradeable._lock -DA:49,28881 +FNDA:28912,LockOperatorUpgradeable._lock +DA:49,28912 BRDA:49,0,0,2 -DA:50,28879 -DA:51,28879 -DA:52,28879 +DA:50,28910 +DA:51,28910 +DA:52,28910 DA:53,0 -DA:60,8715 +DA:60,8726 FN:60,LockOperatorUpgradeable._release -FNDA:8715,LockOperatorUpgradeable._release -DA:65,8715 +FNDA:8726,LockOperatorUpgradeable._release +DA:65,8726 BRDA:65,1,0,1 -DA:66,8714 -DA:67,8714 -DA:68,8714 +DA:66,8725 +DA:67,8725 +DA:68,8725 DA:69,0 -DA:78,13535 +DA:78,13536 FN:78,LockOperatorUpgradeable._claim -FNDA:13535,LockOperatorUpgradeable._claim -DA:83,13535 +FNDA:13536,LockOperatorUpgradeable._claim +DA:83,13536 BRDA:83,2,0,1 -DA:84,13534 -DA:85,13534 -DA:86,13534 +DA:84,13535 +DA:85,13535 +DA:86,13535 DA:87,0 -DA:95,22248 +DA:95,22260 FN:95,LockOperatorUpgradeable._subLockedAmount -FNDA:22248,LockOperatorUpgradeable._subLockedAmount -DA:96,22248 -DA:97,22248 -DA:105,28879 +FNDA:22260,LockOperatorUpgradeable._subLockedAmount +DA:96,22260 +DA:97,22260 +DA:105,28910 FN:105,LockOperatorUpgradeable._sumLockedAmount -FNDA:28879,LockOperatorUpgradeable._sumLockedAmount -DA:106,28879 -DA:107,28879 -DA:115,22250 +FNDA:28910,LockOperatorUpgradeable._sumLockedAmount +DA:106,28910 +DA:107,28910 +DA:115,22262 FN:115,LockOperatorUpgradeable._getLockedAmount -FNDA:22250,LockOperatorUpgradeable._getLockedAmount -DA:116,22250 -DA:117,22250 -DA:122,73377 +FNDA:22262,LockOperatorUpgradeable._getLockedAmount +DA:116,22262 +DA:117,22262 +DA:122,73432 FN:122,LockOperatorUpgradeable._getLockOperatorStorage -FNDA:73377,LockOperatorUpgradeable._getLockOperatorStorage +FNDA:73432,LockOperatorUpgradeable._getLockOperatorStorage DA:124,0 FNF:9 FNH:8 @@ -803,49 +803,49 @@ FNDA:62,QuorumUpgradeable.__Quorum_init DA:53,0 FN:53,QuorumUpgradeable.__Quorum_init_unchained FNDA:0,QuorumUpgradeable.__Quorum_init_unchained -DA:57,222415 +DA:57,222441 FN:57,QuorumUpgradeable._status -FNDA:222415,QuorumUpgradeable._status -DA:58,222415 -DA:59,222415 -DA:65,2125 +FNDA:222441,QuorumUpgradeable._status +DA:58,222441 +DA:59,222441 +DA:65,2129 FN:65,QuorumUpgradeable._revoke -FNDA:2125,QuorumUpgradeable._revoke -DA:66,2125 -DA:67,2125 +FNDA:2129,QuorumUpgradeable._revoke +DA:66,2129 +DA:67,2129 BRDA:67,0,0,1 -DA:68,2124 -DA:74,4218 +DA:68,2128 +DA:74,4214 FN:74,QuorumUpgradeable._block -FNDA:4218,QuorumUpgradeable._block -DA:75,4218 -DA:76,4218 +FNDA:4214,QuorumUpgradeable._block +DA:75,4214 +DA:76,4214 BRDA:76,1,0,1 -DA:77,4217 -DA:82,49687 +DA:77,4213 +DA:82,49717 FN:82,QuorumUpgradeable._approve -FNDA:49687,QuorumUpgradeable._approve -DA:83,49687 -DA:84,49687 +FNDA:49717,QuorumUpgradeable._approve +DA:83,49717 +DA:84,49717 BRDA:84,2,0,1 -DA:85,49686 -DA:90,295 +DA:85,49716 +DA:90,294 FN:90,QuorumUpgradeable._quit -FNDA:295,QuorumUpgradeable._quit -DA:91,295 -DA:92,295 +FNDA:294,QuorumUpgradeable._quit +DA:91,294 +DA:92,294 BRDA:92,3,0,1 -DA:93,294 -DA:98,68865 +DA:93,293 +DA:98,68842 FN:98,QuorumUpgradeable._register -FNDA:68865,QuorumUpgradeable._register -DA:99,68865 -DA:100,68865 +FNDA:68842,QuorumUpgradeable._register +DA:99,68842 +DA:100,68842 BRDA:100,4,0,1 -DA:101,68864 -DA:105,347605 +DA:101,68841 +DA:105,347637 FN:105,QuorumUpgradeable._getRegistryStorage -FNDA:347605,QuorumUpgradeable._getRegistryStorage +FNDA:347637,QuorumUpgradeable._getRegistryStorage DA:107,0 FNF:9 FNH:8 @@ -1049,10 +1049,10 @@ BRDA:74,2,0,- DA:75,0 DA:78,51367 DA:79,51367 -DA:82,12417 -BRDA:82,3,0,12417 -DA:83,12417 -DA:84,12417 +DA:82,12408 +BRDA:82,3,0,12408 +DA:83,12408 +DA:84,12408 BRDA:84,4,0,1 DA:92,40 FN:92,Tollgate.constructor @@ -1063,24 +1063,24 @@ FN:98,Tollgate.initialize FNDA:40,Tollgate.initialize DA:99,0 DA:100,40 -DA:107,46040 +DA:107,46102 FN:107,Tollgate.isSupportedCurrency -FNDA:46040,Tollgate.isSupportedCurrency -DA:108,46040 +FNDA:46102,Tollgate.isSupportedCurrency +DA:108,46102 DA:114,257 FN:114,Tollgate.supportedCurrencies FNDA:257,Tollgate.supportedCurrencies DA:115,257 -DA:122,23922 +DA:122,23953 FN:122,Tollgate.getFees -FNDA:23922,Tollgate.getFees -DA:124,23922 +FNDA:23953,Tollgate.getFees +DA:124,23953 BRDA:124,5,0,1 DA:125,1 -DA:128,23921 -DA:129,23921 -DA:130,23921 -DA:131,23921 +DA:128,23952 +DA:129,23952 +DA:130,23952 +DA:131,23952 DA:139,51364 FN:139,Tollgate.setFees FNDA:51364,Tollgate.setFees @@ -1094,16 +1094,16 @@ DA:158,51364 DA:163,0 FN:163,Tollgate._authorizeUpgrade FNDA:0,Tollgate._authorizeUpgrade -DA:169,69962 +DA:169,70055 FN:169,Tollgate._isSchemeSupported -FNDA:69962,Tollgate._isSchemeSupported -DA:170,69962 -DA:171,69962 -DA:172,69962 -DA:180,145247 +FNDA:70055,Tollgate._isSchemeSupported +DA:170,70055 +DA:171,70055 +DA:172,70055 +DA:180,145371 FN:180,Tollgate._computeComposedKey -FNDA:145247,Tollgate._computeComposedKey -DA:181,145247 +FNDA:145371,Tollgate._computeComposedKey +DA:181,145371 FNF:11 FNH:10 LF:41 @@ -1155,11 +1155,11 @@ BRH:0 end_of_record TN: SF:contracts/financial/AgreementManager.sol -DA:70,23148 +DA:70,23179 FN:70,AgreementManager.onlySupportedCurrency -FNDA:23148,AgreementManager.onlySupportedCurrency -DA:71,23148 -DA:72,23148 +FNDA:23179,AgreementManager.onlySupportedCurrency +DA:71,23179 +DA:72,23179 BRDA:72,0,0,- DA:77,38 FN:77,AgreementManager.constructor @@ -1173,65 +1173,65 @@ FNDA:38,AgreementManager.initialize DA:88,0 DA:89,38 DA:90,38 -DA:95,37889 +DA:95,37876 FN:95,AgreementManager.setMaxParties -FNDA:37889,AgreementManager.setMaxParties -DA:96,37889 +FNDA:37876,AgreementManager.setMaxParties +DA:96,37876 BRDA:96,1,0,1 -DA:97,37888 -DA:101,75249 +DA:97,37875 +DA:101,75245 FN:101,AgreementManager.maxParties -FNDA:75249,AgreementManager.maxParties -DA:102,75249 -DA:111,22635 +FNDA:75245,AgreementManager.maxParties +DA:102,75245 +DA:111,22666 FN:111,AgreementManager.createAgreement -FNDA:22635,AgreementManager.createAgreement -DA:119,22635 -DA:120,22635 -DA:124,22633 -DA:125,22633 +FNDA:22666,AgreementManager.createAgreement +DA:119,22666 +DA:120,22666 +DA:124,22664 +DA:125,22664 DA:126,0 -DA:131,35860 +DA:131,35892 FN:131,AgreementManager.getAgreement -FNDA:35860,AgreementManager.getAgreement -DA:132,35860 -DA:141,23148 +FNDA:35892,AgreementManager.getAgreement +DA:132,35892 +DA:141,23179 FN:141,AgreementManager.previewAgreement -FNDA:23148,AgreementManager.previewAgreement -DA:160,23148 -DA:164,23147 -DA:165,23147 -DA:169,23147 +FNDA:23179,AgreementManager.previewAgreement +DA:160,23179 +DA:164,23178 +DA:165,23178 +DA:169,23178 DA:185,0 FN:185,AgreementManager._authorizeUpgrade FNDA:0,AgreementManager._authorizeUpgrade -DA:188,22633 +DA:188,22664 FN:188,AgreementManager._createAndStoreProof -FNDA:22633,AgreementManager._createAndStoreProof -DA:190,22633 -DA:191,22633 -DA:192,22633 +FNDA:22664,AgreementManager._createAndStoreProof +DA:190,22664 +DA:191,22664 +DA:192,22664 DA:193,0 -DA:197,23147 +DA:197,23178 FN:197,AgreementManager._calculatePenalization -FNDA:23147,AgreementManager._calculatePenalization -DA:198,23147 -DA:199,6541 -DA:200,6541 -DA:201,6541 -DA:209,6541 +FNDA:23178,AgreementManager._calculatePenalization +DA:198,23178 +DA:199,6536 +DA:200,6536 +DA:201,6536 +DA:209,6536 FN:209,AgreementManager._penaltyBps -FNDA:6541,AgreementManager._penaltyBps -DA:210,6541 -DA:214,6541 -DA:218,6541 +FNDA:6536,AgreementManager._penaltyBps +DA:210,6536 +DA:214,6536 +DA:218,6536 BRDA:218,4,0,- DA:219,0 -DA:229,23148 +DA:229,23179 FN:229,AgreementManager._calcFees -FNDA:23148,AgreementManager._calcFees -DA:231,23148 -DA:232,23148 +FNDA:23179,AgreementManager._calcFees +DA:231,23179 +DA:232,23179 DA:233,1 DA:234,1 BRDA:234,7,0,1 @@ -1245,10 +1245,10 @@ BRH:2 end_of_record TN: SF:contracts/financial/AgreementSettler.sol -DA:85,6783 +DA:85,6794 FN:85,AgreementSettler.onlyValidAgreement -FNDA:6783,AgreementSettler.onlyValidAgreement -DA:86,6783 +FNDA:6794,AgreementSettler.onlyValidAgreement +DA:86,6794 BRDA:86,0,0,1 DA:87,1 DA:93,23 @@ -1272,51 +1272,51 @@ DA:117,0 DA:119,0 DA:120,0 DA:121,0 -DA:138,6782 +DA:138,6793 FN:138,AgreementSettler.quitAgreement -FNDA:6782,AgreementSettler.quitAgreement -DA:139,6782 -DA:140,6782 +FNDA:6793,AgreementSettler.quitAgreement +DA:139,6793 +DA:140,6793 BRDA:140,2,0,1 -DA:154,6781 -DA:155,6781 -DA:156,6781 -DA:164,6781 -DA:165,6781 -DA:166,6781 -DA:168,6781 -DA:170,6781 -DA:172,6781 -BRDA:172,3,0,6781 -DA:174,6781 +DA:154,6792 +DA:155,6792 +DA:156,6792 +DA:164,6792 +DA:165,6792 +DA:166,6792 +DA:168,6792 +DA:170,6792 +DA:172,6792 +BRDA:172,3,0,6792 +DA:174,6792 DA:175,0 -DA:201,6445 +DA:201,6435 FN:201,AgreementSettler.settleAgreement -FNDA:6445,AgreementSettler.settleAgreement -DA:206,6445 -DA:207,6445 +FNDA:6435,AgreementSettler.settleAgreement +DA:206,6435 +DA:207,6435 BRDA:207,4,0,1 -DA:209,6444 -DA:210,6444 -DA:211,6444 -DA:212,6444 -DA:213,6444 -DA:215,6444 -DA:216,6444 -DA:217,6444 -DA:222,6444 -DA:226,6444 -DA:228,6444 -BRDA:228,5,0,6444 -DA:229,6444 +DA:209,6434 +DA:210,6434 +DA:211,6434 +DA:212,6434 +DA:213,6434 +DA:215,6434 +DA:216,6434 +DA:217,6434 +DA:222,6434 +DA:226,6434 +DA:228,6434 +BRDA:228,5,0,6434 +DA:229,6434 DA:230,0 DA:236,0 FN:236,AgreementSettler._authorizeUpgrade FNDA:0,AgreementSettler._authorizeUpgrade -DA:240,13225 +DA:240,13226 FN:240,AgreementSettler._setProofAsSettled -FNDA:13225,AgreementSettler._setProofAsSettled -DA:241,13225 +FNDA:13226,AgreementSettler._setProofAsSettled +DA:241,13226 FNF:8 FNH:6 LF:51 @@ -1340,18 +1340,18 @@ DA:41,0 DA:42,0 DA:43,0 DA:44,38 -DA:54,22634 +DA:54,22665 FN:54,LedgerVault.lock -FNDA:22634,LedgerVault.lock -DA:59,22634 -DA:66,6781 +FNDA:22665,LedgerVault.lock +DA:59,22665 +DA:66,6792 FN:66,LedgerVault.release -FNDA:6781,LedgerVault.release -DA:71,6781 -DA:80,13225 +FNDA:6792,LedgerVault.release +DA:71,6792 +DA:80,13226 FN:80,LedgerVault.claim -FNDA:13225,LedgerVault.claim -DA:85,13225 +FNDA:13226,LedgerVault.claim +DA:85,13226 DA:92,0 FN:92,LedgerVault.approve FNDA:0,LedgerVault.approve @@ -1372,10 +1372,10 @@ DA:128,0 FN:128,LedgerVault.withdraw FNDA:0,LedgerVault.withdraw DA:133,0 -DA:140,6444 +DA:140,6434 FN:140,LedgerVault.transfer -FNDA:6444,LedgerVault.transfer -DA:141,6444 +FNDA:6434,LedgerVault.transfer +DA:141,6434 DA:147,0 FN:147,LedgerVault._authorizeUpgrade FNDA:0,LedgerVault._authorizeUpgrade @@ -2825,49 +2825,49 @@ DA:35,2 DA:36,2 DA:38,2 DA:39,12 -DA:43,12648 +DA:43,12650 FN:43,AssetReferendumHandler.submit -FNDA:12648,AssetReferendumHandler.submit -DA:44,12648 -DA:46,12648 -DA:47,12648 -DA:48,12648 +FNDA:12650,AssetReferendumHandler.submit +DA:44,12650 +DA:46,12650 +DA:47,12650 +DA:48,12650 DA:50,12610 DA:52,12610 DA:53,12610 DA:55,12610 DA:56,12610 DA:57,12610 -DA:60,12509 +DA:60,12519 FN:60,AssetReferendumHandler.approve -FNDA:12509,AssetReferendumHandler.approve -DA:61,12509 -DA:63,10604 -DA:64,10604 -DA:65,10604 -DA:67,4009 -DA:68,4009 -DA:70,4009 -DA:73,12461 +FNDA:12519,AssetReferendumHandler.approve +DA:61,12519 +DA:63,10610 +DA:64,10610 +DA:65,10610 +DA:67,4013 +DA:68,4013 +DA:70,4013 +DA:73,12459 FN:73,AssetReferendumHandler.reject -FNDA:12461,AssetReferendumHandler.reject -DA:74,12461 -DA:76,10572 -DA:77,10572 -DA:78,10572 -DA:80,3926 -DA:81,3926 -DA:83,3926 -DA:86,12432 +FNDA:12459,AssetReferendumHandler.reject +DA:74,12459 +DA:76,10567 +DA:77,10567 +DA:78,10567 +DA:80,3920 +DA:81,3920 +DA:83,3920 +DA:86,12422 FN:86,AssetReferendumHandler.revoke -FNDA:12432,AssetReferendumHandler.revoke -DA:87,12432 -DA:89,10484 -DA:90,10484 -DA:91,10484 -DA:93,1865 -DA:94,1865 -DA:96,1865 +FNDA:12422,AssetReferendumHandler.revoke +DA:87,12422 +DA:89,10474 +DA:90,10474 +DA:91,10474 +DA:93,1869 +DA:94,1869 +DA:96,1869 DA:99,0 FN:99,AssetReferendumHandler.trackedLength FNDA:0,AssetReferendumHandler.trackedLength @@ -2899,58 +2899,58 @@ DA:33,3 DA:35,3 DA:36,3 DA:37,15 -DA:41,19036 +DA:41,19040 FN:41,AssetRegistryHandler.register -FNDA:19036,AssetRegistryHandler.register -DA:42,19036 -DA:44,19036 -DA:45,19036 -DA:48,18992 -DA:50,18992 -DA:51,18992 -DA:53,18992 -DA:54,18992 -DA:56,18992 -DA:57,18992 -DA:59,18992 -DA:60,18992 -DA:61,18992 -DA:62,18992 -DA:63,18992 -DA:66,18770 +FNDA:19040,AssetRegistryHandler.register +DA:42,19040 +DA:44,19040 +DA:45,19040 +DA:48,18996 +DA:50,18996 +DA:51,18996 +DA:53,18996 +DA:54,18996 +DA:56,18996 +DA:57,18996 +DA:59,18996 +DA:60,18996 +DA:61,18996 +DA:62,18996 +DA:63,18996 +DA:66,18772 FN:66,AssetRegistryHandler.transfer -FNDA:18770,AssetRegistryHandler.transfer -DA:67,18770 -DA:69,15880 -DA:70,15880 -DA:71,15880 -DA:73,8839 -DA:74,8839 -DA:76,7380 -DA:77,7380 -DA:79,7380 -DA:82,18815 +FNDA:18772,AssetRegistryHandler.transfer +DA:67,18772 +DA:69,15877 +DA:70,15877 +DA:71,15877 +DA:73,8835 +DA:74,8835 +DA:76,7379 +DA:77,7379 +DA:79,7379 +DA:82,18811 FN:82,AssetRegistryHandler.switchState -FNDA:18815,AssetRegistryHandler.switchState -DA:83,18815 -DA:85,15889 -DA:86,15889 -DA:87,15889 -DA:89,8918 -DA:90,8918 -DA:91,8918 -DA:94,18454 +FNDA:18811,AssetRegistryHandler.switchState +DA:83,18811 +DA:85,15881 +DA:86,15881 +DA:87,15881 +DA:89,8912 +DA:90,8912 +DA:91,8912 +DA:94,18452 FN:94,AssetRegistryHandler.revoke -FNDA:18454,AssetRegistryHandler.revoke -DA:95,18454 -DA:97,15555 -DA:98,15555 -DA:99,15555 -DA:101,8499 -DA:102,8499 -DA:104,8499 -DA:105,8499 -DA:106,8499 +FNDA:18452,AssetRegistryHandler.revoke +DA:95,18452 +DA:97,15549 +DA:98,15549 +DA:99,15549 +DA:101,8503 +DA:102,8503 +DA:104,8503 +DA:105,8503 +DA:106,8503 DA:109,0 FN:109,AssetRegistryHandler.assetIdsLength FNDA:0,AssetRegistryHandler.assetIdsLength @@ -2981,52 +2981,52 @@ DA:32,3 DA:33,3 DA:35,3 DA:36,18 -DA:40,25187 +DA:40,25203 FN:40,AssetSafeHandler.registerAsset -FNDA:25187,AssetSafeHandler.registerAsset -DA:41,25187 -DA:43,25187 -DA:46,25084 -DA:47,25084 -DA:49,25084 -DA:50,25084 -DA:52,25084 -DA:53,25084 -DA:55,25084 -DA:56,25084 -DA:58,25084 -DA:59,25084 -DA:60,25084 -DA:63,25042 +FNDA:25203,AssetSafeHandler.registerAsset +DA:41,25203 +DA:43,25203 +DA:46,25100 +DA:47,25100 +DA:49,25100 +DA:50,25100 +DA:52,25100 +DA:53,25100 +DA:55,25100 +DA:56,25100 +DA:58,25100 +DA:59,25100 +DA:60,25100 +DA:63,25003 FN:63,AssetSafeHandler.transferAsset -FNDA:25042,AssetSafeHandler.transferAsset -DA:64,25042 -DA:66,22046 -DA:67,22046 -DA:69,22046 -DA:70,22046 -DA:72,22046 -DA:73,22046 -DA:75,18402 -DA:76,18402 -DA:78,18402 -DA:81,24846 +FNDA:25003,AssetSafeHandler.transferAsset +DA:64,25003 +DA:66,22062 +DA:67,22062 +DA:69,22062 +DA:70,22062 +DA:72,22062 +DA:73,22062 +DA:75,18393 +DA:76,18393 +DA:78,18393 +DA:81,24869 FN:81,AssetSafeHandler.setContent -FNDA:24846,AssetSafeHandler.setContent -DA:82,24846 -DA:84,21972 -DA:85,21972 -DA:87,21972 -DA:88,21972 -DA:90,21972 -DA:91,21972 -DA:92,21972 -DA:94,21972 -DA:95,21972 -DA:97,21972 -DA:98,21972 -DA:99,21972 -DA:100,21972 +FNDA:24869,AssetSafeHandler.setContent +DA:82,24869 +DA:84,22005 +DA:85,22005 +DA:87,22005 +DA:88,22005 +DA:90,22005 +DA:91,22005 +DA:92,22005 +DA:94,22005 +DA:95,22005 +DA:97,22005 +DA:98,22005 +DA:99,22005 +DA:100,22005 DA:103,0 FN:103,AssetSafeHandler.trackedLength FNDA:0,AssetSafeHandler.trackedLength @@ -3068,10 +3068,10 @@ BRH:0 end_of_record TN: SF:test/economics/Tollgate.t.sol -DA:20,12417 +DA:20,12408 FN:20,TargetD.isFeeSchemeSupported -FNDA:12417,TargetD.isFeeSchemeSupported -DA:22,12417 +FNDA:12408,TargetD.isFeeSchemeSupported +DA:22,12408 DA:42,2 FN:42,TollgateHandler.constructor FNDA:2,TollgateHandler.constructor @@ -3097,13 +3097,13 @@ DA:64,50050 DA:65,50050 DA:67,50050 DA:68,50050 -BRDA:68,1,0,25299 +BRDA:68,1,0,25288 BRDA:68,1,1,12370 -DA:69,25299 -DA:70,24751 -BRDA:70,2,0,12381 +DA:69,25288 +DA:70,24762 +BRDA:70,2,0,12392 BRDA:70,2,1,12370 -DA:71,12381 +DA:71,12392 DA:73,12370 DA:76,50050 DA:77,50050 @@ -3111,9 +3111,9 @@ DA:79,50050 DA:80,50050 DA:81,50050 DA:83,50050 -BRDA:83,3,0,21293 -DA:84,21293 -DA:85,21293 +BRDA:83,3,0,21298 +DA:84,21298 +DA:85,21298 DA:89,0 FN:89,TollgateHandler.targetsLength FNDA:0,TollgateHandler.targetsLength @@ -3153,35 +3153,35 @@ DA:239,3 DA:240,3 DA:241,3 DA:242,3 -DA:245,37188 +DA:245,37201 FN:245,AgreementManagerHandler.createAgreement -FNDA:37188,AgreementManagerHandler.createAgreement -DA:246,37188 -DA:247,37188 -DA:249,6961 -DA:250,6961 -DA:251,6961 -DA:252,6961 -DA:254,6961 -DA:255,6961 -BRDA:255,2,0,2349 -DA:256,2349 -DA:258,6961 -DA:260,6684 -DA:261,6684 -DA:262,6684 -DA:264,6684 -DA:265,6684 -DA:269,6684 -DA:270,6684 -DA:271,6684 -DA:272,6684 -DA:275,37887 +FNDA:37201,AgreementManagerHandler.createAgreement +DA:246,37201 +DA:247,37201 +DA:249,6979 +DA:250,6979 +DA:251,6979 +DA:252,6979 +DA:254,6979 +DA:255,6979 +BRDA:255,2,0,2361 +DA:256,2361 +DA:258,6979 +DA:260,6700 +DA:261,6700 +DA:262,6700 +DA:264,6700 +DA:265,6700 +DA:269,6700 +DA:270,6700 +DA:271,6700 +DA:272,6700 +DA:275,37874 FN:275,AgreementManagerHandler.setMaxParties -FNDA:37887,AgreementManagerHandler.setMaxParties -DA:276,37887 -DA:277,37887 -DA:278,37887 +FNDA:37874,AgreementManagerHandler.setMaxParties +DA:276,37874 +DA:277,37874 +DA:278,37874 DA:281,0 FN:281,AgreementManagerHandler.proofsLength FNDA:0,AgreementManagerHandler.proofsLength @@ -3206,18 +3206,18 @@ DA:299,0 DA:300,0 DA:301,0 DA:302,0 -DA:306,6684 +DA:306,6700 FN:306,AgreementManagerHandler._buildParties -FNDA:6684,AgreementManagerHandler._buildParties -DA:307,6684 -DA:308,6684 -DA:309,26000 -DA:313,6961 +FNDA:6700,AgreementManagerHandler._buildParties +DA:307,6700 +DA:308,6700 +DA:309,26116 +DA:313,6979 FN:313,AgreementManagerHandler._penaltyBps -FNDA:6961,AgreementManagerHandler._penaltyBps -DA:314,6961 -DA:315,2349 -DA:316,2349 +FNDA:6979,AgreementManagerHandler._penaltyBps +DA:314,6979 +DA:315,2361 +DA:316,2361 FNF:10 FNH:5 LF:54 @@ -3244,61 +3244,61 @@ DA:220,4 DA:221,4 DA:222,4 DA:223,4 -DA:226,33374 +DA:226,33363 FN:226,AgreementSettlerHandler.createAgreement -FNDA:33374,AgreementSettlerHandler.createAgreement -DA:227,33374 -DA:228,33374 -DA:229,33374 -DA:230,33374 -DA:232,15566 -DA:233,15566 -BRDA:233,1,0,4391 -DA:234,4391 -DA:236,15566 -DA:238,15175 -DA:239,15175 -DA:240,15175 -DA:241,15175 -DA:242,15175 -DA:245,15175 -DA:246,15175 -DA:256,15175 -DA:257,15175 -DA:260,33050 +FNDA:33363,AgreementSettlerHandler.createAgreement +DA:227,33363 +DA:228,33363 +DA:229,33363 +DA:230,33363 +DA:232,15574 +DA:233,15574 +BRDA:233,1,0,4369 +DA:234,4369 +DA:236,15574 +DA:238,15190 +DA:239,15190 +DA:240,15190 +DA:241,15190 +DA:242,15190 +DA:245,15190 +DA:246,15190 +DA:256,15190 +DA:257,15190 +DA:260,33082 FN:260,AgreementSettlerHandler.settle -FNDA:33050,AgreementSettlerHandler.settle -DA:261,33050 -DA:262,29331 -DA:263,29331 -DA:264,29331 +FNDA:33082,AgreementSettlerHandler.settle +DA:261,33082 +DA:262,29339 +DA:263,29339 +DA:264,29339 DA:266,0 -DA:267,6190 +DA:267,6180 DA:268,3 -DA:271,6187 -DA:272,6187 -DA:273,6187 -DA:274,6187 -DA:276,6187 -DA:277,6187 -DA:278,6187 -DA:280,6187 -DA:281,6187 -DA:282,6187 -DA:285,33676 +DA:271,6177 +DA:272,6177 +DA:273,6177 +DA:274,6177 +DA:276,6177 +DA:277,6177 +DA:278,6177 +DA:280,6177 +DA:281,6177 +DA:282,6177 +DA:285,33655 FN:285,AgreementSettlerHandler.quit -FNDA:33676,AgreementSettlerHandler.quit -DA:286,33676 -DA:287,29658 -DA:288,29658 -DA:289,29658 -DA:291,6524 -DA:292,6524 -DA:293,6524 -DA:295,6524 -DA:296,6524 -DA:298,6524 -DA:299,6524 +FNDA:33655,AgreementSettlerHandler.quit +DA:286,33655 +DA:287,29625 +DA:288,29625 +DA:289,29625 +DA:291,6535 +DA:292,6535 +DA:293,6535 +DA:295,6535 +DA:296,6535 +DA:298,6535 +DA:299,6535 DA:302,0 FN:302,AgreementSettlerHandler.proofsLength FNDA:0,AgreementSettlerHandler.proofsLength @@ -3331,18 +3331,18 @@ DA:328,0 DA:329,0 DA:330,0 DA:331,0 -DA:335,15175 +DA:335,15190 FN:335,AgreementSettlerHandler._buildParties -FNDA:15175,AgreementSettlerHandler._buildParties -DA:336,15175 -DA:337,15175 -DA:338,52225 -DA:342,33374 +FNDA:15190,AgreementSettlerHandler._buildParties +DA:336,15190 +DA:337,15190 +DA:338,52269 +DA:342,33363 FN:342,AgreementSettlerHandler._penaltyBps -FNDA:33374,AgreementSettlerHandler._penaltyBps -DA:343,33374 -DA:344,9396 -DA:345,9396 +FNDA:33363,AgreementSettlerHandler._penaltyBps +DA:343,33363 +DA:344,9357 +DA:345,9357 FNF:15 FNH:8 LF:85 @@ -3783,14 +3783,14 @@ DA:9,5 FN:9,LedgerUpgradeableHarness.initialize FNDA:5,LedgerUpgradeableHarness.initialize DA:10,0 -DA:13,8745 +DA:13,8729 FN:13,LedgerUpgradeableHarness.setEntry -FNDA:8745,LedgerUpgradeableHarness.setEntry -DA:14,8745 -DA:17,8583 +FNDA:8729,LedgerUpgradeableHarness.setEntry +DA:14,8729 +DA:17,8590 FN:17,LedgerUpgradeableHarness.sumEntry -FNDA:8583,LedgerUpgradeableHarness.sumEntry -DA:18,8583 +FNDA:8590,LedgerUpgradeableHarness.sumEntry +DA:18,8590 DA:21,364 FN:21,LedgerUpgradeableHarness.subEntry FNDA:364,LedgerUpgradeableHarness.subEntry @@ -3799,37 +3799,37 @@ DA:93,1 FN:93,LedgerUpgradeableHandler.constructor FNDA:1,LedgerUpgradeableHandler.constructor DA:94,1 -DA:97,8491 +DA:97,8473 FN:97,LedgerUpgradeableHandler.setEntry -FNDA:8491,LedgerUpgradeableHandler.setEntry -DA:98,8491 -DA:99,8486 -DA:101,8486 -DA:102,8486 -BRDA:102,1,0,8486 -DA:103,8486 -DA:104,8486 -DA:106,8486 -DA:109,8340 +FNDA:8473,LedgerUpgradeableHandler.setEntry +DA:98,8473 +DA:99,8470 +DA:101,8470 +DA:102,8470 +BRDA:102,1,0,8470 +DA:103,8470 +DA:104,8470 +DA:106,8470 +DA:109,8348 FN:109,LedgerUpgradeableHandler.sumEntry -FNDA:8340,LedgerUpgradeableHandler.sumEntry -DA:110,8340 -DA:112,8326 -DA:113,8326 +FNDA:8348,LedgerUpgradeableHandler.sumEntry +DA:110,8348 +DA:112,8333 +DA:113,8333 DA:114,0 -DA:116,8326 -DA:118,8326 -BRDA:118,3,0,8326 -DA:119,8326 -DA:120,8326 -DA:122,8326 -DA:125,8194 +DA:116,8333 +DA:118,8333 +BRDA:118,3,0,8333 +DA:119,8333 +DA:120,8333 +DA:122,8333 +DA:125,8204 FN:125,LedgerUpgradeableHandler.subEntry -FNDA:8194,LedgerUpgradeableHandler.subEntry -DA:126,8194 -DA:128,8181 -DA:129,8181 -DA:130,8181 +FNDA:8204,LedgerUpgradeableHandler.subEntry +DA:126,8204 +DA:128,8191 +DA:129,8191 +DA:130,8191 DA:132,107 DA:134,107 BRDA:134,6,0,107 @@ -3862,10 +3862,10 @@ DA:16,13 FN:16,LockOperatorHarness.initialize FNDA:13,LockOperatorHarness.initialize DA:17,0 -DA:20,21336 +DA:20,21337 FN:20,LockOperatorHarness.boostLedger -FNDA:21336,LockOperatorHarness.boostLedger -DA:21,21336 +FNDA:21337,LockOperatorHarness.boostLedger +DA:21,21337 DA:24,6249 FN:24,LockOperatorHarness.lock FNDA:6249,LockOperatorHarness.lock @@ -3896,40 +3896,40 @@ FNDA:3,LockOperatorHandler.constructor DA:254,3 DA:255,3 DA:256,9 -DA:260,692242 +DA:260,692279 FN:260,LockOperatorHandler.seedLedger -FNDA:692242,LockOperatorHandler.seedLedger -DA:261,692242 -DA:262,20817 -DA:263,20817 -DA:264,20817 -DA:265,20817 -DA:268,692334 +FNDA:692279,LockOperatorHandler.seedLedger +DA:261,692279 +DA:262,20818 +DA:263,20818 +DA:264,20818 +DA:265,20818 +DA:268,692353 FN:268,LockOperatorHandler.lock -FNDA:692334,LockOperatorHandler.lock -DA:269,692334 -DA:270,20769 -DA:271,20769 -DA:272,20769 +FNDA:692353,LockOperatorHandler.lock +DA:269,692353 +DA:270,20768 +DA:271,20768 +DA:272,20768 DA:274,5728 DA:275,5728 DA:277,5728 DA:278,5728 -DA:281,692567 +DA:281,692563 FN:281,LockOperatorHandler.release -FNDA:692567,LockOperatorHandler.release -DA:282,692567 -DA:283,20848 -DA:284,20848 -DA:285,20848 +FNDA:692563,LockOperatorHandler.release +DA:282,692563 +DA:283,20847 +DA:284,20847 +DA:285,20847 DA:287,1677 DA:288,1677 DA:290,1677 DA:291,1677 -DA:294,692932 +DA:294,692956 FN:294,LockOperatorHandler.claim -FNDA:692932,LockOperatorHandler.claim -DA:295,692932 +FNDA:692956,LockOperatorHandler.claim +DA:295,692956 DA:296,611 DA:297,611 DA:298,611 @@ -3975,22 +3975,22 @@ DA:14,50824 FN:14,QuorumUpgradeableHarness.statusOf FNDA:50824,QuorumUpgradeableHarness.statusOf DA:15,50824 -DA:18,10624 +DA:18,10581 FN:18,QuorumUpgradeableHarness.register -FNDA:10624,QuorumUpgradeableHarness.register -DA:19,10624 -DA:22,307 +FNDA:10581,QuorumUpgradeableHarness.register +DA:19,10581 +DA:22,313 FN:22,QuorumUpgradeableHarness.approve -FNDA:307,QuorumUpgradeableHarness.approve -DA:23,307 -DA:26,34 +FNDA:313,QuorumUpgradeableHarness.approve +DA:23,313 +DA:26,36 FN:26,QuorumUpgradeableHarness.blockEntry -FNDA:34,QuorumUpgradeableHarness.blockEntry -DA:27,34 -DA:30,295 +FNDA:36,QuorumUpgradeableHarness.blockEntry +DA:27,36 +DA:30,294 FN:30,QuorumUpgradeableHarness.quit -FNDA:295,QuorumUpgradeableHarness.quit -DA:31,295 +FNDA:294,QuorumUpgradeableHarness.quit +DA:31,294 DA:34,2 FN:34,QuorumUpgradeableHarness.revoke FNDA:2,QuorumUpgradeableHarness.revoke @@ -3999,39 +3999,39 @@ DA:138,2 FN:138,QuorumHandler.constructor FNDA:2,QuorumHandler.constructor DA:139,2 -DA:142,10145 +DA:142,10102 FN:142,QuorumHandler.register -FNDA:10145,QuorumHandler.register -DA:143,10145 -DA:144,10145 -DA:145,10105 -DA:146,10105 -DA:149,9755 +FNDA:10102,QuorumHandler.register +DA:143,10102 +DA:144,10102 +DA:145,10062 +DA:146,10062 +DA:149,9833 FN:149,QuorumHandler.approve -FNDA:9755,QuorumHandler.approve -DA:150,9755 -DA:151,9755 -DA:152,48 -DA:153,48 -DA:156,10174 +FNDA:9833,QuorumHandler.approve +DA:150,9833 +DA:151,9833 +DA:152,54 +DA:153,54 +DA:156,10167 FN:156,QuorumHandler.quit -FNDA:10174,QuorumHandler.quit -DA:157,10174 -DA:158,10174 -DA:159,37 -DA:160,37 -DA:163,10068 +FNDA:10167,QuorumHandler.quit +DA:157,10167 +DA:158,10167 +DA:159,36 +DA:160,36 +DA:163,10073 FN:163,QuorumHandler.blockEntry -FNDA:10068,QuorumHandler.blockEntry -DA:164,10068 -DA:165,10068 -DA:166,32 -DA:167,32 -DA:170,9908 +FNDA:10073,QuorumHandler.blockEntry +DA:164,10073 +DA:165,10073 +DA:166,34 +DA:167,34 +DA:170,9875 FN:170,QuorumHandler.revoke -FNDA:9908,QuorumHandler.revoke -DA:171,9908 -DA:172,9908 +FNDA:9875,QuorumHandler.revoke +DA:171,9875 +DA:172,9875 DA:173,0 DA:174,0 DA:177,0 @@ -4046,14 +4046,14 @@ DA:185,0 FN:185,QuorumHandler.expectedStatus FNDA:0,QuorumHandler.expectedStatus DA:186,0 -DA:189,10222 +DA:189,10186 FN:189,QuorumHandler._update -FNDA:10222,QuorumHandler._update -DA:190,10222 -BRDA:190,5,0,10105 -DA:191,10105 -DA:192,10105 -DA:194,10222 +FNDA:10186,QuorumHandler._update +DA:190,10186 +BRDA:190,5,0,10062 +DA:191,10062 +DA:192,10062 +DA:194,10186 DA:197,50050 FN:197,QuorumHandler._normalize FNDA:50050,QuorumHandler._normalize diff --git a/test/libraries/FeesOps.t.sol b/test/libraries/FeesOps.t.sol new file mode 100644 index 0000000..b931f7c --- /dev/null +++ b/test/libraries/FeesOps.t.sol @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import "forge-std/Test.sol"; + +import { FeesOps } from "contracts/core/libraries/FeesOps.sol"; +import { C } from "contracts/core/primitives/Constants.sol"; + +contract FeesOpsHarness { + function isBasePoint(uint256 fee) external pure returns (bool) { + return FeesOps.isBasePoint(fee); + } + + function isNominal(uint256 fee) external pure returns (bool) { + return FeesOps.isNominal(fee); + } + + function perOf(uint256 amount, uint256 bps) external pure returns (uint256) { + return FeesOps.perOf(amount, bps); + } + + function calcBps(uint256 percentage) external pure returns (uint256) { + return FeesOps.calcBps(percentage); + } +} + +contract FeesOpsTest is Test { + FeesOpsHarness harness; + + function setUp() public { + harness = new FeesOpsHarness(); + } + + function test_IsBasePoint_TrueWhenWithinBpsMax() public { + assertTrue(harness.isBasePoint(C.BPS_MAX), "BPS max should be valid"); + assertTrue(harness.isBasePoint(0), "Zero should be valid bps"); + } + + function test_IsBasePoint_FalseWhenAboveMax() public { + assertFalse(harness.isBasePoint(C.BPS_MAX + 1), "Above max should be invalid"); + } + + function test_IsNominal_TrueWhenWithinScale() public { + assertTrue(harness.isNominal(C.SCALE_FACTOR), "Scale factor should be valid nominal"); + assertTrue(harness.isNominal(0), "Zero should be valid nominal"); + } + + function test_IsNominal_FalseWhenAboveScale() public { + assertFalse(harness.isNominal(C.SCALE_FACTOR + 1), "Above scale should be invalid nominal"); + } + + function test_PerOf_ComputesPercentage() public { + uint256 amount = 1_000 ether; + uint256 bps = 250; // 2.5% + uint256 expected = (amount * bps) / C.BPS_MAX; + assertEq(harness.perOf(amount, bps), expected, "Percentage calculation mismatch"); + } + + function test_PerOf_RevertsWhen_BpsAboveMax() public { + vm.expectRevert(bytes("BPS cannot be greater than 10_000")); + harness.perOf(1, C.BPS_MAX + 1); + } + + function test_CalcBps_ComputesNominalToBps() public { + uint256 per = 5; + assertEq(harness.calcBps(per), per * C.SCALE_FACTOR, "calcBps mismatch"); + } + + function testFuzz_PerOfMatchesManual(uint256 amount, uint256 bps) public { + amount = bound(amount, 0, type(uint128).max); + bps = bound(bps, 0, C.BPS_MAX); + + uint256 expected = (amount * bps) / C.BPS_MAX; + assertEq(harness.perOf(amount, bps), expected, "Fuzz percentage mismatch"); + } + + function testFuzz_CalcBpsInverse(uint256 per) public { + per = bound(per, 0, 1_000_000); + uint256 bps = harness.calcBps(per); + assertEq(bps / C.SCALE_FACTOR, per, "calcBps inverse mismatch"); + } +} + +contract FeesOpsHandler is Test { + FeesOpsHarness public immutable harness; + + uint256 internal totalAmount; + uint256 internal lastPercentage; + + constructor(FeesOpsHarness harness_) { + harness = harness_; + } + + function recordPerOf(uint256 amount, uint256 bps) external { + bps = bound(bps, 0, C.BPS_MAX); + amount = bound(amount, 0, type(uint128).max); + uint256 result = harness.perOf(amount, bps); + totalAmount += result; + } + + function recordCalcBps(uint256 per) external { + per = bound(per, 0, 1_000_000); + lastPercentage = harness.calcBps(per); + } + + function reset() external { + totalAmount = 0; + lastPercentage = 0; + } +} + +contract FeesOpsInvariantTest is Test { + FeesOpsHarness harness; + FeesOpsHandler handler; + + function setUp() public { + harness = new FeesOpsHarness(); + handler = new FeesOpsHandler(harness); + targetContract(address(handler)); + } + + function invariant_TotalAmountWithinBounds() external view { + assertLe(handler.totalAmount(), type(uint256).max, "Total amount overflowed"); + } + + function invariant_LastPercentageValid() external view { + assertEq(handler.lastPercentage() % C.SCALE_FACTOR, 0, "calcBps outputs should be multiples of scale factor"); + } +} From 016406f5c6fdead99c8517b9fff7d05e8c316498 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Mon, 29 Sep 2025 14:26:29 -0600 Subject: [PATCH 19/33] test: coverage upgrade --- .github/workflows/cov-badge.svg | 2 +- contracts/rights/RightsPolicyAuthorizer.sol | 8 +- contracts/rights/RightsPolicyManager.sol | 4 +- lcov.info | 2125 +++++++++++-------- test/finance/AgreementManager.t.sol | 4 +- test/libraries/FeesOps.t.sol | 22 +- test/libraries/RollingOps.t.sol | 363 ++-- 7 files changed, 1420 insertions(+), 1108 deletions(-) diff --git a/.github/workflows/cov-badge.svg b/.github/workflows/cov-badge.svg index 01d7808..a7eae2a 100644 --- a/.github/workflows/cov-badge.svg +++ b/.github/workflows/cov-badge.svg @@ -1 +1 @@ -coveragecoverage56.47%56.47% \ No newline at end of file +coveragecoverage58.25%58.25% \ No newline at end of file diff --git a/contracts/rights/RightsPolicyAuthorizer.sol b/contracts/rights/RightsPolicyAuthorizer.sol index b884326..806834a 100644 --- a/contracts/rights/RightsPolicyAuthorizer.sol +++ b/contracts/rights/RightsPolicyAuthorizer.sol @@ -11,7 +11,6 @@ import { ReentrancyGuardTransientUpgradeable } from "@openzeppelin/contracts-upg import { IRightsPolicyAuthorizer } from "@synaps3/core/interfaces/rights/IRightsPolicyAuthorizer.sol"; import { IPolicyAuditorVerifiable } from "@synaps3/core/interfaces/policies/IPolicyAuditorVerifiable.sol"; import { IPolicy } from "@synaps3/core/interfaces/policies/IPolicy.sol"; -import { ArrayOps } from "@synaps3/core/libraries/ArrayOps.sol"; import { LoopOps } from "@synaps3/core/libraries/LoopOps.sol"; /// @title RightsPolicyAuthorizer @@ -26,7 +25,6 @@ contract RightsPolicyAuthorizer is IRightsPolicyAuthorizer { using LoopOps for uint256; - using ArrayOps for address[]; using EnumerableSet for EnumerableSet.AddressSet; /// KIM: any initialization here is ephemeral and not included in bytecode.. @@ -41,6 +39,10 @@ contract RightsPolicyAuthorizer is /// @dev Mapping to store the delegated rights for each policy contract (address) mapping(address => EnumerableSet.AddressSet) private _authorizedPolicies; + mapping(address => uint256) private _planIdx; // pos+1 + mapping(address => address[]) private _plan; + + /// @notice Emitted when rights are granted to a policy for content. /// @param policy The policy contract address granted rights. /// @param holder The address of the asset rights holder. @@ -147,7 +149,7 @@ contract RightsPolicyAuthorizer is // it may contain uninitialized elements (`address(0)`) if some policies were invalid. // - The variable `j` represents the number of valid policies that passed the filtering process. // - To ensure that the returned array contains only these valid policies and no extra default values, - // we call `slice(j)`, which creates a new array of exact length `j` and copies only + // we slice, which creates a new array of exact length `j` and copies only // the first `j` elements from `filtered`. // - This prevents returning an array with trailing `address(0)` values, ensuring data integrity // and reducing unnecessary gas costs when the array is processed elsewhere. diff --git a/contracts/rights/RightsPolicyManager.sol b/contracts/rights/RightsPolicyManager.sol index 543a67c..5175682 100644 --- a/contracts/rights/RightsPolicyManager.sol +++ b/contracts/rights/RightsPolicyManager.sol @@ -181,7 +181,7 @@ contract RightsPolicyManager is return filtered; } - /// @notice Retrieves the list of policies associated with a specific account and content ID. + /// @notice Retrieves the list of policies associated with a specific account. /// @param account The address of the account for which policies are being retrieved. function getPolicies(address account) public view returns (address[] memory) { // https://docs.openzeppelin.com/contracts/5.x/api/utils#EnumerableSet-values-struct-EnumerableSet-AddressSet- @@ -219,7 +219,7 @@ contract RightsPolicyManager is /// @dev Verifies access permissions by calling the policy contract. /// @param account The address of the user requesting access. /// @param policy The address of the policy contract. - /// @param criteria Encoded parameters required for access verification. + /// @param criteria Encoded parameters required for access verification. eg. assetId, rightsHolder /// @return `true` if the policy grants access, otherwise `false`. function _verifyPolicyAccess(address account, address policy, bytes memory criteria) private view returns (bool) { bytes memory callData = abi.encodeCall(IPolicy.isAccessAllowed, (account, criteria)); diff --git a/lcov.info b/lcov.info index 850f63b..d05933d 100644 --- a/lcov.info +++ b/lcov.info @@ -35,40 +35,40 @@ FNDA:34,AssetReferendum.initialize DA:64,0 DA:65,0 DA:66,34 -DA:72,58261 +DA:72,58206 FN:72,AssetReferendum.submit -FNDA:58261,AssetReferendum.submit -DA:74,58261 -DA:75,58261 +FNDA:58206,AssetReferendum.submit +DA:74,58206 +DA:75,58206 BRDA:75,0,0,- -DA:76,58261 -DA:77,58261 -DA:99,2127 +DA:76,58206 +DA:77,58206 +DA:99,2122 FN:99,AssetReferendum.revoke -FNDA:2127,AssetReferendum.revoke -DA:100,2127 -DA:101,2127 -DA:106,4178 +FNDA:2122,AssetReferendum.revoke +DA:100,2122 +DA:101,2122 +DA:106,4180 FN:106,AssetReferendum.reject -FNDA:4178,AssetReferendum.reject -DA:107,4178 -DA:108,4178 -DA:113,49404 +FNDA:4180,AssetReferendum.reject +DA:107,4180 +DA:108,4180 +DA:113,49355 FN:113,AssetReferendum.approve -FNDA:49404,AssetReferendum.approve -DA:114,49404 -DA:115,49404 -DA:121,45649 +FNDA:49355,AssetReferendum.approve +DA:114,49355 +DA:115,49355 +DA:121,45602 FN:121,AssetReferendum.isApproved -FNDA:45649,AssetReferendum.isApproved -DA:122,45649 -DA:123,45649 -DA:124,45649 -DA:126,45649 -DA:131,46421 +FNDA:45602,AssetReferendum.isApproved +DA:122,45602 +DA:123,45602 +DA:124,45602 +DA:126,45602 +DA:131,46374 FN:131,AssetReferendum.isActive -FNDA:46421,AssetReferendum.isActive -DA:132,46421 +FNDA:46374,AssetReferendum.isActive +DA:132,46374 DA:138,0 FN:138,AssetReferendum._authorizeUpgrade FNDA:0,AssetReferendum._authorizeUpgrade @@ -81,16 +81,16 @@ BRH:0 end_of_record TN: SF:contracts/assets/AssetRegistry.sol -DA:69,44877 +DA:69,44830 FN:69,AssetRegistry.onlyApprovedAsset -FNDA:44877,AssetRegistry.onlyApprovedAsset -DA:70,44877 +FNDA:44830,AssetRegistry.onlyApprovedAsset +DA:70,44830 BRDA:70,0,0,1 DA:71,1 -DA:78,8914 +DA:78,8984 FN:78,AssetRegistry.onlyOwner -FNDA:8914,AssetRegistry.onlyOwner -DA:79,8914 +FNDA:8984,AssetRegistry.onlyOwner +DA:79,8984 BRDA:79,1,0,- DA:80,0 DA:87,21 @@ -110,34 +110,34 @@ DA:108,0 FN:108,AssetRegistry.supportsInterface FNDA:0,AssetRegistry.supportsInterface DA:111,0 -DA:127,44876 +DA:127,44829 FN:127,AssetRegistry.register -FNDA:44876,AssetRegistry.register -DA:128,44876 -DA:129,44875 -DA:130,44876 -DA:136,8504 +FNDA:44829,AssetRegistry.register +DA:128,44829 +DA:129,44828 +DA:130,44829 +DA:136,8446 FN:136,AssetRegistry.revoke -FNDA:8504,AssetRegistry.revoke -DA:137,8504 -DA:139,8504 -DA:140,8504 -DA:141,8504 -DA:147,25773 +FNDA:8446,AssetRegistry.revoke +DA:137,8446 +DA:139,8446 +DA:140,8446 +DA:141,8446 +DA:147,25871 FN:147,AssetRegistry.transfer -FNDA:25773,AssetRegistry.transfer -DA:148,25773 -DA:149,25773 -DA:156,8914 +FNDA:25871,AssetRegistry.transfer +DA:148,25871 +DA:149,25871 +DA:156,8984 FN:156,AssetRegistry.switchState -FNDA:8914,AssetRegistry.switchState -DA:157,8914 -DA:159,8914 -DA:161,8914 -DA:165,79153 +FNDA:8984,AssetRegistry.switchState +DA:157,8984 +DA:159,8984 +DA:161,8984 +DA:165,79146 FN:165,AssetRegistry._update -FNDA:79153,AssetRegistry._update -DA:170,79153 +FNDA:79146,AssetRegistry._update +DA:170,79146 DA:174,0 FN:174,AssetRegistry._increaseBalance FNDA:0,AssetRegistry._increaseBalance @@ -145,16 +145,16 @@ DA:178,0 DA:183,0 FN:183,AssetRegistry._authorizeUpgrade FNDA:0,AssetRegistry._authorizeUpgrade -DA:186,47073 +DA:186,47051 FN:186,AssetRegistry._enableAsset -FNDA:47073,AssetRegistry._enableAsset -DA:187,47073 -DA:188,47073 -DA:192,15220 +FNDA:47051,AssetRegistry._enableAsset +DA:187,47051 +DA:188,47051 +DA:192,15207 FN:192,AssetRegistry._disableAsset -FNDA:15220,AssetRegistry._disableAsset -DA:193,15220 -DA:194,15220 +FNDA:15207,AssetRegistry._disableAsset +DA:193,15207 +DA:194,15207 FNF:14 FNH:11 LF:44 @@ -164,10 +164,10 @@ BRH:1 end_of_record TN: SF:contracts/assets/AssetSafe.sol -DA:40,22522 +DA:40,22469 FN:40,AssetSafe.onlyHolder -FNDA:22522,AssetSafe.onlyHolder -DA:41,22522 +FNDA:22469,AssetSafe.onlyHolder +DA:41,22469 BRDA:41,0,0,257 DA:42,257 DA:48,10 @@ -188,19 +188,19 @@ DA:71,258 FN:71,AssetSafe.getContent FNDA:258,AssetSafe.getContent DA:72,258 -DA:80,22265 +DA:80,22212 FN:80,AssetSafe.setContent -FNDA:22265,AssetSafe.setContent -DA:81,22265 -DA:82,22265 -DA:83,22265 +FNDA:22212,AssetSafe.setContent +DA:81,22212 +DA:82,22212 +DA:83,22212 DA:88,0 FN:88,AssetSafe._authorizeUpgrade FNDA:0,AssetSafe._authorizeUpgrade -DA:95,22523 +DA:95,22470 FN:95,AssetSafe._computeComposedKey -FNDA:22523,AssetSafe._computeComposedKey -DA:96,22523 +FNDA:22470,AssetSafe._computeComposedKey +DA:96,22470 FNF:8 FNH:7 LF:20 @@ -227,29 +227,29 @@ BRH:0 end_of_record TN: SF:contracts/core/libraries/FeesOps.sol -DA:12,12654 +DA:12,12711 FN:12,FeesOps.isBasePoint -FNDA:12654,FeesOps.isBasePoint -DA:14,12654 -DA:19,12650 +FNDA:12711,FeesOps.isBasePoint +DA:14,12711 +DA:19,12653 FN:19,FeesOps.isNominal -FNDA:12650,FeesOps.isNominal -DA:21,12650 -DA:27,29714 +FNDA:12653,FeesOps.isNominal +DA:21,12653 +DA:27,46395 FN:27,FeesOps.perOf -FNDA:29714,FeesOps.perOf -DA:31,29714 +FNDA:46395,FeesOps.perOf +DA:31,46395 BRDA:31,0,0,- BRDA:31,0,1,- -DA:32,29714 -DA:37,0 +DA:32,46395 +DA:37,17151 FN:37,FeesOps.calcBps -FNDA:0,FeesOps.calcBps -DA:38,0 +FNDA:17151,FeesOps.calcBps +DA:38,17151 FNF:4 -FNH:3 +FNH:4 LF:9 -LH:7 +LH:9 BRF:2 BRH:0 end_of_record @@ -262,10 +262,10 @@ DA:27,15750 DA:28,15750 BRDA:28,0,0,- DA:29,0 -DA:37,30938 +DA:37,36420 FN:37,FinancialOps._erc20Transfer -FNDA:30938,FinancialOps._erc20Transfer -DA:38,30938 +FNDA:36420,FinancialOps._erc20Transfer +DA:38,36420 DA:45,18856 FN:45,FinancialOps._nativeDeposit FNDA:18856,FinancialOps._nativeDeposit @@ -273,13 +273,13 @@ DA:46,18856 BRDA:46,1,0,1 DA:47,1 DA:51,0 -DA:60,43439 +DA:60,53035 FN:60,FinancialOps._erc20Deposit -FNDA:43439,FinancialOps._erc20Deposit -DA:61,43439 -BRDA:61,2,0,2 -DA:62,2 -DA:68,43437 +FNDA:53035,FinancialOps._erc20Deposit +DA:61,53035 +BRDA:61,2,0,3 +DA:62,3 +DA:68,53032 DA:69,0 DA:78,3 FN:78,FinancialOps.increaseAllowance @@ -288,43 +288,43 @@ DA:79,3 BRDA:79,3,0,2 DA:80,2 DA:83,1 -DA:92,43441 +DA:92,53037 FN:92,FinancialOps.allowance -FNDA:43441,FinancialOps.allowance -DA:93,43441 +FNDA:53037,FinancialOps.allowance +DA:93,53037 BRDA:93,4,0,1 DA:94,1 -DA:97,43440 -DA:106,62297 +DA:97,53036 +DA:106,71893 FN:106,FinancialOps.safeDeposit -FNDA:62297,FinancialOps.safeDeposit -DA:107,62297 +FNDA:71893,FinancialOps.safeDeposit +DA:107,71893 BRDA:107,5,0,2 DA:108,2 -DA:111,62295 +DA:111,71891 BRDA:111,6,0,18856 DA:112,18856 -DA:115,43439 -DA:121,46952 +DA:115,53035 +DA:121,52434 FN:121,FinancialOps.balanceOf -FNDA:46952,FinancialOps.balanceOf -DA:122,46952 +FNDA:52434,FinancialOps.balanceOf +DA:122,52434 BRDA:122,7,0,15752 DA:123,15752 -DA:126,31200 -DA:134,46692 +DA:126,36682 +DA:134,52174 FN:134,FinancialOps.transfer -FNDA:46692,FinancialOps.transfer -DA:135,46692 +FNDA:52174,FinancialOps.transfer +DA:135,52174 BRDA:135,8,0,2 DA:136,2 -DA:139,46690 +DA:139,52172 BRDA:139,9,0,2 DA:140,2 -DA:143,46688 +DA:143,52170 BRDA:143,10,0,15750 DA:144,15750 -DA:147,30938 +DA:147,36420 FNF:9 FNH:9 LF:41 @@ -364,83 +364,83 @@ BRH:0 end_of_record TN: SF:contracts/core/libraries/RollingOps.sol -DA:36,6 +DA:36,25658 FN:36,RollingOps.configure -FNDA:6,RollingOps.configure -DA:37,6 +FNDA:25658,RollingOps.configure +DA:37,25658 BRDA:37,0,0,1 -DA:38,5 -DA:42,33 +DA:38,25657 +DA:42,35225 FN:42,RollingOps.roll -FNDA:33,RollingOps.roll -DA:43,33 -DA:47,6 +FNDA:35225,RollingOps.roll +DA:43,35225 +DA:47,2545 FN:47,RollingOps.contains -FNDA:6,RollingOps.contains -DA:48,6 -DA:52,2 +FNDA:2545,RollingOps.contains +DA:48,2545 +DA:52,260 FN:52,RollingOps.length -FNDA:2,RollingOps.length -DA:53,2 -DA:57,3 +FNDA:260,RollingOps.length +DA:53,260 +DA:57,2 FN:57,RollingOps.window -FNDA:3,RollingOps.window -DA:58,3 -DA:62,6 +FNDA:2,RollingOps.window +DA:58,2 +DA:62,2314 FN:62,RollingOps.at -FNDA:6,RollingOps.at -DA:63,6 -DA:67,3 +FNDA:2314,RollingOps.at +DA:63,2314 +DA:67,50051 FN:67,RollingOps.values -FNDA:3,RollingOps.values -DA:68,3 -DA:69,3 +FNDA:50051,RollingOps.values +DA:68,50051 +DA:69,50051 DA:72,0 -DA:75,3 -DA:84,33 +DA:75,50051 +DA:84,35225 FN:84,RollingOps._roll -FNDA:33,RollingOps._roll -DA:87,33 -BRDA:87,1,0,9 -DA:88,9 -DA:91,33 -DA:95,33 +FNDA:35225,RollingOps._roll +DA:87,35225 +BRDA:87,1,0,12271 +DA:88,12271 +DA:91,35225 +DA:95,35225 FN:95,RollingOps._rollin -FNDA:33,RollingOps._rollin -DA:96,33 -DA:97,33 -DA:101,9 +FNDA:35225,RollingOps._rollin +DA:96,35225 +DA:97,35225 +DA:101,12271 FN:101,RollingOps._rollout -FNDA:9,RollingOps._rollout -DA:103,9 -DA:104,9 -DA:106,9 -DA:110,20 -DA:111,20 -DA:114,20 -DA:119,9 -DA:123,6 +FNDA:12271,RollingOps._rollout +DA:103,12271 +DA:104,12271 +DA:106,12271 +DA:110,65856 +DA:111,65856 +DA:114,65856 +DA:119,12271 +DA:123,2545 FN:123,RollingOps._contains -FNDA:6,RollingOps._contains -DA:124,6 -DA:128,74 +FNDA:2545,RollingOps._contains +DA:124,2545 +DA:128,73024 FN:128,RollingOps._length -FNDA:74,RollingOps._length -DA:129,74 -DA:133,6 +FNDA:73024,RollingOps._length +DA:129,73024 +DA:133,2314 FN:133,RollingOps._at -FNDA:6,RollingOps._at -DA:134,6 +FNDA:2314,RollingOps._at +DA:134,2314 BRDA:134,2,0,1 -DA:135,5 -DA:139,65 +DA:135,2313 +DA:139,113354 FN:139,RollingOps._window -FNDA:65,RollingOps._window -DA:140,65 -DA:144,3 +FNDA:113354,RollingOps._window +DA:140,113354 +DA:144,50051 FN:144,RollingOps._values -FNDA:3,RollingOps._values -DA:145,3 +FNDA:50051,RollingOps._values +DA:145,50051 FNF:15 FNH:15 LF:44 @@ -450,43 +450,43 @@ BRH:3 end_of_record TN: SF:contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol -DA:29,54213 +DA:29,57969 FN:29,AccessControlledUpgradeable.onlyAdmin -FNDA:54213,AccessControlledUpgradeable.onlyAdmin -DA:34,54213 +FNDA:57969,AccessControlledUpgradeable.onlyAdmin +DA:34,57969 BRDA:34,0,0,258 DA:35,258 -DA:43,8830 +DA:43,8831 FN:43,AccessControlledUpgradeable.pause -FNDA:8830,AccessControlledUpgradeable.pause +FNDA:8831,AccessControlledUpgradeable.pause DA:44,0 -DA:50,7834 +DA:50,7835 FN:50,AccessControlledUpgradeable.unpause -FNDA:7834,AccessControlledUpgradeable.unpause +FNDA:7835,AccessControlledUpgradeable.unpause DA:51,0 -DA:59,253 +DA:59,281 FN:59,AccessControlledUpgradeable.__AccessControlled_init -FNDA:253,AccessControlledUpgradeable.__AccessControlled_init -DA:60,253 -DA:61,253 -DA:67,253 +FNDA:281,AccessControlledUpgradeable.__AccessControlled_init +DA:60,281 +DA:61,281 +DA:67,281 FN:67,AccessControlledUpgradeable.__AccessControlled_init_unchained -FNDA:253,AccessControlledUpgradeable.__AccessControlled_init_unchained -DA:68,253 +FNDA:281,AccessControlledUpgradeable.__AccessControlled_init_unchained +DA:68,281 BRDA:68,1,0,1 DA:69,1 -DA:72,252 -DA:73,252 -DA:80,100778 +DA:72,280 +DA:73,280 +DA:80,114141 FN:80,AccessControlledUpgradeable._hasRole -FNDA:100778,AccessControlledUpgradeable._hasRole -DA:81,100778 -DA:82,100778 -DA:83,100778 -DA:84,100778 -DA:88,101030 +FNDA:114141,AccessControlledUpgradeable._hasRole +DA:81,114141 +DA:82,114141 +DA:83,114141 +DA:84,114141 +DA:88,114421 FN:88,AccessControlledUpgradeable._getAccessControlStorage -FNDA:101030,AccessControlledUpgradeable._getAccessControlStorage +FNDA:114421,AccessControlledUpgradeable._getAccessControlStorage DA:90,0 FNF:7 FNH:7 @@ -497,9 +497,9 @@ BRH:2 end_of_record TN: SF:contracts/core/primitives/upgradeable/AllowanceOperatorUpgradeable.sol -DA:32,51 +DA:32,66 FN:32,AllowanceOperatorUpgradeable.__AllowanceOperator_init -FNDA:51,AllowanceOperatorUpgradeable.__AllowanceOperator_init +FNDA:66,AllowanceOperatorUpgradeable.__AllowanceOperator_init DA:33,0 DA:39,0 FN:39,AllowanceOperatorUpgradeable.__AllowanceOperator_init_unchained @@ -567,9 +567,9 @@ BRH:4 end_of_record TN: SF:contracts/core/primitives/upgradeable/BalanceOperatorUpgradeable.sol -DA:31,61 +DA:31,76 FN:31,BalanceOperatorUpgradeable.__BalanceOperator_init -FNDA:61,BalanceOperatorUpgradeable.__BalanceOperator_init +FNDA:76,BalanceOperatorUpgradeable.__BalanceOperator_init DA:32,0 DA:37,0 FN:37,BalanceOperatorUpgradeable.__BalanceOperator_init_unchained @@ -578,32 +578,32 @@ DA:42,260 FN:42,BalanceOperatorUpgradeable.getBalance FNDA:260,BalanceOperatorUpgradeable.getBalance DA:43,260 -DA:50,24731 +DA:50,34327 FN:50,BalanceOperatorUpgradeable._deposit -FNDA:24731,BalanceOperatorUpgradeable._deposit -DA:55,24731 -DA:56,24730 -DA:57,24731 +FNDA:34327,BalanceOperatorUpgradeable._deposit +DA:55,34327 +DA:56,34325 +DA:57,34327 DA:58,0 -DA:65,15368 +DA:65,20851 FN:65,BalanceOperatorUpgradeable._withdraw -FNDA:15368,BalanceOperatorUpgradeable._withdraw -DA:70,15368 -BRDA:70,0,0,1 -DA:71,15367 -DA:72,15367 -DA:73,15367 +FNDA:20851,BalanceOperatorUpgradeable._withdraw +DA:70,20851 +BRDA:70,0,0,2 +DA:71,20849 +DA:72,20849 +DA:73,20849 DA:74,0 -DA:81,7494 +DA:81,8042 FN:81,BalanceOperatorUpgradeable._transfer -FNDA:7494,BalanceOperatorUpgradeable._transfer -DA:86,7494 -BRDA:86,1,0,1 -DA:87,7493 +FNDA:8042,BalanceOperatorUpgradeable._transfer +DA:86,8042 +BRDA:86,1,0,2 +DA:87,8040 BRDA:87,2,0,1 -DA:89,7492 -DA:90,7492 -DA:91,7492 +DA:89,8039 +DA:90,8039 +DA:91,8039 DA:92,0 DA:97,0 FN:97,BalanceOperatorUpgradeable._getBalanceOperatorStorage @@ -624,24 +624,24 @@ FNDA:21,ERC721StatefulUpgradeable.__ERC721Stateful_init DA:31,0 FN:31,ERC721StatefulUpgradeable.__ERC721Stateful_init_unchained FNDA:0,ERC721StatefulUpgradeable.__ERC721Stateful_init_unchained -DA:35,47073 +DA:35,47051 FN:35,ERC721StatefulUpgradeable._activate -FNDA:47073,ERC721StatefulUpgradeable._activate -DA:36,47073 -DA:37,47073 -DA:42,15220 +FNDA:47051,ERC721StatefulUpgradeable._activate +DA:36,47051 +DA:37,47051 +DA:42,15207 FN:42,ERC721StatefulUpgradeable._deactivate -FNDA:15220,ERC721StatefulUpgradeable._deactivate -DA:43,15220 -DA:44,15220 -DA:50,9174 +FNDA:15207,ERC721StatefulUpgradeable._deactivate +DA:43,15207 +DA:44,15207 +DA:50,9244 FN:50,ERC721StatefulUpgradeable.isActive -FNDA:9174,ERC721StatefulUpgradeable.isActive -DA:51,9174 -DA:52,9174 -DA:56,71467 +FNDA:9244,ERC721StatefulUpgradeable.isActive +DA:51,9244 +DA:52,9244 +DA:56,71502 FN:56,ERC721StatefulUpgradeable._getERC721StateStorage -FNDA:71467,ERC721StatefulUpgradeable._getERC721StateStorage +FNDA:71502,ERC721StatefulUpgradeable._getERC721StateStorage DA:58,0 FNF:6 FNH:5 @@ -691,40 +691,40 @@ BRH:0 end_of_record TN: SF:contracts/core/primitives/upgradeable/LedgerUpgradeable.sol -DA:28,25705 +DA:28,28082 FN:28,LedgerUpgradeable.onlyValidOperation -FNDA:25705,LedgerUpgradeable.onlyValidOperation -DA:29,25705 +FNDA:28082,LedgerUpgradeable.onlyValidOperation +DA:29,28082 BRDA:29,0,0,4 -DA:36,168867 +DA:36,180665 FN:36,LedgerUpgradeable.getLedgerBalance -FNDA:168867,LedgerUpgradeable.getLedgerBalance -DA:37,168867 -DA:38,168867 -DA:45,168 +FNDA:180665,LedgerUpgradeable.getLedgerBalance +DA:37,180665 +DA:38,180665 +DA:45,213 FN:45,LedgerUpgradeable.__Ledger_init -FNDA:168,LedgerUpgradeable.__Ledger_init +FNDA:213,LedgerUpgradeable.__Ledger_init DA:50,0 FN:50,LedgerUpgradeable.__Ledger_init_unchained FNDA:0,LedgerUpgradeable.__Ledger_init_unchained -DA:57,8729 +DA:57,8712 FN:57,LedgerUpgradeable._setLedgerEntry -FNDA:8729,LedgerUpgradeable._setLedgerEntry -DA:58,8729 -DA:59,8729 -DA:67,116792 +FNDA:8712,LedgerUpgradeable._setLedgerEntry +DA:58,8712 +DA:59,8712 +DA:67,131570 FN:67,LedgerUpgradeable._sumLedgerEntry -FNDA:116792,LedgerUpgradeable._sumLedgerEntry -DA:68,116792 -DA:69,116792 -DA:77,52449 +FNDA:131570,LedgerUpgradeable._sumLedgerEntry +DA:68,131570 +DA:69,131570 +DA:77,63591 FN:77,LedgerUpgradeable._subLedgerEntry -FNDA:52449,LedgerUpgradeable._subLedgerEntry -DA:78,52449 -DA:79,52449 -DA:84,346837 +FNDA:63591,LedgerUpgradeable._subLedgerEntry +DA:78,63591 +DA:79,63591 +DA:84,384538 FN:84,LedgerUpgradeable._getLedgerStorage -FNDA:346837,LedgerUpgradeable._getLedgerStorage +FNDA:384538,LedgerUpgradeable._getLedgerStorage DA:86,0 FNF:8 FNH:7 @@ -735,58 +735,58 @@ BRH:1 end_of_record TN: SF:contracts/core/primitives/upgradeable/LockOperatorUpgradeable.sol -DA:28,51 +DA:28,66 FN:28,LockOperatorUpgradeable.__LockOperator_init -FNDA:51,LockOperatorUpgradeable.__LockOperator_init +FNDA:66,LockOperatorUpgradeable.__LockOperator_init DA:29,0 DA:35,0 FN:35,LockOperatorUpgradeable.__LockOperator_init_unchained FNDA:0,LockOperatorUpgradeable.__LockOperator_init_unchained -DA:44,28912 +DA:44,34022 FN:44,LockOperatorUpgradeable._lock -FNDA:28912,LockOperatorUpgradeable._lock -DA:49,28912 -BRDA:49,0,0,2 -DA:50,28910 -DA:51,28910 -DA:52,28910 +FNDA:34022,LockOperatorUpgradeable._lock +DA:49,34022 +BRDA:49,0,0,3 +DA:50,34019 +DA:51,34019 +DA:52,34019 DA:53,0 -DA:60,8726 +DA:60,11103 FN:60,LockOperatorUpgradeable._release -FNDA:8726,LockOperatorUpgradeable._release -DA:65,8726 +FNDA:11103,LockOperatorUpgradeable._release +DA:65,11103 BRDA:65,1,0,1 -DA:66,8725 -DA:67,8725 -DA:68,8725 +DA:66,11102 +DA:67,11102 +DA:68,11102 DA:69,0 -DA:78,13536 +DA:78,15763 FN:78,LockOperatorUpgradeable._claim -FNDA:13536,LockOperatorUpgradeable._claim -DA:83,13536 +FNDA:15763,LockOperatorUpgradeable._claim +DA:83,15763 BRDA:83,2,0,1 -DA:84,13535 -DA:85,13535 -DA:86,13535 +DA:84,15762 +DA:85,15762 +DA:86,15762 DA:87,0 -DA:95,22260 +DA:95,26864 FN:95,LockOperatorUpgradeable._subLockedAmount -FNDA:22260,LockOperatorUpgradeable._subLockedAmount -DA:96,22260 -DA:97,22260 -DA:105,28910 +FNDA:26864,LockOperatorUpgradeable._subLockedAmount +DA:96,26864 +DA:97,26864 +DA:105,34019 FN:105,LockOperatorUpgradeable._sumLockedAmount -FNDA:28910,LockOperatorUpgradeable._sumLockedAmount -DA:106,28910 -DA:107,28910 -DA:115,22262 +FNDA:34019,LockOperatorUpgradeable._sumLockedAmount +DA:106,34019 +DA:107,34019 +DA:115,26866 FN:115,LockOperatorUpgradeable._getLockedAmount -FNDA:22262,LockOperatorUpgradeable._getLockedAmount -DA:116,22262 -DA:117,22262 -DA:122,73432 +FNDA:26866,LockOperatorUpgradeable._getLockedAmount +DA:116,26866 +DA:117,26866 +DA:122,87749 FN:122,LockOperatorUpgradeable._getLockOperatorStorage -FNDA:73432,LockOperatorUpgradeable._getLockOperatorStorage +FNDA:87749,LockOperatorUpgradeable._getLockOperatorStorage DA:124,0 FNF:9 FNH:8 @@ -797,55 +797,55 @@ BRH:3 end_of_record TN: SF:contracts/core/primitives/upgradeable/QuorumUpgradeable.sol -DA:48,62 +DA:48,75 FN:48,QuorumUpgradeable.__Quorum_init -FNDA:62,QuorumUpgradeable.__Quorum_init +FNDA:75,QuorumUpgradeable.__Quorum_init DA:53,0 FN:53,QuorumUpgradeable.__Quorum_init_unchained FNDA:0,QuorumUpgradeable.__Quorum_init_unchained -DA:57,222441 +DA:57,260172 FN:57,QuorumUpgradeable._status -FNDA:222441,QuorumUpgradeable._status -DA:58,222441 -DA:59,222441 -DA:65,2129 +FNDA:260172,QuorumUpgradeable._status +DA:58,260172 +DA:59,260172 +DA:65,5832 FN:65,QuorumUpgradeable._revoke -FNDA:2129,QuorumUpgradeable._revoke -DA:66,2129 -DA:67,2129 -BRDA:67,0,0,1 -DA:68,2128 -DA:74,4214 +FNDA:5832,QuorumUpgradeable._revoke +DA:66,5832 +DA:67,5832 +BRDA:67,0,0,2 +DA:68,5830 +DA:74,4216 FN:74,QuorumUpgradeable._block -FNDA:4214,QuorumUpgradeable._block -DA:75,4214 -DA:76,4214 +FNDA:4216,QuorumUpgradeable._block +DA:75,4216 +DA:76,4216 BRDA:76,1,0,1 -DA:77,4213 -DA:82,49717 +DA:77,4215 +DA:82,59323 FN:82,QuorumUpgradeable._approve -FNDA:49717,QuorumUpgradeable._approve -DA:83,49717 -DA:84,49717 -BRDA:84,2,0,1 -DA:85,49716 -DA:90,294 +FNDA:59323,QuorumUpgradeable._approve +DA:83,59323 +DA:84,59323 +BRDA:84,2,0,2 +DA:85,59321 +DA:90,297 FN:90,QuorumUpgradeable._quit -FNDA:294,QuorumUpgradeable._quit -DA:91,294 -DA:92,294 +FNDA:297,QuorumUpgradeable._quit +DA:91,297 +DA:92,297 BRDA:92,3,0,1 -DA:93,293 -DA:98,68842 +DA:93,296 +DA:98,89326 FN:98,QuorumUpgradeable._register -FNDA:68842,QuorumUpgradeable._register -DA:99,68842 -DA:100,68842 -BRDA:100,4,0,1 -DA:101,68841 -DA:105,347637 +FNDA:89326,QuorumUpgradeable._register +DA:99,89326 +DA:100,89326 +BRDA:100,4,0,2 +DA:101,89324 +DA:105,419166 FN:105,QuorumUpgradeable._getRegistryStorage -FNDA:347637,QuorumUpgradeable._getRegistryStorage +FNDA:419166,QuorumUpgradeable._getRegistryStorage DA:107,0 FNF:9 FNH:8 @@ -1049,10 +1049,10 @@ BRDA:74,2,0,- DA:75,0 DA:78,51367 DA:79,51367 -DA:82,12408 -BRDA:82,3,0,12408 -DA:83,12408 -DA:84,12408 +DA:82,12471 +BRDA:82,3,0,12471 +DA:83,12471 +DA:84,12471 BRDA:84,4,0,1 DA:92,40 FN:92,Tollgate.constructor @@ -1063,24 +1063,24 @@ FN:98,Tollgate.initialize FNDA:40,Tollgate.initialize DA:99,0 DA:100,40 -DA:107,46102 +DA:107,45664 FN:107,Tollgate.isSupportedCurrency -FNDA:46102,Tollgate.isSupportedCurrency -DA:108,46102 +FNDA:45664,Tollgate.isSupportedCurrency +DA:108,45664 DA:114,257 FN:114,Tollgate.supportedCurrencies FNDA:257,Tollgate.supportedCurrencies DA:115,257 -DA:122,23953 +DA:122,23734 FN:122,Tollgate.getFees -FNDA:23953,Tollgate.getFees -DA:124,23953 +FNDA:23734,Tollgate.getFees +DA:124,23734 BRDA:124,5,0,1 DA:125,1 -DA:128,23952 -DA:129,23952 -DA:130,23952 -DA:131,23952 +DA:128,23733 +DA:129,23733 +DA:130,23733 +DA:131,23733 DA:139,51364 FN:139,Tollgate.setFees FNDA:51364,Tollgate.setFees @@ -1094,16 +1094,16 @@ DA:158,51364 DA:163,0 FN:163,Tollgate._authorizeUpgrade FNDA:0,Tollgate._authorizeUpgrade -DA:169,70055 +DA:169,69398 FN:169,Tollgate._isSchemeSupported -FNDA:70055,Tollgate._isSchemeSupported -DA:170,70055 -DA:171,70055 -DA:172,70055 -DA:180,145371 +FNDA:69398,Tollgate._isSchemeSupported +DA:170,69398 +DA:171,69398 +DA:172,69398 +DA:180,144495 FN:180,Tollgate._computeComposedKey -FNDA:145371,Tollgate._computeComposedKey -DA:181,145371 +FNDA:144495,Tollgate._computeComposedKey +DA:181,144495 FNF:11 FNH:10 LF:41 @@ -1155,11 +1155,11 @@ BRH:0 end_of_record TN: SF:contracts/financial/AgreementManager.sol -DA:70,23179 +DA:70,22960 FN:70,AgreementManager.onlySupportedCurrency -FNDA:23179,AgreementManager.onlySupportedCurrency -DA:71,23179 -DA:72,23179 +FNDA:22960,AgreementManager.onlySupportedCurrency +DA:71,22960 +DA:72,22960 BRDA:72,0,0,- DA:77,38 FN:77,AgreementManager.constructor @@ -1173,65 +1173,65 @@ FNDA:38,AgreementManager.initialize DA:88,0 DA:89,38 DA:90,38 -DA:95,37876 +DA:95,37924 FN:95,AgreementManager.setMaxParties -FNDA:37876,AgreementManager.setMaxParties -DA:96,37876 +FNDA:37924,AgreementManager.setMaxParties +DA:96,37924 BRDA:96,1,0,1 -DA:97,37875 -DA:101,75245 +DA:97,37923 +DA:101,75212 FN:101,AgreementManager.maxParties -FNDA:75245,AgreementManager.maxParties -DA:102,75245 -DA:111,22666 +FNDA:75212,AgreementManager.maxParties +DA:102,75212 +DA:111,22447 FN:111,AgreementManager.createAgreement -FNDA:22666,AgreementManager.createAgreement -DA:119,22666 -DA:120,22666 -DA:124,22664 -DA:125,22664 +FNDA:22447,AgreementManager.createAgreement +DA:119,22447 +DA:120,22447 +DA:124,22445 +DA:125,22445 DA:126,0 -DA:131,35892 +DA:131,35473 FN:131,AgreementManager.getAgreement -FNDA:35892,AgreementManager.getAgreement -DA:132,35892 -DA:141,23179 +FNDA:35473,AgreementManager.getAgreement +DA:132,35473 +DA:141,22960 FN:141,AgreementManager.previewAgreement -FNDA:23179,AgreementManager.previewAgreement -DA:160,23179 -DA:164,23178 -DA:165,23178 -DA:169,23178 +FNDA:22960,AgreementManager.previewAgreement +DA:160,22960 +DA:164,22959 +DA:165,22959 +DA:169,22959 DA:185,0 FN:185,AgreementManager._authorizeUpgrade FNDA:0,AgreementManager._authorizeUpgrade -DA:188,22664 +DA:188,22445 FN:188,AgreementManager._createAndStoreProof -FNDA:22664,AgreementManager._createAndStoreProof -DA:190,22664 -DA:191,22664 -DA:192,22664 +FNDA:22445,AgreementManager._createAndStoreProof +DA:190,22445 +DA:191,22445 +DA:192,22445 DA:193,0 -DA:197,23178 +DA:197,22959 FN:197,AgreementManager._calculatePenalization -FNDA:23178,AgreementManager._calculatePenalization -DA:198,23178 -DA:199,6536 -DA:200,6536 -DA:201,6536 -DA:209,6536 +FNDA:22959,AgreementManager._calculatePenalization +DA:198,22959 +DA:199,6514 +DA:200,6514 +DA:201,6514 +DA:209,6514 FN:209,AgreementManager._penaltyBps -FNDA:6536,AgreementManager._penaltyBps -DA:210,6536 -DA:214,6536 -DA:218,6536 +FNDA:6514,AgreementManager._penaltyBps +DA:210,6514 +DA:214,6514 +DA:218,6514 BRDA:218,4,0,- DA:219,0 -DA:229,23179 +DA:229,22960 FN:229,AgreementManager._calcFees -FNDA:23179,AgreementManager._calcFees -DA:231,23179 -DA:232,23179 +FNDA:22960,AgreementManager._calcFees +DA:231,22960 +DA:232,22960 DA:233,1 DA:234,1 BRDA:234,7,0,1 @@ -1245,10 +1245,10 @@ BRH:2 end_of_record TN: SF:contracts/financial/AgreementSettler.sol -DA:85,6794 +DA:85,6604 FN:85,AgreementSettler.onlyValidAgreement -FNDA:6794,AgreementSettler.onlyValidAgreement -DA:86,6794 +FNDA:6604,AgreementSettler.onlyValidAgreement +DA:86,6604 BRDA:86,0,0,1 DA:87,1 DA:93,23 @@ -1272,51 +1272,51 @@ DA:117,0 DA:119,0 DA:120,0 DA:121,0 -DA:138,6793 +DA:138,6603 FN:138,AgreementSettler.quitAgreement -FNDA:6793,AgreementSettler.quitAgreement -DA:139,6793 -DA:140,6793 +FNDA:6603,AgreementSettler.quitAgreement +DA:139,6603 +DA:140,6603 BRDA:140,2,0,1 -DA:154,6792 -DA:155,6792 -DA:156,6792 -DA:164,6792 -DA:165,6792 -DA:166,6792 -DA:168,6792 -DA:170,6792 -DA:172,6792 -BRDA:172,3,0,6792 -DA:174,6792 +DA:154,6602 +DA:155,6602 +DA:156,6602 +DA:164,6602 +DA:165,6602 +DA:166,6602 +DA:168,6602 +DA:170,6602 +DA:172,6602 +BRDA:172,3,0,6602 +DA:174,6602 DA:175,0 -DA:201,6435 +DA:201,6425 FN:201,AgreementSettler.settleAgreement -FNDA:6435,AgreementSettler.settleAgreement -DA:206,6435 -DA:207,6435 +FNDA:6425,AgreementSettler.settleAgreement +DA:206,6425 +DA:207,6425 BRDA:207,4,0,1 -DA:209,6434 -DA:210,6434 -DA:211,6434 -DA:212,6434 -DA:213,6434 -DA:215,6434 -DA:216,6434 -DA:217,6434 -DA:222,6434 -DA:226,6434 -DA:228,6434 -BRDA:228,5,0,6434 -DA:229,6434 +DA:209,6424 +DA:210,6424 +DA:211,6424 +DA:212,6424 +DA:213,6424 +DA:215,6424 +DA:216,6424 +DA:217,6424 +DA:222,6424 +DA:226,6424 +DA:228,6424 +BRDA:228,5,0,6424 +DA:229,6424 DA:230,0 DA:236,0 FN:236,AgreementSettler._authorizeUpgrade FNDA:0,AgreementSettler._authorizeUpgrade -DA:240,13226 +DA:240,13026 FN:240,AgreementSettler._setProofAsSettled -FNDA:13226,AgreementSettler._setProofAsSettled -DA:241,13226 +FNDA:13026,AgreementSettler._setProofAsSettled +DA:241,13026 FNF:8 FNH:6 LF:51 @@ -1326,32 +1326,32 @@ BRH:5 end_of_record TN: SF:contracts/financial/LedgerVault.sol -DA:31,38 +DA:31,53 FN:31,LedgerVault.constructor -FNDA:38,LedgerVault.constructor +FNDA:53,LedgerVault.constructor DA:34,0 -DA:37,38 +DA:37,53 FN:37,LedgerVault.initialize -FNDA:38,LedgerVault.initialize +FNDA:53,LedgerVault.initialize DA:38,0 DA:39,0 DA:40,0 DA:41,0 DA:42,0 DA:43,0 -DA:44,38 -DA:54,22665 +DA:44,53 +DA:54,27775 FN:54,LedgerVault.lock -FNDA:22665,LedgerVault.lock -DA:59,22665 -DA:66,6792 +FNDA:27775,LedgerVault.lock +DA:59,27775 +DA:66,9169 FN:66,LedgerVault.release -FNDA:6792,LedgerVault.release -DA:71,6792 -DA:80,13226 +FNDA:9169,LedgerVault.release +DA:71,9169 +DA:80,15453 FN:80,LedgerVault.claim -FNDA:13226,LedgerVault.claim -DA:85,13226 +FNDA:15453,LedgerVault.claim +DA:85,15453 DA:92,0 FN:92,LedgerVault.approve FNDA:0,LedgerVault.approve @@ -1364,25 +1364,25 @@ DA:108,0 FN:108,LedgerVault.collect FNDA:0,LedgerVault.collect DA:109,0 -DA:116,25 +DA:116,9621 FN:116,LedgerVault.deposit -FNDA:25,LedgerVault.deposit -DA:121,25 -DA:128,0 +FNDA:9621,LedgerVault.deposit +DA:121,9621 +DA:128,5483 FN:128,LedgerVault.withdraw -FNDA:0,LedgerVault.withdraw -DA:133,0 -DA:140,6434 +FNDA:5483,LedgerVault.withdraw +DA:133,5483 +DA:140,6982 FN:140,LedgerVault.transfer -FNDA:6434,LedgerVault.transfer -DA:141,6434 +FNDA:6982,LedgerVault.transfer +DA:141,6982 DA:147,0 FN:147,LedgerVault._authorizeUpgrade FNDA:0,LedgerVault._authorizeUpgrade FNF:12 -FNH:7 +FNH:8 LF:29 -LH:13 +LH:15 BRF:0 BRH:0 end_of_record @@ -1460,50 +1460,50 @@ BRH:0 end_of_record TN: SF:contracts/policies/PolicyAudit.sol -DA:44,0 +DA:44,20548 FN:44,PolicyAudit.onlyValidPolicy -FNDA:0,PolicyAudit.onlyValidPolicy -DA:45,0 -BRDA:45,0,0,- -DA:46,0 -DA:53,0 +FNDA:20548,PolicyAudit.onlyValidPolicy +DA:45,20548 +BRDA:45,0,0,1 +DA:46,1 +DA:53,13 FN:53,PolicyAudit.constructor -FNDA:0,PolicyAudit.constructor +FNDA:13,PolicyAudit.constructor DA:54,0 -DA:59,0 +DA:59,13 FN:59,PolicyAudit.initialize -FNDA:0,PolicyAudit.initialize +FNDA:13,PolicyAudit.initialize DA:60,0 DA:61,0 -DA:62,0 -DA:70,0 +DA:62,13 +DA:70,20547 FN:70,PolicyAudit.submit -FNDA:0,PolicyAudit.submit -DA:71,0 -DA:72,0 -DA:78,0 +FNDA:20547,PolicyAudit.submit +DA:71,20547 +DA:72,20547 +DA:78,9653 FN:78,PolicyAudit.approve -FNDA:0,PolicyAudit.approve -DA:79,0 -DA:80,0 -DA:86,0 +FNDA:9653,PolicyAudit.approve +DA:79,9653 +DA:80,9653 +DA:86,3708 FN:86,PolicyAudit.reject -FNDA:0,PolicyAudit.reject -DA:87,0 -DA:88,0 -DA:93,0 +FNDA:3708,PolicyAudit.reject +DA:87,3708 +DA:88,3708 +DA:93,1848 FN:93,PolicyAudit.isAudited -FNDA:0,PolicyAudit.isAudited -DA:94,0 +FNDA:1848,PolicyAudit.isAudited +DA:94,1848 DA:100,0 FN:100,PolicyAudit._authorizeUpgrade FNDA:0,PolicyAudit._authorizeUpgrade FNF:8 -FNH:0 +FNH:7 LF:21 -LH:0 +LH:17 BRF:1 -BRH:0 +BRH:1 end_of_record TN: SF:contracts/policies/PolicyBase.sol @@ -1752,48 +1752,55 @@ FNDA:0,RightsPolicyAuthorizer.initialize DA:88,0 DA:89,0 DA:90,0 +DA:93,0 +FN:93,RightsPolicyAuthorizer.setPolicyPlan +FNDA:0,RightsPolicyAuthorizer.setPolicyPlan +DA:94,0 +DA:95,0 DA:96,0 -FN:96,RightsPolicyAuthorizer.authorizePolicy -FNDA:0,RightsPolicyAuthorizer.authorizePolicy DA:98,0 DA:99,0 -BRDA:99,1,0,- DA:100,0 -DA:101,0 -DA:106,0 -FN:106,RightsPolicyAuthorizer.revokePolicy -FNDA:0,RightsPolicyAuthorizer.revokePolicy -DA:108,0 -DA:109,0 -BRDA:109,2,0,- -DA:110,0 +DA:102,0 +DA:112,0 +FN:112,RightsPolicyAuthorizer.authorizePolicy +FNDA:0,RightsPolicyAuthorizer.authorizePolicy +DA:115,0 +BRDA:115,3,0,- DA:116,0 -FN:116,RightsPolicyAuthorizer.isPolicyAuthorized -FNDA:0,RightsPolicyAuthorizer.isPolicyAuthorized DA:117,0 +DA:120,0 +FN:120,RightsPolicyAuthorizer.revokePolicy +FNDA:0,RightsPolicyAuthorizer.revokePolicy DA:124,0 -FN:124,RightsPolicyAuthorizer.getAuthorizedPolicies -FNDA:0,RightsPolicyAuthorizer.getAuthorizedPolicies -DA:131,0 +BRDA:124,4,0,- +DA:125,0 DA:132,0 +FN:132,RightsPolicyAuthorizer.isPolicyAuthorized +FNDA:0,RightsPolicyAuthorizer.isPolicyAuthorized DA:133,0 DA:134,0 -DA:136,0 -DA:137,0 -DA:138,0 -DA:142,0 +DA:140,0 +FN:140,RightsPolicyAuthorizer.getAuthorizedPolicies +FNDA:0,RightsPolicyAuthorizer.getAuthorizedPolicies +DA:147,0 +DA:148,0 +DA:149,0 +DA:150,0 +DA:151,0 +DA:152,0 DA:155,0 -DA:157,0 -DA:163,0 -FN:163,RightsPolicyAuthorizer._authorizeUpgrade +DA:171,0 +DA:176,0 +FN:176,RightsPolicyAuthorizer._authorizeUpgrade FNDA:0,RightsPolicyAuthorizer._authorizeUpgrade -DA:169,0 -FN:169,RightsPolicyAuthorizer._isValidPolicy +DA:184,0 +FN:184,RightsPolicyAuthorizer._isValidPolicy FNDA:0,RightsPolicyAuthorizer._isValidPolicy -DA:170,0 -FNF:9 +DA:185,0 +FNF:10 FNH:0 -LF:34 +LF:39 LH:0 BRF:3 BRH:0 @@ -2825,49 +2832,49 @@ DA:35,2 DA:36,2 DA:38,2 DA:39,12 -DA:43,12650 +DA:43,12640 FN:43,AssetReferendumHandler.submit -FNDA:12650,AssetReferendumHandler.submit -DA:44,12650 -DA:46,12650 -DA:47,12650 -DA:48,12650 -DA:50,12610 -DA:52,12610 -DA:53,12610 -DA:55,12610 -DA:56,12610 -DA:57,12610 -DA:60,12519 +FNDA:12640,AssetReferendumHandler.submit +DA:44,12640 +DA:46,12640 +DA:47,12640 +DA:48,12640 +DA:50,12602 +DA:52,12602 +DA:53,12602 +DA:55,12602 +DA:56,12602 +DA:57,12602 +DA:60,12528 FN:60,AssetReferendumHandler.approve -FNDA:12519,AssetReferendumHandler.approve -DA:61,12519 -DA:63,10610 -DA:64,10610 -DA:65,10610 -DA:67,4013 -DA:68,4013 -DA:70,4013 -DA:73,12459 +FNDA:12528,AssetReferendumHandler.approve +DA:61,12528 +DA:63,10617 +DA:64,10617 +DA:65,10617 +DA:67,4011 +DA:68,4011 +DA:70,4011 +DA:73,12453 FN:73,AssetReferendumHandler.reject -FNDA:12459,AssetReferendumHandler.reject -DA:74,12459 -DA:76,10567 -DA:77,10567 -DA:78,10567 -DA:80,3920 -DA:81,3920 -DA:83,3920 -DA:86,12422 +FNDA:12453,AssetReferendumHandler.reject +DA:74,12453 +DA:76,10564 +DA:77,10564 +DA:78,10564 +DA:80,3922 +DA:81,3922 +DA:83,3922 +DA:86,12429 FN:86,AssetReferendumHandler.revoke -FNDA:12422,AssetReferendumHandler.revoke -DA:87,12422 -DA:89,10474 -DA:90,10474 -DA:91,10474 -DA:93,1869 -DA:94,1869 -DA:96,1869 +FNDA:12429,AssetReferendumHandler.revoke +DA:87,12429 +DA:89,10475 +DA:90,10475 +DA:91,10475 +DA:93,1864 +DA:94,1864 +DA:96,1864 DA:99,0 FN:99,AssetReferendumHandler.trackedLength FNDA:0,AssetReferendumHandler.trackedLength @@ -2899,58 +2906,58 @@ DA:33,3 DA:35,3 DA:36,3 DA:37,15 -DA:41,19040 +DA:41,18991 FN:41,AssetRegistryHandler.register -FNDA:19040,AssetRegistryHandler.register -DA:42,19040 -DA:44,19040 -DA:45,19040 -DA:48,18996 -DA:50,18996 -DA:51,18996 -DA:53,18996 -DA:54,18996 -DA:56,18996 -DA:57,18996 -DA:59,18996 -DA:60,18996 -DA:61,18996 -DA:62,18996 -DA:63,18996 -DA:66,18772 +FNDA:18991,AssetRegistryHandler.register +DA:42,18991 +DA:44,18991 +DA:45,18991 +DA:48,18946 +DA:50,18946 +DA:51,18946 +DA:53,18946 +DA:54,18946 +DA:56,18946 +DA:57,18946 +DA:59,18946 +DA:60,18946 +DA:61,18946 +DA:62,18946 +DA:63,18946 +DA:66,18843 FN:66,AssetRegistryHandler.transfer -FNDA:18772,AssetRegistryHandler.transfer -DA:67,18772 -DA:69,15877 -DA:70,15877 -DA:71,15877 -DA:73,8835 -DA:74,8835 -DA:76,7379 -DA:77,7379 -DA:79,7379 -DA:82,18811 +FNDA:18843,AssetRegistryHandler.transfer +DA:67,18843 +DA:69,15950 +DA:70,15950 +DA:71,15950 +DA:73,8961 +DA:74,8961 +DA:76,7465 +DA:77,7465 +DA:79,7465 +DA:82,18828 FN:82,AssetRegistryHandler.switchState -FNDA:18811,AssetRegistryHandler.switchState -DA:83,18811 -DA:85,15881 -DA:86,15881 -DA:87,15881 -DA:89,8912 -DA:90,8912 -DA:91,8912 -DA:94,18452 +FNDA:18828,AssetRegistryHandler.switchState +DA:83,18828 +DA:85,15873 +DA:86,15873 +DA:87,15873 +DA:89,8982 +DA:90,8982 +DA:91,8982 +DA:94,18413 FN:94,AssetRegistryHandler.revoke -FNDA:18452,AssetRegistryHandler.revoke -DA:95,18452 -DA:97,15549 -DA:98,15549 -DA:99,15549 -DA:101,8503 -DA:102,8503 -DA:104,8503 -DA:105,8503 -DA:106,8503 +FNDA:18413,AssetRegistryHandler.revoke +DA:95,18413 +DA:97,15423 +DA:98,15423 +DA:99,15423 +DA:101,8445 +DA:102,8445 +DA:104,8445 +DA:105,8445 +DA:106,8445 DA:109,0 FN:109,AssetRegistryHandler.assetIdsLength FNDA:0,AssetRegistryHandler.assetIdsLength @@ -2981,52 +2988,52 @@ DA:32,3 DA:33,3 DA:35,3 DA:36,18 -DA:40,25203 +DA:40,25204 FN:40,AssetSafeHandler.registerAsset -FNDA:25203,AssetSafeHandler.registerAsset -DA:41,25203 -DA:43,25203 -DA:46,25100 -DA:47,25100 -DA:49,25100 -DA:50,25100 -DA:52,25100 -DA:53,25100 -DA:55,25100 -DA:56,25100 -DA:58,25100 -DA:59,25100 -DA:60,25100 -DA:63,25003 +FNDA:25204,AssetSafeHandler.registerAsset +DA:41,25204 +DA:43,25204 +DA:46,25103 +DA:47,25103 +DA:49,25103 +DA:50,25103 +DA:52,25103 +DA:53,25103 +DA:55,25103 +DA:56,25103 +DA:58,25103 +DA:59,25103 +DA:60,25103 +DA:63,25050 FN:63,AssetSafeHandler.transferAsset -FNDA:25003,AssetSafeHandler.transferAsset -DA:64,25003 -DA:66,22062 -DA:67,22062 -DA:69,22062 -DA:70,22062 -DA:72,22062 -DA:73,22062 -DA:75,18393 -DA:76,18393 -DA:78,18393 -DA:81,24869 +FNDA:25050,AssetSafeHandler.transferAsset +DA:64,25050 +DA:66,22087 +DA:67,22087 +DA:69,22087 +DA:70,22087 +DA:72,22087 +DA:73,22087 +DA:75,18405 +DA:76,18405 +DA:78,18405 +DA:81,24821 FN:81,AssetSafeHandler.setContent -FNDA:24869,AssetSafeHandler.setContent -DA:82,24869 -DA:84,22005 -DA:85,22005 -DA:87,22005 -DA:88,22005 -DA:90,22005 -DA:91,22005 -DA:92,22005 -DA:94,22005 -DA:95,22005 -DA:97,22005 -DA:98,22005 -DA:99,22005 -DA:100,22005 +FNDA:24821,AssetSafeHandler.setContent +DA:82,24821 +DA:84,21952 +DA:85,21952 +DA:87,21952 +DA:88,21952 +DA:90,21952 +DA:91,21952 +DA:92,21952 +DA:94,21952 +DA:95,21952 +DA:97,21952 +DA:98,21952 +DA:99,21952 +DA:100,21952 DA:103,0 FN:103,AssetSafeHandler.trackedLength FNDA:0,AssetSafeHandler.trackedLength @@ -3068,10 +3075,10 @@ BRH:0 end_of_record TN: SF:test/economics/Tollgate.t.sol -DA:20,12408 +DA:20,12471 FN:20,TargetD.isFeeSchemeSupported -FNDA:12408,TargetD.isFeeSchemeSupported -DA:22,12408 +FNDA:12471,TargetD.isFeeSchemeSupported +DA:22,12471 DA:42,2 FN:42,TollgateHandler.constructor FNDA:2,TollgateHandler.constructor @@ -3097,23 +3104,23 @@ DA:64,50050 DA:65,50050 DA:67,50050 DA:68,50050 -BRDA:68,1,0,25288 -BRDA:68,1,1,12370 -DA:69,25288 -DA:70,24762 +BRDA:68,1,0,25234 +BRDA:68,1,1,12424 +DA:69,25234 +DA:70,24816 BRDA:70,2,0,12392 -BRDA:70,2,1,12370 +BRDA:70,2,1,12424 DA:71,12392 -DA:73,12370 +DA:73,12424 DA:76,50050 DA:77,50050 DA:79,50050 DA:80,50050 DA:81,50050 DA:83,50050 -BRDA:83,3,0,21298 -DA:84,21298 -DA:85,21298 +BRDA:83,3,0,21313 +DA:84,21313 +DA:85,21313 DA:89,0 FN:89,TollgateHandler.targetsLength FNDA:0,TollgateHandler.targetsLength @@ -3143,81 +3150,81 @@ BRH:5 end_of_record TN: SF:test/finance/AgreementManager.t.sol -DA:227,3 -FN:227,AgreementManagerHandler.constructor +DA:228,3 +FN:228,AgreementManagerHandler.constructor FNDA:3,AgreementManagerHandler.constructor -DA:236,3 DA:237,3 DA:238,3 DA:239,3 DA:240,3 DA:241,3 DA:242,3 -DA:245,37201 -FN:245,AgreementManagerHandler.createAgreement -FNDA:37201,AgreementManagerHandler.createAgreement -DA:246,37201 -DA:247,37201 -DA:249,6979 -DA:250,6979 -DA:251,6979 -DA:252,6979 -DA:254,6979 -DA:255,6979 -BRDA:255,2,0,2361 -DA:256,2361 -DA:258,6979 -DA:260,6700 -DA:261,6700 -DA:262,6700 -DA:264,6700 -DA:265,6700 -DA:269,6700 -DA:270,6700 -DA:271,6700 -DA:272,6700 -DA:275,37874 -FN:275,AgreementManagerHandler.setMaxParties -FNDA:37874,AgreementManagerHandler.setMaxParties -DA:276,37874 -DA:277,37874 -DA:278,37874 -DA:281,0 -FN:281,AgreementManagerHandler.proofsLength -FNDA:0,AgreementManagerHandler.proofsLength +DA:243,3 +DA:246,37153 +FN:246,AgreementManagerHandler.createAgreement +FNDA:37153,AgreementManagerHandler.createAgreement +DA:247,37153 +DA:248,37153 +DA:250,7126 +DA:251,7126 +DA:252,7126 +DA:253,7126 +DA:255,7126 +DA:256,7126 +BRDA:256,2,0,2529 +DA:257,2529 +DA:259,7126 +DA:261,6742 +DA:262,6742 +DA:263,6742 +DA:265,6742 +DA:266,6742 +DA:270,6742 +DA:271,6742 +DA:272,6742 +DA:273,6742 +DA:276,37922 +FN:276,AgreementManagerHandler.setMaxParties +FNDA:37922,AgreementManagerHandler.setMaxParties +DA:277,37922 +DA:278,37922 +DA:279,37922 DA:282,0 -DA:285,0 -FN:285,AgreementManagerHandler.proofAt -FNDA:0,AgreementManagerHandler.proofAt +FN:282,AgreementManagerHandler.proofsLength +FNDA:0,AgreementManagerHandler.proofsLength +DA:283,0 DA:286,0 -DA:289,0 -FN:289,AgreementManagerHandler.info -FNDA:0,AgreementManagerHandler.info +FN:286,AgreementManagerHandler.proofAt +FNDA:0,AgreementManagerHandler.proofAt +DA:287,0 DA:290,0 -DA:293,0 -FN:293,AgreementManagerHandler.totalLocked -FNDA:0,AgreementManagerHandler.totalLocked +FN:290,AgreementManagerHandler.info +FNDA:0,AgreementManagerHandler.info +DA:291,0 DA:294,0 -DA:297,0 -FN:297,AgreementManagerHandler.recomputeLocked -FNDA:0,AgreementManagerHandler.recomputeLocked +FN:294,AgreementManagerHandler.totalLocked +FNDA:0,AgreementManagerHandler.totalLocked +DA:295,0 DA:298,0 +FN:298,AgreementManagerHandler.recomputeLocked +FNDA:0,AgreementManagerHandler.recomputeLocked DA:299,0 DA:300,0 DA:301,0 DA:302,0 -DA:306,6700 -FN:306,AgreementManagerHandler._buildParties -FNDA:6700,AgreementManagerHandler._buildParties -DA:307,6700 -DA:308,6700 -DA:309,26116 -DA:313,6979 -FN:313,AgreementManagerHandler._penaltyBps -FNDA:6979,AgreementManagerHandler._penaltyBps -DA:314,6979 -DA:315,2361 -DA:316,2361 +DA:303,0 +DA:307,6742 +FN:307,AgreementManagerHandler._buildParties +FNDA:6742,AgreementManagerHandler._buildParties +DA:308,6742 +DA:309,6742 +DA:310,26250 +DA:314,7126 +FN:314,AgreementManagerHandler._penaltyBps +FNDA:7126,AgreementManagerHandler._penaltyBps +DA:315,7126 +DA:316,2529 +DA:317,2529 FNF:10 FNH:5 LF:54 @@ -3244,61 +3251,61 @@ DA:220,4 DA:221,4 DA:222,4 DA:223,4 -DA:226,33363 +DA:226,33273 FN:226,AgreementSettlerHandler.createAgreement -FNDA:33363,AgreementSettlerHandler.createAgreement -DA:227,33363 -DA:228,33363 -DA:229,33363 -DA:230,33363 -DA:232,15574 -DA:233,15574 -BRDA:233,1,0,4369 -DA:234,4369 -DA:236,15574 -DA:238,15190 -DA:239,15190 -DA:240,15190 -DA:241,15190 -DA:242,15190 -DA:245,15190 -DA:246,15190 -DA:256,15190 -DA:257,15190 -DA:260,33082 +FNDA:33273,AgreementSettlerHandler.createAgreement +DA:227,33273 +DA:228,33273 +DA:229,33273 +DA:230,33273 +DA:232,15312 +DA:233,15312 +BRDA:233,1,0,4283 +DA:234,4283 +DA:236,15312 +DA:238,14929 +DA:239,14929 +DA:240,14929 +DA:241,14929 +DA:242,14929 +DA:245,14929 +DA:246,14929 +DA:256,14929 +DA:257,14929 +DA:260,33135 FN:260,AgreementSettlerHandler.settle -FNDA:33082,AgreementSettlerHandler.settle -DA:261,33082 -DA:262,29339 -DA:263,29339 -DA:264,29339 +FNDA:33135,AgreementSettlerHandler.settle +DA:261,33135 +DA:262,29390 +DA:263,29390 +DA:264,29390 DA:266,0 -DA:267,6180 -DA:268,3 -DA:271,6177 -DA:272,6177 -DA:273,6177 -DA:274,6177 -DA:276,6177 -DA:277,6177 -DA:278,6177 -DA:280,6177 -DA:281,6177 -DA:282,6177 -DA:285,33655 +DA:267,6171 +DA:268,4 +DA:271,6167 +DA:272,6167 +DA:273,6167 +DA:274,6167 +DA:276,6167 +DA:277,6167 +DA:278,6167 +DA:280,6167 +DA:281,6167 +DA:282,6167 +DA:285,33692 FN:285,AgreementSettlerHandler.quit -FNDA:33655,AgreementSettlerHandler.quit -DA:286,33655 -DA:287,29625 -DA:288,29625 -DA:289,29625 -DA:291,6535 -DA:292,6535 -DA:293,6535 -DA:295,6535 -DA:296,6535 -DA:298,6535 -DA:299,6535 +FNDA:33692,AgreementSettlerHandler.quit +DA:286,33692 +DA:287,29739 +DA:288,29739 +DA:289,29739 +DA:291,6345 +DA:292,6345 +DA:293,6345 +DA:295,6345 +DA:296,6345 +DA:298,6345 +DA:299,6345 DA:302,0 FN:302,AgreementSettlerHandler.proofsLength FNDA:0,AgreementSettlerHandler.proofsLength @@ -3331,18 +3338,18 @@ DA:328,0 DA:329,0 DA:330,0 DA:331,0 -DA:335,15190 +DA:335,14929 FN:335,AgreementSettlerHandler._buildParties -FNDA:15190,AgreementSettlerHandler._buildParties -DA:336,15190 -DA:337,15190 -DA:338,52269 -DA:342,33363 +FNDA:14929,AgreementSettlerHandler._buildParties +DA:336,14929 +DA:337,14929 +DA:338,51368 +DA:342,33273 FN:342,AgreementSettlerHandler._penaltyBps -FNDA:33363,AgreementSettlerHandler._penaltyBps -DA:343,33363 -DA:344,9357 -DA:345,9357 +FNDA:33273,AgreementSettlerHandler._penaltyBps +DA:343,33273 +DA:344,9313 +DA:345,9313 FNF:15 FNH:8 LF:85 @@ -3351,6 +3358,189 @@ BRF:1 BRH:1 end_of_record TN: +SF:test/finance/LedgerVault.t.sol +DA:21,559 +FN:21,MockToken.mint +FNDA:559,MockToken.mint +DA:22,559 +DA:30,4 +FN:30,LedgerVaultHarness.lockedBalance +FNDA:4,LedgerVaultHarness.lockedBalance +DA:31,4 +DA:32,4 +DA:34,0 +DA:35,0 +DA:36,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:42,0 +DA:301,1 +FN:301,LedgerVaultHandler.constructor +FNDA:1,LedgerVaultHandler.constructor +DA:308,1 +DA:309,1 +DA:310,1 +DA:311,1 +DA:312,1 +DA:313,5 +DA:317,0 +FN:317,LedgerVaultHandler.accountsLength +FNDA:0,LedgerVaultHandler.accountsLength +DA:318,0 +DA:321,0 +FN:321,LedgerVaultHandler.accountAt +FNDA:0,LedgerVaultHandler.accountAt +DA:322,0 +DA:325,0 +FN:325,LedgerVaultHandler.expectedLedgerOf +FNDA:0,LedgerVaultHandler.expectedLedgerOf +DA:326,0 +DA:329,0 +FN:329,LedgerVaultHandler.expectedLockedOf +FNDA:0,LedgerVaultHandler.expectedLockedOf +DA:330,0 +DA:333,9188 +FN:333,LedgerVaultHandler._boundAmount +FNDA:9188,LedgerVaultHandler._boundAmount +DA:334,9188 +DA:335,9188 +DA:336,9073 +DA:339,238792 +FN:339,LedgerVaultHandler.deposit +FNDA:238792,LedgerVaultHandler.deposit +DA:340,238792 +DA:341,9188 +DA:342,9188 +DA:343,9188 +DA:345,9073 +DA:346,9073 +DA:347,9073 +DA:348,9073 +DA:350,9073 +DA:353,238982 +FN:353,LedgerVaultHandler.withdraw +FNDA:238982,LedgerVaultHandler.withdraw +DA:354,238982 +DA:355,9228 +DA:356,9228 +DA:357,9228 +DA:358,5224 +DA:360,5224 +DA:361,5224 +DA:362,5224 +DA:365,239043 +FN:365,LedgerVaultHandler.transfer +FNDA:239043,LedgerVaultHandler.transfer +DA:366,239043 +DA:367,646 +DA:368,493 +DA:369,493 +DA:370,493 +DA:371,493 +DA:372,299 +DA:374,299 +DA:375,299 +DA:377,299 +DA:378,299 +DA:381,239224 +FN:381,LedgerVaultHandler.lock +FNDA:239224,LedgerVaultHandler.lock +DA:382,239224 +DA:383,9326 +DA:384,9326 +DA:385,9326 +DA:386,5324 +DA:388,5324 +DA:389,5324 +DA:391,5324 +DA:392,5324 +DA:395,238671 +FN:395,LedgerVaultHandler.release +FNDA:238671,LedgerVaultHandler.release +DA:396,238671 +DA:397,9384 +DA:398,9384 +DA:399,9384 +DA:400,2565 +DA:402,2565 +DA:403,2565 +DA:405,2565 +DA:406,2565 +DA:409,238673 +FN:409,LedgerVaultHandler.claim +FNDA:238673,LedgerVaultHandler.claim +DA:410,238673 +DA:411,9194 +DA:412,9194 +DA:413,9194 +DA:414,2425 +DA:416,2425 +DA:417,2425 +DA:419,2425 +DA:420,2425 +FNF:14 +FNH:10 +LF:92 +LH:77 +BRF:0 +BRH:0 +end_of_record +TN: +SF:test/libraries/FeesOps.t.sol +DA:10,3 +FN:10,FeesOpsHarness.isBasePoint +FNDA:3,FeesOpsHarness.isBasePoint +DA:11,3 +DA:14,3 +FN:14,FeesOpsHarness.isNominal +FNDA:3,FeesOpsHarness.isNominal +DA:15,3 +DA:18,16922 +FN:18,FeesOpsHarness.perOf +FNDA:16922,FeesOpsHarness.perOf +DA:19,16922 +DA:22,17151 +FN:22,FeesOpsHarness.calcBps +FNDA:17151,FeesOpsHarness.calcBps +DA:23,17151 +DA:90,2 +FN:90,FeesOpsHandler.constructor +FNDA:2,FeesOpsHandler.constructor +DA:91,2 +DA:94,16664 +FN:94,FeesOpsHandler.recordPerOf +FNDA:16664,FeesOpsHandler.recordPerOf +DA:95,16664 +DA:96,16664 +DA:97,16664 +DA:98,16664 +DA:101,16894 +FN:101,FeesOpsHandler.recordCalcBps +FNDA:16894,FeesOpsHandler.recordCalcBps +DA:102,16894 +DA:103,16894 +DA:106,16492 +FN:106,FeesOpsHandler.reset +FNDA:16492,FeesOpsHandler.reset +DA:107,16492 +DA:108,16492 +DA:111,0 +FN:111,FeesOpsHandler.totalAmount +FNDA:0,FeesOpsHandler.totalAmount +DA:112,0 +DA:115,0 +FN:115,FeesOpsHandler.lastCalcBps +FNDA:0,FeesOpsHandler.lastCalcBps +DA:116,0 +FNF:10 +FNH:8 +LF:25 +LH:21 +BRF:0 +BRH:0 +end_of_record +TN: SF:test/libraries/FinancialOps.t.sol DA:13,51 FN:13,TestToken.mint @@ -3471,42 +3661,169 @@ BRH:0 end_of_record TN: SF:test/libraries/RollingOps.t.sol -DA:17,6 -FN:17,RollingOpsWrapper.configureWindow -FNDA:6,RollingOpsWrapper.configureWindow -DA:18,6 -DA:22,3 -FN:22,RollingOpsWrapper.getWindow -FNDA:3,RollingOpsWrapper.getWindow -DA:23,3 -DA:28,33 -FN:28,RollingOpsWrapper.add -FNDA:33,RollingOpsWrapper.add -DA:29,33 -DA:35,6 -FN:35,RollingOpsWrapper.exists -FNDA:6,RollingOpsWrapper.exists -DA:36,6 -DA:41,2 -FN:41,RollingOpsWrapper.getLength -FNDA:2,RollingOpsWrapper.getLength -DA:42,2 -DA:48,6 -FN:48,RollingOpsWrapper.getAt -FNDA:6,RollingOpsWrapper.getAt -DA:49,6 -DA:54,3 -FN:54,RollingOpsWrapper.getAll -FNDA:3,RollingOpsWrapper.getAll -DA:55,3 -FNF:7 -FNH:7 -LF:14 -LH:14 +DA:13,25658 +FN:13,RollingOpsHarness.configure +FNDA:25658,RollingOpsHarness.configure +DA:14,25658 +DA:17,35225 +FN:17,RollingOpsHarness.roll +FNDA:35225,RollingOpsHarness.roll +DA:18,35225 +DA:21,2545 +FN:21,RollingOpsHarness.contains +FNDA:2545,RollingOpsHarness.contains +DA:22,2545 +DA:25,260 +FN:25,RollingOpsHarness.length +FNDA:260,RollingOpsHarness.length +DA:26,260 +DA:29,2 +FN:29,RollingOpsHarness.window +FNDA:2,RollingOpsHarness.window +DA:30,2 +DA:33,2314 +FN:33,RollingOpsHarness.at +FNDA:2314,RollingOpsHarness.at +DA:34,2314 +DA:37,50051 +FN:37,RollingOpsHarness.values +FNDA:50051,RollingOpsHarness.values +DA:38,50051 +DA:170,2 +FN:170,RollingOpsHandler.constructor +FNDA:2,RollingOpsHandler.constructor +DA:171,2 +DA:176,25141 +FN:176,RollingOpsHandler.configure +FNDA:25141,RollingOpsHandler.configure +DA:177,25141 +DA:178,25141 +DA:179,0 +DA:182,24909 +FN:182,RollingOpsHandler.roll +FNDA:24909,RollingOpsHandler.roll +DA:183,24909 +DA:184,0 +DA:187,0 +FN:187,RollingOpsHandler.maxWindow +FNDA:0,RollingOpsHandler.maxWindow +DA:188,0 +DA:191,0 +FN:191,RollingOpsHandler.snapshotLength +FNDA:0,RollingOpsHandler.snapshotLength +DA:192,0 +DA:195,0 +FN:195,RollingOpsHandler.snapshotAt +FNDA:0,RollingOpsHandler.snapshotAt +DA:196,0 +DA:199,50050 +FN:199,RollingOpsHandler._rebuildSnapshot +FNDA:50050,RollingOpsHandler._rebuildSnapshot +DA:200,50050 +DA:201,50050 +DA:202,50050 +DA:203,259169 +FNF:14 +FNH:11 +LF:34 +LH:26 BRF:0 BRH:0 end_of_record TN: +SF:test/policies/PolicyAudit.t.sol +DA:17,0 +FN:17,MockPolicy.setup +FNDA:0,MockPolicy.setup +DA:19,0 +FN:19,MockPolicy.enforce +FNDA:0,MockPolicy.enforce +DA:20,0 +DA:23,0 +FN:23,MockPolicy.isAccessAllowed +FNDA:0,MockPolicy.isAccessAllowed +DA:24,0 +DA:27,0 +FN:27,MockPolicy.getLicense +FNDA:0,MockPolicy.getLicense +DA:28,0 +DA:31,0 +FN:31,MockPolicy.resolveTerms +FNDA:0,MockPolicy.resolveTerms +DA:32,0 +DA:35,0 +FN:35,MockPolicy.getAttestationProvider +FNDA:0,MockPolicy.getAttestationProvider +DA:36,0 +DA:39,0 +FN:39,MockPolicy.name +FNDA:0,MockPolicy.name +DA:40,0 +DA:43,0 +FN:43,MockPolicy.description +FNDA:0,MockPolicy.description +DA:44,0 +DA:47,61641 +FN:47,MockPolicy.supportsInterface +FNDA:61641,MockPolicy.supportsInterface +DA:48,61641 +DA:55,2132 +FN:55,PolicyAuditHarness.status +FNDA:2132,PolicyAuditHarness.status +DA:56,2132 +DA:210,2 +FN:210,PolicyAuditHandler.constructor +FNDA:2,PolicyAuditHandler.constructor +DA:211,2 +DA:212,2 +DA:215,16566 +FN:215,PolicyAuditHandler.submitPolicy +FNDA:16566,PolicyAuditHandler.submitPolicy +DA:216,16566 +DA:217,16566 +BRDA:217,0,0,16566 +DA:218,16566 +DA:219,16566 +DA:223,16998 +FN:223,PolicyAuditHandler.approvePolicy +FNDA:16998,PolicyAuditHandler.approvePolicy +DA:224,16998 +DA:225,15034 +DA:226,15034 +DA:228,7805 +DA:229,7805 +BRDA:229,3,0,7805 +DA:230,7805 +DA:234,16486 +FN:234,PolicyAuditHandler.rejectPolicy +FNDA:16486,PolicyAuditHandler.rejectPolicy +DA:235,16486 +DA:236,14584 +DA:237,14584 +DA:239,3705 +DA:240,3705 +BRDA:240,6,0,3705 +DA:241,3705 +DA:245,0 +FN:245,PolicyAuditHandler.policiesLength +FNDA:0,PolicyAuditHandler.policiesLength +DA:246,0 +DA:249,0 +FN:249,PolicyAuditHandler.policyAt +FNDA:0,PolicyAuditHandler.policyAt +DA:250,0 +DA:253,0 +FN:253,PolicyAuditHandler.storedStatus +FNDA:0,PolicyAuditHandler.storedStatus +DA:254,0 +FNF:17 +FNH:6 +LF:47 +LH:26 +BRF:3 +BRH:3 +end_of_record +TN: SF:test/primitives/AccessControlledUpgradeable.t.sol DA:15,13 FN:15,AccessControlledHarness.initialize @@ -3733,10 +4050,10 @@ DA:266,2 FN:266,BalanceOperatorHandler.getActors FNDA:2,BalanceOperatorHandler.getActors DA:267,2 -DA:270,593058 +DA:270,593056 FN:270,BalanceOperatorHandler.deposit -FNDA:593058,BalanceOperatorHandler.deposit -DA:271,593058 +FNDA:593056,BalanceOperatorHandler.deposit +DA:271,593056 DA:272,24483 DA:273,24483 DA:274,24483 @@ -3746,10 +4063,10 @@ DA:278,24186 DA:279,24186 DA:280,24186 DA:282,24186 -DA:285,590617 +DA:285,590619 FN:285,BalanceOperatorHandler.withdraw -FNDA:590617,BalanceOperatorHandler.withdraw -DA:286,590617 +FNDA:590619,BalanceOperatorHandler.withdraw +DA:286,590619 DA:287,24300 DA:288,24300 DA:289,24300 @@ -3783,59 +4100,59 @@ DA:9,5 FN:9,LedgerUpgradeableHarness.initialize FNDA:5,LedgerUpgradeableHarness.initialize DA:10,0 -DA:13,8729 +DA:13,8712 FN:13,LedgerUpgradeableHarness.setEntry -FNDA:8729,LedgerUpgradeableHarness.setEntry -DA:14,8729 -DA:17,8590 +FNDA:8712,LedgerUpgradeableHarness.setEntry +DA:14,8712 +DA:17,8622 FN:17,LedgerUpgradeableHarness.sumEntry -FNDA:8590,LedgerUpgradeableHarness.sumEntry -DA:18,8590 -DA:21,364 +FNDA:8622,LedgerUpgradeableHarness.sumEntry +DA:18,8622 +DA:21,368 FN:21,LedgerUpgradeableHarness.subEntry -FNDA:364,LedgerUpgradeableHarness.subEntry -DA:22,364 +FNDA:368,LedgerUpgradeableHarness.subEntry +DA:22,368 DA:93,1 FN:93,LedgerUpgradeableHandler.constructor FNDA:1,LedgerUpgradeableHandler.constructor DA:94,1 -DA:97,8473 +DA:97,8456 FN:97,LedgerUpgradeableHandler.setEntry -FNDA:8473,LedgerUpgradeableHandler.setEntry -DA:98,8473 -DA:99,8470 -DA:101,8470 -DA:102,8470 -BRDA:102,1,0,8470 -DA:103,8470 -DA:104,8470 -DA:106,8470 -DA:109,8348 +FNDA:8456,LedgerUpgradeableHandler.setEntry +DA:98,8456 +DA:99,8453 +DA:101,8453 +DA:102,8453 +BRDA:102,1,0,8453 +DA:103,8453 +DA:104,8453 +DA:106,8453 +DA:109,8379 FN:109,LedgerUpgradeableHandler.sumEntry -FNDA:8348,LedgerUpgradeableHandler.sumEntry -DA:110,8348 -DA:112,8333 -DA:113,8333 +FNDA:8379,LedgerUpgradeableHandler.sumEntry +DA:110,8379 +DA:112,8365 +DA:113,8365 DA:114,0 -DA:116,8333 -DA:118,8333 -BRDA:118,3,0,8333 -DA:119,8333 -DA:120,8333 -DA:122,8333 -DA:125,8204 +DA:116,8365 +DA:118,8365 +BRDA:118,3,0,8365 +DA:119,8365 +DA:120,8365 +DA:122,8365 +DA:125,8190 FN:125,LedgerUpgradeableHandler.subEntry -FNDA:8204,LedgerUpgradeableHandler.subEntry -DA:126,8204 -DA:128,8191 -DA:129,8191 -DA:130,8191 -DA:132,107 -DA:134,107 -BRDA:134,6,0,107 -DA:135,107 -DA:136,107 -DA:138,107 +FNDA:8190,LedgerUpgradeableHandler.subEntry +DA:126,8190 +DA:128,8178 +DA:129,8178 +DA:130,8178 +DA:132,111 +DA:134,111 +BRDA:134,6,0,111 +DA:135,111 +DA:136,111 +DA:138,111 DA:141,0 FN:141,LedgerUpgradeableHandler.keysLength FNDA:0,LedgerUpgradeableHandler.keysLength @@ -3975,22 +4292,22 @@ DA:14,50824 FN:14,QuorumUpgradeableHarness.statusOf FNDA:50824,QuorumUpgradeableHarness.statusOf DA:15,50824 -DA:18,10581 +DA:18,10573 FN:18,QuorumUpgradeableHarness.register -FNDA:10581,QuorumUpgradeableHarness.register -DA:19,10581 -DA:22,313 +FNDA:10573,QuorumUpgradeableHarness.register +DA:19,10573 +DA:22,315 FN:22,QuorumUpgradeableHarness.approve -FNDA:313,QuorumUpgradeableHarness.approve -DA:23,313 +FNDA:315,QuorumUpgradeableHarness.approve +DA:23,315 DA:26,36 FN:26,QuorumUpgradeableHarness.blockEntry FNDA:36,QuorumUpgradeableHarness.blockEntry DA:27,36 -DA:30,294 +DA:30,297 FN:30,QuorumUpgradeableHarness.quit -FNDA:294,QuorumUpgradeableHarness.quit -DA:31,294 +FNDA:297,QuorumUpgradeableHarness.quit +DA:31,297 DA:34,2 FN:34,QuorumUpgradeableHarness.revoke FNDA:2,QuorumUpgradeableHarness.revoke @@ -3999,39 +4316,39 @@ DA:138,2 FN:138,QuorumHandler.constructor FNDA:2,QuorumHandler.constructor DA:139,2 -DA:142,10102 +DA:142,10092 FN:142,QuorumHandler.register -FNDA:10102,QuorumHandler.register -DA:143,10102 -DA:144,10102 -DA:145,10062 -DA:146,10062 -DA:149,9833 +FNDA:10092,QuorumHandler.register +DA:143,10092 +DA:144,10092 +DA:145,10054 +DA:146,10054 +DA:149,9804 FN:149,QuorumHandler.approve -FNDA:9833,QuorumHandler.approve -DA:150,9833 -DA:151,9833 -DA:152,54 -DA:153,54 -DA:156,10167 +FNDA:9804,QuorumHandler.approve +DA:150,9804 +DA:151,9804 +DA:152,56 +DA:153,56 +DA:156,10176 FN:156,QuorumHandler.quit -FNDA:10167,QuorumHandler.quit -DA:157,10167 -DA:158,10167 -DA:159,36 -DA:160,36 -DA:163,10073 +FNDA:10176,QuorumHandler.quit +DA:157,10176 +DA:158,10176 +DA:159,39 +DA:160,39 +DA:163,10098 FN:163,QuorumHandler.blockEntry -FNDA:10073,QuorumHandler.blockEntry -DA:164,10073 -DA:165,10073 +FNDA:10098,QuorumHandler.blockEntry +DA:164,10098 +DA:165,10098 DA:166,34 DA:167,34 -DA:170,9875 +DA:170,9880 FN:170,QuorumHandler.revoke -FNDA:9875,QuorumHandler.revoke -DA:171,9875 -DA:172,9875 +FNDA:9880,QuorumHandler.revoke +DA:171,9880 +DA:172,9880 DA:173,0 DA:174,0 DA:177,0 @@ -4046,14 +4363,14 @@ DA:185,0 FN:185,QuorumHandler.expectedStatus FNDA:0,QuorumHandler.expectedStatus DA:186,0 -DA:189,10186 +DA:189,10183 FN:189,QuorumHandler._update -FNDA:10186,QuorumHandler._update -DA:190,10186 -BRDA:190,5,0,10062 -DA:191,10062 -DA:192,10062 -DA:194,10186 +FNDA:10183,QuorumHandler._update +DA:190,10183 +BRDA:190,5,0,10054 +DA:191,10054 +DA:192,10054 +DA:194,10183 DA:197,50050 FN:197,QuorumHandler._normalize FNDA:50050,QuorumHandler._normalize diff --git a/test/finance/AgreementManager.t.sol b/test/finance/AgreementManager.t.sol index 14711c6..5155e5e 100644 --- a/test/finance/AgreementManager.t.sol +++ b/test/finance/AgreementManager.t.sol @@ -223,6 +223,7 @@ contract AgreementManagerHandler is Test { uint256[] private _proofs; mapping(uint256 => AgreementInfo) private _agreements; uint256 private _totalLocked; + uint256 private _nonce; constructor( address manager_, @@ -259,7 +260,7 @@ contract AgreementManagerHandler is Test { uint256 amount = bound(amountSeed, 1e18, maxAmount); address[] memory parties = _buildParties(partiesLen); - bytes memory payload = abi.encode(amountSeed, partiesSeed); + bytes memory payload = abi.encode(amountSeed, partiesSeed, _nonce++); vm.prank(initiator); uint256 proof = manager.createAgreement(amount, token, arbiter, parties, payload); @@ -372,4 +373,3 @@ contract AgreementManagerInvariantTest is BaseTest { assertEq(handler.totalLocked(), handler.recomputeLocked(), "Tracked locked total mismatch"); } } - diff --git a/test/libraries/FeesOps.t.sol b/test/libraries/FeesOps.t.sol index b931f7c..19ddcae 100644 --- a/test/libraries/FeesOps.t.sol +++ b/test/libraries/FeesOps.t.sol @@ -84,8 +84,8 @@ contract FeesOpsTest is Test { contract FeesOpsHandler is Test { FeesOpsHarness public immutable harness; - uint256 internal totalAmount; - uint256 internal lastPercentage; + uint256 internal _totalAmount; + uint256 internal _lastCalcBps; constructor(FeesOpsHarness harness_) { harness = harness_; @@ -95,17 +95,25 @@ contract FeesOpsHandler is Test { bps = bound(bps, 0, C.BPS_MAX); amount = bound(amount, 0, type(uint128).max); uint256 result = harness.perOf(amount, bps); - totalAmount += result; + _totalAmount += result; } function recordCalcBps(uint256 per) external { per = bound(per, 0, 1_000_000); - lastPercentage = harness.calcBps(per); + _lastCalcBps = harness.calcBps(per); } function reset() external { - totalAmount = 0; - lastPercentage = 0; + _totalAmount = 0; + _lastCalcBps = 0; + } + + function totalAmount() external view returns (uint256) { + return _totalAmount; + } + + function lastCalcBps() external view returns (uint256) { + return _lastCalcBps; } } @@ -124,6 +132,6 @@ contract FeesOpsInvariantTest is Test { } function invariant_LastPercentageValid() external view { - assertEq(handler.lastPercentage() % C.SCALE_FACTOR, 0, "calcBps outputs should be multiples of scale factor"); + assertEq(handler.lastCalcBps() % C.SCALE_FACTOR, 0, "calcBps outputs should be multiples of scale factor"); } } diff --git a/test/libraries/RollingOps.t.sol b/test/libraries/RollingOps.t.sol index 9fd776a..98b27b8 100644 --- a/test/libraries/RollingOps.t.sol +++ b/test/libraries/RollingOps.t.sol @@ -2,244 +2,229 @@ pragma solidity 0.8.26; import "forge-std/Test.sol"; + import { RollingOps } from "contracts/core/libraries/RollingOps.sol"; -import { console } from "forge-std/console.sol"; -/// @title RollingOpsWrapper -/// @notice A wrapper contract to test the RollingOps library using Foundry. -contract RollingOpsWrapper { +contract RollingOpsHarness { using RollingOps for RollingOps.AddressArray; - RollingOps.AddressArray private rollingArray; + RollingOps.AddressArray internal set; - /// @notice Configures the max window size of the rolling array. - /// @param window The new max size of the array. - function configureWindow(uint256 window) external { - rollingArray.configure(window); + function configure(uint256 window) external { + set.configure(window); } - /// @notice Returns the maximum window size. - function getWindow() external view returns (uint256) { - return rollingArray.window(); + function roll(address value) external { + set.roll(value); } - /// @notice Adds a new address to the rolling array. - /// @param value The address to be added. - function add(address value) external { - rollingArray.roll(value); + function contains(address value) external view returns (bool) { + return set.contains(value); } - /// @notice Checks if an address exists in the rolling array. - /// @param value The address to check. - /// @return exists True if the address is in the rolling array, false otherwise. - function exists(address value) external view returns (bool) { - return rollingArray.contains(value); + function length() external view returns (uint256) { + return set.length(); } - /// @notice Gets the length of the rolling array. - /// @return The number of stored addresses. - function getLength() external view returns (uint256) { - return rollingArray.length(); + function window() external view returns (uint256) { + return set.window(); } - /// @notice Gets an address at a specific index. - /// @param index The index (1-based) to retrieve. - /// @return The address stored at the given index. - function getAt(uint256 index) external view returns (address) { - return rollingArray.at(index); + function at(uint256 index) external view returns (address) { + return set.at(index); } - /// @notice Retrieves all addresses currently stored in the rolling array. - /// @return An array of all addresses in the rolling array. - function getAll() external view returns (address[] memory) { - return rollingArray.values(); + function values() external view returns (address[] memory) { + return set.values(); } } contract RollingOpsTest is Test { - RollingOpsWrapper private rolling; + uint256 internal constant MAX_WINDOW = 20; + RollingOpsHarness harness; function setUp() public { - rolling = new RollingOpsWrapper(); + harness = new RollingOpsHarness(); + } + + function test_DefaultWindow_IsThree() public { + assertEq(harness.window(), 3, "Default window mismatch"); + assertEq(harness.length(), 0, "Initial length should be zero"); + } + + function test_Configure_SetsCustomWindow() public { + harness.configure(5); + assertEq(harness.window(), 5, "Window should update to configured value"); + } + + function test_Configure_RevertWhen_ZeroWindow() public { + vm.expectRevert(RollingOps.InvalidZeroWindowSize.selector); + harness.configure(0); + } + + function test_Roll_AppendsUntilWindow() public { + address a = vm.addr(1); + address b = vm.addr(2); + harness.roll(a); + harness.roll(b); + assertEq(harness.length(), 2, "Length mismatch after roll"); + assertEq(harness.at(0), a, "First element mismatch"); + assertEq(harness.at(1), b, "Second element mismatch"); } - function test_Window_ReturnDefaultWindowSize() public view { - assertEq(rolling.getWindow(), 3, "Default window size should be 3"); + function test_Roll_RollsOutOldestWhenWindowExceeded() public { + harness.configure(3); + address[4] memory addrs = [vm.addr(1), vm.addr(2), vm.addr(3), vm.addr(4)]; + for (uint256 i = 0; i < addrs.length; i++) { + harness.roll(addrs[i]); + } + + assertEq(harness.length(), 3, "Length should not exceed window"); + assertEq(harness.at(0), addrs[1], "Oldest element not rolled out"); + assertEq(harness.at(1), addrs[2], "Order mismatch after roll"); + assertEq(harness.at(2), addrs[3], "Newest element missing"); } - function test_Configure_SetValidWindowSize() public { - rolling.configureWindow(5); - assertEq(rolling.getWindow(), 5, "Expected window size should be 5"); + function test_Contains_ReturnsFalseWhenMissing() public { + assertFalse(harness.contains(vm.addr(99)), "Contains should be false for missing value"); } - function test_Configure_MaximumWindowSize() public { - uint256 maxWindow = type(uint256).max; - rolling.configureWindow(maxWindow); - assertEq(rolling.getWindow(), maxWindow, "Expected window size should be max uint256"); + function test_Contains_ReturnsTrueAfterRoll() public { + address value = vm.addr(42); + harness.roll(value); + assertTrue(harness.contains(value), "Contains should be true after roll"); } - function test_RevertIf_SetZeroWindowSize() public { - vm.expectRevert(); - rolling.configureWindow(0); + function test_At_RevertWhen_IndexOutOfBounds() public { + vm.expectRevert(RollingOps.IndexOutOfBounds.selector); + harness.at(0); } - function test_Add_NotRollingElements() public { - address addr1 = vm.addr(1); - address addr2 = vm.addr(2); - address addr3 = vm.addr(3); - // using default window - rolling.add(addr1); - rolling.add(addr2); - rolling.add(addr3); + function test_Values_ReturnsAllInOrder() public { + harness.configure(3); + address[3] memory addrs = [vm.addr(1), vm.addr(2), vm.addr(3)]; + for (uint256 i = 0; i < addrs.length; i++) { + harness.roll(addrs[i]); + } + + address[] memory vals = harness.values(); + assertEq(vals.length, 3, "Values length mismatch"); + for (uint256 i = 0; i < vals.length; i++) { + assertEq(vals[i], addrs[i], "Values order mismatch"); + } + } - address[] memory got = rolling.getAll(); - address[] memory expected = new address[](3); - expected[0] = addr1; - expected[1] = addr2; - expected[2] = addr3; + function test_Integration_ConfiguredWindowFlow() public { + harness.configure(2); + address a = vm.addr(1); + address b = vm.addr(2); + address c = vm.addr(3); - assertEq(got, expected, "Expected addresses should match"); + harness.roll(a); + harness.roll(b); + harness.roll(c); + + assertEq(harness.length(), 2, "Length should clamp to window size"); + assertEq(harness.at(0), b, "First element should be second rolled"); + assertEq(harness.at(1), c, "Second element should be latest rolled"); + assertFalse(harness.contains(a), "Rolled out element should not be contained"); } - function test_Add_RollingOldestElement() public { - address addr1 = vm.addr(1); - address addr2 = vm.addr(2); - address addr3 = vm.addr(3); - address addr4 = vm.addr(4); + function testFuzz_RollRespectsWindow(uint256 windowSize, uint256 count) public { + windowSize = bound(windowSize, 1, MAX_WINDOW); + count = bound(count, 1, 60); + harness.configure(windowSize); - // using default window - rolling.add(addr1); - rolling.add(addr2); - rolling.add(addr3); + address[] memory inserted = new address[](count); + for (uint256 i = 0; i < count; i++) { + inserted[i] = vm.addr(i + 1); + harness.roll(inserted[i]); + } - // before = [addr1, addr2, addr3] - // after = [ addr2, addr3, addr4] - rolling.add(addr4); + uint256 expectedLength = count < windowSize ? count : windowSize; + assertEq(harness.length(), expectedLength, "Length should never exceed window"); - address[] memory got = rolling.getAll(); - address[] memory expected = new address[](3); - expected[0] = addr2; - expected[1] = addr3; - expected[2] = addr4; + for (uint256 i = 0; i < expectedLength; i++) { + assertEq(harness.at(i), inserted[count - expectedLength + i], "Order mismatch after rolling"); + } + } - assertEq(got, expected, "Expected addresses should match after rolling"); + function testFuzz_RollContainsMostRecent(address seed, uint256 windowSize) public { + windowSize = bound(windowSize, 1, MAX_WINDOW); + harness.configure(windowSize); + + for (uint256 i = 0; i < windowSize; i++) { + address current = address(uint160(uint256(keccak256(abi.encode(seed, i))))); + harness.roll(current); + assertTrue(harness.contains(current), "Recently rolled address should be contained"); + } } +} - function test_Add_SizeOne() public { - rolling.configureWindow(1); - address addr1 = vm.addr(1); - address addr2 = vm.addr(2); +contract RollingOpsHandler is Test { + using RollingOps for RollingOps.AddressArray; - rolling.add(addr1); - assertEq(rolling.getAt(0), addr1, "First address should be addr1"); + RollingOpsHarness public immutable harness; + address[] internal snapshot; - rolling.add(addr2); - assertEq(rolling.getAt(0), addr2, "Last address should be addr2 after rolling"); + constructor(RollingOpsHarness harness_) { + harness = harness_; } - function test_Add_MultipleRollovers() public { - // using window = 5 - rolling.configureWindow(5); + uint256 internal constant MAX_WINDOW = 20; - address addr1 = vm.addr(1); - address addr2 = vm.addr(2); - address addr3 = vm.addr(3); - address addr4 = vm.addr(4); - address addr5 = vm.addr(5); - address addr6 = vm.addr(6); - address addr7 = vm.addr(7); + function configure(uint256 windowSeed) external { + uint256 window = bound(windowSeed, 1, MAX_WINDOW); + harness.configure(window); + _rebuildSnapshot(); + } + + function roll(address value) external { + harness.roll(value); + _rebuildSnapshot(); + } + + function maxWindow() external pure returns (uint256) { + return MAX_WINDOW; + } + + function snapshotLength() external view returns (uint256) { + return snapshot.length; + } + + function snapshotAt(uint256 index) external view returns (address) { + return snapshot[index]; + } + + function _rebuildSnapshot() private { + delete snapshot; + address[] memory vals = harness.values(); + for (uint256 i = 0; i < vals.length; i++) { + snapshot.push(vals[i]); + } + } +} + +contract RollingOpsInvariantTest is Test { + RollingOpsHarness harness; + RollingOpsHandler handler; + + function setUp() public { + harness = new RollingOpsHarness(); + handler = new RollingOpsHandler(harness); + targetContract(address(handler)); + } + + function invariant_LengthWithinBound() external view { + assertLe(harness.length(), handler.maxWindow(), "Length exceeds handler max window"); + } - rolling.add(addr1); // out - rolling.add(addr2); // out - rolling.add(addr3); - rolling.add(addr4); - rolling.add(addr5); - rolling.add(addr6); - rolling.add(addr7); + function invariant_StateMatchesSnapshot() external view { + uint256 len = handler.snapshotLength(); + assertEq(harness.length(), len, "Length mismatch between harness and snapshot"); - address[] memory got = rolling.getAll(); - address[] memory expected = new address[](5); - expected[0] = addr3; - expected[1] = addr4; - expected[2] = addr5; - expected[3] = addr6; - expected[4] = addr7; - - assertEq(got, expected, "Expected addresses should match after multiple rollovers"); - } - - function test_Exists_ReturnTrueIfExists() public { - address addr1 = vm.addr(1); - address addr2 = vm.addr(2); - address addr3 = vm.addr(3); - address addr4 = vm.addr(4); - address addr5 = vm.addr(5); - address addr6 = vm.addr(6); - - // using default window - rolling.add(addr1); - rolling.add(addr2); - rolling.add(addr3); - rolling.add(addr4); - rolling.add(addr5); - rolling.add(addr6); - - // rolled out should return false - assertFalse(rolling.exists(addr1), "Address should not exist after rolling out"); - assertFalse(rolling.exists(addr2), "Address should not exist after rolling out"); - assertFalse(rolling.exists(addr3), "Address should not exist after rolling out"); - assertTrue(rolling.exists(addr4), "Address should not exist after rolling out"); - assertTrue(rolling.exists(addr5), "Address should not exist after rolling out"); - assertTrue(rolling.exists(addr6), "Address should not exist after rolling out"); - } - - function test_Length_ReturnValidLen() public { - address addr1 = vm.addr(1); - address addr2 = vm.addr(2); - - rolling.add(addr1); - rolling.add(addr2); - assertEq(rolling.getLength(), 2, "Expected length should be 2"); - - address addr3 = vm.addr(3); - address addr4 = vm.addr(4); - address addr5 = vm.addr(5); - rolling.add(addr3); - rolling.add(addr4); - rolling.add(addr5); - // do not grow; default window is 3 - // must keep the same window size - assertEq(rolling.getLength(), 3, "Expected length should be 3 after rolling"); - } - - function test_At_ReturnCorrespondingValue() public { - address addr1 = vm.addr(1); - address addr2 = vm.addr(2); - - rolling.add(addr1); - rolling.add(addr2); - - assertEq(rolling.getAt(0), addr1, "First address should be addr1"); - assertEq(rolling.getAt(1), addr2, "Second address should be addr2"); - } - - function test_At_ReturnLastElement() public { - rolling.configureWindow(3); - address addr1 = vm.addr(1); - address addr2 = vm.addr(2); - address addr3 = vm.addr(3); - rolling.add(addr1); - rolling.add(addr2); - rolling.add(addr3); - - assertEq(rolling.getAt(2), addr3, "Last address should be addr3"); - } - - function test_At_RevertIf_InvalidIndex() public { - address addr1 = vm.addr(1); - rolling.add(addr1); - // only index 0 existing - vm.expectRevert(); - rolling.getAt(1); + for (uint256 i = 0; i < len; i++) { + assertEq(harness.at(i), handler.snapshotAt(i), "Snapshot divergence detected"); + } } } From 7d9d63955e40e5f16dfaaf7e8902179f49d38b69 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Wed, 1 Oct 2025 09:56:12 -0600 Subject: [PATCH 20/33] test: policy authorizer --- .github/workflows/cov-badge.svg | 2 +- contracts/core/primitives/Types.sol | 18 +- contracts/rights/RightsPolicyAuthorizer.sol | 22 +- lcov.info | 2452 +++++++++-------- ...eploy_RightsManager_PolicyAuthorizer.s.sol | 21 + test/BaseTest.t.sol | 19 + test/finance/LedgerVault.t.sol | 512 ++++ test/policies/PolicyAudit.t.sol | 284 ++ test/rights/RightsPolicyAuthorizer.t.sol | 499 ++++ 9 files changed, 2668 insertions(+), 1161 deletions(-) create mode 100644 script/deployment/18_Deploy_RightsManager_PolicyAuthorizer.s.sol create mode 100644 test/finance/LedgerVault.t.sol create mode 100644 test/policies/PolicyAudit.t.sol create mode 100644 test/rights/RightsPolicyAuthorizer.t.sol diff --git a/.github/workflows/cov-badge.svg b/.github/workflows/cov-badge.svg index a7eae2a..a2370c1 100644 --- a/.github/workflows/cov-badge.svg +++ b/.github/workflows/cov-badge.svg @@ -1 +1 @@ -coveragecoverage58.25%58.25% \ No newline at end of file +coveragecoverage60.84%60.84% \ No newline at end of file diff --git a/contracts/core/primitives/Types.sol b/contracts/core/primitives/Types.sol index 78e9432..1660901 100644 --- a/contracts/core/primitives/Types.sol +++ b/contracts/core/primitives/Types.sol @@ -35,6 +35,15 @@ library T { EC // Elliptic Curve cryptography } + /// @title TimeFrame + /// @notice Enum representing the time frame for calculations or actions. + enum TimeFrame { + NONE, // Default value indicating "unset" or "no limit" + HOURLY, // Indicates a rate basis of per hour + DAILY, // Indicates a rate basis of per day + MONTHLY // Indicates a rate basis of per month + } + /// @title Agreement /// @dev Represents an escrow-backed agreement involving payment, distribution or access rights. /// @notice This struct supports flexible interaction models, including 1:1 and 1:N transfers, @@ -62,15 +71,6 @@ library T { bytes payload; } - /// @title TimeFrame - /// @notice Enum representing the time frame for calculations or actions. - enum TimeFrame { - NONE, // Default value indicating "unset" or "no limit" - HOURLY, // Indicates a rate basis of per hour - DAILY, // Indicates a rate basis of per day - MONTHLY // Indicates a rate basis of per month - } - /// @title Terms /// @notice Represents the financial and contractual terms associated with a specific policy or agreement. /// @dev This struct is used to capture both on-chain and off-chain terms for content or agreement management. diff --git a/contracts/rights/RightsPolicyAuthorizer.sol b/contracts/rights/RightsPolicyAuthorizer.sol index 806834a..7d2c04e 100644 --- a/contracts/rights/RightsPolicyAuthorizer.sol +++ b/contracts/rights/RightsPolicyAuthorizer.sol @@ -39,10 +39,6 @@ contract RightsPolicyAuthorizer is /// @dev Mapping to store the delegated rights for each policy contract (address) mapping(address => EnumerableSet.AddressSet) private _authorizedPolicies; - mapping(address => uint256) private _planIdx; // pos+1 - mapping(address => address[]) private _plan; - - /// @notice Emitted when rights are granted to a policy for content. /// @param policy The policy contract address granted rights. /// @param holder The address of the asset rights holder. @@ -97,9 +93,16 @@ contract RightsPolicyAuthorizer is /// @param data The data to initialize policy. e.g., prices, timeframes.. function authorizePolicy(address policy, bytes calldata data) external onlyAuditedPolicies(policy) nonReentrant { // type safe low level call to policy, call policy initialization with provided data.. - (bool success, ) = policy.call(abi.encodeCall(IPolicy.setup, (msg.sender, data))); - if (!success) revert InvalidPolicyInitialization("Error during policy initialization call"); - _authorizedPolicies[msg.sender].add(policy); + (bool success, bytes memory result) = policy.call(abi.encodeCall(IPolicy.setup, (msg.sender, data))); + if (!success && result.length == 0) { + revert InvalidPolicyInitialization("Error during policy initialization call"); + } + + bool authorized = _authorizedPolicies[msg.sender].add(policy); + if (!authorized) { + revert InvalidPolicyInitialization("Error during duplicated policy registration"); + } + emit RightsGranted(policy, msg.sender, data); } @@ -108,7 +111,10 @@ contract RightsPolicyAuthorizer is function revokePolicy(address policy) external { // if the policy is not authorized revoke fails bool revoked = _authorizedPolicies[msg.sender].remove(policy); - if (!revoked) revert RevocationFailed(msg.sender, policy); + if (!revoked) { + revert RevocationFailed(msg.sender, policy); + } + emit RightsRevoked(policy, msg.sender); } diff --git a/lcov.info b/lcov.info index d05933d..74c3a7a 100644 --- a/lcov.info +++ b/lcov.info @@ -1,14 +1,14 @@ TN: SF:contracts/access/AccessManager.sol -DA:17,91 +DA:17,119 FN:17,AccessManager.initialize -FNDA:91,AccessManager.initialize +FNDA:119,AccessManager.initialize DA:18,0 -DA:19,91 -DA:68,91 -DA:69,91 -DA:70,91 -DA:71,91 +DA:19,119 +DA:68,119 +DA:69,119 +DA:70,119 +DA:71,119 DA:76,0 FN:76,AccessManager._authorizeUpgrade FNDA:0,AccessManager._authorizeUpgrade @@ -35,40 +35,40 @@ FNDA:34,AssetReferendum.initialize DA:64,0 DA:65,0 DA:66,34 -DA:72,58206 +DA:72,58617 FN:72,AssetReferendum.submit -FNDA:58206,AssetReferendum.submit -DA:74,58206 -DA:75,58206 +FNDA:58617,AssetReferendum.submit +DA:74,58617 +DA:75,58617 BRDA:75,0,0,- -DA:76,58206 -DA:77,58206 -DA:99,2122 +DA:76,58617 +DA:77,58617 +DA:99,2075 FN:99,AssetReferendum.revoke -FNDA:2122,AssetReferendum.revoke -DA:100,2122 -DA:101,2122 -DA:106,4180 +FNDA:2075,AssetReferendum.revoke +DA:100,2075 +DA:101,2075 +DA:106,4108 FN:106,AssetReferendum.reject -FNDA:4180,AssetReferendum.reject -DA:107,4180 -DA:108,4180 -DA:113,49355 +FNDA:4108,AssetReferendum.reject +DA:107,4108 +DA:108,4108 +DA:113,49731 FN:113,AssetReferendum.approve -FNDA:49355,AssetReferendum.approve -DA:114,49355 -DA:115,49355 -DA:121,45602 +FNDA:49731,AssetReferendum.approve +DA:114,49731 +DA:115,49731 +DA:121,45977 FN:121,AssetReferendum.isApproved -FNDA:45602,AssetReferendum.isApproved -DA:122,45602 -DA:123,45602 -DA:124,45602 -DA:126,45602 -DA:131,46374 +FNDA:45977,AssetReferendum.isApproved +DA:122,45977 +DA:123,45977 +DA:124,45977 +DA:126,45977 +DA:131,46749 FN:131,AssetReferendum.isActive -FNDA:46374,AssetReferendum.isActive -DA:132,46374 +FNDA:46749,AssetReferendum.isActive +DA:132,46749 DA:138,0 FN:138,AssetReferendum._authorizeUpgrade FNDA:0,AssetReferendum._authorizeUpgrade @@ -81,16 +81,16 @@ BRH:0 end_of_record TN: SF:contracts/assets/AssetRegistry.sol -DA:69,44830 +DA:69,45205 FN:69,AssetRegistry.onlyApprovedAsset -FNDA:44830,AssetRegistry.onlyApprovedAsset -DA:70,44830 +FNDA:45205,AssetRegistry.onlyApprovedAsset +DA:70,45205 BRDA:70,0,0,1 DA:71,1 -DA:78,8984 +DA:78,8788 FN:78,AssetRegistry.onlyOwner -FNDA:8984,AssetRegistry.onlyOwner -DA:79,8984 +FNDA:8788,AssetRegistry.onlyOwner +DA:79,8788 BRDA:79,1,0,- DA:80,0 DA:87,21 @@ -110,34 +110,34 @@ DA:108,0 FN:108,AssetRegistry.supportsInterface FNDA:0,AssetRegistry.supportsInterface DA:111,0 -DA:127,44829 +DA:127,45204 FN:127,AssetRegistry.register -FNDA:44829,AssetRegistry.register -DA:128,44829 -DA:129,44828 -DA:130,44829 -DA:136,8446 +FNDA:45204,AssetRegistry.register +DA:128,45204 +DA:129,45203 +DA:130,45204 +DA:136,8581 FN:136,AssetRegistry.revoke -FNDA:8446,AssetRegistry.revoke -DA:137,8446 -DA:139,8446 -DA:140,8446 -DA:141,8446 -DA:147,25871 +FNDA:8581,AssetRegistry.revoke +DA:137,8581 +DA:139,8581 +DA:140,8581 +DA:141,8581 +DA:147,25618 FN:147,AssetRegistry.transfer -FNDA:25871,AssetRegistry.transfer -DA:148,25871 -DA:149,25871 -DA:156,8984 +FNDA:25618,AssetRegistry.transfer +DA:148,25618 +DA:149,25618 +DA:156,8788 FN:156,AssetRegistry.switchState -FNDA:8984,AssetRegistry.switchState -DA:157,8984 -DA:159,8984 -DA:161,8984 -DA:165,79146 +FNDA:8788,AssetRegistry.switchState +DA:157,8788 +DA:159,8788 +DA:161,8788 +DA:165,79403 FN:165,AssetRegistry._update -FNDA:79146,AssetRegistry._update -DA:170,79146 +FNDA:79403,AssetRegistry._update +DA:170,79403 DA:174,0 FN:174,AssetRegistry._increaseBalance FNDA:0,AssetRegistry._increaseBalance @@ -145,16 +145,16 @@ DA:178,0 DA:183,0 FN:183,AssetRegistry._authorizeUpgrade FNDA:0,AssetRegistry._authorizeUpgrade -DA:186,47051 +DA:186,47349 FN:186,AssetRegistry._enableAsset -FNDA:47051,AssetRegistry._enableAsset -DA:187,47051 -DA:188,47051 -DA:192,15207 +FNDA:47349,AssetRegistry._enableAsset +DA:187,47349 +DA:188,47349 +DA:192,15223 FN:192,AssetRegistry._disableAsset -FNDA:15207,AssetRegistry._disableAsset -DA:193,15207 -DA:194,15207 +FNDA:15223,AssetRegistry._disableAsset +DA:193,15223 +DA:194,15223 FNF:14 FNH:11 LF:44 @@ -164,10 +164,10 @@ BRH:1 end_of_record TN: SF:contracts/assets/AssetSafe.sol -DA:40,22469 +DA:40,22686 FN:40,AssetSafe.onlyHolder -FNDA:22469,AssetSafe.onlyHolder -DA:41,22469 +FNDA:22686,AssetSafe.onlyHolder +DA:41,22686 BRDA:41,0,0,257 DA:42,257 DA:48,10 @@ -188,19 +188,19 @@ DA:71,258 FN:71,AssetSafe.getContent FNDA:258,AssetSafe.getContent DA:72,258 -DA:80,22212 +DA:80,22429 FN:80,AssetSafe.setContent -FNDA:22212,AssetSafe.setContent -DA:81,22212 -DA:82,22212 -DA:83,22212 +FNDA:22429,AssetSafe.setContent +DA:81,22429 +DA:82,22429 +DA:83,22429 DA:88,0 FN:88,AssetSafe._authorizeUpgrade FNDA:0,AssetSafe._authorizeUpgrade -DA:95,22470 +DA:95,22687 FN:95,AssetSafe._computeComposedKey -FNDA:22470,AssetSafe._computeComposedKey -DA:96,22470 +FNDA:22687,AssetSafe._computeComposedKey +DA:96,22687 FNF:8 FNH:7 LF:20 @@ -227,21 +227,21 @@ BRH:0 end_of_record TN: SF:contracts/core/libraries/FeesOps.sol -DA:12,12711 +DA:12,12796 FN:12,FeesOps.isBasePoint -FNDA:12711,FeesOps.isBasePoint -DA:14,12711 -DA:19,12653 +FNDA:12796,FeesOps.isBasePoint +DA:14,12796 +DA:19,12751 FN:19,FeesOps.isNominal -FNDA:12653,FeesOps.isNominal -DA:21,12653 -DA:27,46395 +FNDA:12751,FeesOps.isNominal +DA:21,12751 +DA:27,45863 FN:27,FeesOps.perOf -FNDA:46395,FeesOps.perOf -DA:31,46395 +FNDA:45863,FeesOps.perOf +DA:31,45863 BRDA:31,0,0,- BRDA:31,0,1,- -DA:32,46395 +DA:32,45863 DA:37,17151 FN:37,FeesOps.calcBps FNDA:17151,FeesOps.calcBps @@ -262,10 +262,10 @@ DA:27,15750 DA:28,15750 BRDA:28,0,0,- DA:29,0 -DA:37,36420 +DA:37,36250 FN:37,FinancialOps._erc20Transfer -FNDA:36420,FinancialOps._erc20Transfer -DA:38,36420 +FNDA:36250,FinancialOps._erc20Transfer +DA:38,36250 DA:45,18856 FN:45,FinancialOps._nativeDeposit FNDA:18856,FinancialOps._nativeDeposit @@ -273,13 +273,13 @@ DA:46,18856 BRDA:46,1,0,1 DA:47,1 DA:51,0 -DA:60,53035 +DA:60,52914 FN:60,FinancialOps._erc20Deposit -FNDA:53035,FinancialOps._erc20Deposit -DA:61,53035 +FNDA:52914,FinancialOps._erc20Deposit +DA:61,52914 BRDA:61,2,0,3 DA:62,3 -DA:68,53032 +DA:68,52911 DA:69,0 DA:78,3 FN:78,FinancialOps.increaseAllowance @@ -288,43 +288,43 @@ DA:79,3 BRDA:79,3,0,2 DA:80,2 DA:83,1 -DA:92,53037 +DA:92,52916 FN:92,FinancialOps.allowance -FNDA:53037,FinancialOps.allowance -DA:93,53037 +FNDA:52916,FinancialOps.allowance +DA:93,52916 BRDA:93,4,0,1 DA:94,1 -DA:97,53036 -DA:106,71893 +DA:97,52915 +DA:106,71772 FN:106,FinancialOps.safeDeposit -FNDA:71893,FinancialOps.safeDeposit -DA:107,71893 +FNDA:71772,FinancialOps.safeDeposit +DA:107,71772 BRDA:107,5,0,2 DA:108,2 -DA:111,71891 +DA:111,71770 BRDA:111,6,0,18856 DA:112,18856 -DA:115,53035 -DA:121,52434 +DA:115,52914 +DA:121,52264 FN:121,FinancialOps.balanceOf -FNDA:52434,FinancialOps.balanceOf -DA:122,52434 +FNDA:52264,FinancialOps.balanceOf +DA:122,52264 BRDA:122,7,0,15752 DA:123,15752 -DA:126,36682 -DA:134,52174 +DA:126,36512 +DA:134,52004 FN:134,FinancialOps.transfer -FNDA:52174,FinancialOps.transfer -DA:135,52174 +FNDA:52004,FinancialOps.transfer +DA:135,52004 BRDA:135,8,0,2 DA:136,2 -DA:139,52172 +DA:139,52002 BRDA:139,9,0,2 DA:140,2 -DA:143,52170 +DA:143,52000 BRDA:143,10,0,15750 DA:144,15750 -DA:147,36420 +DA:147,36250 FNF:9 FNH:9 LF:41 @@ -334,18 +334,18 @@ BRH:10 end_of_record TN: SF:contracts/core/libraries/LoopOps.sol -DA:15,0 +DA:15,471 FN:15,LoopOps.uncheckedInc -FNDA:0,LoopOps.uncheckedInc -DA:17,0 +FNDA:471,LoopOps.uncheckedInc +DA:17,471 DA:26,0 FN:26,LoopOps.uncheckedDec FNDA:0,LoopOps.uncheckedDec DA:28,0 FNF:2 -FNH:0 +FNH:1 LF:4 -LH:0 +LH:2 BRF:0 BRH:0 end_of_record @@ -364,16 +364,16 @@ BRH:0 end_of_record TN: SF:contracts/core/libraries/RollingOps.sol -DA:36,25658 +DA:36,25663 FN:36,RollingOps.configure -FNDA:25658,RollingOps.configure -DA:37,25658 +FNDA:25663,RollingOps.configure +DA:37,25663 BRDA:37,0,0,1 -DA:38,25657 -DA:42,35225 +DA:38,25662 +DA:42,35220 FN:42,RollingOps.roll -FNDA:35225,RollingOps.roll -DA:43,35225 +FNDA:35220,RollingOps.roll +DA:43,35220 DA:47,2545 FN:47,RollingOps.contains FNDA:2545,RollingOps.contains @@ -397,46 +397,46 @@ DA:68,50051 DA:69,50051 DA:72,0 DA:75,50051 -DA:84,35225 +DA:84,35220 FN:84,RollingOps._roll -FNDA:35225,RollingOps._roll -DA:87,35225 -BRDA:87,1,0,12271 -DA:88,12271 -DA:91,35225 -DA:95,35225 +FNDA:35220,RollingOps._roll +DA:87,35220 +BRDA:87,1,0,12283 +DA:88,12283 +DA:91,35220 +DA:95,35220 FN:95,RollingOps._rollin -FNDA:35225,RollingOps._rollin -DA:96,35225 -DA:97,35225 -DA:101,12271 +FNDA:35220,RollingOps._rollin +DA:96,35220 +DA:97,35220 +DA:101,12283 FN:101,RollingOps._rollout -FNDA:12271,RollingOps._rollout -DA:103,12271 -DA:104,12271 -DA:106,12271 -DA:110,65856 -DA:111,65856 -DA:114,65856 -DA:119,12271 +FNDA:12283,RollingOps._rollout +DA:103,12283 +DA:104,12283 +DA:106,12283 +DA:110,65865 +DA:111,65865 +DA:114,65865 +DA:119,12283 DA:123,2545 FN:123,RollingOps._contains FNDA:2545,RollingOps._contains DA:124,2545 -DA:128,73024 +DA:128,73014 FN:128,RollingOps._length -FNDA:73024,RollingOps._length -DA:129,73024 +FNDA:73014,RollingOps._length +DA:129,73014 DA:133,2314 FN:133,RollingOps._at FNDA:2314,RollingOps._at DA:134,2314 BRDA:134,2,0,1 DA:135,2313 -DA:139,113354 +DA:139,113370 FN:139,RollingOps._window -FNDA:113354,RollingOps._window -DA:140,113354 +FNDA:113370,RollingOps._window +DA:140,113370 DA:144,50051 FN:144,RollingOps._values FNDA:50051,RollingOps._values @@ -450,10 +450,10 @@ BRH:3 end_of_record TN: SF:contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol -DA:29,57969 +DA:29,62457 FN:29,AccessControlledUpgradeable.onlyAdmin -FNDA:57969,AccessControlledUpgradeable.onlyAdmin -DA:34,57969 +FNDA:62457,AccessControlledUpgradeable.onlyAdmin +DA:34,62457 BRDA:34,0,0,258 DA:35,258 DA:43,8831 @@ -464,29 +464,29 @@ DA:50,7835 FN:50,AccessControlledUpgradeable.unpause FNDA:7835,AccessControlledUpgradeable.unpause DA:51,0 -DA:59,281 +DA:59,311 FN:59,AccessControlledUpgradeable.__AccessControlled_init -FNDA:281,AccessControlledUpgradeable.__AccessControlled_init -DA:60,281 -DA:61,281 -DA:67,281 +FNDA:311,AccessControlledUpgradeable.__AccessControlled_init +DA:60,311 +DA:61,311 +DA:67,311 FN:67,AccessControlledUpgradeable.__AccessControlled_init_unchained -FNDA:281,AccessControlledUpgradeable.__AccessControlled_init_unchained -DA:68,281 +FNDA:311,AccessControlledUpgradeable.__AccessControlled_init_unchained +DA:68,311 BRDA:68,1,0,1 DA:69,1 -DA:72,280 -DA:73,280 -DA:80,114141 +DA:72,310 +DA:73,310 +DA:80,131438 FN:80,AccessControlledUpgradeable._hasRole -FNDA:114141,AccessControlledUpgradeable._hasRole -DA:81,114141 -DA:82,114141 -DA:83,114141 -DA:84,114141 -DA:88,114421 +FNDA:131438,AccessControlledUpgradeable._hasRole +DA:81,131438 +DA:82,131438 +DA:83,131438 +DA:84,131438 +DA:88,131748 FN:88,AccessControlledUpgradeable._getAccessControlStorage -FNDA:114421,AccessControlledUpgradeable._getAccessControlStorage +FNDA:131748,AccessControlledUpgradeable._getAccessControlStorage DA:90,0 FNF:7 FNH:7 @@ -578,32 +578,32 @@ DA:42,260 FN:42,BalanceOperatorUpgradeable.getBalance FNDA:260,BalanceOperatorUpgradeable.getBalance DA:43,260 -DA:50,34327 +DA:50,34206 FN:50,BalanceOperatorUpgradeable._deposit -FNDA:34327,BalanceOperatorUpgradeable._deposit -DA:55,34327 -DA:56,34325 -DA:57,34327 +FNDA:34206,BalanceOperatorUpgradeable._deposit +DA:55,34206 +DA:56,34204 +DA:57,34206 DA:58,0 -DA:65,20851 +DA:65,20681 FN:65,BalanceOperatorUpgradeable._withdraw -FNDA:20851,BalanceOperatorUpgradeable._withdraw -DA:70,20851 +FNDA:20681,BalanceOperatorUpgradeable._withdraw +DA:70,20681 BRDA:70,0,0,2 -DA:71,20849 -DA:72,20849 -DA:73,20849 +DA:71,20679 +DA:72,20679 +DA:73,20679 DA:74,0 -DA:81,8042 +DA:81,7861 FN:81,BalanceOperatorUpgradeable._transfer -FNDA:8042,BalanceOperatorUpgradeable._transfer -DA:86,8042 +FNDA:7861,BalanceOperatorUpgradeable._transfer +DA:86,7861 BRDA:86,1,0,2 -DA:87,8040 +DA:87,7859 BRDA:87,2,0,1 -DA:89,8039 -DA:90,8039 -DA:91,8039 +DA:89,7858 +DA:90,7858 +DA:91,7858 DA:92,0 DA:97,0 FN:97,BalanceOperatorUpgradeable._getBalanceOperatorStorage @@ -624,24 +624,24 @@ FNDA:21,ERC721StatefulUpgradeable.__ERC721Stateful_init DA:31,0 FN:31,ERC721StatefulUpgradeable.__ERC721Stateful_init_unchained FNDA:0,ERC721StatefulUpgradeable.__ERC721Stateful_init_unchained -DA:35,47051 +DA:35,47349 FN:35,ERC721StatefulUpgradeable._activate -FNDA:47051,ERC721StatefulUpgradeable._activate -DA:36,47051 -DA:37,47051 -DA:42,15207 +FNDA:47349,ERC721StatefulUpgradeable._activate +DA:36,47349 +DA:37,47349 +DA:42,15223 FN:42,ERC721StatefulUpgradeable._deactivate -FNDA:15207,ERC721StatefulUpgradeable._deactivate -DA:43,15207 -DA:44,15207 -DA:50,9244 +FNDA:15223,ERC721StatefulUpgradeable._deactivate +DA:43,15223 +DA:44,15223 +DA:50,9048 FN:50,ERC721StatefulUpgradeable.isActive -FNDA:9244,ERC721StatefulUpgradeable.isActive -DA:51,9244 -DA:52,9244 -DA:56,71502 +FNDA:9048,ERC721StatefulUpgradeable.isActive +DA:51,9048 +DA:52,9048 +DA:56,71620 FN:56,ERC721StatefulUpgradeable._getERC721StateStorage -FNDA:71502,ERC721StatefulUpgradeable._getERC721StateStorage +FNDA:71620,ERC721StatefulUpgradeable._getERC721StateStorage DA:58,0 FNF:6 FNH:5 @@ -691,40 +691,40 @@ BRH:0 end_of_record TN: SF:contracts/core/primitives/upgradeable/LedgerUpgradeable.sol -DA:28,28082 +DA:28,27792 FN:28,LedgerUpgradeable.onlyValidOperation -FNDA:28082,LedgerUpgradeable.onlyValidOperation -DA:29,28082 +FNDA:27792,LedgerUpgradeable.onlyValidOperation +DA:29,27792 BRDA:29,0,0,4 -DA:36,180665 +DA:36,180411 FN:36,LedgerUpgradeable.getLedgerBalance -FNDA:180665,LedgerUpgradeable.getLedgerBalance -DA:37,180665 -DA:38,180665 +FNDA:180411,LedgerUpgradeable.getLedgerBalance +DA:37,180411 +DA:38,180411 DA:45,213 FN:45,LedgerUpgradeable.__Ledger_init FNDA:213,LedgerUpgradeable.__Ledger_init DA:50,0 FN:50,LedgerUpgradeable.__Ledger_init_unchained FNDA:0,LedgerUpgradeable.__Ledger_init_unchained -DA:57,8712 +DA:57,8730 FN:57,LedgerUpgradeable._setLedgerEntry -FNDA:8712,LedgerUpgradeable._setLedgerEntry -DA:58,8712 -DA:59,8712 -DA:67,131570 +FNDA:8730,LedgerUpgradeable._setLedgerEntry +DA:58,8730 +DA:59,8730 +DA:67,130908 FN:67,LedgerUpgradeable._sumLedgerEntry -FNDA:131570,LedgerUpgradeable._sumLedgerEntry -DA:68,131570 -DA:69,131570 -DA:77,63591 +FNDA:130908,LedgerUpgradeable._sumLedgerEntry +DA:68,130908 +DA:69,130908 +DA:77,62716 FN:77,LedgerUpgradeable._subLedgerEntry -FNDA:63591,LedgerUpgradeable._subLedgerEntry -DA:78,63591 -DA:79,63591 -DA:84,384538 +FNDA:62716,LedgerUpgradeable._subLedgerEntry +DA:78,62716 +DA:79,62716 +DA:84,382765 FN:84,LedgerUpgradeable._getLedgerStorage -FNDA:384538,LedgerUpgradeable._getLedgerStorage +FNDA:382765,LedgerUpgradeable._getLedgerStorage DA:86,0 FNF:8 FNH:7 @@ -742,51 +742,51 @@ DA:29,0 DA:35,0 FN:35,LockOperatorUpgradeable.__LockOperator_init_unchained FNDA:0,LockOperatorUpgradeable.__LockOperator_init_unchained -DA:44,34022 +DA:44,33498 FN:44,LockOperatorUpgradeable._lock -FNDA:34022,LockOperatorUpgradeable._lock -DA:49,34022 +FNDA:33498,LockOperatorUpgradeable._lock +DA:49,33498 BRDA:49,0,0,3 -DA:50,34019 -DA:51,34019 -DA:52,34019 +DA:50,33495 +DA:51,33495 +DA:52,33495 DA:53,0 -DA:60,11103 +DA:60,10983 FN:60,LockOperatorUpgradeable._release -FNDA:11103,LockOperatorUpgradeable._release -DA:65,11103 +FNDA:10983,LockOperatorUpgradeable._release +DA:65,10983 BRDA:65,1,0,1 -DA:66,11102 -DA:67,11102 -DA:68,11102 +DA:66,10982 +DA:67,10982 +DA:68,10982 DA:69,0 -DA:78,15763 +DA:78,15503 FN:78,LockOperatorUpgradeable._claim -FNDA:15763,LockOperatorUpgradeable._claim -DA:83,15763 +FNDA:15503,LockOperatorUpgradeable._claim +DA:83,15503 BRDA:83,2,0,1 -DA:84,15762 -DA:85,15762 -DA:86,15762 +DA:84,15502 +DA:85,15502 +DA:86,15502 DA:87,0 -DA:95,26864 +DA:95,26484 FN:95,LockOperatorUpgradeable._subLockedAmount -FNDA:26864,LockOperatorUpgradeable._subLockedAmount -DA:96,26864 -DA:97,26864 -DA:105,34019 +FNDA:26484,LockOperatorUpgradeable._subLockedAmount +DA:96,26484 +DA:97,26484 +DA:105,33495 FN:105,LockOperatorUpgradeable._sumLockedAmount -FNDA:34019,LockOperatorUpgradeable._sumLockedAmount -DA:106,34019 -DA:107,34019 -DA:115,26866 +FNDA:33495,LockOperatorUpgradeable._sumLockedAmount +DA:106,33495 +DA:107,33495 +DA:115,26486 FN:115,LockOperatorUpgradeable._getLockedAmount -FNDA:26866,LockOperatorUpgradeable._getLockedAmount -DA:116,26866 -DA:117,26866 -DA:122,87749 +FNDA:26486,LockOperatorUpgradeable._getLockedAmount +DA:116,26486 +DA:117,26486 +DA:122,86465 FN:122,LockOperatorUpgradeable._getLockOperatorStorage -FNDA:87749,LockOperatorUpgradeable._getLockOperatorStorage +FNDA:86465,LockOperatorUpgradeable._getLockOperatorStorage DA:124,0 FNF:9 FNH:8 @@ -797,55 +797,55 @@ BRH:3 end_of_record TN: SF:contracts/core/primitives/upgradeable/QuorumUpgradeable.sol -DA:48,75 +DA:48,90 FN:48,QuorumUpgradeable.__Quorum_init -FNDA:75,QuorumUpgradeable.__Quorum_init +FNDA:90,QuorumUpgradeable.__Quorum_init DA:53,0 FN:53,QuorumUpgradeable.__Quorum_init_unchained FNDA:0,QuorumUpgradeable.__Quorum_init_unchained -DA:57,260172 +DA:57,312648 FN:57,QuorumUpgradeable._status -FNDA:260172,QuorumUpgradeable._status -DA:58,260172 -DA:59,260172 -DA:65,5832 +FNDA:312648,QuorumUpgradeable._status +DA:58,312648 +DA:59,312648 +DA:65,10611 FN:65,QuorumUpgradeable._revoke -FNDA:5832,QuorumUpgradeable._revoke -DA:66,5832 -DA:67,5832 +FNDA:10611,QuorumUpgradeable._revoke +DA:66,10611 +DA:67,10611 BRDA:67,0,0,2 -DA:68,5830 -DA:74,4216 +DA:68,10609 +DA:74,4146 FN:74,QuorumUpgradeable._block -FNDA:4216,QuorumUpgradeable._block -DA:75,4216 -DA:76,4216 +FNDA:4146,QuorumUpgradeable._block +DA:75,4146 +DA:76,4146 BRDA:76,1,0,1 -DA:77,4215 -DA:82,59323 +DA:77,4145 +DA:82,72126 FN:82,QuorumUpgradeable._approve -FNDA:59323,QuorumUpgradeable._approve -DA:83,59323 -DA:84,59323 -BRDA:84,2,0,2 -DA:85,59321 -DA:90,297 +FNDA:72126,QuorumUpgradeable._approve +DA:83,72126 +DA:84,72126 +BRDA:84,2,0,11487 +DA:85,60639 +DA:90,290 FN:90,QuorumUpgradeable._quit -FNDA:297,QuorumUpgradeable._quit -DA:91,297 -DA:92,297 +FNDA:290,QuorumUpgradeable._quit +DA:91,290 +DA:92,290 BRDA:92,3,0,1 -DA:93,296 -DA:98,89326 +DA:93,289 +DA:98,102293 FN:98,QuorumUpgradeable._register -FNDA:89326,QuorumUpgradeable._register -DA:99,89326 -DA:100,89326 -BRDA:100,4,0,2 -DA:101,89324 -DA:105,419166 +FNDA:102293,QuorumUpgradeable._register +DA:99,102293 +DA:100,102293 +BRDA:100,4,0,11486 +DA:101,90807 +DA:105,502114 FN:105,QuorumUpgradeable._getRegistryStorage -FNDA:419166,QuorumUpgradeable._getRegistryStorage +FNDA:502114,QuorumUpgradeable._getRegistryStorage DA:107,0 FNF:9 FNH:8 @@ -1021,10 +1021,10 @@ DA:31,0 FN:31,MMC.nonces FNDA:0,MMC.nonces DA:32,0 -DA:36,40174 +DA:36,39883 FN:36,MMC._update -FNDA:40174,MMC._update -DA:37,40174 +FNDA:39883,MMC._update +DA:37,39883 FNF:4 FNH:2 LF:8 @@ -1049,10 +1049,10 @@ BRDA:74,2,0,- DA:75,0 DA:78,51367 DA:79,51367 -DA:82,12471 -BRDA:82,3,0,12471 -DA:83,12471 -DA:84,12471 +DA:82,12287 +BRDA:82,3,0,12287 +DA:83,12287 +DA:84,12287 BRDA:84,4,0,1 DA:92,40 FN:92,Tollgate.constructor @@ -1063,24 +1063,24 @@ FN:98,Tollgate.initialize FNDA:40,Tollgate.initialize DA:99,0 DA:100,40 -DA:107,45664 +DA:107,44616 FN:107,Tollgate.isSupportedCurrency -FNDA:45664,Tollgate.isSupportedCurrency -DA:108,45664 +FNDA:44616,Tollgate.isSupportedCurrency +DA:108,44616 DA:114,257 FN:114,Tollgate.supportedCurrencies FNDA:257,Tollgate.supportedCurrencies DA:115,257 -DA:122,23734 +DA:122,23210 FN:122,Tollgate.getFees -FNDA:23734,Tollgate.getFees -DA:124,23734 +FNDA:23210,Tollgate.getFees +DA:124,23210 BRDA:124,5,0,1 DA:125,1 -DA:128,23733 -DA:129,23733 -DA:130,23733 -DA:131,23733 +DA:128,23209 +DA:129,23209 +DA:130,23209 +DA:131,23209 DA:139,51364 FN:139,Tollgate.setFees FNDA:51364,Tollgate.setFees @@ -1094,16 +1094,16 @@ DA:158,51364 DA:163,0 FN:163,Tollgate._authorizeUpgrade FNDA:0,Tollgate._authorizeUpgrade -DA:169,69398 +DA:169,67826 FN:169,Tollgate._isSchemeSupported -FNDA:69398,Tollgate._isSchemeSupported -DA:170,69398 -DA:171,69398 -DA:172,69398 -DA:180,144495 +FNDA:67826,Tollgate._isSchemeSupported +DA:170,67826 +DA:171,67826 +DA:172,67826 +DA:180,142399 FN:180,Tollgate._computeComposedKey -FNDA:144495,Tollgate._computeComposedKey -DA:181,144495 +FNDA:142399,Tollgate._computeComposedKey +DA:181,142399 FNF:11 FNH:10 LF:41 @@ -1155,11 +1155,11 @@ BRH:0 end_of_record TN: SF:contracts/financial/AgreementManager.sol -DA:70,22960 +DA:70,22436 FN:70,AgreementManager.onlySupportedCurrency -FNDA:22960,AgreementManager.onlySupportedCurrency -DA:71,22960 -DA:72,22960 +FNDA:22436,AgreementManager.onlySupportedCurrency +DA:71,22436 +DA:72,22436 BRDA:72,0,0,- DA:77,38 FN:77,AgreementManager.constructor @@ -1173,65 +1173,65 @@ FNDA:38,AgreementManager.initialize DA:88,0 DA:89,38 DA:90,38 -DA:95,37924 +DA:95,37586 FN:95,AgreementManager.setMaxParties -FNDA:37924,AgreementManager.setMaxParties -DA:96,37924 +FNDA:37586,AgreementManager.setMaxParties +DA:96,37586 BRDA:96,1,0,1 -DA:97,37923 -DA:101,75212 +DA:97,37585 +DA:101,75511 FN:101,AgreementManager.maxParties -FNDA:75212,AgreementManager.maxParties -DA:102,75212 -DA:111,22447 +FNDA:75511,AgreementManager.maxParties +DA:102,75511 +DA:111,21923 FN:111,AgreementManager.createAgreement -FNDA:22447,AgreementManager.createAgreement -DA:119,22447 -DA:120,22447 -DA:124,22445 -DA:125,22445 +FNDA:21923,AgreementManager.createAgreement +DA:119,21923 +DA:120,21923 +DA:124,21921 +DA:125,21921 DA:126,0 -DA:131,35473 +DA:131,34689 FN:131,AgreementManager.getAgreement -FNDA:35473,AgreementManager.getAgreement -DA:132,35473 -DA:141,22960 +FNDA:34689,AgreementManager.getAgreement +DA:132,34689 +DA:141,22436 FN:141,AgreementManager.previewAgreement -FNDA:22960,AgreementManager.previewAgreement -DA:160,22960 -DA:164,22959 -DA:165,22959 -DA:169,22959 +FNDA:22436,AgreementManager.previewAgreement +DA:160,22436 +DA:164,22435 +DA:165,22435 +DA:169,22435 DA:185,0 FN:185,AgreementManager._authorizeUpgrade FNDA:0,AgreementManager._authorizeUpgrade -DA:188,22445 +DA:188,21921 FN:188,AgreementManager._createAndStoreProof -FNDA:22445,AgreementManager._createAndStoreProof -DA:190,22445 -DA:191,22445 -DA:192,22445 +FNDA:21921,AgreementManager._createAndStoreProof +DA:190,21921 +DA:191,21921 +DA:192,21921 DA:193,0 -DA:197,22959 +DA:197,22435 FN:197,AgreementManager._calculatePenalization -FNDA:22959,AgreementManager._calculatePenalization -DA:198,22959 -DA:199,6514 -DA:200,6514 -DA:201,6514 -DA:209,6514 +FNDA:22435,AgreementManager._calculatePenalization +DA:198,22435 +DA:199,6506 +DA:200,6506 +DA:201,6506 +DA:209,6506 FN:209,AgreementManager._penaltyBps -FNDA:6514,AgreementManager._penaltyBps -DA:210,6514 -DA:214,6514 -DA:218,6514 +FNDA:6506,AgreementManager._penaltyBps +DA:210,6506 +DA:214,6506 +DA:218,6506 BRDA:218,4,0,- DA:219,0 -DA:229,22960 +DA:229,22436 FN:229,AgreementManager._calcFees -FNDA:22960,AgreementManager._calcFees -DA:231,22960 -DA:232,22960 +FNDA:22436,AgreementManager._calcFees +DA:231,22436 +DA:232,22436 DA:233,1 DA:234,1 BRDA:234,7,0,1 @@ -1245,10 +1245,10 @@ BRH:2 end_of_record TN: SF:contracts/financial/AgreementSettler.sol -DA:85,6604 +DA:85,6484 FN:85,AgreementSettler.onlyValidAgreement -FNDA:6604,AgreementSettler.onlyValidAgreement -DA:86,6604 +FNDA:6484,AgreementSettler.onlyValidAgreement +DA:86,6484 BRDA:86,0,0,1 DA:87,1 DA:93,23 @@ -1272,51 +1272,51 @@ DA:117,0 DA:119,0 DA:120,0 DA:121,0 -DA:138,6603 +DA:138,6483 FN:138,AgreementSettler.quitAgreement -FNDA:6603,AgreementSettler.quitAgreement -DA:139,6603 -DA:140,6603 +FNDA:6483,AgreementSettler.quitAgreement +DA:139,6483 +DA:140,6483 BRDA:140,2,0,1 -DA:154,6602 -DA:155,6602 -DA:156,6602 -DA:164,6602 -DA:165,6602 -DA:166,6602 -DA:168,6602 -DA:170,6602 -DA:172,6602 -BRDA:172,3,0,6602 -DA:174,6602 +DA:154,6482 +DA:155,6482 +DA:156,6482 +DA:164,6482 +DA:165,6482 +DA:166,6482 +DA:168,6482 +DA:170,6482 +DA:172,6482 +BRDA:172,3,0,6482 +DA:174,6482 DA:175,0 -DA:201,6425 +DA:201,6285 FN:201,AgreementSettler.settleAgreement -FNDA:6425,AgreementSettler.settleAgreement -DA:206,6425 -DA:207,6425 +FNDA:6285,AgreementSettler.settleAgreement +DA:206,6285 +DA:207,6285 BRDA:207,4,0,1 -DA:209,6424 -DA:210,6424 -DA:211,6424 -DA:212,6424 -DA:213,6424 -DA:215,6424 -DA:216,6424 -DA:217,6424 -DA:222,6424 -DA:226,6424 -DA:228,6424 -BRDA:228,5,0,6424 -DA:229,6424 +DA:209,6284 +DA:210,6284 +DA:211,6284 +DA:212,6284 +DA:213,6284 +DA:215,6284 +DA:216,6284 +DA:217,6284 +DA:222,6284 +DA:226,6284 +DA:228,6284 +BRDA:228,5,0,6284 +DA:229,6284 DA:230,0 DA:236,0 FN:236,AgreementSettler._authorizeUpgrade FNDA:0,AgreementSettler._authorizeUpgrade -DA:240,13026 +DA:240,12766 FN:240,AgreementSettler._setProofAsSettled -FNDA:13026,AgreementSettler._setProofAsSettled -DA:241,13026 +FNDA:12766,AgreementSettler._setProofAsSettled +DA:241,12766 FNF:8 FNH:6 LF:51 @@ -1340,18 +1340,18 @@ DA:41,0 DA:42,0 DA:43,0 DA:44,53 -DA:54,27775 +DA:54,27251 FN:54,LedgerVault.lock -FNDA:27775,LedgerVault.lock -DA:59,27775 -DA:66,9169 +FNDA:27251,LedgerVault.lock +DA:59,27251 +DA:66,9049 FN:66,LedgerVault.release -FNDA:9169,LedgerVault.release -DA:71,9169 -DA:80,15453 +FNDA:9049,LedgerVault.release +DA:71,9049 +DA:80,15193 FN:80,LedgerVault.claim -FNDA:15453,LedgerVault.claim -DA:85,15453 +FNDA:15193,LedgerVault.claim +DA:85,15193 DA:92,0 FN:92,LedgerVault.approve FNDA:0,LedgerVault.approve @@ -1372,10 +1372,10 @@ DA:128,5483 FN:128,LedgerVault.withdraw FNDA:5483,LedgerVault.withdraw DA:133,5483 -DA:140,6982 +DA:140,6842 FN:140,LedgerVault.transfer -FNDA:6982,LedgerVault.transfer -DA:141,6982 +FNDA:6842,LedgerVault.transfer +DA:141,6842 DA:147,0 FN:147,LedgerVault._authorizeUpgrade FNDA:0,LedgerVault._authorizeUpgrade @@ -1460,41 +1460,41 @@ BRH:0 end_of_record TN: SF:contracts/policies/PolicyAudit.sol -DA:44,20548 +DA:44,33061 FN:44,PolicyAudit.onlyValidPolicy -FNDA:20548,PolicyAudit.onlyValidPolicy -DA:45,20548 +FNDA:33061,PolicyAudit.onlyValidPolicy +DA:45,33061 BRDA:45,0,0,1 DA:46,1 -DA:53,13 +DA:53,28 FN:53,PolicyAudit.constructor -FNDA:13,PolicyAudit.constructor +FNDA:28,PolicyAudit.constructor DA:54,0 -DA:59,13 +DA:59,28 FN:59,PolicyAudit.initialize -FNDA:13,PolicyAudit.initialize +FNDA:28,PolicyAudit.initialize DA:60,0 DA:61,0 -DA:62,13 -DA:70,20547 +DA:62,28 +DA:70,33060 FN:70,PolicyAudit.submit -FNDA:20547,PolicyAudit.submit -DA:71,20547 -DA:72,20547 -DA:78,9653 +FNDA:33060,PolicyAudit.submit +DA:71,33060 +DA:72,33060 +DA:78,22087 FN:78,PolicyAudit.approve -FNDA:9653,PolicyAudit.approve -DA:79,9653 -DA:80,9653 -DA:86,3708 +FNDA:22087,PolicyAudit.approve +DA:79,22087 +DA:80,22087 +DA:86,8534 FN:86,PolicyAudit.reject -FNDA:3708,PolicyAudit.reject -DA:87,3708 -DA:88,3708 -DA:93,1848 +FNDA:8534,PolicyAudit.reject +DA:87,8534 +DA:88,8534 +DA:93,23334 FN:93,PolicyAudit.isAudited -FNDA:1848,PolicyAudit.isAudited -DA:94,1848 +FNDA:23334,PolicyAudit.isAudited +DA:94,23334 DA:100,0 FN:100,PolicyAudit._authorizeUpgrade FNDA:0,PolicyAudit._authorizeUpgrade @@ -1736,74 +1736,72 @@ BRH:0 end_of_record TN: SF:contracts/rights/RightsPolicyAuthorizer.sol -DA:71,0 -FN:71,RightsPolicyAuthorizer.onlyAuditedPolicies -FNDA:0,RightsPolicyAuthorizer.onlyAuditedPolicies -DA:73,0 -BRDA:73,0,0,- -DA:78,0 -FN:78,RightsPolicyAuthorizer.constructor -FNDA:0,RightsPolicyAuthorizer.constructor -DA:81,0 -DA:83,0 +DA:69,9688 +FN:69,RightsPolicyAuthorizer.onlyAuditedPolicies +FNDA:9688,RightsPolicyAuthorizer.onlyAuditedPolicies +DA:71,9688 +BRDA:71,0,0,1 +DA:76,15 +FN:76,RightsPolicyAuthorizer.constructor +FNDA:15,RightsPolicyAuthorizer.constructor +DA:79,0 +DA:81,15 +DA:85,15 +FN:85,RightsPolicyAuthorizer.initialize +FNDA:15,RightsPolicyAuthorizer.initialize +DA:86,0 DA:87,0 -FN:87,RightsPolicyAuthorizer.initialize -FNDA:0,RightsPolicyAuthorizer.initialize -DA:88,0 -DA:89,0 -DA:90,0 -DA:93,0 -FN:93,RightsPolicyAuthorizer.setPolicyPlan -FNDA:0,RightsPolicyAuthorizer.setPolicyPlan -DA:94,0 -DA:95,0 -DA:96,0 -DA:98,0 -DA:99,0 -DA:100,0 -DA:102,0 -DA:112,0 -FN:112,RightsPolicyAuthorizer.authorizePolicy -FNDA:0,RightsPolicyAuthorizer.authorizePolicy -DA:115,0 -BRDA:115,3,0,- -DA:116,0 -DA:117,0 -DA:120,0 -FN:120,RightsPolicyAuthorizer.revokePolicy -FNDA:0,RightsPolicyAuthorizer.revokePolicy -DA:124,0 -BRDA:124,4,0,- -DA:125,0 -DA:132,0 -FN:132,RightsPolicyAuthorizer.isPolicyAuthorized -FNDA:0,RightsPolicyAuthorizer.isPolicyAuthorized -DA:133,0 -DA:134,0 -DA:140,0 -FN:140,RightsPolicyAuthorizer.getAuthorizedPolicies -FNDA:0,RightsPolicyAuthorizer.getAuthorizedPolicies -DA:147,0 -DA:148,0 -DA:149,0 -DA:150,0 -DA:151,0 -DA:152,0 -DA:155,0 +DA:88,15 +DA:94,9686 +FN:94,RightsPolicyAuthorizer.authorizePolicy +FNDA:9686,RightsPolicyAuthorizer.authorizePolicy +DA:96,9686 +DA:97,9686 +BRDA:97,1,0,1 +DA:98,1 +DA:101,9685 +DA:102,9685 +BRDA:102,2,0,3492 +DA:103,3492 +DA:106,6193 +DA:111,3531 +FN:111,RightsPolicyAuthorizer.revokePolicy +FNDA:3531,RightsPolicyAuthorizer.revokePolicy +DA:113,3531 +DA:114,3531 +BRDA:114,3,0,1 +DA:115,1 +DA:118,3530 +DA:124,5 +FN:124,RightsPolicyAuthorizer.isPolicyAuthorized +FNDA:5,RightsPolicyAuthorizer.isPolicyAuthorized +DA:125,5 +DA:132,262 +FN:132,RightsPolicyAuthorizer.getAuthorizedPolicies +FNDA:262,RightsPolicyAuthorizer.getAuthorizedPolicies +DA:139,262 +DA:140,262 +DA:141,262 +DA:142,262 +DA:144,262 +DA:145,270 +DA:146,201 +DA:150,201 +DA:163,0 +DA:165,0 DA:171,0 -DA:176,0 -FN:176,RightsPolicyAuthorizer._authorizeUpgrade +FN:171,RightsPolicyAuthorizer._authorizeUpgrade FNDA:0,RightsPolicyAuthorizer._authorizeUpgrade -DA:184,0 -FN:184,RightsPolicyAuthorizer._isValidPolicy -FNDA:0,RightsPolicyAuthorizer._isValidPolicy -DA:185,0 -FNF:10 -FNH:0 -LF:39 -LH:0 -BRF:3 -BRH:0 +DA:177,9959 +FN:177,RightsPolicyAuthorizer._isValidPolicy +FNDA:9959,RightsPolicyAuthorizer._isValidPolicy +DA:178,9959 +FNF:9 +FNH:8 +LF:38 +LH:32 +BRF:4 +BRH:4 end_of_record TN: SF:contracts/rights/RightsPolicyManager.sol @@ -1908,14 +1906,14 @@ BRH:0 end_of_record TN: SF:script/create3/CREATE3Factory.sol -DA:10,401 +DA:10,459 FN:10,CREATE3Factory.deploy -FNDA:401,CREATE3Factory.deploy -DA:12,401 -DA:16,830 +FNDA:459,CREATE3Factory.deploy +DA:12,459 +DA:16,888 FN:16,CREATE3Factory.getDeployed -FNDA:830,CREATE3Factory.getDeployed -DA:18,830 +FNDA:888,CREATE3Factory.getDeployed +DA:18,888 FNF:2 FNH:2 LF:4 @@ -1925,47 +1923,47 @@ BRH:0 end_of_record TN: SF:script/deployment/00_Deploy_Base.s.sol -DA:14,1231 +DA:14,1347 FN:14,DeployBase.getCreate3FactoryAddress -FNDA:1231,DeployBase.getCreate3FactoryAddress -DA:15,1231 -DA:18,492 +FNDA:1347,DeployBase.getCreate3FactoryAddress +DA:15,1347 +DA:18,578 FN:18,DeployBase.getAdminPK -FNDA:492,DeployBase.getAdminPK -DA:19,492 -DA:23,1322 +FNDA:578,DeployBase.getAdminPK +DA:19,578 +DA:23,1466 FN:23,DeployBase.getSalt -FNDA:1322,DeployBase.getSalt -DA:24,1322 -DA:27,830 +FNDA:1466,DeployBase.getSalt +DA:24,1466 +DA:27,888 FN:27,DeployBase.computeCreate3Address -FNDA:830,DeployBase.computeCreate3Address -DA:32,830 -DA:43,830 +FNDA:888,DeployBase.computeCreate3Address +DA:32,888 +DA:43,888 DA:46,70 FN:46,DeployBase.deploy FNDA:70,DeployBase.deploy DA:48,70 DA:49,70 -DA:52,331 +DA:52,389 FN:52,DeployBase.deployUUPS -FNDA:331,DeployBase.deployUUPS -DA:58,331 -DA:62,331 -DA:63,331 -DA:65,331 -DA:85,331 -DA:89,401 +FNDA:389,DeployBase.deployUUPS +DA:58,389 +DA:62,389 +DA:63,389 +DA:65,389 +DA:85,389 +DA:89,444 FN:89,DeployBase._checkExpectedAddress -FNDA:401,DeployBase._checkExpectedAddress -DA:90,401 -DA:91,401 +FNDA:444,DeployBase._checkExpectedAddress +DA:90,444 +DA:91,444 BRDA:91,0,0,- BRDA:91,0,1,- -DA:94,492 +DA:94,563 FN:94,DeployBase._logAddress -FNDA:492,DeployBase._logAddress -DA:95,492 +FNDA:563,DeployBase._logAddress +DA:95,563 DA:96,0 DA:97,0 FNF:8 @@ -1977,18 +1975,18 @@ BRH:0 end_of_record TN: SF:script/deployment/01_Deploy_Base_Create3.s.sol -DA:8,91 +DA:8,119 FN:8,DeployCreate3Factory.run -FNDA:91,DeployCreate3Factory.run -DA:10,91 -DA:11,91 -DA:12,91 +FNDA:119,DeployCreate3Factory.run +DA:10,119 +DA:11,119 +DA:12,119 DA:15,0 DA:16,0 BRDA:16,0,0,- DA:17,0 -DA:21,91 -DA:22,91 +DA:21,119 +DA:22,119 DA:23,0 FNF:1 FNH:1 @@ -1999,18 +1997,18 @@ BRH:0 end_of_record TN: SF:script/deployment/02_Deploy_Access_AccessManager.s.sol -DA:9,91 +DA:9,119 FN:9,DeployAccessManager.run -FNDA:91,DeployAccessManager.run -DA:10,91 -DA:11,91 -DA:13,91 -DA:14,91 -DA:15,91 -DA:16,91 -DA:17,91 -DA:19,91 -DA:20,91 +FNDA:119,DeployAccessManager.run +DA:10,119 +DA:11,119 +DA:13,119 +DA:14,119 +DA:15,119 +DA:16,119 +DA:17,119 +DA:19,119 +DA:20,119 DA:21,0 FNF:1 FNH:1 @@ -2261,22 +2259,22 @@ BRH:0 end_of_record TN: SF:script/deployment/14_Deploy_Policies_PolicyAudit.s.sol -DA:10,0 +DA:10,15 FN:10,DeployPolicyAudit.run -FNDA:0,DeployPolicyAudit.run -DA:11,0 -DA:12,0 -DA:13,0 -DA:14,0 -DA:15,0 -DA:16,0 -DA:18,0 -DA:19,0 +FNDA:15,DeployPolicyAudit.run +DA:11,15 +DA:12,15 +DA:13,15 +DA:14,15 +DA:15,15 +DA:16,15 +DA:18,15 +DA:19,15 DA:20,0 FNF:1 -FNH:0 +FNH:1 LF:10 -LH:0 +LH:9 BRF:0 BRH:0 end_of_record @@ -2348,6 +2346,24 @@ BRF:0 BRH:0 end_of_record TN: +SF:script/deployment/18_Deploy_RightsManager_PolicyAuthorizer.s.sol +DA:10,15 +FN:10,DeployRightsPolicyAuthorizer.run +FNDA:15,DeployRightsPolicyAuthorizer.run +DA:11,15 +DA:13,15 +DA:14,15 +DA:15,15 +DA:17,15 +DA:18,15 +FNF:1 +FNH:1 +LF:7 +LH:7 +BRF:0 +BRH:0 +end_of_record +TN: SF:script/orchestration/01_Orchestrate_ProtocolHydration.s.sol DA:19,0 FN:19,OrchestrateProtocolHydration.run @@ -2672,154 +2688,165 @@ BRH:0 end_of_record TN: SF:test/BaseTest.t.sol -DA:60,91 -FN:60,BaseTest.initialize -FNDA:91,BaseTest.initialize -DA:62,91 -DA:63,91 -DA:64,91 -DA:65,91 -DA:66,91 -DA:68,0 -DA:69,0 -DA:75,91 -FN:75,BaseTest.deployCreate3Factory -FNDA:91,BaseTest.deployCreate3Factory -DA:77,91 -DA:78,91 -DA:80,91 -DA:81,91 -DA:82,91 -DA:86,70 -FN:86,BaseTest.deployToken +DA:64,119 +FN:64,BaseTest.initialize +FNDA:119,BaseTest.initialize +DA:66,119 +DA:67,119 +DA:68,119 +DA:69,119 +DA:70,119 +DA:72,0 +DA:73,0 +DA:79,119 +FN:79,BaseTest.deployCreate3Factory +FNDA:119,BaseTest.deployCreate3Factory +DA:81,119 +DA:82,119 +DA:84,119 +DA:85,119 +DA:86,119 +DA:90,70 +FN:90,BaseTest.deployToken FNDA:70,BaseTest.deployToken -DA:88,70 -DA:89,70 -DA:93,91 -FN:93,BaseTest.deployAccessManager -FNDA:91,BaseTest.deployAccessManager -DA:95,91 -DA:96,91 -DA:98,91 -DA:100,91 -DA:101,91 -DA:103,91 -DA:105,91 -DA:106,91 -DA:107,91 -DA:111,53 -FN:111,BaseTest.deployTollgate -FNDA:53,BaseTest.deployTollgate -DA:113,0 +DA:92,70 +DA:93,70 +DA:97,119 +FN:97,BaseTest.deployAccessManager +FNDA:119,BaseTest.deployAccessManager +DA:99,119 +DA:100,119 +DA:102,119 +DA:104,119 +DA:105,119 +DA:107,119 +DA:109,119 +DA:110,119 +DA:111,119 DA:115,53 -DA:116,53 -DA:117,53 -DA:119,40 -DA:123,61 -FN:123,BaseTest.deployLedgerVault -FNDA:61,BaseTest.deployLedgerVault -DA:125,61 -DA:126,61 +FN:115,BaseTest.deployTollgate +FNDA:53,BaseTest.deployTollgate +DA:117,0 +DA:119,53 +DA:120,53 +DA:121,53 +DA:123,40 DA:127,61 +FN:127,BaseTest.deployLedgerVault +FNDA:61,BaseTest.deployLedgerVault DA:129,61 +DA:130,61 DA:131,61 -DA:132,61 DA:133,61 -DA:137,23 -FN:137,BaseTest.deployTreasury -FNDA:23,BaseTest.deployTreasury -DA:139,23 -DA:140,23 +DA:135,61 +DA:136,61 +DA:137,61 DA:141,23 -DA:142,23 -DA:145,38 -FN:145,BaseTest.deployAgreementManager -FNDA:38,BaseTest.deployAgreementManager -DA:146,0 -DA:147,38 +FN:141,BaseTest.deployTreasury +FNDA:23,BaseTest.deployTreasury +DA:143,23 +DA:144,23 +DA:145,23 +DA:146,23 DA:149,38 -DA:150,38 -DA:152,38 -DA:155,23 -FN:155,BaseTest.deployAgreementSettler +FN:149,BaseTest.deployAgreementManager +FNDA:38,BaseTest.deployAgreementManager +DA:150,0 +DA:151,38 +DA:153,38 +DA:154,38 +DA:156,38 +DA:159,23 +FN:159,BaseTest.deployAgreementSettler FNDA:23,BaseTest.deployAgreementSettler -DA:156,0 -DA:157,23 -DA:158,0 -DA:160,23 +DA:160,0 DA:161,23 -DA:163,23 -DA:167,34 -FN:167,BaseTest.deployAssetReferendum -FNDA:34,BaseTest.deployAssetReferendum -DA:169,34 -DA:170,34 +DA:162,0 +DA:164,23 +DA:165,23 +DA:167,23 DA:171,34 -DA:172,34 -DA:175,21 -FN:175,BaseTest.deployAssetRegistry -FNDA:21,BaseTest.deployAssetRegistry -DA:176,0 -DA:178,21 +FN:171,BaseTest.deployAssetReferendum +FNDA:34,BaseTest.deployAssetReferendum +DA:173,34 +DA:174,34 +DA:175,34 +DA:176,34 DA:179,21 -DA:182,10 -FN:182,BaseTest.deployAssetSafe +FN:179,BaseTest.deployAssetRegistry +FNDA:21,BaseTest.deployAssetRegistry +DA:180,0 +DA:182,21 +DA:183,21 +DA:186,10 +FN:186,BaseTest.deployAssetSafe FNDA:10,BaseTest.deployAssetSafe -DA:183,0 -DA:184,10 -DA:185,10 -DA:189,13 -FN:189,BaseTest.deployCustodianFactory +DA:187,0 +DA:188,10 +DA:189,10 +DA:193,13 +FN:193,BaseTest.deployCustodianFactory FNDA:13,BaseTest.deployCustodianFactory -DA:190,13 -DA:191,13 DA:194,13 -FN:194,BaseTest.deployCustodianReferendum +DA:195,13 +DA:198,13 +FN:198,BaseTest.deployCustodianReferendum FNDA:13,BaseTest.deployCustodianReferendum -DA:195,0 -DA:196,0 -DA:199,13 -DA:200,13 -DA:201,13 +DA:199,0 +DA:200,0 DA:203,13 -DA:207,0 -FN:207,BaseTest.deployRightsAssetCustodian -FNDA:0,BaseTest.deployRightsAssetCustodian -DA:208,0 -DA:210,0 +DA:204,13 +DA:205,13 +DA:207,13 DA:211,0 -DA:214,34 -FN:214,BaseTest._setContentCouncilPermissions +FN:211,BaseTest.deployRightsAssetCustodian +FNDA:0,BaseTest.deployRightsAssetCustodian +DA:212,0 +DA:214,0 +DA:215,0 +DA:218,15 +FN:218,BaseTest.deployPolicyAudit +FNDA:15,BaseTest.deployPolicyAudit +DA:219,15 +DA:220,15 +DA:223,15 +FN:223,BaseTest.deployRightsPolicyAuthorizer +FNDA:15,BaseTest.deployRightsPolicyAuthorizer +DA:224,0 +DA:226,15 +DA:227,15 +DA:232,34 +FN:232,BaseTest._setContentCouncilPermissions FNDA:34,BaseTest._setContentCouncilPermissions -DA:215,34 -DA:216,34 -DA:218,34 -DA:219,34 -DA:222,13 -FN:222,BaseTest._setNodesCouncilPermissions +DA:233,34 +DA:234,34 +DA:236,34 +DA:237,34 +DA:240,13 +FN:240,BaseTest._setNodesCouncilPermissions FNDA:13,BaseTest._setNodesCouncilPermissions -DA:223,13 -DA:224,13 -DA:226,13 -DA:227,13 -DA:230,76 -FN:230,BaseTest._setGovPermissions +DA:241,13 +DA:242,13 +DA:244,13 +DA:245,13 +DA:248,76 +FN:248,BaseTest._setGovPermissions FNDA:76,BaseTest._setGovPermissions -DA:231,76 -DA:232,76 -DA:234,76 -DA:235,76 -DA:238,61 -FN:238,BaseTest._assignOpRole +DA:249,76 +DA:250,76 +DA:252,76 +DA:253,76 +DA:256,61 +FN:256,BaseTest._assignOpRole FNDA:61,BaseTest._assignOpRole -DA:239,61 -DA:240,61 -DA:241,61 -DA:242,61 -FNF:19 -FNH:18 -LF:106 -LH:92 +DA:257,61 +DA:258,61 +DA:259,61 +DA:260,61 +FNF:21 +FNH:20 +LF:113 +LH:98 BRF:0 BRH:0 end_of_record @@ -2832,49 +2859,49 @@ DA:35,2 DA:36,2 DA:38,2 DA:39,12 -DA:43,12640 +DA:43,12680 FN:43,AssetReferendumHandler.submit -FNDA:12640,AssetReferendumHandler.submit -DA:44,12640 -DA:46,12640 -DA:47,12640 -DA:48,12640 -DA:50,12602 -DA:52,12602 -DA:53,12602 -DA:55,12602 -DA:56,12602 -DA:57,12602 -DA:60,12528 +FNDA:12680,AssetReferendumHandler.submit +DA:44,12680 +DA:46,12680 +DA:47,12680 +DA:48,12680 +DA:50,12638 +DA:52,12638 +DA:53,12638 +DA:55,12638 +DA:56,12638 +DA:57,12638 +DA:60,12475 FN:60,AssetReferendumHandler.approve -FNDA:12528,AssetReferendumHandler.approve -DA:61,12528 -DA:63,10617 -DA:64,10617 -DA:65,10617 -DA:67,4011 -DA:68,4011 -DA:70,4011 -DA:73,12453 +FNDA:12475,AssetReferendumHandler.approve +DA:61,12475 +DA:63,10496 +DA:64,10496 +DA:65,10496 +DA:67,4012 +DA:68,4012 +DA:70,4012 +DA:73,12475 FN:73,AssetReferendumHandler.reject -FNDA:12453,AssetReferendumHandler.reject -DA:74,12453 -DA:76,10564 -DA:77,10564 -DA:78,10564 -DA:80,3922 -DA:81,3922 -DA:83,3922 -DA:86,12429 +FNDA:12475,AssetReferendumHandler.reject +DA:74,12475 +DA:76,10501 +DA:77,10501 +DA:78,10501 +DA:80,3850 +DA:81,3850 +DA:83,3850 +DA:86,12420 FN:86,AssetReferendumHandler.revoke -FNDA:12429,AssetReferendumHandler.revoke -DA:87,12429 -DA:89,10475 -DA:90,10475 -DA:91,10475 -DA:93,1864 -DA:94,1864 -DA:96,1864 +FNDA:12420,AssetReferendumHandler.revoke +DA:87,12420 +DA:89,10447 +DA:90,10447 +DA:91,10447 +DA:93,1817 +DA:94,1817 +DA:96,1817 DA:99,0 FN:99,AssetReferendumHandler.trackedLength FNDA:0,AssetReferendumHandler.trackedLength @@ -2906,58 +2933,58 @@ DA:33,3 DA:35,3 DA:36,3 DA:37,15 -DA:41,18991 +DA:41,18988 FN:41,AssetRegistryHandler.register -FNDA:18991,AssetRegistryHandler.register -DA:42,18991 -DA:44,18991 -DA:45,18991 -DA:48,18946 -DA:50,18946 -DA:51,18946 -DA:53,18946 -DA:54,18946 -DA:56,18946 -DA:57,18946 -DA:59,18946 -DA:60,18946 -DA:61,18946 -DA:62,18946 -DA:63,18946 -DA:66,18843 +FNDA:18988,AssetRegistryHandler.register +DA:42,18988 +DA:44,18988 +DA:45,18988 +DA:48,18961 +DA:50,18961 +DA:51,18961 +DA:53,18961 +DA:54,18961 +DA:56,18961 +DA:57,18961 +DA:59,18961 +DA:60,18961 +DA:61,18961 +DA:62,18961 +DA:63,18961 +DA:66,18833 FN:66,AssetRegistryHandler.transfer -FNDA:18843,AssetRegistryHandler.transfer -DA:67,18843 -DA:69,15950 -DA:70,15950 -DA:71,15950 -DA:73,8961 -DA:74,8961 -DA:76,7465 -DA:77,7465 -DA:79,7465 -DA:82,18828 +FNDA:18833,AssetRegistryHandler.transfer +DA:67,18833 +DA:69,15757 +DA:70,15757 +DA:71,15757 +DA:73,8776 +DA:74,8776 +DA:76,7307 +DA:77,7307 +DA:79,7307 +DA:82,18810 FN:82,AssetRegistryHandler.switchState -FNDA:18828,AssetRegistryHandler.switchState -DA:83,18828 -DA:85,15873 -DA:86,15873 -DA:87,15873 -DA:89,8982 -DA:90,8982 -DA:91,8982 -DA:94,18413 +FNDA:18810,AssetRegistryHandler.switchState +DA:83,18810 +DA:85,15739 +DA:86,15739 +DA:87,15739 +DA:89,8786 +DA:90,8786 +DA:91,8786 +DA:94,18444 FN:94,AssetRegistryHandler.revoke -FNDA:18413,AssetRegistryHandler.revoke -DA:95,18413 -DA:97,15423 -DA:98,15423 -DA:99,15423 -DA:101,8445 -DA:102,8445 -DA:104,8445 -DA:105,8445 -DA:106,8445 +FNDA:18444,AssetRegistryHandler.revoke +DA:95,18444 +DA:97,15393 +DA:98,15393 +DA:99,15393 +DA:101,8580 +DA:102,8580 +DA:104,8580 +DA:105,8580 +DA:106,8580 DA:109,0 FN:109,AssetRegistryHandler.assetIdsLength FNDA:0,AssetRegistryHandler.assetIdsLength @@ -2988,52 +3015,52 @@ DA:32,3 DA:33,3 DA:35,3 DA:36,18 -DA:40,25204 +DA:40,25531 FN:40,AssetSafeHandler.registerAsset -FNDA:25204,AssetSafeHandler.registerAsset -DA:41,25204 -DA:43,25204 -DA:46,25103 -DA:47,25103 -DA:49,25103 -DA:50,25103 -DA:52,25103 -DA:53,25103 -DA:55,25103 -DA:56,25103 -DA:58,25103 -DA:59,25103 -DA:60,25103 -DA:63,25050 +FNDA:25531,AssetSafeHandler.registerAsset +DA:41,25531 +DA:43,25531 +DA:46,25463 +DA:47,25463 +DA:49,25463 +DA:50,25463 +DA:52,25463 +DA:53,25463 +DA:55,25463 +DA:56,25463 +DA:58,25463 +DA:59,25463 +DA:60,25463 +DA:63,24696 FN:63,AssetSafeHandler.transferAsset -FNDA:25050,AssetSafeHandler.transferAsset -DA:64,25050 -DA:66,22087 -DA:67,22087 -DA:69,22087 -DA:70,22087 -DA:72,22087 -DA:73,22087 -DA:75,18405 -DA:76,18405 -DA:78,18405 -DA:81,24821 +FNDA:24696,AssetSafeHandler.transferAsset +DA:64,24696 +DA:66,21934 +DA:67,21934 +DA:69,21934 +DA:70,21934 +DA:72,21934 +DA:73,21934 +DA:75,18310 +DA:76,18310 +DA:78,18310 +DA:81,24848 FN:81,AssetSafeHandler.setContent -FNDA:24821,AssetSafeHandler.setContent -DA:82,24821 -DA:84,21952 -DA:85,21952 -DA:87,21952 -DA:88,21952 -DA:90,21952 -DA:91,21952 -DA:92,21952 -DA:94,21952 -DA:95,21952 -DA:97,21952 -DA:98,21952 -DA:99,21952 -DA:100,21952 +FNDA:24848,AssetSafeHandler.setContent +DA:82,24848 +DA:84,22169 +DA:85,22169 +DA:87,22169 +DA:88,22169 +DA:90,22169 +DA:91,22169 +DA:92,22169 +DA:94,22169 +DA:95,22169 +DA:97,22169 +DA:98,22169 +DA:99,22169 +DA:100,22169 DA:103,0 FN:103,AssetSafeHandler.trackedLength FNDA:0,AssetSafeHandler.trackedLength @@ -3075,10 +3102,10 @@ BRH:0 end_of_record TN: SF:test/economics/Tollgate.t.sol -DA:20,12471 +DA:20,12287 FN:20,TargetD.isFeeSchemeSupported -FNDA:12471,TargetD.isFeeSchemeSupported -DA:22,12471 +FNDA:12287,TargetD.isFeeSchemeSupported +DA:22,12287 DA:42,2 FN:42,TollgateHandler.constructor FNDA:2,TollgateHandler.constructor @@ -3104,23 +3131,23 @@ DA:64,50050 DA:65,50050 DA:67,50050 DA:68,50050 -BRDA:68,1,0,25234 -BRDA:68,1,1,12424 -DA:69,25234 -DA:70,24816 -BRDA:70,2,0,12392 -BRDA:70,2,1,12424 -DA:71,12392 -DA:73,12424 +BRDA:68,1,0,25051 +BRDA:68,1,1,12509 +DA:69,25051 +DA:70,24999 +BRDA:70,2,0,12490 +BRDA:70,2,1,12509 +DA:71,12490 +DA:73,12509 DA:76,50050 DA:77,50050 DA:79,50050 DA:80,50050 DA:81,50050 DA:83,50050 -BRDA:83,3,0,21313 -DA:84,21313 -DA:85,21313 +BRDA:83,3,0,21321 +DA:84,21321 +DA:85,21321 DA:89,0 FN:89,TollgateHandler.targetsLength FNDA:0,TollgateHandler.targetsLength @@ -3160,35 +3187,35 @@ DA:240,3 DA:241,3 DA:242,3 DA:243,3 -DA:246,37153 +DA:246,37491 FN:246,AgreementManagerHandler.createAgreement -FNDA:37153,AgreementManagerHandler.createAgreement -DA:247,37153 -DA:248,37153 -DA:250,7126 -DA:251,7126 -DA:252,7126 -DA:253,7126 -DA:255,7126 -DA:256,7126 -BRDA:256,2,0,2529 -DA:257,2529 -DA:259,7126 -DA:261,6742 -DA:262,6742 -DA:263,6742 -DA:265,6742 -DA:266,6742 -DA:270,6742 -DA:271,6742 -DA:272,6742 -DA:273,6742 -DA:276,37922 +FNDA:37491,AgreementManagerHandler.createAgreement +DA:247,37491 +DA:248,37491 +DA:250,6995 +DA:251,6995 +DA:252,6995 +DA:253,6995 +DA:255,6995 +DA:256,6995 +BRDA:256,2,0,2461 +DA:257,2461 +DA:259,6995 +DA:261,6655 +DA:262,6655 +DA:263,6655 +DA:265,6655 +DA:266,6655 +DA:270,6655 +DA:271,6655 +DA:272,6655 +DA:273,6655 +DA:276,37584 FN:276,AgreementManagerHandler.setMaxParties -FNDA:37922,AgreementManagerHandler.setMaxParties -DA:277,37922 -DA:278,37922 -DA:279,37922 +FNDA:37584,AgreementManagerHandler.setMaxParties +DA:277,37584 +DA:278,37584 +DA:279,37584 DA:282,0 FN:282,AgreementManagerHandler.proofsLength FNDA:0,AgreementManagerHandler.proofsLength @@ -3213,18 +3240,18 @@ DA:300,0 DA:301,0 DA:302,0 DA:303,0 -DA:307,6742 +DA:307,6655 FN:307,AgreementManagerHandler._buildParties -FNDA:6742,AgreementManagerHandler._buildParties -DA:308,6742 -DA:309,6742 -DA:310,26250 -DA:314,7126 +FNDA:6655,AgreementManagerHandler._buildParties +DA:308,6655 +DA:309,6655 +DA:310,24785 +DA:314,6995 FN:314,AgreementManagerHandler._penaltyBps -FNDA:7126,AgreementManagerHandler._penaltyBps -DA:315,7126 -DA:316,2529 -DA:317,2529 +FNDA:6995,AgreementManagerHandler._penaltyBps +DA:315,6995 +DA:316,2461 +DA:317,2461 FNF:10 FNH:5 LF:54 @@ -3251,61 +3278,61 @@ DA:220,4 DA:221,4 DA:222,4 DA:223,4 -DA:226,33273 +DA:226,33488 FN:226,AgreementSettlerHandler.createAgreement -FNDA:33273,AgreementSettlerHandler.createAgreement -DA:227,33273 -DA:228,33273 -DA:229,33273 -DA:230,33273 -DA:232,15312 -DA:233,15312 -BRDA:233,1,0,4283 -DA:234,4283 -DA:236,15312 -DA:238,14929 -DA:239,14929 -DA:240,14929 -DA:241,14929 -DA:242,14929 -DA:245,14929 -DA:246,14929 -DA:256,14929 -DA:257,14929 -DA:260,33135 +FNDA:33488,AgreementSettlerHandler.createAgreement +DA:227,33488 +DA:228,33488 +DA:229,33488 +DA:230,33488 +DA:232,14835 +DA:233,14835 +BRDA:233,1,0,4224 +DA:234,4224 +DA:236,14835 +DA:238,14492 +DA:239,14492 +DA:240,14492 +DA:241,14492 +DA:242,14492 +DA:245,14492 +DA:246,14492 +DA:256,14492 +DA:257,14492 +DA:260,32954 FN:260,AgreementSettlerHandler.settle -FNDA:33135,AgreementSettlerHandler.settle -DA:261,33135 -DA:262,29390 -DA:263,29390 -DA:264,29390 +FNDA:32954,AgreementSettlerHandler.settle +DA:261,32954 +DA:262,28934 +DA:263,28934 +DA:264,28934 DA:266,0 -DA:267,6171 +DA:267,6031 DA:268,4 -DA:271,6167 -DA:272,6167 -DA:273,6167 -DA:274,6167 -DA:276,6167 -DA:277,6167 -DA:278,6167 -DA:280,6167 -DA:281,6167 -DA:282,6167 -DA:285,33692 +DA:271,6027 +DA:272,6027 +DA:273,6027 +DA:274,6027 +DA:276,6027 +DA:277,6027 +DA:278,6027 +DA:280,6027 +DA:281,6027 +DA:282,6027 +DA:285,33658 FN:285,AgreementSettlerHandler.quit -FNDA:33692,AgreementSettlerHandler.quit -DA:286,33692 -DA:287,29739 -DA:288,29739 -DA:289,29739 -DA:291,6345 -DA:292,6345 -DA:293,6345 -DA:295,6345 -DA:296,6345 -DA:298,6345 -DA:299,6345 +FNDA:33658,AgreementSettlerHandler.quit +DA:286,33658 +DA:287,29570 +DA:288,29570 +DA:289,29570 +DA:291,6225 +DA:292,6225 +DA:293,6225 +DA:295,6225 +DA:296,6225 +DA:298,6225 +DA:299,6225 DA:302,0 FN:302,AgreementSettlerHandler.proofsLength FNDA:0,AgreementSettlerHandler.proofsLength @@ -3338,18 +3365,18 @@ DA:328,0 DA:329,0 DA:330,0 DA:331,0 -DA:335,14929 +DA:335,14492 FN:335,AgreementSettlerHandler._buildParties -FNDA:14929,AgreementSettlerHandler._buildParties -DA:336,14929 -DA:337,14929 -DA:338,51368 -DA:342,33273 +FNDA:14492,AgreementSettlerHandler._buildParties +DA:336,14492 +DA:337,14492 +DA:338,50247 +DA:342,33488 FN:342,AgreementSettlerHandler._penaltyBps -FNDA:33273,AgreementSettlerHandler._penaltyBps -DA:343,33273 -DA:344,9313 -DA:345,9313 +FNDA:33488,AgreementSettlerHandler._penaltyBps +DA:343,33488 +DA:344,9402 +DA:345,9402 FNF:15 FNH:8 LF:85 @@ -3661,14 +3688,14 @@ BRH:0 end_of_record TN: SF:test/libraries/RollingOps.t.sol -DA:13,25658 +DA:13,25663 FN:13,RollingOpsHarness.configure -FNDA:25658,RollingOpsHarness.configure -DA:14,25658 -DA:17,35225 +FNDA:25663,RollingOpsHarness.configure +DA:14,25663 +DA:17,35220 FN:17,RollingOpsHarness.roll -FNDA:35225,RollingOpsHarness.roll -DA:18,35225 +FNDA:35220,RollingOpsHarness.roll +DA:18,35220 DA:21,2545 FN:21,RollingOpsHarness.contains FNDA:2545,RollingOpsHarness.contains @@ -3693,16 +3720,16 @@ DA:170,2 FN:170,RollingOpsHandler.constructor FNDA:2,RollingOpsHandler.constructor DA:171,2 -DA:176,25141 +DA:176,25146 FN:176,RollingOpsHandler.configure -FNDA:25141,RollingOpsHandler.configure -DA:177,25141 -DA:178,25141 +FNDA:25146,RollingOpsHandler.configure +DA:177,25146 +DA:178,25146 DA:179,0 -DA:182,24909 +DA:182,24904 FN:182,RollingOpsHandler.roll -FNDA:24909,RollingOpsHandler.roll -DA:183,24909 +FNDA:24904,RollingOpsHandler.roll +DA:183,24904 DA:184,0 DA:187,0 FN:187,RollingOpsHandler.maxWindow @@ -3722,7 +3749,7 @@ FNDA:50050,RollingOpsHandler._rebuildSnapshot DA:200,50050 DA:201,50050 DA:202,50050 -DA:203,259169 +DA:203,258802 FNF:14 FNH:11 LF:34 @@ -3763,59 +3790,59 @@ DA:43,0 FN:43,MockPolicy.description FNDA:0,MockPolicy.description DA:44,0 -DA:47,61641 +DA:47,62373 FN:47,MockPolicy.supportsInterface -FNDA:61641,MockPolicy.supportsInterface -DA:48,61641 -DA:55,2132 +FNDA:62373,MockPolicy.supportsInterface +DA:48,62373 +DA:55,2275 FN:55,PolicyAuditHarness.status -FNDA:2132,PolicyAuditHarness.status -DA:56,2132 -DA:210,2 -FN:210,PolicyAuditHandler.constructor +FNDA:2275,PolicyAuditHarness.status +DA:56,2275 +DA:202,2 +FN:202,PolicyAuditHandler.constructor FNDA:2,PolicyAuditHandler.constructor -DA:211,2 -DA:212,2 -DA:215,16566 -FN:215,PolicyAuditHandler.submitPolicy -FNDA:16566,PolicyAuditHandler.submitPolicy -DA:216,16566 -DA:217,16566 -BRDA:217,0,0,16566 -DA:218,16566 -DA:219,16566 -DA:223,16998 -FN:223,PolicyAuditHandler.approvePolicy -FNDA:16998,PolicyAuditHandler.approvePolicy -DA:224,16998 -DA:225,15034 -DA:226,15034 -DA:228,7805 -DA:229,7805 -BRDA:229,3,0,7805 -DA:230,7805 -DA:234,16486 -FN:234,PolicyAuditHandler.rejectPolicy -FNDA:16486,PolicyAuditHandler.rejectPolicy -DA:235,16486 -DA:236,14584 -DA:237,14584 -DA:239,3705 -DA:240,3705 -BRDA:240,6,0,3705 -DA:241,3705 -DA:245,0 -FN:245,PolicyAuditHandler.policiesLength +DA:203,2 +DA:204,2 +DA:207,16624 +FN:207,PolicyAuditHandler.submitPolicy +FNDA:16624,PolicyAuditHandler.submitPolicy +DA:208,16624 +DA:209,16624 +BRDA:209,0,0,16624 +DA:210,16624 +DA:211,16624 +DA:215,16718 +FN:215,PolicyAuditHandler.approvePolicy +FNDA:16718,PolicyAuditHandler.approvePolicy +DA:216,16718 +DA:217,14808 +DA:218,14808 +DA:220,7926 +DA:221,7926 +BRDA:221,3,0,7926 +DA:222,7926 +DA:226,16708 +FN:226,PolicyAuditHandler.rejectPolicy +FNDA:16708,PolicyAuditHandler.rejectPolicy +DA:227,16708 +DA:228,14760 +DA:229,14760 +DA:231,3574 +DA:232,3574 +BRDA:232,6,0,3574 +DA:233,3574 +DA:237,0 +FN:237,PolicyAuditHandler.policiesLength FNDA:0,PolicyAuditHandler.policiesLength -DA:246,0 -DA:249,0 -FN:249,PolicyAuditHandler.policyAt +DA:238,0 +DA:241,0 +FN:241,PolicyAuditHandler.policyAt FNDA:0,PolicyAuditHandler.policyAt -DA:250,0 -DA:253,0 -FN:253,PolicyAuditHandler.storedStatus +DA:242,0 +DA:245,0 +FN:245,PolicyAuditHandler.storedStatus FNDA:0,PolicyAuditHandler.storedStatus -DA:254,0 +DA:246,0 FNF:17 FNH:6 LF:47 @@ -4027,18 +4054,18 @@ BRH:0 end_of_record TN: SF:test/primitives/BalanceOperatorUpgradeable.t.sol -DA:16,24708 +DA:16,24587 FN:16,BalanceOperatorHarness.deposit -FNDA:24708,BalanceOperatorHarness.deposit -DA:17,24708 -DA:20,15370 +FNDA:24587,BalanceOperatorHarness.deposit +DA:17,24587 +DA:20,15200 FN:20,BalanceOperatorHarness.withdraw -FNDA:15370,BalanceOperatorHarness.withdraw -DA:21,15370 -DA:24,1062 +FNDA:15200,BalanceOperatorHarness.withdraw +DA:21,15200 +DA:24,1021 FN:24,BalanceOperatorHarness.transfer -FNDA:1062,BalanceOperatorHarness.transfer -DA:25,1062 +FNDA:1021,BalanceOperatorHarness.transfer +DA:25,1021 DA:257,2 FN:257,BalanceOperatorHandler.constructor FNDA:2,BalanceOperatorHandler.constructor @@ -4050,43 +4077,43 @@ DA:266,2 FN:266,BalanceOperatorHandler.getActors FNDA:2,BalanceOperatorHandler.getActors DA:267,2 -DA:270,593056 +DA:270,582752 FN:270,BalanceOperatorHandler.deposit -FNDA:593056,BalanceOperatorHandler.deposit -DA:271,593056 -DA:272,24483 -DA:273,24483 -DA:274,24483 -DA:275,24186 -DA:277,24186 -DA:278,24186 -DA:279,24186 -DA:280,24186 -DA:282,24186 -DA:285,590619 +FNDA:582752,BalanceOperatorHandler.deposit +DA:271,582752 +DA:272,24395 +DA:273,24395 +DA:274,24395 +DA:275,24065 +DA:277,24065 +DA:278,24065 +DA:279,24065 +DA:280,24065 +DA:282,24065 +DA:285,583341 FN:285,BalanceOperatorHandler.withdraw -FNDA:590619,BalanceOperatorHandler.withdraw -DA:286,590619 -DA:287,24300 -DA:288,24300 -DA:289,24300 -DA:290,15108 -DA:292,15108 -DA:293,15108 -DA:294,15108 -DA:297,592494 +FNDA:583341,BalanceOperatorHandler.withdraw +DA:286,583341 +DA:287,24374 +DA:288,24374 +DA:289,24374 +DA:290,14938 +DA:292,14938 +DA:293,14938 +DA:294,14938 +DA:297,583194 FN:297,BalanceOperatorHandler.transfer -FNDA:592494,BalanceOperatorHandler.transfer -DA:298,592494 -DA:299,24405 -DA:300,1630 -DA:302,1267 -DA:303,1267 -DA:304,1267 -DA:305,1267 -DA:306,798 -DA:308,798 -DA:309,798 +FNDA:583194,BalanceOperatorHandler.transfer +DA:298,583194 +DA:299,23803 +DA:300,1640 +DA:302,1281 +DA:303,1281 +DA:304,1281 +DA:305,1281 +DA:306,757 +DA:308,757 +DA:309,757 FNF:8 FNH:8 LF:44 @@ -4100,14 +4127,14 @@ DA:9,5 FN:9,LedgerUpgradeableHarness.initialize FNDA:5,LedgerUpgradeableHarness.initialize DA:10,0 -DA:13,8712 +DA:13,8730 FN:13,LedgerUpgradeableHarness.setEntry -FNDA:8712,LedgerUpgradeableHarness.setEntry -DA:14,8712 -DA:17,8622 +FNDA:8730,LedgerUpgradeableHarness.setEntry +DA:14,8730 +DA:17,8643 FN:17,LedgerUpgradeableHarness.sumEntry -FNDA:8622,LedgerUpgradeableHarness.sumEntry -DA:18,8622 +FNDA:8643,LedgerUpgradeableHarness.sumEntry +DA:18,8643 DA:21,368 FN:21,LedgerUpgradeableHarness.subEntry FNDA:368,LedgerUpgradeableHarness.subEntry @@ -4116,37 +4143,37 @@ DA:93,1 FN:93,LedgerUpgradeableHandler.constructor FNDA:1,LedgerUpgradeableHandler.constructor DA:94,1 -DA:97,8456 +DA:97,8475 FN:97,LedgerUpgradeableHandler.setEntry -FNDA:8456,LedgerUpgradeableHandler.setEntry -DA:98,8456 -DA:99,8453 -DA:101,8453 -DA:102,8453 -BRDA:102,1,0,8453 -DA:103,8453 -DA:104,8453 -DA:106,8453 -DA:109,8379 +FNDA:8475,LedgerUpgradeableHandler.setEntry +DA:98,8475 +DA:99,8471 +DA:101,8471 +DA:102,8471 +BRDA:102,1,0,8471 +DA:103,8471 +DA:104,8471 +DA:106,8471 +DA:109,8399 FN:109,LedgerUpgradeableHandler.sumEntry -FNDA:8379,LedgerUpgradeableHandler.sumEntry -DA:110,8379 -DA:112,8365 -DA:113,8365 +FNDA:8399,LedgerUpgradeableHandler.sumEntry +DA:110,8399 +DA:112,8386 +DA:113,8386 DA:114,0 -DA:116,8365 -DA:118,8365 -BRDA:118,3,0,8365 -DA:119,8365 -DA:120,8365 -DA:122,8365 -DA:125,8190 +DA:116,8386 +DA:118,8386 +BRDA:118,3,0,8386 +DA:119,8386 +DA:120,8386 +DA:122,8386 +DA:125,8151 FN:125,LedgerUpgradeableHandler.subEntry -FNDA:8190,LedgerUpgradeableHandler.subEntry -DA:126,8190 -DA:128,8178 -DA:129,8178 -DA:130,8178 +FNDA:8151,LedgerUpgradeableHandler.subEntry +DA:126,8151 +DA:128,8137 +DA:129,8137 +DA:130,8137 DA:132,111 DA:134,111 BRDA:134,6,0,111 @@ -4179,10 +4206,10 @@ DA:16,13 FN:16,LockOperatorHarness.initialize FNDA:13,LockOperatorHarness.initialize DA:17,0 -DA:20,21337 +DA:20,21336 FN:20,LockOperatorHarness.boostLedger -FNDA:21337,LockOperatorHarness.boostLedger -DA:21,21337 +FNDA:21336,LockOperatorHarness.boostLedger +DA:21,21336 DA:24,6249 FN:24,LockOperatorHarness.lock FNDA:6249,LockOperatorHarness.lock @@ -4213,40 +4240,40 @@ FNDA:3,LockOperatorHandler.constructor DA:254,3 DA:255,3 DA:256,9 -DA:260,692279 +DA:260,692242 FN:260,LockOperatorHandler.seedLedger -FNDA:692279,LockOperatorHandler.seedLedger -DA:261,692279 -DA:262,20818 -DA:263,20818 -DA:264,20818 -DA:265,20818 -DA:268,692353 +FNDA:692242,LockOperatorHandler.seedLedger +DA:261,692242 +DA:262,20817 +DA:263,20817 +DA:264,20817 +DA:265,20817 +DA:268,692334 FN:268,LockOperatorHandler.lock -FNDA:692353,LockOperatorHandler.lock -DA:269,692353 -DA:270,20768 -DA:271,20768 -DA:272,20768 +FNDA:692334,LockOperatorHandler.lock +DA:269,692334 +DA:270,20769 +DA:271,20769 +DA:272,20769 DA:274,5728 DA:275,5728 DA:277,5728 DA:278,5728 -DA:281,692563 +DA:281,692567 FN:281,LockOperatorHandler.release -FNDA:692563,LockOperatorHandler.release -DA:282,692563 -DA:283,20847 -DA:284,20847 -DA:285,20847 +FNDA:692567,LockOperatorHandler.release +DA:282,692567 +DA:283,20848 +DA:284,20848 +DA:285,20848 DA:287,1677 DA:288,1677 DA:290,1677 DA:291,1677 -DA:294,692956 +DA:294,692932 FN:294,LockOperatorHandler.claim -FNDA:692956,LockOperatorHandler.claim -DA:295,692956 +FNDA:692932,LockOperatorHandler.claim +DA:295,692932 DA:296,611 DA:297,611 DA:298,611 @@ -4292,22 +4319,22 @@ DA:14,50824 FN:14,QuorumUpgradeableHarness.statusOf FNDA:50824,QuorumUpgradeableHarness.statusOf DA:15,50824 -DA:18,10573 +DA:18,10616 FN:18,QuorumUpgradeableHarness.register -FNDA:10573,QuorumUpgradeableHarness.register -DA:19,10573 -DA:22,315 +FNDA:10616,QuorumUpgradeableHarness.register +DA:19,10616 +DA:22,308 FN:22,QuorumUpgradeableHarness.approve -FNDA:315,QuorumUpgradeableHarness.approve -DA:23,315 -DA:26,36 +FNDA:308,QuorumUpgradeableHarness.approve +DA:23,308 +DA:26,38 FN:26,QuorumUpgradeableHarness.blockEntry -FNDA:36,QuorumUpgradeableHarness.blockEntry -DA:27,36 -DA:30,297 +FNDA:38,QuorumUpgradeableHarness.blockEntry +DA:27,38 +DA:30,290 FN:30,QuorumUpgradeableHarness.quit -FNDA:297,QuorumUpgradeableHarness.quit -DA:31,297 +FNDA:290,QuorumUpgradeableHarness.quit +DA:31,290 DA:34,2 FN:34,QuorumUpgradeableHarness.revoke FNDA:2,QuorumUpgradeableHarness.revoke @@ -4316,39 +4343,39 @@ DA:138,2 FN:138,QuorumHandler.constructor FNDA:2,QuorumHandler.constructor DA:139,2 -DA:142,10092 +DA:142,10140 FN:142,QuorumHandler.register -FNDA:10092,QuorumHandler.register -DA:143,10092 -DA:144,10092 -DA:145,10054 -DA:146,10054 -DA:149,9804 +FNDA:10140,QuorumHandler.register +DA:143,10140 +DA:144,10140 +DA:145,10097 +DA:146,10097 +DA:149,9810 FN:149,QuorumHandler.approve -FNDA:9804,QuorumHandler.approve -DA:150,9804 -DA:151,9804 -DA:152,56 -DA:153,56 -DA:156,10176 +FNDA:9810,QuorumHandler.approve +DA:150,9810 +DA:151,9810 +DA:152,49 +DA:153,49 +DA:156,10024 FN:156,QuorumHandler.quit -FNDA:10176,QuorumHandler.quit -DA:157,10176 -DA:158,10176 -DA:159,39 -DA:160,39 -DA:163,10098 +FNDA:10024,QuorumHandler.quit +DA:157,10024 +DA:158,10024 +DA:159,32 +DA:160,32 +DA:163,10104 FN:163,QuorumHandler.blockEntry -FNDA:10098,QuorumHandler.blockEntry -DA:164,10098 -DA:165,10098 -DA:166,34 -DA:167,34 -DA:170,9880 +FNDA:10104,QuorumHandler.blockEntry +DA:164,10104 +DA:165,10104 +DA:166,36 +DA:167,36 +DA:170,9972 FN:170,QuorumHandler.revoke -FNDA:9880,QuorumHandler.revoke -DA:171,9880 -DA:172,9880 +FNDA:9972,QuorumHandler.revoke +DA:171,9972 +DA:172,9972 DA:173,0 DA:174,0 DA:177,0 @@ -4363,14 +4390,14 @@ DA:185,0 FN:185,QuorumHandler.expectedStatus FNDA:0,QuorumHandler.expectedStatus DA:186,0 -DA:189,10183 +DA:189,10214 FN:189,QuorumHandler._update -FNDA:10183,QuorumHandler._update -DA:190,10183 -BRDA:190,5,0,10054 -DA:191,10054 -DA:192,10054 -DA:194,10183 +FNDA:10214,QuorumHandler._update +DA:190,10214 +BRDA:190,5,0,10097 +DA:191,10097 +DA:192,10097 +DA:194,10214 DA:197,50050 FN:197,QuorumHandler._normalize FNDA:50050,QuorumHandler._normalize @@ -4382,3 +4409,142 @@ LH:45 BRF:1 BRH:1 end_of_record +TN: +SF:test/rights/RightsPolicyAuthorizer.t.sol +DA:23,0 +FN:23,PolicyMock.configureRevert +FNDA:0,PolicyMock.configureRevert +DA:24,0 +DA:28,9684 +FN:28,PolicyMock.setup +FNDA:9684,PolicyMock.setup +DA:29,0 +BRDA:29,0,0,- +DA:30,9684 +DA:31,9684 +DA:35,0 +FN:35,PolicyMock.enforce +FNDA:0,PolicyMock.enforce +DA:36,0 +DA:40,0 +FN:40,PolicyMock.isAccessAllowed +FNDA:0,PolicyMock.isAccessAllowed +DA:41,0 +DA:45,0 +FN:45,PolicyMock.getLicense +FNDA:0,PolicyMock.getLicense +DA:46,0 +DA:50,0 +FN:50,PolicyMock.resolveTerms +FNDA:0,PolicyMock.resolveTerms +DA:51,0 +DA:55,0 +FN:55,PolicyMock.getAttestationProvider +FNDA:0,PolicyMock.getAttestationProvider +DA:56,0 +DA:60,0 +FN:60,PolicyMock.name +FNDA:0,PolicyMock.name +DA:61,0 +DA:65,0 +FN:65,PolicyMock.description +FNDA:0,PolicyMock.description +DA:66,0 +DA:69,36807 +FN:69,PolicyMock.supportsInterface +FNDA:36807,PolicyMock.supportsInterface +DA:70,36807 +DA:75,1 +FN:75,PolicyNoDataRevertMock.setup +FNDA:1,PolicyNoDataRevertMock.setup +DA:77,0 +DA:87,1 +FN:87,ReentrantPolicyMock.constructor +FNDA:1,ReentrantPolicyMock.constructor +DA:88,1 +DA:91,1 +FN:91,ReentrantPolicyMock.setup +FNDA:1,ReentrantPolicyMock.setup +DA:93,1 +DA:94,1 +DA:95,0 +DA:382,2 +FN:382,RightsPolicyAuthorizerHandler.constructor +FNDA:2,RightsPolicyAuthorizerHandler.constructor +DA:383,2 +DA:384,2 +DA:385,2 +DA:386,2 +DA:388,2 +DA:389,6 +DA:390,6 +DA:391,6 +DA:395,25052 +FN:395,RightsPolicyAuthorizerHandler._audit +FNDA:25052,RightsPolicyAuthorizerHandler._audit +DA:398,11370 +DA:399,11370 +BRDA:399,1,0,11370 +DA:401,11370 +DA:402,11370 +BRDA:402,2,0,11370 +DA:403,6 +DA:406,11370 +BRDA:406,3,0,- +DA:407,0 +DA:411,0 +FN:411,RightsPolicyAuthorizerHandler.policiesLength +FNDA:0,RightsPolicyAuthorizerHandler.policiesLength +DA:412,0 +DA:415,0 +FN:415,RightsPolicyAuthorizerHandler.policyAt +FNDA:0,RightsPolicyAuthorizerHandler.policyAt +DA:416,0 +DA:419,0 +FN:419,RightsPolicyAuthorizerHandler.isAuthorized +FNDA:0,RightsPolicyAuthorizerHandler.isAuthorized +DA:420,0 +DA:423,16746 +FN:423,RightsPolicyAuthorizerHandler.authorize +FNDA:16746,RightsPolicyAuthorizerHandler.authorize +DA:424,16746 +DA:425,16746 +DA:427,16746 +DA:428,16746 +DA:430,9172 +DA:431,9172 +BRDA:431,5,0,9172 +DA:432,5681 +DA:436,16716 +FN:436,RightsPolicyAuthorizerHandler.revoke +FNDA:16716,RightsPolicyAuthorizerHandler.revoke +DA:437,16716 +DA:438,16716 +DA:439,16716 +DA:441,3287 +DA:442,3287 +BRDA:442,7,0,3287 +DA:443,3287 +DA:447,16588 +FN:447,RightsPolicyAuthorizerHandler.toggleAudit +FNDA:16588,RightsPolicyAuthorizerHandler.toggleAudit +DA:448,16588 +DA:449,16588 +DA:451,8300 +BRDA:451,8,0,8300 +BRDA:451,8,1,- +DA:452,8300 +DA:453,4552 +BRDA:453,9,0,4552 +DA:454,4552 +DA:455,4552 +BRDA:455,10,0,4552 +DA:456,4552 +DA:457,4552 +FNF:21 +FNH:10 +LF:78 +LH:52 +BRF:10 +BRH:7 +end_of_record diff --git a/script/deployment/18_Deploy_RightsManager_PolicyAuthorizer.s.sol b/script/deployment/18_Deploy_RightsManager_PolicyAuthorizer.s.sol new file mode 100644 index 0000000..c3dc4f2 --- /dev/null +++ b/script/deployment/18_Deploy_RightsManager_PolicyAuthorizer.s.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import { DeployBase } from "script/deployment/00_Deploy_Base.s.sol"; +import { RightsPolicyAuthorizer } from "contracts/rights/RightsPolicyAuthorizer.sol"; + +/// @notice Local deployment helper for test environments. +/// @dev Mirrors the production deployment but allows injecting custom dependencies when needed. +contract DeployRightsPolicyAuthorizer is DeployBase { + function run(address policyAudit, address accessManager) external returns (address) { + vm.startBroadcast(getAdminPK()); + + address implementation = address(new RightsPolicyAuthorizer(policyAudit)); + bytes memory initData = abi.encodeCall(RightsPolicyAuthorizer.initialize, accessManager); + address proxy = deployUUPS(implementation, initData, "SALT_RIGHT_POLICY_AUTHORIZER"); + + vm.stopBroadcast(); + return proxy; + } +} + diff --git a/test/BaseTest.t.sol b/test/BaseTest.t.sol index b29f413..d1f1b07 100644 --- a/test/BaseTest.t.sol +++ b/test/BaseTest.t.sol @@ -17,6 +17,8 @@ import { DeployCustodianReferendum } from "script/deployment/10_Deploy_Custody_C import { DeployAgreementManager } from "script/deployment/07_Deploy_Financial_AgreementManager.s.sol"; import { DeployAgreementSettler } from "script/deployment/08_Deploy_Financial_AgreementSettler.s.sol"; import { DeployRightsAssetCustodian } from "script/deployment/15_Deploy_RightsManager_AssetCustodian.s.sol"; +import { DeployRightsPolicyAuthorizer } from "script/deployment/18_Deploy_RightsManager_PolicyAuthorizer.s.sol"; +import { DeployPolicyAudit } from "script/deployment/14_Deploy_Policies_PolicyAudit.s.sol"; import { getGovPermissions as TollgateGovPermissions } from "script/permissions/Permissions_Tollgate.sol"; import { getGovPermissions as TreasuryGovPermissions } from "script/permissions/Permissions_Treasury.sol"; @@ -51,6 +53,9 @@ abstract contract BaseTest is Test { address custodianFactory; address rightAssetCustodian; + address policyAudit; + address rightsPolicyAuthorizer; + address rightsPolicyManager; address tollgate; address treasury; @@ -211,6 +216,20 @@ abstract contract BaseTest is Test { rightAssetCustodian = rightAssetCustodian == address(0) ? rightAssetCustodianDeployer.run() : rightAssetCustodian; } + function deployPolicyAudit() public { + DeployPolicyAudit policyAuditDeployer = new DeployPolicyAudit(); + policyAudit = policyAudit == address(0) ? policyAuditDeployer.run() : policyAudit; + } + + function deployRightsPolicyAuthorizer() public { + deployPolicyAudit(); + + DeployRightsPolicyAuthorizer rightsAuthorizerDeployer = new DeployRightsPolicyAuthorizer(); + rightsPolicyAuthorizer = rightsPolicyAuthorizer == address(0) + ? rightsAuthorizerDeployer.run(policyAudit, accessManager) + : rightsPolicyAuthorizer; + } + function _setContentCouncilPermissions(address target, bytes4[] memory allowed) public { vm.startPrank(admin); IAccessManager authority = IAccessManager(accessManager); diff --git a/test/finance/LedgerVault.t.sol b/test/finance/LedgerVault.t.sol new file mode 100644 index 0000000..992a558 --- /dev/null +++ b/test/finance/LedgerVault.t.sol @@ -0,0 +1,512 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import "forge-std/Test.sol"; + +import { AccessManager } from "@openzeppelin/contracts/access/manager/AccessManager.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; +import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import { AccessControlledUpgradeable } from "contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol"; + +import { LedgerVault } from "contracts/financial/LedgerVault.sol"; +import { C } from "contracts/core/primitives/Constants.sol"; +import { ILedgerVerifiable } from "contracts/core/interfaces/base/ILedgerVerifiable.sol"; +import { FinancialOps } from "contracts/core/libraries/FinancialOps.sol"; + +contract MockToken is ERC20 { + constructor() ERC20("Mock Token", "MOCK") {} + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } +} + +contract LedgerVaultHarness is LedgerVault { + bytes32 private constant LOCK_SLOT = + 0xece3ff917f3a3127e521e0c3f2f90ff09a3c8199be32f9b40bff79e776960800; + + function lockedBalance(address account, address currency) external view returns (uint256 balance_) { + bytes32 first; + bytes32 second; + assembly { + mstore(0x00, account) + mstore(0x20, LOCK_SLOT) + first := keccak256(0x00, 0x40) + + mstore(0x00, currency) + mstore(0x20, first) + second := keccak256(0x00, 0x40) + + balance_ := sload(second) + } + } +} + +contract LedgerVaultTest is Test { + LedgerVaultHarness vault; + AccessManager manager; + MockToken token; + + address admin = vm.addr(1); + address operator = vm.addr(2); + address claimer = vm.addr(3); + address user = vm.addr(4); + address other = vm.addr(5); + + function setUp() public { + token = new MockToken(); + manager = new AccessManager(admin); + + LedgerVaultHarness implementation = new LedgerVaultHarness(); + ERC1967Proxy proxy = new ERC1967Proxy( + address(implementation), + abi.encodeWithSignature("initialize(address)", address(manager)) + ); + vault = LedgerVaultHarness(address(proxy)); + + vm.startPrank(admin); + bytes4[] memory adminSelectors = new bytes4[](2); + adminSelectors[0] = AccessControlledUpgradeable.pause.selector; + adminSelectors[1] = AccessControlledUpgradeable.unpause.selector; + manager.setTargetFunctionRole(address(vault), adminSelectors, C.ADMIN_ROLE); + + bytes4[] memory opsSelectors = new bytes4[](3); + opsSelectors[0] = LedgerVault.lock.selector; + opsSelectors[1] = LedgerVault.release.selector; + opsSelectors[2] = LedgerVault.claim.selector; + manager.setTargetFunctionRole(address(vault), opsSelectors, C.OPS_ROLE); + manager.setRoleAdmin(C.OPS_ROLE, C.ADMIN_ROLE); + manager.grantRole(C.OPS_ROLE, operator, 0); + manager.grantRole(C.OPS_ROLE, claimer, 0); + vm.stopPrank(); + + token.mint(admin, 1_000_000 ether); + token.mint(user, 1_000_000 ether); + token.mint(other, 1_000_000 ether); + } + + function _deposit(address account, uint256 amount) internal returns (uint256) { + vm.startPrank(account); + token.approve(address(vault), amount); + uint256 confirmed = vault.deposit(account, amount, address(token)); + vm.stopPrank(); + return confirmed; + } + + function test_Deposit_Succeeds() public { + uint256 confirmed = _deposit(admin, 100 ether); + + assertEq(confirmed, 100 ether, "Deposit return mismatch"); + assertEq( + ILedgerVerifiable(address(vault)).getLedgerBalance(admin, address(token)), + 100 ether, + "Ledger balance mismatch" + ); + assertEq(token.balanceOf(address(vault)), 100 ether, "Vault token balance mismatch"); + } + + function test_Deposit_RevertWhen_NoAllowance() public { + vm.prank(admin); + vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringDeposit.selector, "Amount exceeds allowance.")); + vault.deposit(admin, 10 ether, address(token)); + } + + function test_Withdraw_Succeeds() public { + _deposit(admin, 200 ether); + + vm.prank(admin); + uint256 withdrawn = vault.withdraw(admin, 150 ether, address(token)); + + assertEq(withdrawn, 150 ether, "Withdrawn amount mismatch"); + assertEq( + ILedgerVerifiable(address(vault)).getLedgerBalance(admin, address(token)), + 50 ether, + "Ledger balance after withdraw" + ); + assertEq(token.balanceOf(admin), 1_000_000 ether - 50 ether, "Admin token balance mismatch"); + } + + function test_Withdraw_RevertWhen_NoFunds() public { + vm.prank(admin); + vm.expectRevert(bytes4(keccak256("NoFundsToWithdraw()"))); + vault.withdraw(admin, 1 ether, address(token)); + } + + function test_Transfer_Succeeds() public { + _deposit(admin, 100 ether); + + vm.prank(admin); + uint256 moved = vault.transfer(user, 40 ether, address(token)); + + assertEq(moved, 40 ether, "Transfer amount mismatch"); + assertEq( + ILedgerVerifiable(address(vault)).getLedgerBalance(admin, address(token)), + 60 ether, + "Admin ledger after transfer" + ); + assertEq( + ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(token)), + 40 ether, + "User ledger after transfer" + ); + } + + function test_Transfer_RevertWhen_Self() public { + _deposit(admin, 50 ether); + + vm.prank(admin); + vm.expectRevert(bytes4(keccak256("InvalidOperationParameters()"))); + vault.transfer(admin, 10 ether, address(token)); + } + + function test_Lock_Succeeds() public { + _deposit(user, 120 ether); + + vm.prank(operator); + uint256 locked = vault.lock(user, 70 ether, address(token)); + + assertEq(locked, 70 ether, "Locked amount mismatch"); + assertEq( + ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(token)), + 50 ether, + "User ledger after lock" + ); + assertEq(vault.lockedBalance(user, address(token)), 70 ether, "Locked balance mismatch"); + } + + function test_Lock_RevertWhen_Insufficient() public { + _deposit(user, 10 ether); + + vm.prank(operator); + vm.expectRevert(bytes4(keccak256("NoFundsToLock()"))); + vault.lock(user, 20 ether, address(token)); + } + + function test_Release_Succeeds() public { + _deposit(user, 90 ether); + vm.prank(operator); + vault.lock(user, 60 ether, address(token)); + + vm.prank(operator); + uint256 released = vault.release(user, 30 ether, address(token)); + + assertEq(released, 30 ether, "Released amount mismatch"); + assertEq(vault.lockedBalance(user, address(token)), 30 ether, "Locked balance after release"); + assertEq( + ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(token)), + 60 ether, + "Ledger after release" + ); + } + + function test_Claim_Succeeds() public { + _deposit(user, 100 ether); + vm.prank(operator); + vault.lock(user, 40 ether, address(token)); + + vm.prank(claimer); + uint256 claimed = vault.claim(user, 25 ether, address(token)); + + assertEq(claimed, 25 ether, "Claim amount mismatch"); + assertEq(vault.lockedBalance(user, address(token)), 15 ether, "Locked balance after claim"); + assertEq( + ILedgerVerifiable(address(vault)).getLedgerBalance(claimer, address(token)), + 25 ether, + "Claimer ledger after claim" + ); + } + + function test_Pause_BlocksStateChanging() public { + _deposit(admin, 10 ether); + vm.prank(admin); + vault.pause(); + + vm.prank(admin); + vm.expectRevert(PausableUpgradeable.EnforcedPause.selector); + vault.withdraw(admin, 1 ether, address(token)); + + vm.prank(admin); + vault.unpause(); + + vm.prank(admin); + vault.withdraw(admin, 1 ether, address(token)); + } + + function test_Integration_FullFlow() public { + _deposit(user, 200 ether); + vm.prank(operator); + vault.lock(user, 120 ether, address(token)); + vm.prank(claimer); + vault.claim(user, 70 ether, address(token)); + vm.prank(operator); + vault.release(user, 30 ether, address(token)); + vm.prank(user); + vault.transfer(other, 40 ether, address(token)); + + assertEq(vault.lockedBalance(user, address(token)), 20 ether, "Remaining locked"); + assertEq( + ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(token)), + 70 ether, + "User ledger after flow" + ); + assertEq( + ILedgerVerifiable(address(vault)).getLedgerBalance(claimer, address(token)), + 70 ether, + "Claimer ledger after flow" + ); + } + + function testFuzz_DepositWithdraw(uint256 amount) public { + amount = bound(amount, 1 ether, 1_000 ether); + token.mint(user, amount); + _deposit(user, amount); + + vm.prank(user); + uint256 withdrawn = vault.withdraw(user, amount, address(token)); + assertEq(withdrawn, amount, "Withdrawn amount mismatch"); + assertEq( + ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(token)), + 0, + "Ledger should be zero" + ); + } + + function testFuzz_TransferMaintainsLedger(uint256 depositAmount, uint256 transferAmount) public { + depositAmount = bound(depositAmount, 2 ether, 1_000 ether); + transferAmount = bound(transferAmount, 1 ether, depositAmount - 1 ether); + token.mint(user, depositAmount); + _deposit(user, depositAmount); + + vm.prank(user); + vault.transfer(other, transferAmount, address(token)); + + uint256 ledgerUser = ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(token)); + uint256 ledgerOther = ILedgerVerifiable(address(vault)).getLedgerBalance(other, address(token)); + assertEq(ledgerUser + ledgerOther, depositAmount, "Ledger conservation failed"); + } +} + +contract LedgerVaultHandler is Test { + LedgerVaultHarness public immutable vault; + MockToken public immutable token; + address public immutable operator; + address public immutable claimer; + address[] internal accounts; + + mapping(address => uint256) internal expectedLedger; + mapping(address => uint256) internal expectedLocked; + + constructor( + LedgerVaultHarness vault_, + MockToken token_, + address operator_, + address claimer_, + address[] memory actors + ) { + vault = vault_; + token = token_; + operator = operator_; + claimer = claimer_; + for (uint256 i = 0; i < actors.length; i++) { + accounts.push(actors[i]); + } + } + + function accountsLength() external view returns (uint256) { + return accounts.length; + } + + function accountAt(uint256 idx) external view returns (address) { + return accounts[idx]; + } + + function expectedLedgerOf(address account) external view returns (uint256) { + return expectedLedger[account]; + } + + function expectedLockedOf(address account) external view returns (uint256) { + return expectedLocked[account]; + } + + function _boundAmount(address account, uint256 amount) internal view returns (uint256) { + uint256 balance = token.balanceOf(account); + if (balance == 0) return 0; + return bound(amount, 1, balance); + } + + function deposit(uint256 idx, uint256 amount) external { + vm.assume(idx < accounts.length); + address account = accounts[idx]; + amount = _boundAmount(account, amount); + if (amount == 0) return; + + vm.startPrank(account); + token.approve(address(vault), amount); + uint256 confirmed = vault.deposit(account, amount, address(token)); + vm.stopPrank(); + + expectedLedger[account] += confirmed; + } + + function withdraw(uint256 idx, uint256 amount) external { + vm.assume(idx < accounts.length); + address account = accounts[idx]; + uint256 available = expectedLedger[account]; + vm.assume(available > 0); + amount = bound(amount, 1, available); + + vm.prank(account); + uint256 confirmed = vault.withdraw(account, amount, address(token)); + expectedLedger[account] = available - confirmed; + } + + function transfer(uint256 fromIdx, uint256 toIdx, uint256 amount) external { + vm.assume(fromIdx < accounts.length && toIdx < accounts.length); + vm.assume(fromIdx != toIdx); + address from = accounts[fromIdx]; + address to = accounts[toIdx]; + uint256 available = expectedLedger[from]; + vm.assume(available > 0); + amount = bound(amount, 1, available); + + vm.prank(from); + vault.transfer(to, amount, address(token)); + + expectedLedger[from] = available - amount; + expectedLedger[to] += amount; + } + + function lock(uint256 idx, uint256 amount) external { + vm.assume(idx < accounts.length); + address account = accounts[idx]; + uint256 available = expectedLedger[account]; + vm.assume(available > 0); + amount = bound(amount, 1, available); + + vm.prank(operator); + vault.lock(account, amount, address(token)); + + expectedLedger[account] = available - amount; + expectedLocked[account] += amount; + } + + function release(uint256 idx, uint256 amount) external { + vm.assume(idx < accounts.length); + address account = accounts[idx]; + uint256 locked = expectedLocked[account]; + vm.assume(locked > 0); + amount = bound(amount, 1, locked); + + vm.prank(operator); + vault.release(account, amount, address(token)); + + expectedLocked[account] = locked - amount; + expectedLedger[account] += amount; + } + + function claim(uint256 idx, uint256 amount) external { + vm.assume(idx < accounts.length); + address account = accounts[idx]; + uint256 locked = expectedLocked[account]; + vm.assume(locked > 0); + amount = bound(amount, 1, locked); + + vm.prank(claimer); + vault.claim(account, amount, address(token)); + + expectedLocked[account] = locked - amount; + expectedLedger[claimer] += amount; + } +} + +contract LedgerVaultInvariantTest is Test { + LedgerVaultHarness vault; + AccessManager manager; + MockToken token; + LedgerVaultHandler handler; + + address admin = vm.addr(11); + address operator = vm.addr(12); + address claimer = vm.addr(13); + address[] accounts; + + function setUp() public { + token = new MockToken(); + manager = new AccessManager(admin); + + LedgerVaultHarness implementation = new LedgerVaultHarness(); + ERC1967Proxy proxy = new ERC1967Proxy( + address(implementation), + abi.encodeWithSignature("initialize(address)", address(manager)) + ); + vault = LedgerVaultHarness(address(proxy)); + + vm.startPrank(admin); + bytes4[] memory adminSelectors = new bytes4[](2); + adminSelectors[0] = AccessControlledUpgradeable.pause.selector; + adminSelectors[1] = AccessControlledUpgradeable.unpause.selector; + manager.setTargetFunctionRole(address(vault), adminSelectors, C.ADMIN_ROLE); + + bytes4[] memory opsSelectors = new bytes4[](3); + opsSelectors[0] = LedgerVault.lock.selector; + opsSelectors[1] = LedgerVault.release.selector; + opsSelectors[2] = LedgerVault.claim.selector; + manager.setTargetFunctionRole(address(vault), opsSelectors, C.OPS_ROLE); + manager.setRoleAdmin(C.OPS_ROLE, C.ADMIN_ROLE); + manager.grantRole(C.OPS_ROLE, operator, 0); + manager.grantRole(C.OPS_ROLE, claimer, 0); + vm.stopPrank(); + + accounts = new address[](5); + for (uint256 i = 0; i < accounts.length; i++) { + accounts[i] = vm.addr(20 + i); + token.mint(accounts[i], 1_000_000 ether); + } + + handler = new LedgerVaultHandler(vault, token, operator, claimer, accounts); + targetContract(address(handler)); + } + + function _aggregateLedgerAndLocked() + internal + view + returns (uint256 ledgerSum, uint256 lockedSum) + { + uint256 len = handler.accountsLength(); + for (uint256 i = 0; i < len; i++) { + address account = handler.accountAt(i); + ledgerSum += ILedgerVerifiable(address(vault)).getLedgerBalance(account, address(token)); + lockedSum += vault.lockedBalance(account, address(token)); + assertEq( + handler.expectedLedgerOf(account), + ILedgerVerifiable(address(vault)).getLedgerBalance(account, address(token)), + "Ledger expectation mismatch" + ); + assertEq( + handler.expectedLockedOf(account), + vault.lockedBalance(account, address(token)), + "Locked expectation mismatch" + ); + } + + ledgerSum += ILedgerVerifiable(address(vault)).getLedgerBalance(claimer, address(token)); + lockedSum += vault.lockedBalance(claimer, address(token)); + assertEq( + handler.expectedLedgerOf(claimer), + ILedgerVerifiable(address(vault)).getLedgerBalance(claimer, address(token)), + "Claimer ledger mismatch" + ); + assertEq( + handler.expectedLockedOf(claimer), + vault.lockedBalance(claimer, address(token)), + "Claimer locked mismatch" + ); + } + + function invariant_LedgerAndLockedBalance() external view { + (uint256 ledgerSum, uint256 lockedSum) = _aggregateLedgerAndLocked(); + assertEq(ledgerSum + lockedSum, token.balanceOf(address(vault)), "Ledger + locked must match vault balance"); + } +} diff --git a/test/policies/PolicyAudit.t.sol b/test/policies/PolicyAudit.t.sol new file mode 100644 index 0000000..5e0c9fa --- /dev/null +++ b/test/policies/PolicyAudit.t.sol @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import "forge-std/Test.sol"; + +import { PolicyAudit } from "contracts/policies/PolicyAudit.sol"; +import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import { AccessControlledUpgradeable } from "contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol"; +import { QuorumUpgradeable } from "contracts/core/primitives/upgradeable/QuorumUpgradeable.sol"; +import { IPolicy } from "contracts/core/interfaces/policies/IPolicy.sol"; +import { T } from "contracts/core/primitives/Types.sol"; +import { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; + +import { BaseTest } from "test/BaseTest.t.sol"; + +contract MockPolicy is ERC165, IPolicy { + function setup(address, bytes calldata) external override {} + + function enforce(address, T.Agreement calldata) external pure override returns (uint256[] memory) { + return new uint256[](0); + } + + function isAccessAllowed(address, bytes calldata) external pure override returns (bool) { + return true; + } + + function getLicense(address, bytes calldata) external pure override returns (uint256) { + return 0; + } + + function resolveTerms(bytes calldata) external pure override returns (T.Terms memory) { + return T.Terms({ amount: 0, currency: address(0), timeFrame: T.TimeFrame.NONE, uri: "" }); + } + + function getAttestationProvider() external pure override returns (address) { + return address(0); + } + + function name() external pure override returns (string memory) { + return "Mock Policy"; + } + + function description() external pure override returns (string memory) { + return "Mock policy for testing"; + } + + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IPolicy).interfaceId || super.supportsInterface(interfaceId); + } +} + +contract NotPolicy {} + +contract PolicyAuditHarness is PolicyAudit { + function status(address policy) external view returns (T.Status) { + return _status(uint160(policy)); + } +} + +contract PolicyAuditTest is BaseTest { + PolicyAuditHarness internal audit; + address internal nonAdmin; + + function setUp() public initialize { + PolicyAuditHarness implementation = new PolicyAuditHarness(); + ERC1967Proxy proxy = new ERC1967Proxy( + address(implementation), + abi.encodeCall(PolicyAudit.initialize, accessManager) + ); + audit = PolicyAuditHarness(address(proxy)); + nonAdmin = vm.addr(77); + } + + function test_Submit_RevertWhen_InvalidPolicy() public { + NotPolicy invalid = new NotPolicy(); + vm.expectRevert(abi.encodeWithSelector(PolicyAudit.InvalidPolicyContract.selector, address(invalid))); + audit.submit(address(invalid)); + } + + function test_Submit_RegistersPolicy() public { + MockPolicy policy = new MockPolicy(); + vm.expectEmit(true, true, false, true, address(audit)); + emit PolicyAudit.PolicySubmitted(address(policy), address(this)); + audit.submit(address(policy)); + assertEq(uint8(audit.status(address(policy))), uint8(T.Status.Waiting), "Status should be waiting"); + assertFalse(audit.isAudited(address(policy)), "Policy should not be active yet"); + } + + function test_Submit_RevertWhen_AlreadySubmitted() public { + MockPolicy policy = new MockPolicy(); + audit.submit(address(policy)); + vm.expectRevert(QuorumUpgradeable.NotPendingApproval.selector); + audit.submit(address(policy)); + } + + function test_Approve_TransitionsToActive() public { + MockPolicy policy = new MockPolicy(); + audit.submit(address(policy)); + + vm.expectEmit(true, true, false, true, address(audit)); + emit PolicyAudit.PolicyApproved(address(policy), admin); + vm.prank(admin); + audit.approve(address(policy)); + assertEq(uint8(audit.status(address(policy))), uint8(T.Status.Active), "Policy not active"); + assertTrue(audit.isAudited(address(policy)), "isAudited should be true"); + } + + function test_Approve_RevertWhen_NotWaiting() public { + MockPolicy policy = new MockPolicy(); + vm.prank(admin); + vm.expectRevert(QuorumUpgradeable.NotWaitingApproval.selector); + audit.approve(address(policy)); + } + + function test_Reject_TransitionsToBlocked() public { + MockPolicy policy = new MockPolicy(); + audit.submit(address(policy)); + vm.prank(admin); + audit.approve(address(policy)); + + vm.expectEmit(true, true, false, true, address(audit)); + emit PolicyAudit.PolicyRevoked(address(policy), admin); + vm.prank(admin); + audit.reject(address(policy)); + assertEq(uint8(audit.status(address(policy))), uint8(T.Status.Blocked), "Policy not blocked"); + assertFalse(audit.isAudited(address(policy)), "isAudited should be false after revoke"); + vm.expectRevert(QuorumUpgradeable.NotWaitingApproval.selector); + vm.prank(admin); + audit.approve(address(policy)); + } + + function test_Reject_RevertWhen_NotActive() public { + MockPolicy policy = new MockPolicy(); + audit.submit(address(policy)); + vm.prank(admin); + vm.expectRevert(QuorumUpgradeable.InvalidInactiveState.selector); + audit.reject(address(policy)); + } + + function test_OnlyAdminMayApprove() public { + MockPolicy policy = new MockPolicy(); + audit.submit(address(policy)); + + vm.expectRevert( + abi.encodeWithSelector( + AccessControlledUpgradeable.InvalidUnauthorizedOperation.selector, + "Only admin can perform this action." + ) + ); + vm.prank(nonAdmin); + audit.approve(address(policy)); + } + + function test_Integration_SubmitApproveRejectMultiple() public { + MockPolicy policy1 = new MockPolicy(); + MockPolicy policy2 = new MockPolicy(); + MockPolicy policy3 = new MockPolicy(); + + audit.submit(address(policy1)); + audit.submit(address(policy2)); + audit.submit(address(policy3)); + + vm.prank(admin); + audit.approve(address(policy1)); + vm.prank(admin); + audit.approve(address(policy2)); + vm.prank(admin); + audit.reject(address(policy2)); + + assertTrue(audit.isAudited(address(policy1)), "Policy1 should be active"); + assertFalse(audit.isAudited(address(policy2)), "Policy2 should be blocked"); + assertEq(uint8(audit.status(address(policy3))), uint8(T.Status.Waiting), "Policy3 should remain waiting"); + } + + function testFuzz_SubmitMultiple(uint8 count) public { + count = uint8(bound(count, 1, 25)); + for (uint8 i = 0; i < count; i++) { + MockPolicy policy = new MockPolicy(); + audit.submit(address(policy)); + assertEq(uint8(audit.status(address(policy))), uint8(T.Status.Waiting), "Status should be waiting"); + } + } + + function testFuzz_SubmitApprove(uint8 count) public { + count = uint8(bound(count, 1, 20)); + for (uint8 i = 0; i < count; i++) { + MockPolicy policy = new MockPolicy(); + audit.submit(address(policy)); + vm.prank(admin); + audit.approve(address(policy)); + assertTrue(audit.isAudited(address(policy)), "Policy should be active"); + } + } +} + +contract PolicyAuditHandler is Test { + PolicyAuditHarness public immutable audit; + address public immutable admin; + address[] internal policies; + mapping(address => T.Status) internal statusStore; + + constructor(PolicyAuditHarness audit_, address admin_) { + audit = audit_; + admin = admin_; + } + + function submitPolicy() external { + MockPolicy policy = new MockPolicy(); + try audit.submit(address(policy)) { + policies.push(address(policy)); + statusStore[address(policy)] = T.Status.Waiting; + } catch {} + } + + function approvePolicy(uint256 idx) external { + if (policies.length == 0) return; + address policy = policies[idx % policies.length]; + if (statusStore[policy] != T.Status.Waiting) return; + + vm.prank(admin); + try audit.approve(policy) { + statusStore[policy] = T.Status.Active; + } catch {} + } + + function rejectPolicy(uint256 idx) external { + if (policies.length == 0) return; + address policy = policies[idx % policies.length]; + if (statusStore[policy] != T.Status.Active) return; + + vm.prank(admin); + try audit.reject(policy) { + statusStore[policy] = T.Status.Blocked; + } catch {} + } + + function policiesLength() external view returns (uint256) { + return policies.length; + } + + function policyAt(uint256 idx) external view returns (address) { + return policies[idx]; + } + + function storedStatus(address policy) external view returns (T.Status) { + return statusStore[policy]; + } +} + +contract PolicyAuditInvariantTest is BaseTest { + PolicyAuditHarness audit; + PolicyAuditHandler handler; + + function setUp() public initialize { + PolicyAuditHarness implementation = new PolicyAuditHarness(); + ERC1967Proxy proxy = new ERC1967Proxy( + address(implementation), + abi.encodeCall(PolicyAudit.initialize, accessManager) + ); + audit = PolicyAuditHarness(address(proxy)); + + handler = new PolicyAuditHandler(audit, admin); + targetContract(address(handler)); + } + + function invariant_StatusSynchronization() external view { + uint256 len = handler.policiesLength(); + for (uint256 i = 0; i < len; i++) { + address policy = handler.policyAt(i); + T.Status expected = handler.storedStatus(policy); + assertEq(uint8(audit.status(policy)), uint8(expected), "Status mismatch"); + } + } + + function invariant_IsAuditedMatchesActive() external view { + uint256 len = handler.policiesLength(); + for (uint256 i = 0; i < len; i++) { + address policy = handler.policyAt(i); + bool audited = audit.isAudited(policy); + bool expected = handler.storedStatus(policy) == T.Status.Active; + assertEq(audited, expected, "isAudited mismatch"); + } + } +} diff --git a/test/rights/RightsPolicyAuthorizer.t.sol b/test/rights/RightsPolicyAuthorizer.t.sol new file mode 100644 index 0000000..ee3b76f --- /dev/null +++ b/test/rights/RightsPolicyAuthorizer.t.sol @@ -0,0 +1,499 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import "forge-std/Test.sol"; + +import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; + +import { RightsPolicyAuthorizer } from "contracts/rights/RightsPolicyAuthorizer.sol"; +import { IRightsPolicyAuthorizer } from "contracts/core/interfaces/rights/IRightsPolicyAuthorizer.sol"; +import { IPolicy } from "contracts/core/interfaces/policies/IPolicy.sol"; +import { IPolicyAuditor } from "contracts/core/interfaces/policies/IPolicyAuditor.sol"; +import { T } from "contracts/core/primitives/Types.sol"; + +import { BaseTest } from "test/BaseTest.t.sol"; + +/// @dev Minimal policy mock exposing setup side-effects for assertions. +contract PolicyMock is ERC165, IPolicy { + address public lastHolder; + bytes public lastInit; + bool public shouldRevert; + + function configureRevert(bool status) external { + shouldRevert = status; + } + + /// @inheritdoc IPolicy + function setup(address holder, bytes calldata init) public virtual override { + if (shouldRevert) revert("policy setup failed"); + lastHolder = holder; + lastInit = init; + } + + /// @inheritdoc IPolicy + function enforce(address, T.Agreement calldata) external pure override returns (uint256[] memory result) { + return result; + } + + /// @inheritdoc IPolicy + function isAccessAllowed(address, bytes calldata) external pure override returns (bool) { + return false; + } + + /// @inheritdoc IPolicy + function getLicense(address, bytes calldata) external pure override returns (uint256) { + return 0; + } + + /// @inheritdoc IPolicy + function resolveTerms(bytes calldata) external pure override returns (T.Terms memory terms) { + return terms; + } + + /// @inheritdoc IPolicy + function getAttestationProvider() external pure override returns (address) { + return address(0); + } + + /// @inheritdoc IPolicy + function name() external pure override returns (string memory) { + return "MockPolicy"; + } + + /// @inheritdoc IPolicy + function description() external pure override returns (string memory) { + return "Mock policy used for testing"; + } + + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IPolicy).interfaceId || super.supportsInterface(interfaceId); + } +} + +contract PolicyNoDataRevertMock is PolicyMock { + function setup(address, bytes calldata) public pure override { + assembly { + revert(0, 0) + } + } +} + +/// @dev Policy mock exercising reentrancy protection. +contract ReentrantPolicyMock is PolicyMock { + IRightsPolicyAuthorizer public immutable authorizer; + bool private triggered; + + constructor(IRightsPolicyAuthorizer authorizer_) { + authorizer = authorizer_; + } + + function setup(address holder, bytes calldata init) public override { + if (triggered) return; + triggered = true; + authorizer.authorizePolicy(address(this), init); + super.setup(holder, init); + } +} + +contract RightsPolicyAuthorizerTest is BaseTest { + IRightsPolicyAuthorizer internal authorizer; + IPolicyAuditor internal auditor; + address internal holder; + + mapping(address => bool) internal audited; + + event RightsGranted(address indexed policy, address indexed holder, bytes data); + event RightsRevoked(address indexed policy, address indexed holder); + + function setUp() public initialize { + deployRightsPolicyAuthorizer(); + authorizer = IRightsPolicyAuthorizer(rightsPolicyAuthorizer); + auditor = IPolicyAuditor(policyAudit); + holder = user; + } + + function _auditPolicy(address policy) internal { + if (audited[policy]) return; + + vm.prank(holder); + try auditor.submit(policy) {} catch {} + + vm.prank(admin); + try auditor.approve(policy) { + audited[policy] = true; + } catch {} + + if (!audited[policy] && auditor.isAudited(policy)) { + audited[policy] = true; + } + } + + function _revokeAudit(address policy) internal { + if (!audited[policy]) return; + + vm.prank(admin); + try auditor.reject(policy) { + audited[policy] = false; + } catch {} + + if (audited[policy] && !auditor.isAudited(policy)) { + audited[policy] = false; + } + } + + function test_Initialize_RevertsOnSecondCall() public { + vm.expectRevert(Initializable.InvalidInitialization.selector); + vm.prank(admin); + RightsPolicyAuthorizer(address(authorizer)).initialize(accessManager); + } + + function test_AuthorizePolicy_SucceedsForAuditedPolicy() public { + PolicyMock policy = new PolicyMock(); + _auditPolicy(address(policy)); + + bytes memory initData = abi.encode(uint256(1)); + vm.expectEmit(true, true, true, true, address(authorizer)); + emit RightsGranted(address(policy), holder, initData); + + vm.prank(holder); + authorizer.authorizePolicy(address(policy), initData); + + assertTrue(authorizer.isPolicyAuthorized(address(policy), holder), "Policy should be authorized"); + assertEq(policy.lastHolder(), holder, "Holder mismatch recorded in policy setup"); + assertEq(policy.lastInit(), initData, "Init payload mismatch in policy setup"); + } + + function test_AuthorizePolicy_RevertsWhenPolicyNotAudited() public { + PolicyMock policy = new PolicyMock(); + + vm.expectRevert(abi.encodeWithSelector(RightsPolicyAuthorizer.InvalidNotAuditedPolicy.selector, address(policy))); + vm.prank(holder); + authorizer.authorizePolicy(address(policy), ""); + } + + function test_AuthorizePolicy_RevertsWhenSetupFails() public { + PolicyNoDataRevertMock policy = new PolicyNoDataRevertMock(); + _auditPolicy(address(policy)); + + vm.expectRevert( + abi.encodeWithSelector( + RightsPolicyAuthorizer.InvalidPolicyInitialization.selector, + "Error during policy initialization call" + ) + ); + vm.prank(holder); + authorizer.authorizePolicy(address(policy), ""); + } + + function test_AuthorizePolicy_ReentrancyIsBlocked() public { + ReentrantPolicyMock policy = new ReentrantPolicyMock(authorizer); + _auditPolicy(address(policy)); + + vm.prank(holder); + authorizer.authorizePolicy(address(policy), "data"); + + address[] memory holderPolicies = authorizer.getAuthorizedPolicies(holder); + assertEq(holderPolicies.length, 1, "Holder should keep a single authorized policy"); + assertEq(holderPolicies[0], address(policy), "Unexpected policy stored for holder"); + + assertFalse( + authorizer.isPolicyAuthorized(address(policy), address(policy)), + "Reentrancy guard should prevent policy self-authorization" + ); + } + + function test_RevokePolicy_RemovesAuthorization() public { + PolicyMock policy = new PolicyMock(); + _auditPolicy(address(policy)); + + vm.prank(holder); + authorizer.authorizePolicy(address(policy), ""); + + vm.expectEmit(true, true, false, false, address(authorizer)); + emit RightsRevoked(address(policy), holder); + + vm.prank(holder); + authorizer.revokePolicy(address(policy)); + + assertFalse(authorizer.isPolicyAuthorized(address(policy), holder), "Policy should be revoked"); + } + + function test_RevokePolicy_RevertsWhenNotAuthorized() public { + PolicyMock policy = new PolicyMock(); + + vm.expectRevert(abi.encodeWithSelector(RightsPolicyAuthorizer.RevocationFailed.selector, holder, address(policy))); + vm.prank(holder); + authorizer.revokePolicy(address(policy)); + } + + function test_AuthorizePolicy_RevertsOnDuplicate() public { + PolicyMock policy = new PolicyMock(); + _auditPolicy(address(policy)); + + vm.startPrank(holder); + authorizer.authorizePolicy(address(policy), ""); + + vm.expectRevert( + abi.encodeWithSelector( + RightsPolicyAuthorizer.InvalidPolicyInitialization.selector, + "Error during duplicated policy registration" + ) + ); + authorizer.authorizePolicy(address(policy), ""); + vm.stopPrank(); + } + + function test_GetAuthorizedPolicies_FiltersOutNonAudited() public { + PolicyMock policy = new PolicyMock(); + _auditPolicy(address(policy)); + + vm.prank(holder); + authorizer.authorizePolicy(address(policy), ""); + + address[] memory authorizedBefore = authorizer.getAuthorizedPolicies(holder); + assertEq(authorizedBefore.length, 1, "Authorized list should include policy"); + + _revokeAudit(address(policy)); + + address[] memory authorizedAfter = authorizer.getAuthorizedPolicies(holder); + assertEq(authorizedAfter.length, 0, "Non-audited policies must be filtered out"); + } + + function test_GetAuthorizedPolicies_ReturnsUniqueAuthorizedEntries() public { + PolicyMock policyA = new PolicyMock(); + PolicyMock policyB = new PolicyMock(); + _auditPolicy(address(policyA)); + _auditPolicy(address(policyB)); + + vm.startPrank(holder); + authorizer.authorizePolicy(address(policyA), "A"); + authorizer.authorizePolicy(address(policyB), "B"); + vm.stopPrank(); + + address[] memory authorized = authorizer.getAuthorizedPolicies(holder); + assertEq(authorized.length, 2, "Two policies expected"); + assertTrue(authorized[0] != authorized[1], "Duplicate entries detected"); + } + + function test_IsPolicyAuthorized_ReturnsFalseWhenNeverAuthorized() public { + PolicyMock policy = new PolicyMock(); + _auditPolicy(address(policy)); + + assertFalse(authorizer.isPolicyAuthorized(address(policy), holder), "Policy should not be authorized"); + } + + function test_Integration_AuthorizeRevokeAndAuditFlow() public { + PolicyMock policyA = new PolicyMock(); + PolicyMock policyB = new PolicyMock(); + _auditPolicy(address(policyA)); + _auditPolicy(address(policyB)); + + vm.startPrank(holder); + authorizer.authorizePolicy(address(policyA), abi.encode("A")); + authorizer.authorizePolicy(address(policyB), abi.encode("B")); + vm.stopPrank(); + + address[] memory list = authorizer.getAuthorizedPolicies(holder); + assertEq(list.length, 2, "Both policies should be present"); + + vm.prank(holder); + authorizer.revokePolicy(address(policyB)); + + assertFalse(authorizer.isPolicyAuthorized(address(policyB), holder), "Policy B should be revoked"); + + _revokeAudit(address(policyA)); + list = authorizer.getAuthorizedPolicies(holder); + assertEq(list.length, 0, "Revoked or non-audited policies must be excluded"); + } + + function testFuzz_AuthorizePoliciesMaintainsConsistency(bytes32 salt) public { + PolicyMock[3] memory policies; + bool[3] memory expectedAuthorized; + bool[3] memory expectedAudited; + + for (uint256 i = 0; i < policies.length; i++) { + policies[i] = new PolicyMock(); + _auditPolicy(address(policies[i])); + expectedAudited[i] = true; + } + + uint256 steps = 12; + for (uint256 step = 0; step < steps; step++) { + uint8 op = uint8(uint256(keccak256(abi.encode(salt, step)))) % 3; + uint8 idx = uint8(uint256(keccak256(abi.encode(salt, step, "IDX")))) % uint8(policies.length); + address policyAddr = address(policies[idx]); + + if (op == 0) { + if (!expectedAudited[idx] || expectedAuthorized[idx]) continue; + vm.prank(holder); + authorizer.authorizePolicy(policyAddr, abi.encode(step)); + expectedAuthorized[idx] = true; + } else if (op == 1) { + if (!expectedAuthorized[idx]) continue; + vm.prank(holder); + authorizer.revokePolicy(policyAddr); + expectedAuthorized[idx] = false; + } else { + bool auditStatus = uint8(uint256(keccak256(abi.encode(salt, step, "AUDIT")))) % 2 == 0; + if (auditStatus) { + _auditPolicy(policyAddr); + } else { + _revokeAudit(policyAddr); + } + expectedAudited[idx] = audited[policyAddr]; + } + } + + address[] memory actual = authorizer.getAuthorizedPolicies(holder); + address[] memory expected = new address[](policies.length); + uint256 expectedLen; + + for (uint256 i = 0; i < policies.length; i++) { + if (expectedAuthorized[i] && expectedAudited[i]) { + expected[expectedLen++] = address(policies[i]); + } + } + + assertEq(actual.length, expectedLen, "Unexpected authorized length"); + for (uint256 i = 0; i < expectedLen; i++) { + bool found; + for (uint256 j = 0; j < actual.length; j++) { + if (actual[j] == expected[i]) { + found = true; + break; + } + } + assertTrue(found, "Expected policy missing"); + } + } +} + +contract RightsPolicyAuthorizerHandler is Test { + IRightsPolicyAuthorizer public immutable authorizer; + IPolicyAuditor public immutable auditor; + address public immutable holder; + address public immutable admin; + + PolicyMock[] internal policies; + mapping(address => bool) internal authorized; + mapping(address => bool) internal audited; + + constructor(IRightsPolicyAuthorizer authorizer_, IPolicyAuditor auditor_, address holder_, address admin_) { + authorizer = authorizer_; + auditor = auditor_; + holder = holder_; + admin = admin_; + + for (uint256 i = 0; i < 3; i++) { + PolicyMock policy = new PolicyMock(); + policies.push(policy); + _audit(address(policy)); + } + } + + function _audit(address policy) internal { + if (audited[policy]) return; + + vm.prank(holder); + try auditor.submit(policy) {} catch {} + + vm.prank(admin); + try auditor.approve(policy) { + audited[policy] = true; + } catch {} + + if (!audited[policy] && auditor.isAudited(policy)) { + audited[policy] = true; + } + } + + function policiesLength() external view returns (uint256) { + return policies.length; + } + + function policyAt(uint256 idx) external view returns (address) { + return address(policies[idx]); + } + + function isAuthorized(address policy) external view returns (bool) { + return authorized[policy] && audited[policy] && auditor.isAudited(policy); + } + + function authorize(uint256 seed) external { + PolicyMock policy = policies[seed % policies.length]; + address addr = address(policy); + + _audit(addr); + if (!audited[addr]) return; + + vm.prank(holder); + try authorizer.authorizePolicy(addr, abi.encode(seed)) { + authorized[addr] = true; + } catch {} + } + + function revoke(uint256 seed) external { + PolicyMock policy = policies[seed % policies.length]; + address addr = address(policy); + if (!authorized[addr]) return; + + vm.prank(holder); + try authorizer.revokePolicy(addr) { + authorized[addr] = false; + } catch {} + } + + function toggleAudit(uint256 seed, bool status) external { + PolicyMock policy = policies[seed % policies.length]; + address addr = address(policy); + + if (status) { + _audit(addr); + } else if (audited[addr]) { + vm.prank(admin); + try auditor.reject(addr) { + audited[addr] = false; + authorized[addr] = false; + } catch {} + } + } +} + +contract RightsPolicyAuthorizerInvariantTest is BaseTest { + IRightsPolicyAuthorizer internal authorizer; + IPolicyAuditor internal auditor; + RightsPolicyAuthorizerHandler internal handler; + + function setUp() public initialize { + deployRightsPolicyAuthorizer(); + authorizer = IRightsPolicyAuthorizer(rightsPolicyAuthorizer); + auditor = IPolicyAuditor(policyAudit); + + handler = new RightsPolicyAuthorizerHandler(authorizer, auditor, user, admin); + targetContract(address(handler)); + } + + function invariant_NoZeroOrUnauditedPoliciesInSet() external { + address[] memory list = authorizer.getAuthorizedPolicies(user); + + for (uint256 i = 0; i < list.length; i++) { + address policy = list[i]; + assertTrue(policy != address(0), "Authorized list should not contain zero address"); + assertTrue(auditor.isAudited(policy), "Authorized list should only include audited policies"); + + for (uint256 j = 0; j < i; j++) { + require(list[j] != policy, "Authorized list should contain unique policies"); + } + } + } + + function invariant_AuthorizationReflectsHandlerState() external { + for (uint256 i = 0; i < handler.policiesLength(); i++) { + address policy = handler.policyAt(i); + bool expected = handler.isAuthorized(policy); + bool actual = authorizer.isPolicyAuthorized(policy, user); + assertEq(actual, expected, "Authorization state mismatch"); + } + } +} From 09809ce1cca0a53b5ff02168cc128b9ebd30cef0 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Mon, 13 Oct 2025 12:03:06 -0600 Subject: [PATCH 21/33] test: right policy managet + authorizer --- .github/workflows/cov-badge.svg | 2 +- Makefile | 6 +- contracts/access/AccessManager.sol | 113 +- .../policies/IPolicyAuditorVerifiable.sol | 12 +- contracts/core/libraries/ArrayOps.sol | 24 - contracts/core/libraries/CriteriaOps.sol | 40 + contracts/core/libraries/FinancialOps.sol | 10 +- contracts/core/primitives/Constants.sol | 17 +- contracts/financial/AgreementManager.sol | 1 - contracts/policies/PolicyAudit.sol | 16 +- contracts/policies/PolicyBase.sol | 16 +- contracts/rights/RightsPolicyAuthorizer.sol | 17 +- contracts/rights/RightsPolicyManager.sol | 6 +- lcov.info | 4729 +++++++---------- packages/protocol/package.json | 2 +- packages/types/package.json | 2 +- .../01_Orchestrate_ProtocolHydration.s.sol | 29 +- .../Permissions_AccessControlled.sol | 13 + test/BaseTest.t.sol | 9 + test/assets/AssetReferendum.t.sol | 179 +- test/assets/AssetRegistry.t.sol | 223 +- test/assets/AssetSafe.t.sol | 218 +- test/economics/Tollgate.t.sol | 224 +- test/finance/AgreementManager.t.sol | 265 +- test/finance/AgreementSettler.t.sol | 274 +- test/finance/LedgerVault.t.sol | 275 +- test/libraries/FeesOps.t.sol | 70 +- test/libraries/FinancialOps.t.sol | 225 +- test/libraries/RollingOps.t.sol | 99 - test/policies/PolicyAudit.t.sol | 155 +- test/policies/PolicyBase.t.sol | 273 + .../AccessControlledUpgradeable.t.sol | 190 +- .../AllowanceOperatorUpgradeable.t.sol | 271 +- .../BalanceOperatorUpgradeable.t.sol | 421 +- test/primitives/LedgerUpgradeable.t.sol | 158 +- test/primitives/LockOperatorUpgradeable.t.sol | 339 +- test/primitives/QuorumUpgradeable.t.sol | 188 +- test/rights/RightsPolicyAuthorizer.t.sol | 349 +- test/rights/RightsPolicyManager.t.sol | 506 ++ 39 files changed, 3633 insertions(+), 6333 deletions(-) delete mode 100644 contracts/core/libraries/ArrayOps.sol create mode 100644 contracts/core/libraries/CriteriaOps.sol create mode 100644 script/permissions/Permissions_AccessControlled.sol create mode 100644 test/policies/PolicyBase.t.sol create mode 100644 test/rights/RightsPolicyManager.t.sol diff --git a/.github/workflows/cov-badge.svg b/.github/workflows/cov-badge.svg index a2370c1..d090b2f 100644 --- a/.github/workflows/cov-badge.svg +++ b/.github/workflows/cov-badge.svg @@ -1 +1 @@ -coveragecoverage60.84%60.84% \ No newline at end of file +coveragecoverage60.73%60.73% \ No newline at end of file diff --git a/Makefile b/Makefile index 03ebd29..d7250cb 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,11 @@ force-compile: .PHONY: test ## run tests test: - @export CI=true && forge test --show-progress --gas-report -vvv + @export CI=true && forge test --show-progress --gas-report -vvvv + +.PHONY: testfork ## run tests +testfork: + @export CI=true && forge test --fork-url $(network) --gas-report -vvvv .PHONY: coverage ## run tests coverage report coverage: diff --git a/contracts/access/AccessManager.sol b/contracts/access/AccessManager.sol index 09b4aa0..b8d85b2 100644 --- a/contracts/access/AccessManager.sol +++ b/contracts/access/AccessManager.sol @@ -31,42 +31,113 @@ contract AccessManager is Initializable, UUPSUpgradeable, AccessManagerUpgradeab // return (true, getRoleAdmin(roleId), 0); // => (true, 0, 0) // } - // Strategic roles for governance classification within the protocol: + // Multisig Assignment & Rotation + // ─────────────────────────────────────────────────────────────── + // + // All operational multisigs (Admin, Pauser, Councils, Treasury signers) + // are granted and managed by the Community Governance (GOV_ROLE). + // Any rotation, addition, or removal of a signer or council member + // must be approved by governance through a proposal, queued in the Timelock, + // and executed on-chain. + // + // This ensures that the execution layer (multisigs) remains accountable + // to the collective will of the community. + + // Strategic roles for governance classification within the protocol + // ─────────────────────────────────────────────────────────────── // // Community Governance Role: // - GOV_ROLE: Represents decentralized community governance. - // Decisions are made through collective voting mechanisms (e.g., token-weighted, quadratic). + // Decisions are made collectively through token-weighted, quadratic, + // or other approved voting mechanisms, and executed via a Timelock + // (e.g., 48–72 hours delay) for transparency and reaction time. + // + // Group / Council-Based Roles: + // - ADMIN_ROLE: Managed by a multisig smart account. + // Approves policy attestations, contract upgrades, + // hook registrations, and moderates operational parameters. + // + // - SEC_ROLE: Managed by a designated security council multisig or EOA. + // Authorized to pause protocol modules for monitoring, threat mitigation, + // or emergency response; actions must be reported and are subject to limits. + // + // - TREASURER_ROLE: Managed by a treasury multisig smart account. + // Executes disbursements and manages treasury flows within spending limits + // and policies set by the Community Governance (GOV_ROLE). + // + // - CONTENT_COUNCIL_ROLE: Managed by a multisig smart account. + // Participates in governance referenda and oversees content curation policies. + // + // - CUSTODY_COUNCIL_ROLE: Managed by a multisig smart account. + // Participates in governance referenda for node/custodian validation policies. // - // Group/Council Based Roles: - // - ADMIN_ROLE: Managed by a smart account or council. - // Approves policy submissions and moderates hook operations. - // - CONTENT_COUNCIL_ROLE: Managed by a smart account or council. - // Participates in governance referenda for content curation. - // - CUSTODY_COUNCIL_ROLE: Managed by a smart account or council. - // Participates in governance referenda for nodes validation. + // Individual / Contract-Based Roles: + // - OPS_ROLE: Internal operational role assigned to protocol-trusted contracts, + // enabling direct interaction with core modules. No human control. + // - VER_ROLE: Individual role granted to trusted creators, + // allowing them to upload content without conventional KYC-style verification. + + // OPS_ROLE + // ─────────────────────────────────────────────────────────────── + // Critical operational role used by internal protocol contracts + // (e.g., Vault, Escrow) to call sensitive functions like lockFunds + // and releaseFunds. + // + // The roleAdmin of OPS_ROLE is held by the ADMIN_ROLE multisig, + // which itself is controlled by Community Governance (GOV_ROLE) + // via proposals + timelock and supervised by SEC_ROLE guardian. // - // Individual/Contract Based Roles: - // - OPS_ROLE: Internal operational role assigned to protocol-trusted contracts - // for direct module interactions. No human involvement. - // - VER_ROLE: Individual role assigned to trusted creators, enabling - // content uploads without conventional verification. + // This design preserves flexibility to onboard future audited + // protocol modules while preventing unilateral assignment: + // any change requires a governance proposal, a timelock delay, + // and transparent on-chain execution with published audit evidence. + // + // OPS_ROLE must never be granted to EOAs or multisigs directly. + // Hierarchy / Relationship Diagram + // ─────────────────────────────────────────────────────────────── /* - GOV_ROLE (Community Governance) + GOV_ROLE (Community Governance) + │ + ├── ADMIN_ROLE (Multisig Council) + │ ├── OPS_ROLE (Internal Contract Role) + │ └── SEC_ROLE (Security Council / Guardian) │ - ├── ADMIN_ROLE (Smart Account / Council) - │ │ - │ └── OPS_ROLE (Internal Contract Role) + ├── TREASURER_ROLE (Treasury Multisig under GOV policy) │ - ├── CONTENT_COUNCIL_ROLE (Smart Account / Council) + ├── CONTENT_COUNCIL_ROLE (Multisig Council) │ - ├── CUSTODY_COUNCIL_ROLE (Smart Account / Council) + ├── CUSTODY_COUNCIL_ROLE (Multisig Council) │ - ├── VER_ROLE (Individual Trusted Creator) + └── VER_ROLE (Individual Trusted Creator) */ + // Proposals Lifecycle (per-domain) + // ─────────────────────────────────────────────────────────────── + // PROPOSER (domain governor/council) EXECUTOR (domain timelock) + // └─────────────── propose/schedule ───────────────┘ + // domain ──> domain Timelock (delay) ──> execution on domain modules + // + // Example: + // admin-governor (only allowlisted proposers) ──> AdminTimelock ──> Admin modules + // + // Notes: + // • Each domain has its own Governor (proposers allowlisted) and its own Timelock. + // • The domain Timelock is the ONLY authority recognized by that domain’s modules + // (i.e., it holds the role or is the roleAdmin for that domain). + // • EXECUTOR is typically open (EXECUTOR_ROLE = address(0)); anyone can execute after delay. + // • SEC_ROLE: emergency actions MAY execute directly (no timelock) with strict scope limits. + + // Role Admin Hierarchy (as configured) + // ─────────────────────────────────────────────────────────────── + // Admin domain controls low-level ops & security roles: _setRoleAdmin(C.OPS_ROLE, C.ADMIN_ROLE); + _setRoleAdmin(C.SEC_ROLE, C.ADMIN_ROLE); + + // Governance domain controls councils & treasury/community-facing roles: _setRoleAdmin(C.VER_ROLE, C.GOV_ROLE); + // _setRoleAdmin(C.ADMIN_ROLE, C.GOV_ROLE); + _setRoleAdmin(C.TREASURER_ROLE, C.GOV_ROLE); _setRoleAdmin(C.CUSTODY_COUNCIL_ROLE, C.GOV_ROLE); _setRoleAdmin(C.CONTENT_COUNCIL_ROLE, C.GOV_ROLE); } diff --git a/contracts/core/interfaces/policies/IPolicyAuditorVerifiable.sol b/contracts/core/interfaces/policies/IPolicyAuditorVerifiable.sol index 6b8ae02..a5497a4 100644 --- a/contracts/core/interfaces/policies/IPolicyAuditorVerifiable.sol +++ b/contracts/core/interfaces/policies/IPolicyAuditorVerifiable.sol @@ -6,7 +6,15 @@ pragma solidity 0.8.26; /// @notice Interface that defines the methods required to verify if a policy has been audited. /// @dev This interface can be implemented by any contract that aims to provide audit verification for policies. interface IPolicyAuditorVerifiable { - /// @notice Checks if a specific policy contract has been audited. + /// @notice Checks if a specific policy has been approved and remains active. /// @param policy The address of the policy contract to verify. - function isAudited(address policy) external view returns (bool); + function isApproved(address policy) external view returns (bool); + + /// @notice Checks if a specific policy has been rejected or blocked by the auditor. + /// @param policy The address of the policy contract to verify. + function isRejected(address policy) external view returns (bool); + + /// @notice Checks if a specific policy is awaiting approval. + /// @param policy The address of the policy contract to verify. + function isPending(address policy) external view returns (bool); } diff --git a/contracts/core/libraries/ArrayOps.sol b/contracts/core/libraries/ArrayOps.sol deleted file mode 100644 index 9e8a03f..0000000 --- a/contracts/core/libraries/ArrayOps.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -// NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html -pragma solidity 0.8.26; - -/// @title ArrayOps -/// @notice Library providing utility functions for manipulating arrays in memory. -library ArrayOps { - // TODO expand types using private methods and bytes32 as base type - - /// @notice Returns a new array containing only the first `cap` elements. - /// @dev Creates a new array with a maximum size of `cap` and copies - /// only the first `cap` elements from the original array. - /// @param array The input array from which elements will be copied. - /// @param cap The maximum number of elements to keep in the new array. - /// @return sliced A new array containing only the first `cap` elements. - function slice(address[] memory array, uint256 cap) internal pure returns (address[] memory sliced) { - if (cap > array.length) cap = array.length; // Ensure cap does not exceed array length - sliced = new address[](cap); - - for (uint256 i = 0; i < cap; i++) { - sliced[i] = array[i]; - } - } -} diff --git a/contracts/core/libraries/CriteriaOps.sol b/contracts/core/libraries/CriteriaOps.sol new file mode 100644 index 0000000..bd1e739 --- /dev/null +++ b/contracts/core/libraries/CriteriaOps.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: BUSL-1.1 +// NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html +pragma solidity 0.8.26; + +/// @title CriteriaOps +/// @notice Standard (de)serialization for policy criteria across core/periphery. +/// @dev Canonical shape: `criteria := abi.encode(uint8 kind, bytes value)`. +library CriteriaOps { + /// @notice Encodes criteria with an address-type payload. + /// @param kind The discriminant indicating the criterion type. + /// @param addr The address payload (e.g. holder, group, etc.). + /// @return criteria Canonical `(uint8 kind, bytes value)` encoding. + function encode(uint256 kind, address addr) internal pure returns (bytes memory criteria) { + return abi.encode(kind, abi.encode(addr)); + } + + /// @notice Encodes criteria with a uint256-type payload. + /// @param kind The discriminant indicating the criterion type. + /// @param id The numeric payload (e.g. assetId, tokenId, etc.). + /// @return criteria Canonical `(uint8 kind, bytes value)` encoding. + function encode(uint256 kind, uint256 id) internal pure returns (bytes memory criteria) { + return abi.encode(kind, abi.encode(id)); + } + + /// @notice Encodes criteria with a bytes32-type payload. + /// @param kind The discriminant indicating the criterion type. + /// @param key The fixed-size 32-byte payload (e.g. collectionId, hashed key, etc.). + /// @return criteria Canonical `(uint8 kind, bytes value)` encoding. + function encode(uint256 kind, bytes32 key) internal pure returns (bytes memory criteria) { + return abi.encode(kind, abi.encode(key)); + } + + /// @notice Decodes a canonical criteria blob into its discriminant and raw ABI-encoded value. + /// @param criteria The canonical criteria blob to decode. + /// @return kind The discriminant to interpret `value`. + /// @return value The ABI-encoded payload; decode it further according to `kind`. + function decode(bytes memory criteria) internal pure returns (uint256 kind, bytes memory value) { + return abi.decode(criteria, (uint8, bytes)); + } +} diff --git a/contracts/core/libraries/FinancialOps.sol b/contracts/core/libraries/FinancialOps.sol index 3328381..f249c5e 100644 --- a/contracts/core/libraries/FinancialOps.sol +++ b/contracts/core/libraries/FinancialOps.sol @@ -44,7 +44,7 @@ library FinancialOps { /// @return The deposited amount. function _nativeDeposit(uint256 amount) internal returns (uint256) { if (amount != msg.value) { - revert FailDuringDeposit("Amount exceeds balance sent."); + revert FailDuringDeposit("Invalid expected sent balance."); } // the transfer is not needed since the transfer is implicit here @@ -104,8 +104,8 @@ library FinancialOps { /// @param amount The amount of tokens to deposit. /// @param token The address of the token to deposit. function safeDeposit(address from, uint256 amount, address token) internal returns (uint256) { - if (amount == 0) { - revert FailDuringDeposit("Invalid zero amount."); + if (amount == 0 || from == address(0)) { + revert FailDuringDeposit("Invalid amount or sender."); } if (token == address(0)) { @@ -132,8 +132,8 @@ library FinancialOps { /// @param amount The amount of tokens to transfer. /// @param token The address of the ERC20 token to transfer or address(0) for native token. function transfer(address to, uint256 amount, address token) internal { - if (amount == 0) { - revert FailDuringTransfer("Invalid zero amount to transfer."); + if (amount == 0 || to == address(0)) { + revert FailDuringTransfer("Invalid amount or recipient."); } if (balanceOf(address(this), token) < amount) { diff --git a/contracts/core/primitives/Constants.sol b/contracts/core/primitives/Constants.sol index 50beab8..8540b05 100644 --- a/contracts/core/primitives/Constants.sol +++ b/contracts/core/primitives/Constants.sol @@ -11,13 +11,26 @@ library C { uint256 internal constant SCALE_FACTOR = 100; uint256 internal constant BPS_MAX = 10_000; + // Criteria provide a standardized, compact (kind, value) reference to identify the resource or context to which a policy applies. + // The protocol’s core treats criteria as opaque data, while external components interpret the semantics. + // This abstraction unifies enforcement, access verification, and term resolution under a single interface, enabling extensibility + // and interoperability across policies and resource types without altering the core. + /// @notice Criterion based on the rights holder (e.g., the content owner). + /// @dev Encoded as `uint256` value `0`. + uint256 internal constant HOLDER_CRITERIA = 0; + /// @notice Criterion based on a specific asset, identified by its unique ID. + /// @dev Encoded as `uint256` value `1`. + uint256 internal constant ASSET_CRITERIA = 1; + uint64 internal constant ADMIN_ROLE = 0; // alias type(uint64).min AccessManager uint64 internal constant GOV_ROLE = 1; // governance role uint64 internal constant OPS_ROLE = 2; // operations roles uint64 internal constant VER_ROLE = 3; // account verified role + uint64 internal constant SEC_ROLE = 4; // protocol security council + uint64 internal constant TREASURER_ROLE = 5; // protocol treasurer - uint64 internal constant CONTENT_COUNCIL_ROLE = 5; // content validation/curation roles - uint64 internal constant CUSTODY_COUNCIL_ROLE = 6; // nodes validations roles + uint64 internal constant CONTENT_COUNCIL_ROLE = 6; // content validation/curation roles + uint64 internal constant CUSTODY_COUNCIL_ROLE = 7; // nodes validations roles bytes32 internal constant REFERENDUM_SUBMIT_TYPEHASH = keccak256("Submission(uint256 assetId, address initiator, uint256 nonce)"); diff --git a/contracts/financial/AgreementManager.sol b/contracts/financial/AgreementManager.sol index fb2a450..5b4f563 100644 --- a/contracts/financial/AgreementManager.sol +++ b/contracts/financial/AgreementManager.sol @@ -118,7 +118,6 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg // IMPORTANT: The process of distributing funds to accounts should be handled within the settlement logic. T.Agreement memory agreement = previewAgreement(amount, currency, arbiter, parties, payload); uint256 confirmed = LEDGER_VAULT.lock(msg.sender, agreement.locked, currency); - // only the initiator can operate with this agreement proof, or transfer the proof to the other party.. // each agreement is unique and immutable, ensuring that it cannot be modified or reconstructed. uint256 proof = _createAndStoreProof(agreement); diff --git a/contracts/policies/PolicyAudit.sol b/contracts/policies/PolicyAudit.sol index a936db5..d92120d 100644 --- a/contracts/policies/PolicyAudit.sol +++ b/contracts/policies/PolicyAudit.sol @@ -88,12 +88,24 @@ contract PolicyAudit is Initializable, UUPSUpgradeable, AccessControlledUpgradea emit PolicyRevoked(policy, msg.sender); } - /// @notice Checks if a specific policy contract has been audited. + /// @notice Checks if a policy has been approved and remains active. /// @param policy The address of the policy contract to verify. - function isAudited(address policy) external view returns (bool) { + function isApproved(address policy) external view returns (bool) { return _status(uint160(policy)) == T.Status.Active; } + /// @notice Checks if a policy has been rejected or blocked by the auditor. + /// @param policy The address of the policy contract to verify. + function isRejected(address policy) external view returns (bool) { + return _status(uint160(policy)) == T.Status.Blocked; + } + + /// @notice Checks if a policy is awaiting approval. + /// @param policy The address of the policy contract to verify. + function isPending(address policy) external view returns (bool) { + return _status(uint160(policy)) == T.Status.Waiting; + } + /// @dev Authorizes the upgrade of the contract. /// @notice Only the owner can authorize the upgrade. /// @param newImplementation The address of the new implementation contract. diff --git a/contracts/policies/PolicyBase.sol b/contracts/policies/PolicyBase.sol index 25cc6e2..5a8de6d 100644 --- a/contracts/policies/PolicyBase.sol +++ b/contracts/policies/PolicyBase.sol @@ -129,10 +129,20 @@ abstract contract PolicyBase is ERC165, IPolicy { T.Agreement memory agreement, uint256 expireAt ) internal returns (uint256[] memory) { + uint256 fees = agreement.fees; + uint256 total = agreement.total; + address initiator = agreement.initiator; + address[] memory parties = agreement.parties; + bytes memory payload = abi.encode(agreement); - bytes memory data = abi.encode(holder, agreement.initiator, address(this), agreement.parties, payload); - emit AgreementCommitted(holder, agreement.parties.length, agreement.total, agreement.fees); - return ATTESTATION_PROVIDER.attest(agreement.parties, expireAt, data); + bytes memory data = abi.encode(holder, initiator, address(this), parties, payload); + + // expected invariant results 1:1 between attestations <> parties relation + uint256[] memory attestationIds = ATTESTATION_PROVIDER.attest(parties, expireAt, data); + assert(attestationIds.length == parties.length); + + emit AgreementCommitted(holder, parties.length, total, fees); + return attestationIds; } /// @notice Internal function to create and register an attestation. diff --git a/contracts/rights/RightsPolicyAuthorizer.sol b/contracts/rights/RightsPolicyAuthorizer.sol index 7d2c04e..ff7aebd 100644 --- a/contracts/rights/RightsPolicyAuthorizer.sol +++ b/contracts/rights/RightsPolicyAuthorizer.sol @@ -93,15 +93,11 @@ contract RightsPolicyAuthorizer is /// @param data The data to initialize policy. e.g., prices, timeframes.. function authorizePolicy(address policy, bytes calldata data) external onlyAuditedPolicies(policy) nonReentrant { // type safe low level call to policy, call policy initialization with provided data.. - (bool success, bytes memory result) = policy.call(abi.encodeCall(IPolicy.setup, (msg.sender, data))); - if (!success && result.length == 0) { - revert InvalidPolicyInitialization("Error during policy initialization call"); - } + (bool success, ) = policy.call(abi.encodeCall(IPolicy.setup, (msg.sender, data))); + if (!success) revert InvalidPolicyInitialization("Error during policy initialization call"); bool authorized = _authorizedPolicies[msg.sender].add(policy); - if (!authorized) { - revert InvalidPolicyInitialization("Error during duplicated policy registration"); - } + if (!authorized) revert InvalidPolicyInitialization("Error during duplicated policy registration"); emit RightsGranted(policy, msg.sender, data); } @@ -111,10 +107,7 @@ contract RightsPolicyAuthorizer is function revokePolicy(address policy) external { // if the policy is not authorized revoke fails bool revoked = _authorizedPolicies[msg.sender].remove(policy); - if (!revoked) { - revert RevocationFailed(msg.sender, policy); - } - + if (!revoked) revert RevocationFailed(msg.sender, policy); emit RightsRevoked(policy, msg.sender); } @@ -175,6 +168,6 @@ contract RightsPolicyAuthorizer is /// and that the policy has been audited. /// @param policy The address of the policy contract to verify. function _isValidPolicy(address policy) private view returns (bool) { - return (policy != address(0) && POLICY_AUDIT.isAudited(policy)); + return (policy != address(0) && POLICY_AUDIT.isApproved(policy)); } } diff --git a/contracts/rights/RightsPolicyManager.sol b/contracts/rights/RightsPolicyManager.sol index 5175682..aa6e0fb 100644 --- a/contracts/rights/RightsPolicyManager.sol +++ b/contracts/rights/RightsPolicyManager.sol @@ -16,7 +16,6 @@ import { IRightsPolicyManager } from "@synaps3/core/interfaces/rights/IRightsPol // solhint-disable-next-line max-line-length import { IRightsPolicyAuthorizerVerifiable } from "@synaps3/core/interfaces/rights/IRightsPolicyAuthorizerVerifiable.sol"; import { LoopOps } from "@synaps3/core/libraries/LoopOps.sol"; -import { ArrayOps } from "@synaps3/core/libraries/ArrayOps.sol"; import { T } from "@synaps3/core/primitives/Types.sol"; /// @title RightsPolicyManager @@ -32,7 +31,6 @@ contract RightsPolicyManager is IRightsPolicyManager { using EnumerableSet for EnumerableSet.AddressSet; - using ArrayOps for address[]; using LoopOps for uint256; /// Our immutables behave as constants after deployment @@ -147,7 +145,7 @@ contract RightsPolicyManager is /// @notice Retrieves the list of active policies matching the criteria for an account. /// @dev This function filters out policies that are not active, ensuring the returned array /// contains only valid policies. It first creates a temporary array of the same size as `policies`, - /// then filters and resizes it to the exact number of valid policies using `slice()`. + /// then filters and resizes it to the exact number of valid policies using `slicing`. /// @param account Address of the account to evaluate. /// @param criteria Encoded data containing parameters for access verification. eg: assetId, holder, groups, etc function getActivePolicies(address account, bytes memory criteria) external view returns (address[] memory) { @@ -171,7 +169,7 @@ contract RightsPolicyManager is // it may contain uninitialized elements (`address(0)`) if some policies were invalid. // - The variable `j` represents the number of valid policies that passed the filtering process. // - To ensure that the returned array contains only these valid policies and no extra default values, - // we call `slice(j)`, which creates a new array of exact length `j` and copies only + // we slice, which creates a new array of exact length `j` and copies only // the first `j` elements from `filtered`. // - This prevents returning an array with trailing `address(0)` values, ensuring data integrity // and reducing unnecessary gas costs when the array is processed elsewhere. diff --git a/lcov.info b/lcov.info index 74c3a7a..a24dcaa 100644 --- a/lcov.info +++ b/lcov.info @@ -1,74 +1,76 @@ TN: SF:contracts/access/AccessManager.sol -DA:17,119 +DA:17,89 FN:17,AccessManager.initialize -FNDA:119,AccessManager.initialize +FNDA:89,AccessManager.initialize DA:18,0 -DA:19,119 -DA:68,119 -DA:69,119 -DA:70,119 -DA:71,119 -DA:76,0 -FN:76,AccessManager._authorizeUpgrade +DA:19,89 +DA:134,89 +DA:135,89 +DA:138,89 +DA:140,89 +DA:141,89 +DA:142,89 +DA:147,0 +FN:147,AccessManager._authorizeUpgrade FNDA:0,AccessManager._authorizeUpgrade -DA:77,0 -DA:79,0 -BRDA:79,0,0,- -BRDA:79,0,1,- +DA:148,0 +DA:150,0 +BRDA:150,0,0,- +BRDA:150,0,1,- FNF:2 FNH:1 -LF:10 -LH:6 +LF:12 +LH:8 BRF:2 BRH:0 end_of_record TN: SF:contracts/assets/AssetReferendum.sol -DA:58,34 +DA:58,31 FN:58,AssetReferendum.constructor -FNDA:34,AssetReferendum.constructor +FNDA:31,AssetReferendum.constructor DA:59,0 -DA:63,34 +DA:63,31 FN:63,AssetReferendum.initialize -FNDA:34,AssetReferendum.initialize +FNDA:31,AssetReferendum.initialize DA:64,0 DA:65,0 -DA:66,34 -DA:72,58617 +DA:66,31 +DA:72,1304 FN:72,AssetReferendum.submit -FNDA:58617,AssetReferendum.submit -DA:74,58617 -DA:75,58617 -BRDA:75,0,0,- -DA:76,58617 -DA:77,58617 -DA:99,2075 +FNDA:1304,AssetReferendum.submit +DA:74,1304 +DA:75,1304 +BRDA:75,0,0,1 +DA:76,1303 +DA:77,1303 +DA:99,258 FN:99,AssetReferendum.revoke -FNDA:2075,AssetReferendum.revoke -DA:100,2075 -DA:101,2075 -DA:106,4108 +FNDA:258,AssetReferendum.revoke +DA:100,258 +DA:101,258 +DA:106,258 FN:106,AssetReferendum.reject -FNDA:4108,AssetReferendum.reject -DA:107,4108 -DA:108,4108 -DA:113,49731 +FNDA:258,AssetReferendum.reject +DA:107,258 +DA:108,258 +DA:113,1042 FN:113,AssetReferendum.approve -FNDA:49731,AssetReferendum.approve -DA:114,49731 -DA:115,49731 -DA:121,45977 +FNDA:1042,AssetReferendum.approve +DA:114,1042 +DA:115,1042 +DA:121,1301 FN:121,AssetReferendum.isApproved -FNDA:45977,AssetReferendum.isApproved -DA:122,45977 -DA:123,45977 -DA:124,45977 -DA:126,45977 -DA:131,46749 +FNDA:1301,AssetReferendum.isApproved +DA:122,1301 +DA:123,1301 +DA:124,1301 +DA:126,1301 +DA:131,2073 FN:131,AssetReferendum.isActive -FNDA:46749,AssetReferendum.isActive -DA:132,46749 +FNDA:2073,AssetReferendum.isActive +DA:132,2073 DA:138,0 FN:138,AssetReferendum._authorizeUpgrade FNDA:0,AssetReferendum._authorizeUpgrade @@ -77,67 +79,67 @@ FNH:8 LF:28 LH:24 BRF:1 -BRH:0 +BRH:1 end_of_record TN: SF:contracts/assets/AssetRegistry.sol -DA:69,45205 +DA:69,528 FN:69,AssetRegistry.onlyApprovedAsset -FNDA:45205,AssetRegistry.onlyApprovedAsset -DA:70,45205 +FNDA:528,AssetRegistry.onlyApprovedAsset +DA:70,528 BRDA:70,0,0,1 DA:71,1 -DA:78,8788 +DA:78,3 FN:78,AssetRegistry.onlyOwner -FNDA:8788,AssetRegistry.onlyOwner -DA:79,8788 -BRDA:79,1,0,- -DA:80,0 -DA:87,21 +FNDA:3,AssetRegistry.onlyOwner +DA:79,3 +BRDA:79,1,0,1 +DA:80,1 +DA:87,18 FN:87,AssetRegistry.constructor -FNDA:21,AssetRegistry.constructor +FNDA:18,AssetRegistry.constructor DA:90,0 -DA:92,21 -DA:97,21 +DA:92,18 +DA:97,18 FN:97,AssetRegistry.initialize -FNDA:21,AssetRegistry.initialize +FNDA:18,AssetRegistry.initialize DA:98,0 DA:99,0 DA:100,0 -DA:101,21 -DA:102,21 +DA:101,18 +DA:102,18 DA:108,0 FN:108,AssetRegistry.supportsInterface FNDA:0,AssetRegistry.supportsInterface DA:111,0 -DA:127,45204 +DA:127,527 FN:127,AssetRegistry.register -FNDA:45204,AssetRegistry.register -DA:128,45204 -DA:129,45203 -DA:130,45204 -DA:136,8581 +FNDA:527,AssetRegistry.register +DA:128,527 +DA:129,526 +DA:130,527 +DA:136,1 FN:136,AssetRegistry.revoke -FNDA:8581,AssetRegistry.revoke -DA:137,8581 -DA:139,8581 -DA:140,8581 -DA:141,8581 -DA:147,25618 +FNDA:1,AssetRegistry.revoke +DA:137,1 +DA:139,1 +DA:140,1 +DA:141,1 +DA:147,1 FN:147,AssetRegistry.transfer -FNDA:25618,AssetRegistry.transfer -DA:148,25618 -DA:149,25618 -DA:156,8788 +FNDA:1,AssetRegistry.transfer +DA:148,1 +DA:149,1 +DA:156,2 FN:156,AssetRegistry.switchState -FNDA:8788,AssetRegistry.switchState -DA:157,8788 -DA:159,8788 -DA:161,8788 -DA:165,79403 +FNDA:2,AssetRegistry.switchState +DA:157,2 +DA:159,2 +DA:161,2 +DA:165,529 FN:165,AssetRegistry._update -FNDA:79403,AssetRegistry._update -DA:170,79403 +FNDA:529,AssetRegistry._update +DA:170,529 DA:174,0 FN:174,AssetRegistry._increaseBalance FNDA:0,AssetRegistry._increaseBalance @@ -145,62 +147,62 @@ DA:178,0 DA:183,0 FN:183,AssetRegistry._authorizeUpgrade FNDA:0,AssetRegistry._authorizeUpgrade -DA:186,47349 +DA:186,527 FN:186,AssetRegistry._enableAsset -FNDA:47349,AssetRegistry._enableAsset -DA:187,47349 -DA:188,47349 -DA:192,15223 +FNDA:527,AssetRegistry._enableAsset +DA:187,527 +DA:188,527 +DA:192,2 FN:192,AssetRegistry._disableAsset -FNDA:15223,AssetRegistry._disableAsset -DA:193,15223 -DA:194,15223 +FNDA:2,AssetRegistry._disableAsset +DA:193,2 +DA:194,2 FNF:14 FNH:11 LF:44 -LH:34 +LH:35 BRF:2 -BRH:1 +BRH:2 end_of_record TN: SF:contracts/assets/AssetSafe.sol -DA:40,22686 +DA:40,519 FN:40,AssetSafe.onlyHolder -FNDA:22686,AssetSafe.onlyHolder -DA:41,22686 +FNDA:519,AssetSafe.onlyHolder +DA:41,519 BRDA:41,0,0,257 DA:42,257 -DA:48,10 +DA:48,9 FN:48,AssetSafe.constructor -FNDA:10,AssetSafe.constructor +FNDA:9,AssetSafe.constructor DA:49,0 -DA:50,10 -DA:54,10 +DA:50,9 +DA:54,9 FN:54,AssetSafe.initialize -FNDA:10,AssetSafe.initialize +FNDA:9,AssetSafe.initialize DA:55,0 -DA:56,10 -DA:62,257 +DA:56,9 +DA:62,258 FN:62,AssetSafe.getType -FNDA:257,AssetSafe.getType -DA:63,257 -DA:71,258 +FNDA:258,AssetSafe.getType +DA:63,258 +DA:71,261 FN:71,AssetSafe.getContent -FNDA:258,AssetSafe.getContent -DA:72,258 -DA:80,22429 +FNDA:261,AssetSafe.getContent +DA:72,261 +DA:80,262 FN:80,AssetSafe.setContent -FNDA:22429,AssetSafe.setContent -DA:81,22429 -DA:82,22429 -DA:83,22429 +FNDA:262,AssetSafe.setContent +DA:81,262 +DA:82,262 +DA:83,262 DA:88,0 FN:88,AssetSafe._authorizeUpgrade FNDA:0,AssetSafe._authorizeUpgrade -DA:95,22687 +DA:95,523 FN:95,AssetSafe._computeComposedKey -FNDA:22687,AssetSafe._computeComposedKey -DA:96,22687 +FNDA:523,AssetSafe._computeComposedKey +DA:96,523 FNF:8 FNH:7 LF:20 @@ -209,43 +211,51 @@ BRF:1 BRH:1 end_of_record TN: -SF:contracts/core/libraries/ArrayOps.sol -DA:16,0 -FN:16,ArrayOps.slice -FNDA:0,ArrayOps.slice -DA:17,0 -BRDA:17,0,0,- -DA:18,0 -DA:20,0 +SF:contracts/core/libraries/CriteriaOps.sol +DA:13,0 +FN:13,CriteriaOps.encode +FNDA:0,CriteriaOps.encode +DA:14,0 DA:21,0 -FNF:1 +FN:21,CriteriaOps.encode +FNDA:0,CriteriaOps.encode +DA:22,0 +DA:29,0 +FN:29,CriteriaOps.encode +FNDA:0,CriteriaOps.encode +DA:30,0 +DA:37,0 +FN:37,CriteriaOps.decode +FNDA:0,CriteriaOps.decode +DA:38,0 +FNF:4 FNH:0 -LF:5 +LF:8 LH:0 -BRF:1 +BRF:0 BRH:0 end_of_record TN: SF:contracts/core/libraries/FeesOps.sol -DA:12,12796 +DA:12,37 FN:12,FeesOps.isBasePoint -FNDA:12796,FeesOps.isBasePoint -DA:14,12796 -DA:19,12751 +FNDA:37,FeesOps.isBasePoint +DA:14,37 +DA:19,6 FN:19,FeesOps.isNominal -FNDA:12751,FeesOps.isNominal -DA:21,12751 -DA:27,45863 +FNDA:6,FeesOps.isNominal +DA:21,6 +DA:27,519 FN:27,FeesOps.perOf -FNDA:45863,FeesOps.perOf -DA:31,45863 +FNDA:519,FeesOps.perOf +DA:31,519 BRDA:31,0,0,- BRDA:31,0,1,- -DA:32,45863 -DA:37,17151 +DA:32,519 +DA:37,3 FN:37,FeesOps.calcBps -FNDA:17151,FeesOps.calcBps -DA:38,17151 +FNDA:3,FeesOps.calcBps +DA:38,3 FNF:4 FNH:4 LF:9 @@ -255,31 +265,31 @@ BRH:0 end_of_record TN: SF:contracts/core/libraries/FinancialOps.sol -DA:24,15750 +DA:24,3 FN:24,FinancialOps._nativeTransfer -FNDA:15750,FinancialOps._nativeTransfer -DA:27,15750 -DA:28,15750 +FNDA:3,FinancialOps._nativeTransfer +DA:27,3 +DA:28,3 BRDA:28,0,0,- DA:29,0 -DA:37,36250 +DA:37,9 FN:37,FinancialOps._erc20Transfer -FNDA:36250,FinancialOps._erc20Transfer -DA:38,36250 -DA:45,18856 +FNDA:9,FinancialOps._erc20Transfer +DA:38,9 +DA:45,7 FN:45,FinancialOps._nativeDeposit -FNDA:18856,FinancialOps._nativeDeposit -DA:46,18856 +FNDA:7,FinancialOps._nativeDeposit +DA:46,7 BRDA:46,1,0,1 DA:47,1 DA:51,0 -DA:60,52914 +DA:60,57 FN:60,FinancialOps._erc20Deposit -FNDA:52914,FinancialOps._erc20Deposit -DA:61,52914 +FNDA:57,FinancialOps._erc20Deposit +DA:61,57 BRDA:61,2,0,3 DA:62,3 -DA:68,52911 +DA:68,54 DA:69,0 DA:78,3 FN:78,FinancialOps.increaseAllowance @@ -288,56 +298,56 @@ DA:79,3 BRDA:79,3,0,2 DA:80,2 DA:83,1 -DA:92,52916 +DA:92,59 FN:92,FinancialOps.allowance -FNDA:52916,FinancialOps.allowance -DA:93,52916 +FNDA:59,FinancialOps.allowance +DA:93,59 BRDA:93,4,0,1 DA:94,1 -DA:97,52915 -DA:106,71772 +DA:97,58 +DA:106,66 FN:106,FinancialOps.safeDeposit -FNDA:71772,FinancialOps.safeDeposit -DA:107,71772 +FNDA:66,FinancialOps.safeDeposit +DA:107,66 BRDA:107,5,0,2 DA:108,2 -DA:111,71770 -BRDA:111,6,0,18856 -DA:112,18856 -DA:115,52914 -DA:121,52264 +DA:111,64 +BRDA:111,6,0,7 +DA:112,7 +DA:115,57 +DA:121,17 FN:121,FinancialOps.balanceOf -FNDA:52264,FinancialOps.balanceOf -DA:122,52264 -BRDA:122,7,0,15752 -DA:123,15752 -DA:126,36512 -DA:134,52004 +FNDA:17,FinancialOps.balanceOf +DA:122,17 +BRDA:122,7,0,4 +DA:123,4 +DA:126,13 +DA:134,13 FN:134,FinancialOps.transfer -FNDA:52004,FinancialOps.transfer -DA:135,52004 -BRDA:135,8,0,2 -DA:136,2 -DA:139,52002 -BRDA:139,9,0,2 -DA:140,2 -DA:143,52000 -BRDA:143,10,0,15750 -DA:144,15750 -DA:147,36250 +FNDA:13,FinancialOps.transfer +DA:135,13 +BRDA:135,8,0,1 +DA:136,1 +DA:139,12 +BRDA:139,9,0,- +DA:140,0 +DA:143,12 +BRDA:143,10,0,3 +DA:144,3 +DA:147,9 FNF:9 FNH:9 LF:41 -LH:38 +LH:37 BRF:11 -BRH:10 +BRH:9 end_of_record TN: SF:contracts/core/libraries/LoopOps.sol -DA:15,471 +DA:15,1003 FN:15,LoopOps.uncheckedInc -FNDA:471,LoopOps.uncheckedInc -DA:17,471 +FNDA:1003,LoopOps.uncheckedInc +DA:17,1003 DA:26,0 FN:26,LoopOps.uncheckedDec FNDA:0,LoopOps.uncheckedDec @@ -364,83 +374,83 @@ BRH:0 end_of_record TN: SF:contracts/core/libraries/RollingOps.sol -DA:36,25663 +DA:36,5 FN:36,RollingOps.configure -FNDA:25663,RollingOps.configure -DA:37,25663 +FNDA:5,RollingOps.configure +DA:37,5 BRDA:37,0,0,1 -DA:38,25662 -DA:42,35220 +DA:38,4 +DA:42,13 FN:42,RollingOps.roll -FNDA:35220,RollingOps.roll -DA:43,35220 -DA:47,2545 +FNDA:13,RollingOps.roll +DA:43,13 +DA:47,3 FN:47,RollingOps.contains -FNDA:2545,RollingOps.contains -DA:48,2545 -DA:52,260 +FNDA:3,RollingOps.contains +DA:48,3 +DA:52,4 FN:52,RollingOps.length -FNDA:260,RollingOps.length -DA:53,260 +FNDA:4,RollingOps.length +DA:53,4 DA:57,2 FN:57,RollingOps.window FNDA:2,RollingOps.window DA:58,2 -DA:62,2314 +DA:62,8 FN:62,RollingOps.at -FNDA:2314,RollingOps.at -DA:63,2314 -DA:67,50051 +FNDA:8,RollingOps.at +DA:63,8 +DA:67,1 FN:67,RollingOps.values -FNDA:50051,RollingOps.values -DA:68,50051 -DA:69,50051 +FNDA:1,RollingOps.values +DA:68,1 +DA:69,1 DA:72,0 -DA:75,50051 -DA:84,35220 +DA:75,1 +DA:84,13 FN:84,RollingOps._roll -FNDA:35220,RollingOps._roll -DA:87,35220 -BRDA:87,1,0,12283 -DA:88,12283 -DA:91,35220 -DA:95,35220 +FNDA:13,RollingOps._roll +DA:87,13 +BRDA:87,1,0,2 +DA:88,2 +DA:91,13 +DA:95,13 FN:95,RollingOps._rollin -FNDA:35220,RollingOps._rollin -DA:96,35220 -DA:97,35220 -DA:101,12283 +FNDA:13,RollingOps._rollin +DA:96,13 +DA:97,13 +DA:101,2 FN:101,RollingOps._rollout -FNDA:12283,RollingOps._rollout -DA:103,12283 -DA:104,12283 -DA:106,12283 -DA:110,65865 -DA:111,65865 -DA:114,65865 -DA:119,12283 -DA:123,2545 +FNDA:2,RollingOps._rollout +DA:103,2 +DA:104,2 +DA:106,2 +DA:110,3 +DA:111,3 +DA:114,3 +DA:119,2 +DA:123,3 FN:123,RollingOps._contains -FNDA:2545,RollingOps._contains -DA:124,2545 -DA:128,73014 +FNDA:3,RollingOps._contains +DA:124,3 +DA:128,38 FN:128,RollingOps._length -FNDA:73014,RollingOps._length -DA:129,73014 -DA:133,2314 +FNDA:38,RollingOps._length +DA:129,38 +DA:133,8 FN:133,RollingOps._at -FNDA:2314,RollingOps._at -DA:134,2314 +FNDA:8,RollingOps._at +DA:134,8 BRDA:134,2,0,1 -DA:135,2313 -DA:139,113370 +DA:135,7 +DA:139,20 FN:139,RollingOps._window -FNDA:113370,RollingOps._window -DA:140,113370 -DA:144,50051 +FNDA:20,RollingOps._window +DA:140,20 +DA:144,1 FN:144,RollingOps._values -FNDA:50051,RollingOps._values -DA:145,50051 +FNDA:1,RollingOps._values +DA:145,1 FNF:15 FNH:15 LF:44 @@ -450,43 +460,43 @@ BRH:3 end_of_record TN: SF:contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol -DA:29,62457 +DA:29,247 FN:29,AccessControlledUpgradeable.onlyAdmin -FNDA:62457,AccessControlledUpgradeable.onlyAdmin -DA:34,62457 -BRDA:34,0,0,258 -DA:35,258 -DA:43,8831 +FNDA:247,AccessControlledUpgradeable.onlyAdmin +DA:34,247 +BRDA:34,0,0,3 +DA:35,3 +DA:43,2 FN:43,AccessControlledUpgradeable.pause -FNDA:8831,AccessControlledUpgradeable.pause +FNDA:2,AccessControlledUpgradeable.pause DA:44,0 -DA:50,7835 +DA:50,2 FN:50,AccessControlledUpgradeable.unpause -FNDA:7835,AccessControlledUpgradeable.unpause +FNDA:2,AccessControlledUpgradeable.unpause DA:51,0 -DA:59,311 +DA:59,317 FN:59,AccessControlledUpgradeable.__AccessControlled_init -FNDA:311,AccessControlledUpgradeable.__AccessControlled_init -DA:60,311 -DA:61,311 -DA:67,311 +FNDA:317,AccessControlledUpgradeable.__AccessControlled_init +DA:60,317 +DA:61,317 +DA:67,317 FN:67,AccessControlledUpgradeable.__AccessControlled_init_unchained -FNDA:311,AccessControlledUpgradeable.__AccessControlled_init_unchained -DA:68,311 +FNDA:317,AccessControlledUpgradeable.__AccessControlled_init_unchained +DA:68,317 BRDA:68,1,0,1 DA:69,1 -DA:72,310 -DA:73,310 -DA:80,131438 +DA:72,316 +DA:73,316 +DA:80,2636 FN:80,AccessControlledUpgradeable._hasRole -FNDA:131438,AccessControlledUpgradeable._hasRole -DA:81,131438 -DA:82,131438 -DA:83,131438 -DA:84,131438 -DA:88,131748 +FNDA:2636,AccessControlledUpgradeable._hasRole +DA:81,2636 +DA:82,2636 +DA:83,2636 +DA:84,2636 +DA:88,2952 FN:88,AccessControlledUpgradeable._getAccessControlStorage -FNDA:131748,AccessControlledUpgradeable._getAccessControlStorage +FNDA:2952,AccessControlledUpgradeable._getAccessControlStorage DA:90,0 FNF:7 FNH:7 @@ -497,66 +507,66 @@ BRH:2 end_of_record TN: SF:contracts/core/primitives/upgradeable/AllowanceOperatorUpgradeable.sol -DA:32,66 +DA:32,63 FN:32,AllowanceOperatorUpgradeable.__AllowanceOperator_init -FNDA:66,AllowanceOperatorUpgradeable.__AllowanceOperator_init +FNDA:63,AllowanceOperatorUpgradeable.__AllowanceOperator_init DA:33,0 DA:39,0 FN:39,AllowanceOperatorUpgradeable.__AllowanceOperator_init_unchained FNDA:0,AllowanceOperatorUpgradeable.__AllowanceOperator_init_unchained -DA:46,899 +DA:46,13 FN:46,AllowanceOperatorUpgradeable.getApprovedAmount -FNDA:899,AllowanceOperatorUpgradeable.getApprovedAmount -DA:47,899 -DA:48,899 -DA:49,899 -DA:56,1607 +FNDA:13,AllowanceOperatorUpgradeable.getApprovedAmount +DA:47,13 +DA:48,13 +DA:49,13 +DA:56,8 FN:56,AllowanceOperatorUpgradeable._approve -FNDA:1607,AllowanceOperatorUpgradeable._approve -DA:61,1607 +FNDA:8,AllowanceOperatorUpgradeable._approve +DA:61,8 BRDA:61,0,0,1 -DA:62,1606 -DA:63,1606 +DA:62,7 +DA:63,7 DA:64,0 -DA:71,320 +DA:71,3 FN:71,AllowanceOperatorUpgradeable._revoke -FNDA:320,AllowanceOperatorUpgradeable._revoke -DA:76,320 +FNDA:3,AllowanceOperatorUpgradeable._revoke +DA:76,3 BRDA:76,1,0,1 -DA:77,319 -DA:78,319 +DA:77,2 +DA:78,2 DA:79,0 -DA:86,318 +DA:86,5 FN:86,AllowanceOperatorUpgradeable._collect -FNDA:318,AllowanceOperatorUpgradeable._collect -DA:91,318 +FNDA:5,AllowanceOperatorUpgradeable._collect +DA:91,5 BRDA:91,2,0,1 -DA:92,317 +DA:92,4 BRDA:92,3,0,1 -DA:94,316 -DA:95,316 -DA:96,316 -DA:97,316 +DA:94,3 +DA:95,3 +DA:96,3 +DA:97,3 DA:98,0 -DA:107,635 +DA:107,5 FN:107,AllowanceOperatorUpgradeable._subApprovedAmount -FNDA:635,AllowanceOperatorUpgradeable._subApprovedAmount -DA:108,635 -DA:109,635 -DA:110,635 -DA:119,1606 +FNDA:5,AllowanceOperatorUpgradeable._subApprovedAmount +DA:108,5 +DA:109,5 +DA:110,5 +DA:119,7 FN:119,AllowanceOperatorUpgradeable._sumApprovedAmount -FNDA:1606,AllowanceOperatorUpgradeable._sumApprovedAmount -DA:120,1606 -DA:121,1606 -DA:122,1606 -DA:130,3140 +FNDA:7,AllowanceOperatorUpgradeable._sumApprovedAmount +DA:120,7 +DA:121,7 +DA:122,7 +DA:130,25 FN:130,AllowanceOperatorUpgradeable._computeComposedKey -FNDA:3140,AllowanceOperatorUpgradeable._computeComposedKey -DA:131,3140 -DA:136,3140 +FNDA:25,AllowanceOperatorUpgradeable._computeComposedKey +DA:131,25 +DA:136,25 FN:136,AllowanceOperatorUpgradeable._getAllowanceOperatorStorage -FNDA:3140,AllowanceOperatorUpgradeable._getAllowanceOperatorStorage +FNDA:25,AllowanceOperatorUpgradeable._getAllowanceOperatorStorage DA:138,0 FNF:10 FNH:9 @@ -567,43 +577,43 @@ BRH:4 end_of_record TN: SF:contracts/core/primitives/upgradeable/BalanceOperatorUpgradeable.sol -DA:31,76 +DA:31,81 FN:31,BalanceOperatorUpgradeable.__BalanceOperator_init -FNDA:76,BalanceOperatorUpgradeable.__BalanceOperator_init +FNDA:81,BalanceOperatorUpgradeable.__BalanceOperator_init DA:32,0 DA:37,0 FN:37,BalanceOperatorUpgradeable.__BalanceOperator_init_unchained FNDA:0,BalanceOperatorUpgradeable.__BalanceOperator_init_unchained -DA:42,260 +DA:42,3 FN:42,BalanceOperatorUpgradeable.getBalance -FNDA:260,BalanceOperatorUpgradeable.getBalance -DA:43,260 -DA:50,34206 +FNDA:3,BalanceOperatorUpgradeable.getBalance +DA:43,3 +DA:50,50 FN:50,BalanceOperatorUpgradeable._deposit -FNDA:34206,BalanceOperatorUpgradeable._deposit -DA:55,34206 -DA:56,34204 -DA:57,34206 +FNDA:50,BalanceOperatorUpgradeable._deposit +DA:55,50 +DA:56,48 +DA:57,50 DA:58,0 -DA:65,20681 +DA:65,8 FN:65,BalanceOperatorUpgradeable._withdraw -FNDA:20681,BalanceOperatorUpgradeable._withdraw -DA:70,20681 +FNDA:8,BalanceOperatorUpgradeable._withdraw +DA:70,8 BRDA:70,0,0,2 -DA:71,20679 -DA:72,20679 -DA:73,20679 +DA:71,6 +DA:72,6 +DA:73,6 DA:74,0 -DA:81,7861 +DA:81,505 FN:81,BalanceOperatorUpgradeable._transfer -FNDA:7861,BalanceOperatorUpgradeable._transfer -DA:86,7861 +FNDA:505,BalanceOperatorUpgradeable._transfer +DA:86,505 BRDA:86,1,0,2 -DA:87,7859 -BRDA:87,2,0,1 -DA:89,7858 -DA:90,7858 -DA:91,7858 +DA:87,503 +BRDA:87,2,0,- +DA:89,503 +DA:90,503 +DA:91,503 DA:92,0 DA:97,0 FN:97,BalanceOperatorUpgradeable._getBalanceOperatorStorage @@ -614,34 +624,34 @@ FNH:5 LF:25 LH:18 BRF:3 -BRH:3 +BRH:2 end_of_record TN: SF:contracts/core/primitives/upgradeable/ERC721StatefulUpgradeable.sol -DA:26,21 +DA:26,18 FN:26,ERC721StatefulUpgradeable.__ERC721Stateful_init -FNDA:21,ERC721StatefulUpgradeable.__ERC721Stateful_init +FNDA:18,ERC721StatefulUpgradeable.__ERC721Stateful_init DA:31,0 FN:31,ERC721StatefulUpgradeable.__ERC721Stateful_init_unchained FNDA:0,ERC721StatefulUpgradeable.__ERC721Stateful_init_unchained -DA:35,47349 +DA:35,527 FN:35,ERC721StatefulUpgradeable._activate -FNDA:47349,ERC721StatefulUpgradeable._activate -DA:36,47349 -DA:37,47349 -DA:42,15223 +FNDA:527,ERC721StatefulUpgradeable._activate +DA:36,527 +DA:37,527 +DA:42,2 FN:42,ERC721StatefulUpgradeable._deactivate -FNDA:15223,ERC721StatefulUpgradeable._deactivate -DA:43,15223 -DA:44,15223 -DA:50,9048 +FNDA:2,ERC721StatefulUpgradeable._deactivate +DA:43,2 +DA:44,2 +DA:50,6 FN:50,ERC721StatefulUpgradeable.isActive -FNDA:9048,ERC721StatefulUpgradeable.isActive -DA:51,9048 -DA:52,9048 -DA:56,71620 +FNDA:6,ERC721StatefulUpgradeable.isActive +DA:51,6 +DA:52,6 +DA:56,535 FN:56,ERC721StatefulUpgradeable._getERC721StateStorage -FNDA:71620,ERC721StatefulUpgradeable._getERC721StateStorage +FNDA:535,ERC721StatefulUpgradeable._getERC721StateStorage DA:58,0 FNF:6 FNH:5 @@ -663,24 +673,24 @@ FN:49,FeesCollectorUpgradeable.getTreasuryAddress FNDA:0,FeesCollectorUpgradeable.getTreasuryAddress DA:50,0 DA:51,0 -DA:58,23 +DA:58,26 FN:58,FeesCollectorUpgradeable.__FeesCollector_init -FNDA:23,FeesCollectorUpgradeable.__FeesCollector_init -DA:59,23 -DA:66,23 +FNDA:26,FeesCollectorUpgradeable.__FeesCollector_init +DA:59,26 +DA:66,26 FN:66,FeesCollectorUpgradeable.__FeesCollector_init_unchained -FNDA:23,FeesCollectorUpgradeable.__FeesCollector_init_unchained -DA:67,23 -DA:73,23 +FNDA:26,FeesCollectorUpgradeable.__FeesCollector_init_unchained +DA:67,26 +DA:73,26 FN:73,FeesCollectorUpgradeable._setTreasuryAddress -FNDA:23,FeesCollectorUpgradeable._setTreasuryAddress -DA:74,23 +FNDA:26,FeesCollectorUpgradeable._setTreasuryAddress +DA:74,26 BRDA:74,1,0,- -DA:75,23 -DA:76,23 -DA:82,23 +DA:75,26 +DA:76,26 +DA:82,26 FN:82,FeesCollectorUpgradeable._getFeesCollectorStorage -FNDA:23,FeesCollectorUpgradeable._getFeesCollectorStorage +FNDA:26,FeesCollectorUpgradeable._getFeesCollectorStorage DA:84,0 FNF:6 FNH:4 @@ -691,40 +701,40 @@ BRH:0 end_of_record TN: SF:contracts/core/primitives/upgradeable/LedgerUpgradeable.sol -DA:28,27792 +DA:28,21 FN:28,LedgerUpgradeable.onlyValidOperation -FNDA:27792,LedgerUpgradeable.onlyValidOperation -DA:29,27792 -BRDA:29,0,0,4 -DA:36,180411 +FNDA:21,LedgerUpgradeable.onlyValidOperation +DA:29,21 +BRDA:29,0,0,2 +DA:36,1087 FN:36,LedgerUpgradeable.getLedgerBalance -FNDA:180411,LedgerUpgradeable.getLedgerBalance -DA:37,180411 -DA:38,180411 +FNDA:1087,LedgerUpgradeable.getLedgerBalance +DA:37,1087 +DA:38,1087 DA:45,213 FN:45,LedgerUpgradeable.__Ledger_init FNDA:213,LedgerUpgradeable.__Ledger_init DA:50,0 FN:50,LedgerUpgradeable.__Ledger_init_unchained FNDA:0,LedgerUpgradeable.__Ledger_init_unchained -DA:57,8730 +DA:57,7 FN:57,LedgerUpgradeable._setLedgerEntry -FNDA:8730,LedgerUpgradeable._setLedgerEntry -DA:58,8730 -DA:59,8730 -DA:67,130908 +FNDA:7,LedgerUpgradeable._setLedgerEntry +DA:58,7 +DA:59,7 +DA:67,1078 FN:67,LedgerUpgradeable._sumLedgerEntry -FNDA:130908,LedgerUpgradeable._sumLedgerEntry -DA:68,130908 -DA:69,130908 -DA:77,62716 +FNDA:1078,LedgerUpgradeable._sumLedgerEntry +DA:68,1078 +DA:69,1078 +DA:77,1035 FN:77,LedgerUpgradeable._subLedgerEntry -FNDA:62716,LedgerUpgradeable._subLedgerEntry -DA:78,62716 -DA:79,62716 -DA:84,382765 +FNDA:1035,LedgerUpgradeable._subLedgerEntry +DA:78,1035 +DA:79,1035 +DA:84,3207 FN:84,LedgerUpgradeable._getLedgerStorage -FNDA:382765,LedgerUpgradeable._getLedgerStorage +FNDA:3207,LedgerUpgradeable._getLedgerStorage DA:86,0 FNF:8 FNH:7 @@ -735,58 +745,58 @@ BRH:1 end_of_record TN: SF:contracts/core/primitives/upgradeable/LockOperatorUpgradeable.sol -DA:28,66 +DA:28,63 FN:28,LockOperatorUpgradeable.__LockOperator_init -FNDA:66,LockOperatorUpgradeable.__LockOperator_init +FNDA:63,LockOperatorUpgradeable.__LockOperator_init DA:29,0 DA:35,0 FN:35,LockOperatorUpgradeable.__LockOperator_init_unchained FNDA:0,LockOperatorUpgradeable.__LockOperator_init_unchained -DA:44,33498 +DA:44,523 FN:44,LockOperatorUpgradeable._lock -FNDA:33498,LockOperatorUpgradeable._lock -DA:49,33498 +FNDA:523,LockOperatorUpgradeable._lock +DA:49,523 BRDA:49,0,0,3 -DA:50,33495 -DA:51,33495 -DA:52,33495 +DA:50,520 +DA:51,520 +DA:52,520 DA:53,0 -DA:60,10983 +DA:60,7 FN:60,LockOperatorUpgradeable._release -FNDA:10983,LockOperatorUpgradeable._release -DA:65,10983 +FNDA:7,LockOperatorUpgradeable._release +DA:65,7 BRDA:65,1,0,1 -DA:66,10982 -DA:67,10982 -DA:68,10982 +DA:66,6 +DA:67,6 +DA:68,6 DA:69,0 -DA:78,15503 +DA:78,506 FN:78,LockOperatorUpgradeable._claim -FNDA:15503,LockOperatorUpgradeable._claim -DA:83,15503 +FNDA:506,LockOperatorUpgradeable._claim +DA:83,506 BRDA:83,2,0,1 -DA:84,15502 -DA:85,15502 -DA:86,15502 +DA:84,505 +DA:85,505 +DA:86,505 DA:87,0 -DA:95,26484 +DA:95,511 FN:95,LockOperatorUpgradeable._subLockedAmount -FNDA:26484,LockOperatorUpgradeable._subLockedAmount -DA:96,26484 -DA:97,26484 -DA:105,33495 +FNDA:511,LockOperatorUpgradeable._subLockedAmount +DA:96,511 +DA:97,511 +DA:105,520 FN:105,LockOperatorUpgradeable._sumLockedAmount -FNDA:33495,LockOperatorUpgradeable._sumLockedAmount -DA:106,33495 -DA:107,33495 -DA:115,26486 +FNDA:520,LockOperatorUpgradeable._sumLockedAmount +DA:106,520 +DA:107,520 +DA:115,513 FN:115,LockOperatorUpgradeable._getLockedAmount -FNDA:26486,LockOperatorUpgradeable._getLockedAmount -DA:116,26486 -DA:117,26486 -DA:122,86465 +FNDA:513,LockOperatorUpgradeable._getLockedAmount +DA:116,513 +DA:117,513 +DA:122,1544 FN:122,LockOperatorUpgradeable._getLockOperatorStorage -FNDA:86465,LockOperatorUpgradeable._getLockOperatorStorage +FNDA:1544,LockOperatorUpgradeable._getLockOperatorStorage DA:124,0 FNF:9 FNH:8 @@ -797,55 +807,55 @@ BRH:3 end_of_record TN: SF:contracts/core/primitives/upgradeable/QuorumUpgradeable.sol -DA:48,90 +DA:48,81 FN:48,QuorumUpgradeable.__Quorum_init -FNDA:90,QuorumUpgradeable.__Quorum_init +FNDA:81,QuorumUpgradeable.__Quorum_init DA:53,0 FN:53,QuorumUpgradeable.__Quorum_init_unchained FNDA:0,QuorumUpgradeable.__Quorum_init_unchained -DA:57,312648 +DA:57,8823 FN:57,QuorumUpgradeable._status -FNDA:312648,QuorumUpgradeable._status -DA:58,312648 -DA:59,312648 -DA:65,10611 +FNDA:8823,QuorumUpgradeable._status +DA:58,8823 +DA:59,8823 +DA:65,501 FN:65,QuorumUpgradeable._revoke -FNDA:10611,QuorumUpgradeable._revoke -DA:66,10611 -DA:67,10611 +FNDA:501,QuorumUpgradeable._revoke +DA:66,501 +DA:67,501 BRDA:67,0,0,2 -DA:68,10609 -DA:74,4146 +DA:68,499 +DA:74,260 FN:74,QuorumUpgradeable._block -FNDA:4146,QuorumUpgradeable._block -DA:75,4146 -DA:76,4146 +FNDA:260,QuorumUpgradeable._block +DA:75,260 +DA:76,260 BRDA:76,1,0,1 -DA:77,4145 -DA:82,72126 +DA:77,259 +DA:82,2129 FN:82,QuorumUpgradeable._approve -FNDA:72126,QuorumUpgradeable._approve -DA:83,72126 -DA:84,72126 -BRDA:84,2,0,11487 -DA:85,60639 -DA:90,290 +FNDA:2129,QuorumUpgradeable._approve +DA:83,2129 +DA:84,2129 +BRDA:84,2,0,40 +DA:85,2089 +DA:90,2 FN:90,QuorumUpgradeable._quit -FNDA:290,QuorumUpgradeable._quit -DA:91,290 -DA:92,290 +FNDA:2,QuorumUpgradeable._quit +DA:91,2 +DA:92,2 BRDA:92,3,0,1 -DA:93,289 -DA:98,102293 +DA:93,1 +DA:98,2398 FN:98,QuorumUpgradeable._register -FNDA:102293,QuorumUpgradeable._register -DA:99,102293 -DA:100,102293 -BRDA:100,4,0,11486 -DA:101,90807 -DA:105,502114 +FNDA:2398,QuorumUpgradeable._register +DA:99,2398 +DA:100,2398 +BRDA:100,4,0,39 +DA:101,2359 +DA:105,14113 FN:105,QuorumUpgradeable._getRegistryStorage -FNDA:502114,QuorumUpgradeable._getRegistryStorage +FNDA:14113,QuorumUpgradeable._getRegistryStorage DA:107,0 FNF:9 FNH:8 @@ -953,17 +963,17 @@ FNDA:0,CustodianReferendum.onlyValidCustodian DA:52,0 BRDA:52,0,0,- DA:53,0 -DA:59,13 +DA:59,11 FN:59,CustodianReferendum.constructor -FNDA:13,CustodianReferendum.constructor +FNDA:11,CustodianReferendum.constructor DA:62,0 -DA:63,13 -DA:67,13 +DA:63,11 +DA:67,11 FN:67,CustodianReferendum.initialize -FNDA:13,CustodianReferendum.initialize +FNDA:11,CustodianReferendum.initialize DA:68,0 DA:69,0 -DA:70,13 +DA:70,11 DA:76,0 FN:76,CustodianReferendum.isActive FNDA:0,CustodianReferendum.isActive @@ -1009,10 +1019,10 @@ BRH:0 end_of_record TN: SF:contracts/economics/MMC.sol -DA:19,57 +DA:19,39 FN:19,MMC.constructor -FNDA:57,MMC.constructor -DA:23,57 +FNDA:39,MMC.constructor +DA:23,39 DA:26,0 FN:26,MMC.burn FNDA:0,MMC.burn @@ -1021,10 +1031,10 @@ DA:31,0 FN:31,MMC.nonces FNDA:0,MMC.nonces DA:32,0 -DA:36,39883 +DA:36,67 FN:36,MMC._update -FNDA:39883,MMC._update -DA:37,39883 +FNDA:67,MMC._update +DA:37,67 FNF:4 FNH:2 LF:8 @@ -1034,96 +1044,96 @@ BRH:0 end_of_record TN: SF:contracts/economics/Tollgate.sol -DA:59,51366 +DA:59,44 FN:59,Tollgate.onlyValidFeeRepresentation -FNDA:51366,Tollgate.onlyValidFeeRepresentation -DA:60,51366 +FNDA:44,Tollgate.onlyValidFeeRepresentation +DA:60,44 BRDA:60,0,0,1 -DA:61,51365 +DA:61,43 BRDA:61,1,0,1 -DA:72,51367 +DA:72,46 FN:72,Tollgate.onlySupportedScheme -FNDA:51367,Tollgate.onlySupportedScheme -DA:74,51367 -BRDA:74,2,0,- -DA:75,0 -DA:78,51367 -DA:79,51367 -DA:82,12287 -BRDA:82,3,0,12287 -DA:83,12287 -DA:84,12287 +FNDA:46,Tollgate.onlySupportedScheme +DA:74,46 +BRDA:74,2,0,1 +DA:75,1 +DA:78,45 +DA:79,45 +DA:82,1 +BRDA:82,3,0,1 +DA:83,1 +DA:84,1 BRDA:84,4,0,1 -DA:92,40 +DA:92,39 FN:92,Tollgate.constructor -FNDA:40,Tollgate.constructor +FNDA:39,Tollgate.constructor DA:93,0 -DA:98,40 +DA:98,39 FN:98,Tollgate.initialize -FNDA:40,Tollgate.initialize +FNDA:39,Tollgate.initialize DA:99,0 -DA:100,40 -DA:107,44616 +DA:100,39 +DA:107,1025 FN:107,Tollgate.isSupportedCurrency -FNDA:44616,Tollgate.isSupportedCurrency -DA:108,44616 -DA:114,257 +FNDA:1025,Tollgate.isSupportedCurrency +DA:108,1025 +DA:114,1 FN:114,Tollgate.supportedCurrencies -FNDA:257,Tollgate.supportedCurrencies -DA:115,257 -DA:122,23210 +FNDA:1,Tollgate.supportedCurrencies +DA:115,1 +DA:122,519 FN:122,Tollgate.getFees -FNDA:23210,Tollgate.getFees -DA:124,23210 +FNDA:519,Tollgate.getFees +DA:124,519 BRDA:124,5,0,1 DA:125,1 -DA:128,23209 -DA:129,23209 -DA:130,23209 -DA:131,23209 -DA:139,51364 +DA:128,518 +DA:129,518 +DA:130,518 +DA:131,518 +DA:139,41 FN:139,Tollgate.setFees -FNDA:51364,Tollgate.setFees -DA:152,51364 +FNDA:41,Tollgate.setFees +DA:152,41 BRDA:152,6,0,- -DA:153,51364 -DA:155,51364 -DA:156,51364 -DA:157,51364 -DA:158,51364 +DA:153,41 +DA:155,41 +DA:156,41 +DA:157,41 +DA:158,41 DA:163,0 FN:163,Tollgate._authorizeUpgrade FNDA:0,Tollgate._authorizeUpgrade -DA:169,67826 +DA:169,1544 FN:169,Tollgate._isSchemeSupported -FNDA:67826,Tollgate._isSchemeSupported -DA:170,67826 -DA:171,67826 -DA:172,67826 -DA:180,142399 +FNDA:1544,Tollgate._isSchemeSupported +DA:170,1544 +DA:171,1544 +DA:172,1544 +DA:180,2103 FN:180,Tollgate._computeComposedKey -FNDA:142399,Tollgate._computeComposedKey -DA:181,142399 +FNDA:2103,Tollgate._computeComposedKey +DA:181,2103 FNF:11 FNH:10 LF:41 -LH:37 +LH:38 BRF:7 -BRH:5 +BRH:6 end_of_record TN: SF:contracts/economics/Treasury.sol -DA:37,23 +DA:37,26 FN:37,Treasury.constructor -FNDA:23,Treasury.constructor +FNDA:26,Treasury.constructor DA:40,0 -DA:43,23 +DA:43,26 FN:43,Treasury.initialize -FNDA:23,Treasury.initialize +FNDA:26,Treasury.initialize DA:44,0 DA:45,0 DA:46,0 -DA:47,23 +DA:47,26 DA:65,0 FN:65,Treasury.deposit FNDA:0,Treasury.deposit @@ -1155,115 +1165,115 @@ BRH:0 end_of_record TN: SF:contracts/financial/AgreementManager.sol -DA:70,22436 +DA:70,513 FN:70,AgreementManager.onlySupportedCurrency -FNDA:22436,AgreementManager.onlySupportedCurrency -DA:71,22436 -DA:72,22436 +FNDA:513,AgreementManager.onlySupportedCurrency +DA:71,513 +DA:72,513 BRDA:72,0,0,- -DA:77,38 +DA:77,39 FN:77,AgreementManager.constructor -FNDA:38,AgreementManager.constructor +FNDA:39,AgreementManager.constructor DA:80,0 -DA:82,38 -DA:83,38 -DA:87,38 +DA:82,39 +DA:83,39 +DA:87,39 FN:87,AgreementManager.initialize -FNDA:38,AgreementManager.initialize +FNDA:39,AgreementManager.initialize DA:88,0 -DA:89,38 -DA:90,38 -DA:95,37586 +DA:89,39 +DA:90,39 +DA:95,2 FN:95,AgreementManager.setMaxParties -FNDA:37586,AgreementManager.setMaxParties -DA:96,37586 +FNDA:2,AgreementManager.setMaxParties +DA:96,2 BRDA:96,1,0,1 -DA:97,37585 -DA:101,75511 +DA:97,1 +DA:101,6 FN:101,AgreementManager.maxParties -FNDA:75511,AgreementManager.maxParties -DA:102,75511 -DA:111,21923 +FNDA:6,AgreementManager.maxParties +DA:102,6 +DA:111,511 FN:111,AgreementManager.createAgreement -FNDA:21923,AgreementManager.createAgreement -DA:119,21923 -DA:120,21923 -DA:124,21921 -DA:125,21921 -DA:126,0 -DA:131,34689 -FN:131,AgreementManager.getAgreement -FNDA:34689,AgreementManager.getAgreement -DA:132,34689 -DA:141,22436 -FN:141,AgreementManager.previewAgreement -FNDA:22436,AgreementManager.previewAgreement -DA:160,22436 -DA:164,22435 -DA:165,22435 -DA:169,22435 -DA:185,0 -FN:185,AgreementManager._authorizeUpgrade +FNDA:511,AgreementManager.createAgreement +DA:119,511 +DA:120,511 +DA:123,508 +DA:124,508 +DA:125,0 +DA:130,1011 +FN:130,AgreementManager.getAgreement +FNDA:1011,AgreementManager.getAgreement +DA:131,1011 +DA:140,513 +FN:140,AgreementManager.previewAgreement +FNDA:513,AgreementManager.previewAgreement +DA:159,513 +DA:163,512 +DA:164,511 +DA:168,511 +DA:184,0 +FN:184,AgreementManager._authorizeUpgrade FNDA:0,AgreementManager._authorizeUpgrade -DA:188,21921 -FN:188,AgreementManager._createAndStoreProof -FNDA:21921,AgreementManager._createAndStoreProof -DA:190,21921 -DA:191,21921 -DA:192,21921 -DA:193,0 -DA:197,22435 -FN:197,AgreementManager._calculatePenalization -FNDA:22435,AgreementManager._calculatePenalization -DA:198,22435 -DA:199,6506 -DA:200,6506 -DA:201,6506 -DA:209,6506 -FN:209,AgreementManager._penaltyBps -FNDA:6506,AgreementManager._penaltyBps -DA:210,6506 -DA:214,6506 -DA:218,6506 -BRDA:218,4,0,- -DA:219,0 -DA:229,22436 -FN:229,AgreementManager._calcFees -FNDA:22436,AgreementManager._calcFees -DA:231,22436 -DA:232,22436 +DA:187,508 +FN:187,AgreementManager._createAndStoreProof +FNDA:508,AgreementManager._createAndStoreProof +DA:189,508 +DA:190,508 +DA:191,508 +DA:192,0 +DA:196,512 +FN:196,AgreementManager._calculatePenalization +FNDA:512,AgreementManager._calculatePenalization +DA:197,512 +DA:198,4 +DA:199,4 +DA:200,4 +DA:208,4 +FN:208,AgreementManager._penaltyBps +FNDA:4,AgreementManager._penaltyBps +DA:209,4 +DA:213,4 +DA:217,4 +BRDA:217,4,0,1 +DA:218,1 +DA:228,513 +FN:228,AgreementManager._calcFees +FNDA:513,AgreementManager._calcFees +DA:230,513 +DA:231,513 +DA:232,2 DA:233,1 -DA:234,1 -BRDA:234,7,0,1 -DA:235,0 +BRDA:233,7,0,1 +DA:234,0 FNF:13 FNH:12 LF:51 -LH:44 +LH:45 BRF:4 -BRH:2 +BRH:3 end_of_record TN: SF:contracts/financial/AgreementSettler.sol -DA:85,6484 +DA:85,4 FN:85,AgreementSettler.onlyValidAgreement -FNDA:6484,AgreementSettler.onlyValidAgreement -DA:86,6484 -BRDA:86,0,0,1 -DA:87,1 -DA:93,23 +FNDA:4,AgreementSettler.onlyValidAgreement +DA:86,4 +BRDA:86,0,0,2 +DA:87,2 +DA:93,26 FN:93,AgreementSettler.constructor -FNDA:23,AgreementSettler.constructor +FNDA:26,AgreementSettler.constructor DA:96,0 -DA:97,23 -DA:98,23 -DA:99,23 -DA:103,23 +DA:97,26 +DA:98,26 +DA:99,26 +DA:103,26 FN:103,AgreementSettler.initialize -FNDA:23,AgreementSettler.initialize +FNDA:26,AgreementSettler.initialize DA:104,0 -DA:105,23 -DA:106,23 +DA:105,26 +DA:106,26 DA:114,0 FN:114,AgreementSettler.disburse FNDA:0,AgreementSettler.disburse @@ -1272,51 +1282,51 @@ DA:117,0 DA:119,0 DA:120,0 DA:121,0 -DA:138,6483 +DA:138,2 FN:138,AgreementSettler.quitAgreement -FNDA:6483,AgreementSettler.quitAgreement -DA:139,6483 -DA:140,6483 +FNDA:2,AgreementSettler.quitAgreement +DA:139,2 +DA:140,2 BRDA:140,2,0,1 -DA:154,6482 -DA:155,6482 -DA:156,6482 -DA:164,6482 -DA:165,6482 -DA:166,6482 -DA:168,6482 -DA:170,6482 -DA:172,6482 -BRDA:172,3,0,6482 -DA:174,6482 +DA:154,1 +DA:155,1 +DA:156,1 +DA:164,1 +DA:165,1 +DA:166,1 +DA:168,1 +DA:170,1 +DA:172,1 +BRDA:172,3,0,1 +DA:174,1 DA:175,0 -DA:201,6285 +DA:201,501 FN:201,AgreementSettler.settleAgreement -FNDA:6285,AgreementSettler.settleAgreement -DA:206,6285 -DA:207,6285 -BRDA:207,4,0,1 -DA:209,6284 -DA:210,6284 -DA:211,6284 -DA:212,6284 -DA:213,6284 -DA:215,6284 -DA:216,6284 -DA:217,6284 -DA:222,6284 -DA:226,6284 -DA:228,6284 -BRDA:228,5,0,6284 -DA:229,6284 +FNDA:501,AgreementSettler.settleAgreement +DA:206,501 +DA:207,501 +BRDA:207,4,0,2 +DA:209,499 +DA:210,499 +DA:211,499 +DA:212,499 +DA:213,499 +DA:215,499 +DA:216,499 +DA:217,499 +DA:222,499 +DA:226,499 +DA:228,499 +BRDA:228,5,0,499 +DA:229,499 DA:230,0 DA:236,0 FN:236,AgreementSettler._authorizeUpgrade FNDA:0,AgreementSettler._authorizeUpgrade -DA:240,12766 +DA:240,500 FN:240,AgreementSettler._setProofAsSettled -FNDA:12766,AgreementSettler._setProofAsSettled -DA:241,12766 +FNDA:500,AgreementSettler._setProofAsSettled +DA:241,500 FNF:8 FNH:6 LF:51 @@ -1326,32 +1336,32 @@ BRH:5 end_of_record TN: SF:contracts/financial/LedgerVault.sol -DA:31,53 +DA:31,55 FN:31,LedgerVault.constructor -FNDA:53,LedgerVault.constructor +FNDA:55,LedgerVault.constructor DA:34,0 -DA:37,53 +DA:37,55 FN:37,LedgerVault.initialize -FNDA:53,LedgerVault.initialize +FNDA:55,LedgerVault.initialize DA:38,0 DA:39,0 DA:40,0 DA:41,0 DA:42,0 DA:43,0 -DA:44,53 -DA:54,27251 +DA:44,55 +DA:54,516 FN:54,LedgerVault.lock -FNDA:27251,LedgerVault.lock -DA:59,27251 -DA:66,9049 +FNDA:516,LedgerVault.lock +DA:59,516 +DA:66,4 FN:66,LedgerVault.release -FNDA:9049,LedgerVault.release -DA:71,9049 -DA:80,15193 +FNDA:4,LedgerVault.release +DA:71,4 +DA:80,503 FN:80,LedgerVault.claim -FNDA:15193,LedgerVault.claim -DA:85,15193 +FNDA:503,LedgerVault.claim +DA:85,503 DA:92,0 FN:92,LedgerVault.approve FNDA:0,LedgerVault.approve @@ -1364,18 +1374,18 @@ DA:108,0 FN:108,LedgerVault.collect FNDA:0,LedgerVault.collect DA:109,0 -DA:116,9621 +DA:116,43 FN:116,LedgerVault.deposit -FNDA:9621,LedgerVault.deposit -DA:121,9621 -DA:128,5483 +FNDA:43,LedgerVault.deposit +DA:121,43 +DA:128,4 FN:128,LedgerVault.withdraw -FNDA:5483,LedgerVault.withdraw -DA:133,5483 -DA:140,6842 +FNDA:4,LedgerVault.withdraw +DA:133,4 +DA:140,502 FN:140,LedgerVault.transfer -FNDA:6842,LedgerVault.transfer -DA:141,6842 +FNDA:502,LedgerVault.transfer +DA:141,502 DA:147,0 FN:147,LedgerVault._authorizeUpgrade FNDA:0,LedgerVault._authorizeUpgrade @@ -1460,10 +1470,10 @@ BRH:0 end_of_record TN: SF:contracts/policies/PolicyAudit.sol -DA:44,33061 +DA:44,1089 FN:44,PolicyAudit.onlyValidPolicy -FNDA:33061,PolicyAudit.onlyValidPolicy -DA:45,33061 +FNDA:1089,PolicyAudit.onlyValidPolicy +DA:45,1089 BRDA:45,0,0,1 DA:46,1 DA:53,28 @@ -1476,96 +1486,110 @@ FNDA:28,PolicyAudit.initialize DA:60,0 DA:61,0 DA:62,28 -DA:70,33060 +DA:70,1088 FN:70,PolicyAudit.submit -FNDA:33060,PolicyAudit.submit -DA:71,33060 -DA:72,33060 -DA:78,22087 +FNDA:1088,PolicyAudit.submit +DA:71,1088 +DA:72,1088 +DA:78,1084 FN:78,PolicyAudit.approve -FNDA:22087,PolicyAudit.approve -DA:79,22087 -DA:80,22087 -DA:86,8534 +FNDA:1084,PolicyAudit.approve +DA:79,1084 +DA:80,1084 +DA:86,241 FN:86,PolicyAudit.reject -FNDA:8534,PolicyAudit.reject -DA:87,8534 -DA:88,8534 -DA:93,23334 -FN:93,PolicyAudit.isAudited -FNDA:23334,PolicyAudit.isAudited -DA:94,23334 -DA:100,0 -FN:100,PolicyAudit._authorizeUpgrade +FNDA:241,PolicyAudit.reject +DA:87,241 +DA:88,241 +DA:93,1445 +FN:93,PolicyAudit.isApproved +FNDA:1445,PolicyAudit.isApproved +DA:94,1445 +DA:99,5 +FN:99,PolicyAudit.isRejected +FNDA:5,PolicyAudit.isRejected +DA:100,5 +DA:105,4 +FN:105,PolicyAudit.isPending +FNDA:4,PolicyAudit.isPending +DA:106,4 +DA:112,0 +FN:112,PolicyAudit._authorizeUpgrade FNDA:0,PolicyAudit._authorizeUpgrade -FNF:8 -FNH:7 -LF:21 -LH:17 +FNF:10 +FNH:9 +LF:25 +LH:21 BRF:1 BRH:1 end_of_record TN: SF:contracts/policies/PolicyBase.sol -DA:72,0 +DA:72,2 FN:72,PolicyBase.onlyPolicyManager -FNDA:0,PolicyBase.onlyPolicyManager -DA:73,0 -BRDA:73,0,0,- -DA:74,0 -DA:80,0 +FNDA:2,PolicyBase.onlyPolicyManager +DA:73,2 +BRDA:73,0,0,1 +DA:74,1 +DA:80,2 FN:80,PolicyBase.onlyPolicyAuthorizer -FNDA:0,PolicyBase.onlyPolicyAuthorizer -DA:81,0 -BRDA:81,1,0,- -DA:82,0 -DA:87,0 +FNDA:2,PolicyBase.onlyPolicyAuthorizer +DA:81,2 +BRDA:81,1,0,1 +DA:82,1 +DA:87,1051 FN:87,PolicyBase.constructor -FNDA:0,PolicyBase.constructor -DA:88,0 -DA:89,0 -DA:90,0 -DA:91,0 -DA:96,0 +FNDA:1051,PolicyBase.constructor +DA:88,1051 +DA:89,1051 +DA:90,1051 +DA:91,1051 +DA:96,1 FN:96,PolicyBase.getAttestationProvider -FNDA:0,PolicyBase.getAttestationProvider -DA:97,0 -DA:103,0 +FNDA:1,PolicyBase.getAttestationProvider +DA:97,1 +DA:103,3236 FN:103,PolicyBase.supportsInterface -FNDA:0,PolicyBase.supportsInterface -DA:104,0 -DA:111,0 +FNDA:3236,PolicyBase.supportsInterface +DA:104,3236 +DA:111,1 FN:111,PolicyBase.getLicense -FNDA:0,PolicyBase.getLicense -DA:113,0 -DA:114,0 -DA:119,0 +FNDA:1,PolicyBase.getLicense +DA:113,1 +DA:114,1 +DA:119,1 FN:119,PolicyBase._getHolder -FNDA:0,PolicyBase._getHolder -DA:120,0 -DA:127,0 +FNDA:1,PolicyBase._getHolder +DA:120,1 +DA:127,495 FN:127,PolicyBase._commit -FNDA:0,PolicyBase._commit -DA:132,0 -DA:133,0 -DA:134,0 -DA:135,0 -DA:143,0 -FN:143,PolicyBase._setAttestation -FNDA:0,PolicyBase._setAttestation +FNDA:495,PolicyBase._commit +DA:132,495 +DA:133,495 +DA:134,495 +DA:135,495 +DA:137,495 +DA:138,495 +DA:141,495 +DA:142,495 +DA:144,495 DA:145,0 -DA:146,0 -DA:147,0 -DA:155,0 -FN:155,PolicyBase._computeComposedKey -FNDA:0,PolicyBase._computeComposedKey -DA:162,0 +DA:153,496 +FN:153,PolicyBase._setAttestation +FNDA:496,PolicyBase._setAttestation +DA:155,496 +DA:156,496 +DA:157,496 +DA:165,497 +FN:165,PolicyBase._computeComposedKey +FNDA:497,PolicyBase._computeComposedKey +DA:172,497 FNF:10 -FNH:0 -LF:31 -LH:0 +FNH:10 +LF:37 +LH:36 BRF:2 -BRH:0 +BRH:2 end_of_record TN: SF:contracts/rights/RightsAssetCustodian.sol @@ -1736,184 +1760,181 @@ BRH:0 end_of_record TN: SF:contracts/rights/RightsPolicyAuthorizer.sol -DA:69,9688 +DA:69,634 FN:69,RightsPolicyAuthorizer.onlyAuditedPolicies -FNDA:9688,RightsPolicyAuthorizer.onlyAuditedPolicies -DA:71,9688 +FNDA:634,RightsPolicyAuthorizer.onlyAuditedPolicies +DA:71,634 BRDA:71,0,0,1 -DA:76,15 +DA:76,19 FN:76,RightsPolicyAuthorizer.constructor -FNDA:15,RightsPolicyAuthorizer.constructor +FNDA:19,RightsPolicyAuthorizer.constructor DA:79,0 -DA:81,15 -DA:85,15 +DA:81,19 +DA:85,19 FN:85,RightsPolicyAuthorizer.initialize -FNDA:15,RightsPolicyAuthorizer.initialize +FNDA:19,RightsPolicyAuthorizer.initialize DA:86,0 DA:87,0 -DA:88,15 -DA:94,9686 +DA:88,19 +DA:94,632 FN:94,RightsPolicyAuthorizer.authorizePolicy -FNDA:9686,RightsPolicyAuthorizer.authorizePolicy -DA:96,9686 -DA:97,9686 -BRDA:97,1,0,1 -DA:98,1 -DA:101,9685 -DA:102,9685 -BRDA:102,2,0,3492 -DA:103,3492 -DA:106,6193 -DA:111,3531 -FN:111,RightsPolicyAuthorizer.revokePolicy -FNDA:3531,RightsPolicyAuthorizer.revokePolicy -DA:113,3531 -DA:114,3531 -BRDA:114,3,0,1 -DA:115,1 -DA:118,3530 -DA:124,5 -FN:124,RightsPolicyAuthorizer.isPolicyAuthorized -FNDA:5,RightsPolicyAuthorizer.isPolicyAuthorized -DA:125,5 -DA:132,262 -FN:132,RightsPolicyAuthorizer.getAuthorizedPolicies -FNDA:262,RightsPolicyAuthorizer.getAuthorizedPolicies -DA:139,262 -DA:140,262 -DA:141,262 -DA:142,262 -DA:144,262 -DA:145,270 -DA:146,201 -DA:150,201 -DA:163,0 -DA:165,0 -DA:171,0 -FN:171,RightsPolicyAuthorizer._authorizeUpgrade +FNDA:632,RightsPolicyAuthorizer.authorizePolicy +DA:96,632 +DA:97,632 +BRDA:97,1,0,2 +DA:99,630 +DA:100,630 +BRDA:100,2,0,1 +DA:102,629 +DA:107,94 +FN:107,RightsPolicyAuthorizer.revokePolicy +FNDA:94,RightsPolicyAuthorizer.revokePolicy +DA:109,94 +DA:110,94 +BRDA:110,3,0,1 +DA:111,93 +DA:117,503 +FN:117,RightsPolicyAuthorizer.isPolicyAuthorized +FNDA:503,RightsPolicyAuthorizer.isPolicyAuthorized +DA:118,503 +DA:125,259 +FN:125,RightsPolicyAuthorizer.getAuthorizedPolicies +FNDA:259,RightsPolicyAuthorizer.getAuthorizedPolicies +DA:132,259 +DA:133,259 +DA:134,259 +DA:135,259 +DA:137,259 +DA:138,270 +DA:139,232 +DA:143,232 +DA:156,0 +DA:158,0 +DA:164,0 +FN:164,RightsPolicyAuthorizer._authorizeUpgrade FNDA:0,RightsPolicyAuthorizer._authorizeUpgrade -DA:177,9959 -FN:177,RightsPolicyAuthorizer._isValidPolicy -FNDA:9959,RightsPolicyAuthorizer._isValidPolicy -DA:178,9959 +DA:170,1402 +FN:170,RightsPolicyAuthorizer._isValidPolicy +FNDA:1402,RightsPolicyAuthorizer._isValidPolicy +DA:171,1402 FNF:9 FNH:8 -LF:38 -LH:32 +LF:35 +LH:29 BRF:4 BRH:4 end_of_record TN: SF:contracts/rights/RightsPolicyManager.sol -DA:77,0 -FN:77,RightsPolicyManager.onlyAuthorizedPolicy -FNDA:0,RightsPolicyManager.onlyAuthorizedPolicy -DA:78,0 -BRDA:78,0,0,- -BRDA:78,0,1,- -DA:79,0 -DA:80,0 -BRDA:80,1,0,- -DA:85,0 -FN:85,RightsPolicyManager.constructor -FNDA:0,RightsPolicyManager.constructor -DA:88,0 -DA:89,0 -DA:90,0 +DA:75,498 +FN:75,RightsPolicyManager.onlyAuthorizedPolicy +FNDA:498,RightsPolicyManager.onlyAuthorizedPolicy +DA:76,498 +BRDA:76,0,0,- +BRDA:76,0,1,- +DA:77,498 +DA:78,498 +BRDA:78,1,0,1 +DA:83,9 +FN:83,RightsPolicyManager.constructor +FNDA:9,RightsPolicyManager.constructor +DA:86,0 +DA:87,9 +DA:88,9 +DA:92,9 +FN:92,RightsPolicyManager.initialize +FNDA:9,RightsPolicyManager.initialize +DA:93,0 DA:94,0 -FN:94,RightsPolicyManager.initialize -FNDA:0,RightsPolicyManager.initialize -DA:95,0 -DA:96,0 -DA:97,0 -DA:105,0 -FN:105,RightsPolicyManager.registerPolicy -FNDA:0,RightsPolicyManager.registerPolicy -DA:111,0 -DA:112,0 -DA:113,0 -BRDA:113,2,0,- -DA:114,0 -DA:121,0 -DA:122,0 -BRDA:122,3,0,- +DA:95,9 +DA:103,497 +FN:103,RightsPolicyManager.registerPolicy +FNDA:497,RightsPolicyManager.registerPolicy +DA:109,497 +DA:110,496 +DA:111,496 +BRDA:111,2,0,1 +DA:112,1 +DA:119,495 +DA:120,495 +BRDA:120,3,0,1 +DA:122,494 +DA:123,494 DA:124,0 -DA:125,0 -DA:126,0 -DA:132,0 -FN:132,RightsPolicyManager.getActivePolicy -FNDA:0,RightsPolicyManager.getActivePolicy -DA:133,0 -DA:134,0 -DA:137,0 -DA:139,0 -BRDA:139,4,0,- -DA:140,0 -DA:144,0 -DA:153,0 -FN:153,RightsPolicyManager.getActivePolicies -FNDA:0,RightsPolicyManager.getActivePolicies -DA:154,0 -DA:155,0 -DA:156,0 -DA:157,0 -DA:160,0 -DA:161,0 -DA:162,0 -DA:166,0 +DA:130,1 +FN:130,RightsPolicyManager.getActivePolicy +FNDA:1,RightsPolicyManager.getActivePolicy +DA:131,1 +DA:132,1 +DA:135,1 +DA:137,2 +BRDA:137,4,0,1 +DA:138,1 +DA:142,0 +DA:151,1 +FN:151,RightsPolicyManager.getActivePolicies +FNDA:1,RightsPolicyManager.getActivePolicies +DA:152,1 +DA:153,1 +DA:154,1 +DA:155,1 +DA:158,1 +DA:159,3 +DA:160,2 +DA:164,2 +DA:177,0 DA:179,0 -DA:181,0 -DA:186,0 -FN:186,RightsPolicyManager.getPolicies -FNDA:0,RightsPolicyManager.getPolicies -DA:193,0 -DA:201,0 -FN:201,RightsPolicyManager.isActivePolicy -FNDA:0,RightsPolicyManager.isActivePolicy -DA:202,0 -DA:203,0 -DA:210,0 -FN:210,RightsPolicyManager.isRegisteredPolicy -FNDA:0,RightsPolicyManager.isRegisteredPolicy -DA:211,0 -DA:217,0 -FN:217,RightsPolicyManager._authorizeUpgrade +DA:184,260 +FN:184,RightsPolicyManager.getPolicies +FNDA:260,RightsPolicyManager.getPolicies +DA:191,260 +DA:199,7 +FN:199,RightsPolicyManager.isActivePolicy +FNDA:7,RightsPolicyManager.isActivePolicy +DA:200,7 +DA:201,6 +DA:208,7 +FN:208,RightsPolicyManager.isRegisteredPolicy +FNDA:7,RightsPolicyManager.isRegisteredPolicy +DA:209,7 +DA:215,0 +FN:215,RightsPolicyManager._authorizeUpgrade FNDA:0,RightsPolicyManager._authorizeUpgrade -DA:224,0 -FN:224,RightsPolicyManager._verifyPolicyAccess -FNDA:0,RightsPolicyManager._verifyPolicyAccess -DA:225,0 -DA:226,0 -DA:227,0 -DA:228,0 -DA:238,0 -FN:238,RightsPolicyManager._registerBatchPolicies -FNDA:0,RightsPolicyManager._registerBatchPolicies -DA:244,0 -DA:246,0 -DA:247,0 -DA:248,0 -DA:257,0 -FN:257,RightsPolicyManager._registerPolicy -FNDA:0,RightsPolicyManager._registerPolicy -DA:258,0 +DA:222,6 +FN:222,RightsPolicyManager._verifyPolicyAccess +FNDA:6,RightsPolicyManager._verifyPolicyAccess +DA:223,6 +DA:224,6 +DA:225,6 +DA:226,5 +DA:236,494 +FN:236,RightsPolicyManager._registerBatchPolicies +FNDA:494,RightsPolicyManager._registerBatchPolicies +DA:242,494 +DA:244,494 +DA:245,495 +DA:246,495 +DA:255,495 +FN:255,RightsPolicyManager._registerPolicy +FNDA:495,RightsPolicyManager._registerPolicy +DA:256,495 FNF:13 -FNH:0 +FNH:12 LF:60 -LH:0 +LH:52 BRF:6 -BRH:0 +BRH:4 end_of_record TN: SF:script/create3/CREATE3Factory.sol -DA:10,459 +DA:10,433 FN:10,CREATE3Factory.deploy -FNDA:459,CREATE3Factory.deploy -DA:12,459 -DA:16,888 +FNDA:433,CREATE3Factory.deploy +DA:12,433 +DA:16,901 FN:16,CREATE3Factory.getDeployed -FNDA:888,CREATE3Factory.getDeployed -DA:18,888 +FNDA:901,CREATE3Factory.getDeployed +DA:18,901 FNF:2 FNH:2 LF:4 @@ -1923,47 +1944,47 @@ BRH:0 end_of_record TN: SF:script/deployment/00_Deploy_Base.s.sol -DA:14,1347 +DA:14,1334 FN:14,DeployBase.getCreate3FactoryAddress -FNDA:1347,DeployBase.getCreate3FactoryAddress -DA:15,1347 -DA:18,578 +FNDA:1334,DeployBase.getCreate3FactoryAddress +DA:15,1334 +DA:18,522 FN:18,DeployBase.getAdminPK -FNDA:578,DeployBase.getAdminPK -DA:19,578 -DA:23,1466 +FNDA:522,DeployBase.getAdminPK +DA:19,522 +DA:23,1423 FN:23,DeployBase.getSalt -FNDA:1466,DeployBase.getSalt -DA:24,1466 -DA:27,888 +FNDA:1423,DeployBase.getSalt +DA:24,1423 +DA:27,901 FN:27,DeployBase.computeCreate3Address -FNDA:888,DeployBase.computeCreate3Address -DA:32,888 -DA:43,888 -DA:46,70 +FNDA:901,DeployBase.computeCreate3Address +DA:32,901 +DA:43,901 +DA:46,50 FN:46,DeployBase.deploy -FNDA:70,DeployBase.deploy -DA:48,70 -DA:49,70 -DA:52,389 +FNDA:50,DeployBase.deploy +DA:48,50 +DA:49,50 +DA:52,383 FN:52,DeployBase.deployUUPS -FNDA:389,DeployBase.deployUUPS -DA:58,389 -DA:62,389 -DA:63,389 -DA:65,389 -DA:85,389 -DA:89,444 +FNDA:383,DeployBase.deployUUPS +DA:58,383 +DA:62,383 +DA:63,383 +DA:65,383 +DA:85,383 +DA:89,414 FN:89,DeployBase._checkExpectedAddress -FNDA:444,DeployBase._checkExpectedAddress -DA:90,444 -DA:91,444 +FNDA:414,DeployBase._checkExpectedAddress +DA:90,414 +DA:91,414 BRDA:91,0,0,- BRDA:91,0,1,- -DA:94,563 +DA:94,503 FN:94,DeployBase._logAddress -FNDA:563,DeployBase._logAddress -DA:95,563 +FNDA:503,DeployBase._logAddress +DA:95,503 DA:96,0 DA:97,0 FNF:8 @@ -1975,18 +1996,18 @@ BRH:0 end_of_record TN: SF:script/deployment/01_Deploy_Base_Create3.s.sol -DA:8,119 +DA:8,89 FN:8,DeployCreate3Factory.run -FNDA:119,DeployCreate3Factory.run -DA:10,119 -DA:11,119 -DA:12,119 +FNDA:89,DeployCreate3Factory.run +DA:10,89 +DA:11,89 +DA:12,89 DA:15,0 DA:16,0 BRDA:16,0,0,- DA:17,0 -DA:21,119 -DA:22,119 +DA:21,89 +DA:22,89 DA:23,0 FNF:1 FNH:1 @@ -1997,18 +2018,18 @@ BRH:0 end_of_record TN: SF:script/deployment/02_Deploy_Access_AccessManager.s.sol -DA:9,119 +DA:9,89 FN:9,DeployAccessManager.run -FNDA:119,DeployAccessManager.run -DA:10,119 -DA:11,119 -DA:13,119 -DA:14,119 -DA:15,119 -DA:16,119 -DA:17,119 -DA:19,119 -DA:20,119 +FNDA:89,DeployAccessManager.run +DA:10,89 +DA:11,89 +DA:13,89 +DA:14,89 +DA:15,89 +DA:16,89 +DA:17,89 +DA:19,89 +DA:20,89 DA:21,0 FNF:1 FNH:1 @@ -2019,18 +2040,18 @@ BRH:0 end_of_record TN: SF:script/deployment/03_Deploy_Economics_Token.s.sol -DA:8,57 +DA:8,39 FN:8,DeployToken.run -FNDA:57,DeployToken.run -DA:9,57 -DA:10,57 -DA:12,57 -DA:13,57 -DA:15,57 -DA:16,57 -DA:17,57 -DA:19,57 -DA:20,57 +FNDA:39,DeployToken.run +DA:9,39 +DA:10,39 +DA:12,39 +DA:13,39 +DA:15,39 +DA:16,39 +DA:17,39 +DA:19,39 +DA:20,39 DA:21,0 FNF:1 FNH:1 @@ -2041,17 +2062,17 @@ BRH:0 end_of_record TN: SF:script/deployment/04_Deploy_Economics_Tollgate.s.sol -DA:10,40 +DA:10,39 FN:10,DeployTollgate.run -FNDA:40,DeployTollgate.run -DA:11,40 -DA:12,40 -DA:13,40 -DA:14,40 -DA:15,40 -DA:16,40 -DA:18,40 -DA:19,40 +FNDA:39,DeployTollgate.run +DA:11,39 +DA:12,39 +DA:13,39 +DA:14,39 +DA:15,39 +DA:16,39 +DA:18,39 +DA:19,39 DA:20,0 FNF:1 FNH:1 @@ -2062,17 +2083,17 @@ BRH:0 end_of_record TN: SF:script/deployment/05_Deploy_Economics_Treasury.s.sol -DA:10,23 +DA:10,26 FN:10,DeployTreasury.run -FNDA:23,DeployTreasury.run -DA:11,23 -DA:12,23 -DA:13,23 -DA:14,23 -DA:15,23 -DA:16,23 -DA:18,23 -DA:19,23 +FNDA:26,DeployTreasury.run +DA:11,26 +DA:12,26 +DA:13,26 +DA:14,26 +DA:15,26 +DA:16,26 +DA:18,26 +DA:19,26 DA:20,0 FNF:1 FNH:1 @@ -2083,17 +2104,17 @@ BRH:0 end_of_record TN: SF:script/deployment/06_Deploy_Financial_LedgerVault.s.sol -DA:8,38 +DA:8,39 FN:8,DeployLedgerVault.run -FNDA:38,DeployLedgerVault.run -DA:10,38 -DA:11,38 -DA:12,38 -DA:13,38 -DA:14,38 -DA:15,38 -DA:17,38 -DA:18,38 +FNDA:39,DeployLedgerVault.run +DA:10,39 +DA:11,39 +DA:12,39 +DA:13,39 +DA:14,39 +DA:15,39 +DA:17,39 +DA:18,39 DA:19,0 FNF:1 FNH:1 @@ -2104,19 +2125,19 @@ BRH:0 end_of_record TN: SF:script/deployment/07_Deploy_Financial_AgreementManager.s.sol -DA:8,38 +DA:8,39 FN:8,DeployAgreementManager.run -FNDA:38,DeployAgreementManager.run -DA:9,38 -DA:10,38 -DA:11,38 -DA:12,38 -DA:13,38 -DA:14,38 -DA:15,38 -DA:16,38 -DA:18,38 -DA:19,38 +FNDA:39,DeployAgreementManager.run +DA:9,39 +DA:10,39 +DA:11,39 +DA:12,39 +DA:13,39 +DA:14,39 +DA:15,39 +DA:16,39 +DA:18,39 +DA:19,39 DA:20,0 FNF:1 FNH:1 @@ -2127,20 +2148,20 @@ BRH:0 end_of_record TN: SF:script/deployment/08_Deploy_Financial_AgreementSettler.s.sol -DA:8,23 +DA:8,26 FN:8,DeployAgreementSettler.run -FNDA:23,DeployAgreementSettler.run -DA:10,23 -DA:11,23 -DA:12,23 -DA:13,23 -DA:14,23 -DA:15,23 -DA:16,23 -DA:17,23 -DA:18,23 -DA:20,23 -DA:21,23 +FNDA:26,DeployAgreementSettler.run +DA:10,26 +DA:11,26 +DA:12,26 +DA:13,26 +DA:14,26 +DA:15,26 +DA:16,26 +DA:17,26 +DA:18,26 +DA:20,26 +DA:21,26 DA:22,0 FNF:1 FNH:1 @@ -2151,17 +2172,17 @@ BRH:0 end_of_record TN: SF:script/deployment/09_Deploy_Custody_CustodianFactory.s.sol -DA:9,13 +DA:9,11 FN:9,DeployCustodianFactory.run -FNDA:13,DeployCustodianFactory.run -DA:11,13 -DA:12,13 -DA:13,13 -DA:14,13 -DA:15,13 -DA:16,13 -DA:18,13 -DA:19,13 +FNDA:11,DeployCustodianFactory.run +DA:11,11 +DA:12,11 +DA:13,11 +DA:14,11 +DA:15,11 +DA:16,11 +DA:18,11 +DA:19,11 DA:20,0 FNF:1 FNH:1 @@ -2172,18 +2193,18 @@ BRH:0 end_of_record TN: SF:script/deployment/10_Deploy_Custody_CustodianReferendum.s.sol -DA:9,13 +DA:9,11 FN:9,DeployCustodianReferendum.run -FNDA:13,DeployCustodianReferendum.run -DA:10,13 -DA:11,13 -DA:12,13 -DA:13,13 -DA:14,13 -DA:15,13 -DA:16,13 -DA:18,13 -DA:19,13 +FNDA:11,DeployCustodianReferendum.run +DA:10,11 +DA:11,11 +DA:12,11 +DA:13,11 +DA:14,11 +DA:15,11 +DA:16,11 +DA:18,11 +DA:19,11 DA:20,0 FNF:1 FNH:1 @@ -2194,17 +2215,17 @@ BRH:0 end_of_record TN: SF:script/deployment/11_Deploy_Assets_AssetReferendum.s.sol -DA:8,34 +DA:8,31 FN:8,DeployAssetReferendum.run -FNDA:34,DeployAssetReferendum.run -DA:9,34 -DA:10,34 -DA:11,34 -DA:12,34 -DA:13,34 -DA:14,34 -DA:16,34 -DA:17,34 +FNDA:31,DeployAssetReferendum.run +DA:9,31 +DA:10,31 +DA:11,31 +DA:12,31 +DA:13,31 +DA:14,31 +DA:16,31 +DA:17,31 DA:18,0 FNF:1 FNH:1 @@ -2215,18 +2236,18 @@ BRH:0 end_of_record TN: SF:script/deployment/12_Deploy_Assets_AssetRegistry.s.sol -DA:8,21 +DA:8,18 FN:8,DeployAssetRegistry.run -FNDA:21,DeployAssetRegistry.run -DA:10,21 -DA:11,21 -DA:12,21 -DA:13,21 -DA:14,21 -DA:15,21 -DA:16,21 -DA:18,21 -DA:19,21 +FNDA:18,DeployAssetRegistry.run +DA:10,18 +DA:11,18 +DA:12,18 +DA:13,18 +DA:14,18 +DA:15,18 +DA:16,18 +DA:18,18 +DA:19,18 DA:20,0 FNF:1 FNH:1 @@ -2237,18 +2258,18 @@ BRH:0 end_of_record TN: SF:script/deployment/13_Deploy_Assets_AssetSafe.s.sol -DA:8,10 +DA:8,9 FN:8,DeployAssetSafe.run -FNDA:10,DeployAssetSafe.run -DA:10,10 -DA:11,10 -DA:12,10 -DA:13,10 -DA:14,10 -DA:15,10 -DA:16,10 -DA:18,10 -DA:19,10 +FNDA:9,DeployAssetSafe.run +DA:10,9 +DA:11,9 +DA:12,9 +DA:13,9 +DA:14,9 +DA:15,9 +DA:16,9 +DA:18,9 +DA:19,9 DA:20,0 FNF:1 FNH:1 @@ -2259,17 +2280,17 @@ BRH:0 end_of_record TN: SF:script/deployment/14_Deploy_Policies_PolicyAudit.s.sol -DA:10,15 +DA:10,28 FN:10,DeployPolicyAudit.run -FNDA:15,DeployPolicyAudit.run -DA:11,15 -DA:12,15 -DA:13,15 -DA:14,15 -DA:15,15 -DA:16,15 -DA:18,15 -DA:19,15 +FNDA:28,DeployPolicyAudit.run +DA:11,28 +DA:12,28 +DA:13,28 +DA:14,28 +DA:15,28 +DA:16,28 +DA:18,28 +DA:19,28 DA:20,0 FNF:1 FNH:1 @@ -2324,38 +2345,38 @@ BRH:0 end_of_record TN: SF:script/deployment/17_Deploy_RightsManager_PolicyManager.s.sol -DA:8,0 +DA:8,9 FN:8,DeployRightsPolicyManager.run -FNDA:0,DeployRightsPolicyManager.run -DA:10,0 -DA:11,0 -DA:12,0 -DA:13,0 -DA:14,0 -DA:15,0 -DA:16,0 -DA:17,0 -DA:19,0 -DA:20,0 +FNDA:9,DeployRightsPolicyManager.run +DA:10,9 +DA:11,9 +DA:12,9 +DA:13,9 +DA:14,9 +DA:15,9 +DA:16,9 +DA:17,9 +DA:19,9 +DA:20,9 DA:21,0 FNF:1 -FNH:0 +FNH:1 LF:12 -LH:0 +LH:11 BRF:0 BRH:0 end_of_record TN: SF:script/deployment/18_Deploy_RightsManager_PolicyAuthorizer.s.sol -DA:10,15 +DA:10,19 FN:10,DeployRightsPolicyAuthorizer.run -FNDA:15,DeployRightsPolicyAuthorizer.run -DA:11,15 -DA:13,15 -DA:14,15 -DA:15,15 -DA:17,15 -DA:18,15 +FNDA:19,DeployRightsPolicyAuthorizer.run +DA:11,19 +DA:13,19 +DA:14,19 +DA:15,19 +DA:17,19 +DA:18,19 FNF:1 FNH:1 LF:7 @@ -2365,10 +2386,9 @@ BRH:0 end_of_record TN: SF:script/orchestration/01_Orchestrate_ProtocolHydration.s.sol -DA:19,0 -FN:19,OrchestrateProtocolHydration.run -FNDA:0,OrchestrateProtocolHydration.run DA:20,0 +FN:20,OrchestrateProtocolHydration.run +FNDA:0,OrchestrateProtocolHydration.run DA:21,0 DA:22,0 DA:23,0 @@ -2379,34 +2399,44 @@ DA:27,0 DA:28,0 DA:29,0 DA:30,0 +DA:31,0 DA:32,0 -DA:36,0 -DA:37,0 -DA:40,0 -DA:43,0 +DA:34,0 +DA:38,0 +DA:39,0 DA:44,0 -DA:45,0 DA:46,0 -DA:48,0 -DA:49,0 +DA:47,0 DA:50,0 DA:51,0 +DA:52,0 +DA:53,0 DA:54,0 DA:55,0 DA:56,0 -DA:57,0 +DA:59,0 +DA:60,0 +DA:61,0 DA:62,0 -DA:63,0 +DA:64,0 DA:65,0 DA:67,0 +DA:68,0 DA:69,0 -DA:70,0 -BRDA:70,0,0,- -BRDA:70,0,1,- DA:71,0 +DA:72,0 +DA:77,0 +DA:78,0 +DA:80,0 +DA:82,0 +DA:84,0 +DA:85,0 +BRDA:85,0,0,- +BRDA:85,0,1,- +DA:86,0 FNF:1 FNH:0 -LF:35 +LF:44 LH:0 BRF:2 BRH:0 @@ -2688,828 +2718,227 @@ BRH:0 end_of_record TN: SF:test/BaseTest.t.sol -DA:64,119 -FN:64,BaseTest.initialize -FNDA:119,BaseTest.initialize -DA:66,119 -DA:67,119 -DA:68,119 -DA:69,119 -DA:70,119 -DA:72,0 -DA:73,0 -DA:79,119 -FN:79,BaseTest.deployCreate3Factory -FNDA:119,BaseTest.deployCreate3Factory -DA:81,119 -DA:82,119 -DA:84,119 -DA:85,119 -DA:86,119 -DA:90,70 -FN:90,BaseTest.deployToken -FNDA:70,BaseTest.deployToken -DA:92,70 -DA:93,70 -DA:97,119 -FN:97,BaseTest.deployAccessManager -FNDA:119,BaseTest.deployAccessManager -DA:99,119 -DA:100,119 -DA:102,119 -DA:104,119 -DA:105,119 -DA:107,119 -DA:109,119 -DA:110,119 -DA:111,119 -DA:115,53 -FN:115,BaseTest.deployTollgate -FNDA:53,BaseTest.deployTollgate -DA:117,0 -DA:119,53 -DA:120,53 -DA:121,53 -DA:123,40 -DA:127,61 -FN:127,BaseTest.deployLedgerVault -FNDA:61,BaseTest.deployLedgerVault -DA:129,61 -DA:130,61 -DA:131,61 -DA:133,61 -DA:135,61 -DA:136,61 -DA:137,61 -DA:141,23 -FN:141,BaseTest.deployTreasury -FNDA:23,BaseTest.deployTreasury -DA:143,23 -DA:144,23 -DA:145,23 -DA:146,23 -DA:149,38 -FN:149,BaseTest.deployAgreementManager -FNDA:38,BaseTest.deployAgreementManager -DA:150,0 -DA:151,38 -DA:153,38 -DA:154,38 -DA:156,38 -DA:159,23 -FN:159,BaseTest.deployAgreementSettler -FNDA:23,BaseTest.deployAgreementSettler -DA:160,0 -DA:161,23 +DA:66,89 +FN:66,BaseTest.initialize +FNDA:89,BaseTest.initialize +DA:68,89 +DA:69,89 +DA:70,89 +DA:71,89 +DA:72,89 +DA:74,0 +DA:75,0 +DA:81,89 +FN:81,BaseTest.deployCreate3Factory +FNDA:89,BaseTest.deployCreate3Factory +DA:83,89 +DA:84,89 +DA:86,89 +DA:87,89 +DA:88,89 +DA:92,50 +FN:92,BaseTest.deployToken +FNDA:50,BaseTest.deployToken +DA:94,50 +DA:95,50 +DA:99,89 +FN:99,BaseTest.deployAccessManager +FNDA:89,BaseTest.deployAccessManager +DA:101,89 +DA:102,89 +DA:104,89 +DA:106,89 +DA:107,89 +DA:109,89 +DA:111,89 +DA:112,89 +DA:113,89 +DA:117,50 +FN:117,BaseTest.deployTollgate +FNDA:50,BaseTest.deployTollgate +DA:119,0 +DA:121,50 +DA:122,50 +DA:123,50 +DA:125,39 +DA:129,65 +FN:129,BaseTest.deployLedgerVault +FNDA:65,BaseTest.deployLedgerVault +DA:131,65 +DA:132,65 +DA:133,65 +DA:135,65 +DA:137,65 +DA:138,65 +DA:139,65 +DA:143,26 +FN:143,BaseTest.deployTreasury +FNDA:26,BaseTest.deployTreasury +DA:145,26 +DA:146,26 +DA:147,26 +DA:148,26 +DA:151,39 +FN:151,BaseTest.deployAgreementManager +FNDA:39,BaseTest.deployAgreementManager +DA:152,0 +DA:153,39 +DA:155,39 +DA:156,39 +DA:158,39 +DA:161,26 +FN:161,BaseTest.deployAgreementSettler +FNDA:26,BaseTest.deployAgreementSettler DA:162,0 -DA:164,23 -DA:165,23 -DA:167,23 -DA:171,34 -FN:171,BaseTest.deployAssetReferendum -FNDA:34,BaseTest.deployAssetReferendum -DA:173,34 -DA:174,34 -DA:175,34 -DA:176,34 -DA:179,21 -FN:179,BaseTest.deployAssetRegistry -FNDA:21,BaseTest.deployAssetRegistry -DA:180,0 -DA:182,21 -DA:183,21 -DA:186,10 -FN:186,BaseTest.deployAssetSafe -FNDA:10,BaseTest.deployAssetSafe -DA:187,0 -DA:188,10 -DA:189,10 -DA:193,13 -FN:193,BaseTest.deployCustodianFactory -FNDA:13,BaseTest.deployCustodianFactory -DA:194,13 -DA:195,13 -DA:198,13 -FN:198,BaseTest.deployCustodianReferendum -FNDA:13,BaseTest.deployCustodianReferendum -DA:199,0 -DA:200,0 -DA:203,13 -DA:204,13 -DA:205,13 -DA:207,13 -DA:211,0 -FN:211,BaseTest.deployRightsAssetCustodian +DA:163,26 +DA:164,0 +DA:166,26 +DA:167,26 +DA:169,26 +DA:173,31 +FN:173,BaseTest.deployAssetReferendum +FNDA:31,BaseTest.deployAssetReferendum +DA:175,31 +DA:176,31 +DA:177,31 +DA:178,31 +DA:181,18 +FN:181,BaseTest.deployAssetRegistry +FNDA:18,BaseTest.deployAssetRegistry +DA:182,0 +DA:184,18 +DA:185,18 +DA:188,9 +FN:188,BaseTest.deployAssetSafe +FNDA:9,BaseTest.deployAssetSafe +DA:189,0 +DA:190,9 +DA:191,9 +DA:195,11 +FN:195,BaseTest.deployCustodianFactory +FNDA:11,BaseTest.deployCustodianFactory +DA:196,11 +DA:197,11 +DA:200,11 +FN:200,BaseTest.deployCustodianReferendum +FNDA:11,BaseTest.deployCustodianReferendum +DA:201,0 +DA:202,0 +DA:205,11 +DA:206,11 +DA:207,11 +DA:209,11 +DA:213,0 +FN:213,BaseTest.deployRightsAssetCustodian FNDA:0,BaseTest.deployRightsAssetCustodian -DA:212,0 DA:214,0 -DA:215,0 -DA:218,15 -FN:218,BaseTest.deployPolicyAudit -FNDA:15,BaseTest.deployPolicyAudit -DA:219,15 -DA:220,15 -DA:223,15 -FN:223,BaseTest.deployRightsPolicyAuthorizer -FNDA:15,BaseTest.deployRightsPolicyAuthorizer -DA:224,0 -DA:226,15 -DA:227,15 -DA:232,34 -FN:232,BaseTest._setContentCouncilPermissions -FNDA:34,BaseTest._setContentCouncilPermissions -DA:233,34 -DA:234,34 -DA:236,34 -DA:237,34 -DA:240,13 -FN:240,BaseTest._setNodesCouncilPermissions -FNDA:13,BaseTest._setNodesCouncilPermissions -DA:241,13 -DA:242,13 -DA:244,13 -DA:245,13 -DA:248,76 -FN:248,BaseTest._setGovPermissions +DA:216,0 +DA:217,0 +DA:220,28 +FN:220,BaseTest.deployPolicyAudit +FNDA:28,BaseTest.deployPolicyAudit +DA:221,28 +DA:222,28 +DA:225,19 +FN:225,BaseTest.deployRightsPolicyAuthorizer +FNDA:19,BaseTest.deployRightsPolicyAuthorizer +DA:226,0 +DA:228,19 +DA:229,19 +DA:234,9 +FN:234,BaseTest.deployRightsPolicyManager +FNDA:9,BaseTest.deployRightsPolicyManager +DA:235,0 +DA:236,0 +DA:238,9 +DA:239,9 +DA:242,31 +FN:242,BaseTest._setContentCouncilPermissions +FNDA:31,BaseTest._setContentCouncilPermissions +DA:243,31 +DA:244,31 +DA:246,31 +DA:247,31 +DA:250,11 +FN:250,BaseTest._setNodesCouncilPermissions +FNDA:11,BaseTest._setNodesCouncilPermissions +DA:251,11 +DA:252,11 +DA:254,11 +DA:255,11 +DA:258,76 +FN:258,BaseTest._setGovPermissions FNDA:76,BaseTest._setGovPermissions -DA:249,76 -DA:250,76 -DA:252,76 -DA:253,76 -DA:256,61 -FN:256,BaseTest._assignOpRole -FNDA:61,BaseTest._assignOpRole -DA:257,61 -DA:258,61 -DA:259,61 -DA:260,61 -FNF:21 -FNH:20 -LF:113 -LH:98 +DA:259,76 +DA:260,76 +DA:262,76 +DA:263,76 +DA:266,65 +FN:266,BaseTest._assignOpRole +FNDA:65,BaseTest._assignOpRole +DA:267,65 +DA:268,65 +DA:269,65 +DA:270,65 +FNF:22 +FNH:21 +LF:118 +LH:101 BRF:0 BRH:0 end_of_record TN: -SF:test/assets/AssetReferendum.t.sol -DA:34,2 -FN:34,AssetReferendumHandler.constructor -FNDA:2,AssetReferendumHandler.constructor -DA:35,2 -DA:36,2 -DA:38,2 -DA:39,12 -DA:43,12680 -FN:43,AssetReferendumHandler.submit -FNDA:12680,AssetReferendumHandler.submit -DA:44,12680 -DA:46,12680 -DA:47,12680 -DA:48,12680 -DA:50,12638 -DA:52,12638 -DA:53,12638 -DA:55,12638 -DA:56,12638 -DA:57,12638 -DA:60,12475 -FN:60,AssetReferendumHandler.approve -FNDA:12475,AssetReferendumHandler.approve -DA:61,12475 -DA:63,10496 -DA:64,10496 -DA:65,10496 -DA:67,4012 -DA:68,4012 -DA:70,4012 -DA:73,12475 -FN:73,AssetReferendumHandler.reject -FNDA:12475,AssetReferendumHandler.reject -DA:74,12475 -DA:76,10501 -DA:77,10501 -DA:78,10501 -DA:80,3850 -DA:81,3850 -DA:83,3850 -DA:86,12420 -FN:86,AssetReferendumHandler.revoke -FNDA:12420,AssetReferendumHandler.revoke -DA:87,12420 -DA:89,10447 -DA:90,10447 -DA:91,10447 -DA:93,1817 -DA:94,1817 -DA:96,1817 -DA:99,0 -FN:99,AssetReferendumHandler.trackedLength -FNDA:0,AssetReferendumHandler.trackedLength -DA:100,0 -DA:103,0 -FN:103,AssetReferendumHandler.trackedAt -FNDA:0,AssetReferendumHandler.trackedAt -DA:104,0 -DA:107,0 -FN:107,AssetReferendumHandler.stateOf -FNDA:0,AssetReferendumHandler.stateOf -DA:108,0 -FNF:8 -FNH:5 -LF:46 -LH:40 +SF:test/economics/Tollgate.t.sol +DA:21,1 +FN:21,TargetD.isFeeSchemeSupported +FNDA:1,TargetD.isFeeSchemeSupported +DA:23,1 +FNF:1 +FNH:1 +LF:2 +LH:2 BRF:0 BRH:0 end_of_record TN: -SF:test/assets/AssetRegistry.t.sol -DA:29,3 -FN:29,AssetRegistryHandler.constructor -FNDA:3,AssetRegistryHandler.constructor -DA:30,3 -DA:31,3 -DA:32,3 -DA:33,3 -DA:35,3 -DA:36,3 -DA:37,15 -DA:41,18988 -FN:41,AssetRegistryHandler.register -FNDA:18988,AssetRegistryHandler.register -DA:42,18988 -DA:44,18988 -DA:45,18988 -DA:48,18961 -DA:50,18961 -DA:51,18961 -DA:53,18961 -DA:54,18961 -DA:56,18961 -DA:57,18961 -DA:59,18961 -DA:60,18961 -DA:61,18961 -DA:62,18961 -DA:63,18961 -DA:66,18833 -FN:66,AssetRegistryHandler.transfer -FNDA:18833,AssetRegistryHandler.transfer -DA:67,18833 -DA:69,15757 -DA:70,15757 -DA:71,15757 -DA:73,8776 -DA:74,8776 -DA:76,7307 -DA:77,7307 -DA:79,7307 -DA:82,18810 -FN:82,AssetRegistryHandler.switchState -FNDA:18810,AssetRegistryHandler.switchState -DA:83,18810 -DA:85,15739 -DA:86,15739 -DA:87,15739 -DA:89,8786 -DA:90,8786 -DA:91,8786 -DA:94,18444 -FN:94,AssetRegistryHandler.revoke -FNDA:18444,AssetRegistryHandler.revoke -DA:95,18444 -DA:97,15393 -DA:98,15393 -DA:99,15393 -DA:101,8580 -DA:102,8580 -DA:104,8580 -DA:105,8580 -DA:106,8580 -DA:109,0 -FN:109,AssetRegistryHandler.assetIdsLength -FNDA:0,AssetRegistryHandler.assetIdsLength -DA:110,0 -DA:113,0 -FN:113,AssetRegistryHandler.assetIdAt -FNDA:0,AssetRegistryHandler.assetIdAt -DA:114,0 -DA:117,0 -FN:117,AssetRegistryHandler.getAssetInfo -FNDA:0,AssetRegistryHandler.getAssetInfo -DA:118,0 -FNF:8 -FNH:5 -LF:58 -LH:52 -BRF:0 -BRH:0 -end_of_record -TN: -SF:test/assets/AssetSafe.t.sol -DA:29,3 -FN:29,AssetSafeHandler.constructor -FNDA:3,AssetSafeHandler.constructor -DA:30,3 -DA:31,3 -DA:32,3 -DA:33,3 -DA:35,3 -DA:36,18 -DA:40,25531 -FN:40,AssetSafeHandler.registerAsset -FNDA:25531,AssetSafeHandler.registerAsset -DA:41,25531 -DA:43,25531 -DA:46,25463 -DA:47,25463 -DA:49,25463 -DA:50,25463 -DA:52,25463 -DA:53,25463 -DA:55,25463 -DA:56,25463 -DA:58,25463 -DA:59,25463 -DA:60,25463 -DA:63,24696 -FN:63,AssetSafeHandler.transferAsset -FNDA:24696,AssetSafeHandler.transferAsset -DA:64,24696 -DA:66,21934 -DA:67,21934 -DA:69,21934 -DA:70,21934 -DA:72,21934 -DA:73,21934 -DA:75,18310 -DA:76,18310 -DA:78,18310 -DA:81,24848 -FN:81,AssetSafeHandler.setContent -FNDA:24848,AssetSafeHandler.setContent -DA:82,24848 -DA:84,22169 -DA:85,22169 -DA:87,22169 -DA:88,22169 -DA:90,22169 -DA:91,22169 -DA:92,22169 -DA:94,22169 -DA:95,22169 -DA:97,22169 -DA:98,22169 -DA:99,22169 -DA:100,22169 -DA:103,0 -FN:103,AssetSafeHandler.trackedLength -FNDA:0,AssetSafeHandler.trackedLength -DA:104,0 -DA:107,0 -FN:107,AssetSafeHandler.trackedAt -FNDA:0,AssetSafeHandler.trackedAt -DA:108,0 -DA:111,0 -FN:111,AssetSafeHandler.ownerOf -FNDA:0,AssetSafeHandler.ownerOf -DA:112,0 -DA:115,0 -FN:115,AssetSafeHandler.isTracked -FNDA:0,AssetSafeHandler.isTracked -DA:116,0 -DA:119,0 -FN:119,AssetSafeHandler.hasContent -FNDA:0,AssetSafeHandler.hasContent -DA:120,0 -DA:123,0 -FN:123,AssetSafeHandler.contentOf -FNDA:0,AssetSafeHandler.contentOf -DA:124,0 -DA:127,0 -FN:127,AssetSafeHandler.hasLatestCipher -FNDA:0,AssetSafeHandler.hasLatestCipher -DA:128,0 -DA:131,0 -FN:131,AssetSafeHandler.latestCipher -FNDA:0,AssetSafeHandler.latestCipher -DA:132,0 -FNF:12 -FNH:4 -LF:63 -LH:47 -BRF:0 -BRH:0 -end_of_record -TN: -SF:test/economics/Tollgate.t.sol -DA:20,12287 -FN:20,TargetD.isFeeSchemeSupported -FNDA:12287,TargetD.isFeeSchemeSupported -DA:22,12287 -DA:42,2 -FN:42,TollgateHandler.constructor -FNDA:2,TollgateHandler.constructor -DA:43,2 -DA:44,2 -DA:46,2 -DA:47,2 -DA:48,2 -DA:49,2 -DA:51,2 -DA:52,2 -DA:53,2 -DA:54,2 -DA:56,2 -DA:57,2 -DA:58,2 -DA:61,50050 -FN:61,TollgateHandler.setFees -FNDA:50050,TollgateHandler.setFees -DA:62,50050 -DA:63,50050 -DA:64,50050 -DA:65,50050 -DA:67,50050 -DA:68,50050 -BRDA:68,1,0,25051 -BRDA:68,1,1,12509 -DA:69,25051 -DA:70,24999 -BRDA:70,2,0,12490 -BRDA:70,2,1,12509 -DA:71,12490 -DA:73,12509 -DA:76,50050 -DA:77,50050 -DA:79,50050 -DA:80,50050 -DA:81,50050 -DA:83,50050 -BRDA:83,3,0,21321 -DA:84,21321 -DA:85,21321 -DA:89,0 -FN:89,TollgateHandler.targetsLength -FNDA:0,TollgateHandler.targetsLength -DA:90,0 -DA:93,0 -FN:93,TollgateHandler.targetAt -FNDA:0,TollgateHandler.targetAt -DA:94,0 -DA:97,0 -FN:97,TollgateHandler.schemeOf -FNDA:0,TollgateHandler.schemeOf -DA:98,0 -DA:101,0 -FN:101,TollgateHandler.currenciesFor -FNDA:0,TollgateHandler.currenciesFor -DA:102,0 -DA:105,0 -FN:105,TollgateHandler.feeState -FNDA:0,TollgateHandler.feeState -DA:106,0 -FNF:8 -FNH:3 -LF:45 -LH:35 -BRF:5 -BRH:5 -end_of_record -TN: -SF:test/finance/AgreementManager.t.sol -DA:228,3 -FN:228,AgreementManagerHandler.constructor -FNDA:3,AgreementManagerHandler.constructor -DA:237,3 -DA:238,3 -DA:239,3 -DA:240,3 -DA:241,3 -DA:242,3 -DA:243,3 -DA:246,37491 -FN:246,AgreementManagerHandler.createAgreement -FNDA:37491,AgreementManagerHandler.createAgreement -DA:247,37491 -DA:248,37491 -DA:250,6995 -DA:251,6995 -DA:252,6995 -DA:253,6995 -DA:255,6995 -DA:256,6995 -BRDA:256,2,0,2461 -DA:257,2461 -DA:259,6995 -DA:261,6655 -DA:262,6655 -DA:263,6655 -DA:265,6655 -DA:266,6655 -DA:270,6655 -DA:271,6655 -DA:272,6655 -DA:273,6655 -DA:276,37584 -FN:276,AgreementManagerHandler.setMaxParties -FNDA:37584,AgreementManagerHandler.setMaxParties -DA:277,37584 -DA:278,37584 -DA:279,37584 -DA:282,0 -FN:282,AgreementManagerHandler.proofsLength -FNDA:0,AgreementManagerHandler.proofsLength -DA:283,0 -DA:286,0 -FN:286,AgreementManagerHandler.proofAt -FNDA:0,AgreementManagerHandler.proofAt -DA:287,0 -DA:290,0 -FN:290,AgreementManagerHandler.info -FNDA:0,AgreementManagerHandler.info -DA:291,0 -DA:294,0 -FN:294,AgreementManagerHandler.totalLocked -FNDA:0,AgreementManagerHandler.totalLocked -DA:295,0 -DA:298,0 -FN:298,AgreementManagerHandler.recomputeLocked -FNDA:0,AgreementManagerHandler.recomputeLocked -DA:299,0 -DA:300,0 -DA:301,0 -DA:302,0 -DA:303,0 -DA:307,6655 -FN:307,AgreementManagerHandler._buildParties -FNDA:6655,AgreementManagerHandler._buildParties -DA:308,6655 -DA:309,6655 -DA:310,24785 -DA:314,6995 -FN:314,AgreementManagerHandler._penaltyBps -FNDA:6995,AgreementManagerHandler._penaltyBps -DA:315,6995 -DA:316,2461 -DA:317,2461 -FNF:10 -FNH:5 -LF:54 -LH:40 -BRF:1 -BRH:1 -end_of_record -TN: SF:test/finance/AgreementSettler.t.sol -DA:28,10 +DA:28,6 FN:28,SettlerMockArbiter.constructor -FNDA:10,SettlerMockArbiter.constructor -DA:29,10 +FNDA:6,SettlerMockArbiter.constructor +DA:29,6 DA:32,1 FN:32,SettlerMockArbiter.execute FNDA:1,SettlerMockArbiter.execute DA:33,1 -DA:210,4 -FN:210,AgreementSettlerHandler.constructor -FNDA:4,AgreementSettlerHandler.constructor -DA:218,4 -DA:219,4 -DA:220,4 -DA:221,4 -DA:222,4 -DA:223,4 -DA:226,33488 -FN:226,AgreementSettlerHandler.createAgreement -FNDA:33488,AgreementSettlerHandler.createAgreement -DA:227,33488 -DA:228,33488 -DA:229,33488 -DA:230,33488 -DA:232,14835 -DA:233,14835 -BRDA:233,1,0,4224 -DA:234,4224 -DA:236,14835 -DA:238,14492 -DA:239,14492 -DA:240,14492 -DA:241,14492 -DA:242,14492 -DA:245,14492 -DA:246,14492 -DA:256,14492 -DA:257,14492 -DA:260,32954 -FN:260,AgreementSettlerHandler.settle -FNDA:32954,AgreementSettlerHandler.settle -DA:261,32954 -DA:262,28934 -DA:263,28934 -DA:264,28934 -DA:266,0 -DA:267,6031 -DA:268,4 -DA:271,6027 -DA:272,6027 -DA:273,6027 -DA:274,6027 -DA:276,6027 -DA:277,6027 -DA:278,6027 -DA:280,6027 -DA:281,6027 -DA:282,6027 -DA:285,33658 -FN:285,AgreementSettlerHandler.quit -FNDA:33658,AgreementSettlerHandler.quit -DA:286,33658 -DA:287,29570 -DA:288,29570 -DA:289,29570 -DA:291,6225 -DA:292,6225 -DA:293,6225 -DA:295,6225 -DA:296,6225 -DA:298,6225 -DA:299,6225 -DA:302,0 -FN:302,AgreementSettlerHandler.proofsLength -FNDA:0,AgreementSettlerHandler.proofsLength -DA:303,0 -DA:306,0 -FN:306,AgreementSettlerHandler.proofAt -FNDA:0,AgreementSettlerHandler.proofAt -DA:307,0 -DA:310,0 -FN:310,AgreementSettlerHandler.stateOf -FNDA:0,AgreementSettlerHandler.stateOf -DA:311,0 -DA:314,0 -FN:314,AgreementSettlerHandler.activeLocked -FNDA:0,AgreementSettlerHandler.activeLocked -DA:315,0 -DA:318,0 -FN:318,AgreementSettlerHandler.totalProtocolTake -FNDA:0,AgreementSettlerHandler.totalProtocolTake -DA:319,0 -DA:322,0 -FN:322,AgreementSettlerHandler.totalPayout -FNDA:0,AgreementSettlerHandler.totalPayout -DA:323,0 -DA:326,0 -FN:326,AgreementSettlerHandler.recomputeActiveLocked -FNDA:0,AgreementSettlerHandler.recomputeActiveLocked -DA:327,0 -DA:328,0 -DA:329,0 -DA:330,0 -DA:331,0 -DA:335,14492 -FN:335,AgreementSettlerHandler._buildParties -FNDA:14492,AgreementSettlerHandler._buildParties -DA:336,14492 -DA:337,14492 -DA:338,50247 -DA:342,33488 -FN:342,AgreementSettlerHandler._penaltyBps -FNDA:33488,AgreementSettlerHandler._penaltyBps -DA:343,33488 -DA:344,9402 -DA:345,9402 -FNF:15 -FNH:8 -LF:85 -LH:66 -BRF:1 -BRH:1 +FNF:2 +FNH:2 +LF:4 +LH:4 +BRF:0 +BRH:0 end_of_record TN: SF:test/finance/LedgerVault.t.sol -DA:21,559 -FN:21,MockToken.mint -FNDA:559,MockToken.mint -DA:22,559 -DA:30,4 -FN:30,LedgerVaultHarness.lockedBalance -FNDA:4,LedgerVaultHarness.lockedBalance -DA:31,4 -DA:32,4 -DA:34,0 +DA:22,48 +FN:22,MockToken.mint +FNDA:48,MockToken.mint +DA:23,48 +DA:31,5 +FN:31,LedgerVaultHarness.lockedBalance +FNDA:5,LedgerVaultHarness.lockedBalance +DA:32,5 +DA:33,5 DA:35,0 DA:36,0 -DA:38,0 +DA:37,0 DA:39,0 DA:40,0 -DA:42,0 -DA:301,1 -FN:301,LedgerVaultHandler.constructor -FNDA:1,LedgerVaultHandler.constructor -DA:308,1 -DA:309,1 -DA:310,1 -DA:311,1 -DA:312,1 -DA:313,5 -DA:317,0 -FN:317,LedgerVaultHandler.accountsLength -FNDA:0,LedgerVaultHandler.accountsLength -DA:318,0 -DA:321,0 -FN:321,LedgerVaultHandler.accountAt -FNDA:0,LedgerVaultHandler.accountAt -DA:322,0 -DA:325,0 -FN:325,LedgerVaultHandler.expectedLedgerOf -FNDA:0,LedgerVaultHandler.expectedLedgerOf -DA:326,0 -DA:329,0 -FN:329,LedgerVaultHandler.expectedLockedOf -FNDA:0,LedgerVaultHandler.expectedLockedOf -DA:330,0 -DA:333,9188 -FN:333,LedgerVaultHandler._boundAmount -FNDA:9188,LedgerVaultHandler._boundAmount -DA:334,9188 -DA:335,9188 -DA:336,9073 -DA:339,238792 -FN:339,LedgerVaultHandler.deposit -FNDA:238792,LedgerVaultHandler.deposit -DA:340,238792 -DA:341,9188 -DA:342,9188 -DA:343,9188 -DA:345,9073 -DA:346,9073 -DA:347,9073 -DA:348,9073 -DA:350,9073 -DA:353,238982 -FN:353,LedgerVaultHandler.withdraw -FNDA:238982,LedgerVaultHandler.withdraw -DA:354,238982 -DA:355,9228 -DA:356,9228 -DA:357,9228 -DA:358,5224 -DA:360,5224 -DA:361,5224 -DA:362,5224 -DA:365,239043 -FN:365,LedgerVaultHandler.transfer -FNDA:239043,LedgerVaultHandler.transfer -DA:366,239043 -DA:367,646 -DA:368,493 -DA:369,493 -DA:370,493 -DA:371,493 -DA:372,299 -DA:374,299 -DA:375,299 -DA:377,299 -DA:378,299 -DA:381,239224 -FN:381,LedgerVaultHandler.lock -FNDA:239224,LedgerVaultHandler.lock -DA:382,239224 -DA:383,9326 -DA:384,9326 -DA:385,9326 -DA:386,5324 -DA:388,5324 -DA:389,5324 -DA:391,5324 -DA:392,5324 -DA:395,238671 -FN:395,LedgerVaultHandler.release -FNDA:238671,LedgerVaultHandler.release -DA:396,238671 -DA:397,9384 -DA:398,9384 -DA:399,9384 -DA:400,2565 -DA:402,2565 -DA:403,2565 -DA:405,2565 -DA:406,2565 -DA:409,238673 -FN:409,LedgerVaultHandler.claim -FNDA:238673,LedgerVaultHandler.claim -DA:410,238673 -DA:411,9194 -DA:412,9194 -DA:413,9194 -DA:414,2425 -DA:416,2425 -DA:417,2425 -DA:419,2425 -DA:420,2425 -FNF:14 -FNH:10 -LF:92 -LH:77 +DA:41,0 +DA:43,0 +FNF:2 +FNH:2 +LF:12 +LH:5 BRF:0 BRH:0 end_of_record @@ -3523,68 +2952,39 @@ DA:14,3 FN:14,FeesOpsHarness.isNominal FNDA:3,FeesOpsHarness.isNominal DA:15,3 -DA:18,16922 +DA:18,4 FN:18,FeesOpsHarness.perOf -FNDA:16922,FeesOpsHarness.perOf -DA:19,16922 -DA:22,17151 +FNDA:4,FeesOpsHarness.perOf +DA:19,4 +DA:22,2 FN:22,FeesOpsHarness.calcBps -FNDA:17151,FeesOpsHarness.calcBps -DA:23,17151 -DA:90,2 -FN:90,FeesOpsHandler.constructor -FNDA:2,FeesOpsHandler.constructor -DA:91,2 -DA:94,16664 -FN:94,FeesOpsHandler.recordPerOf -FNDA:16664,FeesOpsHandler.recordPerOf -DA:95,16664 -DA:96,16664 -DA:97,16664 -DA:98,16664 -DA:101,16894 -FN:101,FeesOpsHandler.recordCalcBps -FNDA:16894,FeesOpsHandler.recordCalcBps -DA:102,16894 -DA:103,16894 -DA:106,16492 -FN:106,FeesOpsHandler.reset -FNDA:16492,FeesOpsHandler.reset -DA:107,16492 -DA:108,16492 -DA:111,0 -FN:111,FeesOpsHandler.totalAmount -FNDA:0,FeesOpsHandler.totalAmount -DA:112,0 -DA:115,0 -FN:115,FeesOpsHandler.lastCalcBps -FNDA:0,FeesOpsHandler.lastCalcBps -DA:116,0 -FNF:10 -FNH:8 -LF:25 -LH:21 +FNDA:2,FeesOpsHarness.calcBps +DA:23,2 +FNF:4 +FNH:4 +LF:8 +LH:8 BRF:0 BRH:0 end_of_record TN: SF:test/libraries/FinancialOps.t.sol -DA:13,51 +DA:13,36 FN:13,TestToken.mint -FNDA:51,TestToken.mint -DA:14,51 -DA:21,18857 +FNDA:36,TestToken.mint +DA:14,36 +DA:21,8 FN:21,FinancialOpsHarness.depositNative -FNDA:18857,FinancialOpsHarness.depositNative -DA:22,18857 -DA:25,18709 +FNDA:8,FinancialOpsHarness.depositNative +DA:22,8 +DA:25,8 FN:25,FinancialOpsHarness.depositToken -FNDA:18709,FinancialOpsHarness.depositToken -DA:26,18709 -DA:29,31325 +FNDA:8,FinancialOpsHarness.depositToken +DA:26,8 +DA:29,7 FN:29,FinancialOpsHarness.transferFunds -FNDA:31325,FinancialOpsHarness.transferFunds -DA:30,31325 +FNDA:7,FinancialOpsHarness.transferFunds +DA:30,7 DA:33,3 FN:33,FinancialOpsHarness.increaseTokenAllowance FNDA:3,FinancialOpsHarness.increaseTokenAllowance @@ -3601,632 +3001,411 @@ DA:45,2 FN:45,FinancialOpsHarness.queryBalance FNDA:2,FinancialOpsHarness.queryBalance DA:46,2 -DA:298,3 -FN:298,FinancialOpsHandler.constructor -FNDA:3,FinancialOpsHandler.constructor -DA:299,3 -DA:300,3 -DA:302,3 -DA:303,9 -DA:304,9 -DA:305,9 -DA:306,9 -DA:307,9 -DA:308,9 -DA:312,624792 -FN:312,FinancialOpsHandler.depositNative -FNDA:624792,FinancialOpsHandler.depositNative -DA:313,624792 -DA:314,18831 -DA:315,18831 -DA:316,18831 -DA:317,18593 -DA:319,18593 -DA:320,18593 -DA:321,18593 -DA:324,626054 -FN:324,FinancialOpsHandler.transferNative -FNDA:626054,FinancialOpsHandler.transferNative -DA:325,626054 -DA:326,18863 -DA:327,15501 -DA:328,15501 -DA:330,15501 -DA:331,15501 -DA:334,626151 -FN:334,FinancialOpsHandler.depositToken -FNDA:626151,FinancialOpsHandler.depositToken -DA:335,626151 -DA:336,18693 -DA:337,18693 -DA:338,18693 -DA:339,18445 -DA:341,18445 -DA:342,18445 -DA:343,18445 -DA:344,18445 -DA:346,18445 -DA:349,625150 -FN:349,FinancialOpsHandler.transferToken -FNDA:625150,FinancialOpsHandler.transferToken -DA:350,625150 -DA:351,18688 -DA:352,15322 -DA:353,15322 -DA:355,15322 -DA:356,15322 -DA:359,0 -FN:359,FinancialOpsHandler.accountsLength -FNDA:0,FinancialOpsHandler.accountsLength -DA:360,0 -DA:363,0 -FN:363,FinancialOpsHandler.accountAt -FNDA:0,FinancialOpsHandler.accountAt -DA:364,0 -DA:367,0 -FN:367,FinancialOpsHandler.expectedHarnessNativeBalance -FNDA:0,FinancialOpsHandler.expectedHarnessNativeBalance -DA:368,0 -DA:371,0 -FN:371,FinancialOpsHandler.expectedHarnessTokenBalance -FNDA:0,FinancialOpsHandler.expectedHarnessTokenBalance -DA:372,0 -DA:375,0 -FN:375,FinancialOpsHandler.nativeInitialTotal -FNDA:0,FinancialOpsHandler.nativeInitialTotal -DA:376,0 -DA:379,0 -FN:379,FinancialOpsHandler.tokenInitialTotal -FNDA:0,FinancialOpsHandler.tokenInitialTotal -DA:380,0 -FNF:19 -FNH:13 -LF:72 -LH:60 +FNF:8 +FNH:8 +LF:16 +LH:16 BRF:0 BRH:0 end_of_record TN: SF:test/libraries/RollingOps.t.sol -DA:13,25663 +DA:13,5 FN:13,RollingOpsHarness.configure -FNDA:25663,RollingOpsHarness.configure -DA:14,25663 -DA:17,35220 +FNDA:5,RollingOpsHarness.configure +DA:14,5 +DA:17,13 FN:17,RollingOpsHarness.roll -FNDA:35220,RollingOpsHarness.roll -DA:18,35220 -DA:21,2545 +FNDA:13,RollingOpsHarness.roll +DA:18,13 +DA:21,3 FN:21,RollingOpsHarness.contains -FNDA:2545,RollingOpsHarness.contains -DA:22,2545 -DA:25,260 +FNDA:3,RollingOpsHarness.contains +DA:22,3 +DA:25,4 FN:25,RollingOpsHarness.length -FNDA:260,RollingOpsHarness.length -DA:26,260 +FNDA:4,RollingOpsHarness.length +DA:26,4 DA:29,2 FN:29,RollingOpsHarness.window FNDA:2,RollingOpsHarness.window DA:30,2 -DA:33,2314 +DA:33,8 FN:33,RollingOpsHarness.at -FNDA:2314,RollingOpsHarness.at -DA:34,2314 -DA:37,50051 +FNDA:8,RollingOpsHarness.at +DA:34,8 +DA:37,1 FN:37,RollingOpsHarness.values -FNDA:50051,RollingOpsHarness.values -DA:38,50051 -DA:170,2 -FN:170,RollingOpsHandler.constructor -FNDA:2,RollingOpsHandler.constructor -DA:171,2 -DA:176,25146 -FN:176,RollingOpsHandler.configure -FNDA:25146,RollingOpsHandler.configure -DA:177,25146 -DA:178,25146 -DA:179,0 -DA:182,24904 -FN:182,RollingOpsHandler.roll -FNDA:24904,RollingOpsHandler.roll -DA:183,24904 -DA:184,0 -DA:187,0 -FN:187,RollingOpsHandler.maxWindow -FNDA:0,RollingOpsHandler.maxWindow -DA:188,0 -DA:191,0 -FN:191,RollingOpsHandler.snapshotLength -FNDA:0,RollingOpsHandler.snapshotLength -DA:192,0 -DA:195,0 -FN:195,RollingOpsHandler.snapshotAt -FNDA:0,RollingOpsHandler.snapshotAt -DA:196,0 -DA:199,50050 -FN:199,RollingOpsHandler._rebuildSnapshot -FNDA:50050,RollingOpsHandler._rebuildSnapshot -DA:200,50050 -DA:201,50050 -DA:202,50050 -DA:203,258802 -FNF:14 -FNH:11 -LF:34 -LH:26 +FNDA:1,RollingOpsHarness.values +DA:38,1 +FNF:7 +FNH:7 +LF:14 +LH:14 BRF:0 BRH:0 end_of_record TN: SF:test/policies/PolicyAudit.t.sol -DA:17,0 -FN:17,MockPolicy.setup +DA:15,0 +FN:15,MockPolicy.setup FNDA:0,MockPolicy.setup -DA:19,0 -FN:19,MockPolicy.enforce +DA:17,0 +FN:17,MockPolicy.enforce FNDA:0,MockPolicy.enforce -DA:20,0 -DA:23,0 -FN:23,MockPolicy.isAccessAllowed +DA:18,0 +DA:21,0 +FN:21,MockPolicy.isAccessAllowed FNDA:0,MockPolicy.isAccessAllowed -DA:24,0 -DA:27,0 -FN:27,MockPolicy.getLicense +DA:22,0 +DA:25,0 +FN:25,MockPolicy.getLicense FNDA:0,MockPolicy.getLicense -DA:28,0 -DA:31,0 -FN:31,MockPolicy.resolveTerms +DA:26,0 +DA:29,0 +FN:29,MockPolicy.resolveTerms FNDA:0,MockPolicy.resolveTerms -DA:32,0 -DA:35,0 -FN:35,MockPolicy.getAttestationProvider +DA:30,0 +DA:33,0 +FN:33,MockPolicy.getAttestationProvider FNDA:0,MockPolicy.getAttestationProvider -DA:36,0 -DA:39,0 -FN:39,MockPolicy.name +DA:34,0 +DA:37,0 +FN:37,MockPolicy.name FNDA:0,MockPolicy.name +DA:38,0 +DA:41,0 +FN:41,MockPolicy.description +FNDA:0,MockPolicy.description +DA:42,0 +DA:45,30 +FN:45,MockPolicy.supportsInterface +FNDA:30,MockPolicy.supportsInterface +DA:46,30 +FNF:9 +FNH:1 +LF:17 +LH:2 +BRF:0 +BRH:0 +end_of_record +TN: +SF:test/policies/PolicyBase.t.sol +DA:17,0 +FN:17,RightsPolicyManagerVerifiableMock.getPolicies +FNDA:0,RightsPolicyManagerVerifiableMock.getPolicies +DA:18,0 +DA:21,0 +FN:21,RightsPolicyManagerVerifiableMock.getActivePolicy +FNDA:0,RightsPolicyManagerVerifiableMock.getActivePolicy +DA:22,0 +DA:25,0 +FN:25,RightsPolicyManagerVerifiableMock.getActivePolicies +FNDA:0,RightsPolicyManagerVerifiableMock.getActivePolicies +DA:26,0 +DA:29,0 +FN:29,RightsPolicyManagerVerifiableMock.isActivePolicy +FNDA:0,RightsPolicyManagerVerifiableMock.isActivePolicy +DA:30,0 +DA:33,0 +FN:33,RightsPolicyManagerVerifiableMock.isRegisteredPolicy +FNDA:0,RightsPolicyManagerVerifiableMock.isRegisteredPolicy +DA:34,0 +DA:39,0 +FN:39,RightsPolicyAuthorizerVerifiableMock.getAuthorizedPolicies +FNDA:0,RightsPolicyAuthorizerVerifiableMock.getAuthorizedPolicies DA:40,0 DA:43,0 -FN:43,MockPolicy.description -FNDA:0,MockPolicy.description +FN:43,RightsPolicyAuthorizerVerifiableMock.isPolicyAuthorized +FNDA:0,RightsPolicyAuthorizerVerifiableMock.isPolicyAuthorized DA:44,0 -DA:47,62373 -FN:47,MockPolicy.supportsInterface -FNDA:62373,MockPolicy.supportsInterface -DA:48,62373 -DA:55,2275 -FN:55,PolicyAuditHarness.status -FNDA:2275,PolicyAuditHarness.status -DA:56,2275 -DA:202,2 -FN:202,PolicyAuditHandler.constructor -FNDA:2,PolicyAuditHandler.constructor -DA:203,2 -DA:204,2 -DA:207,16624 -FN:207,PolicyAuditHandler.submitPolicy -FNDA:16624,PolicyAuditHandler.submitPolicy -DA:208,16624 -DA:209,16624 -BRDA:209,0,0,16624 -DA:210,16624 -DA:211,16624 -DA:215,16718 -FN:215,PolicyAuditHandler.approvePolicy -FNDA:16718,PolicyAuditHandler.approvePolicy -DA:216,16718 -DA:217,14808 -DA:218,14808 -DA:220,7926 -DA:221,7926 -BRDA:221,3,0,7926 -DA:222,7926 -DA:226,16708 -FN:226,PolicyAuditHandler.rejectPolicy -FNDA:16708,PolicyAuditHandler.rejectPolicy -DA:227,16708 -DA:228,14760 -DA:229,14760 -DA:231,3574 -DA:232,3574 -BRDA:232,6,0,3574 -DA:233,3574 -DA:237,0 -FN:237,PolicyAuditHandler.policiesLength -FNDA:0,PolicyAuditHandler.policiesLength -DA:238,0 -DA:241,0 -FN:241,PolicyAuditHandler.policyAt -FNDA:0,PolicyAuditHandler.policyAt -DA:242,0 -DA:245,0 -FN:245,PolicyAuditHandler.storedStatus -FNDA:0,PolicyAuditHandler.storedStatus -DA:246,0 -FNF:17 -FNH:6 -LF:47 -LH:26 -BRF:3 -BRH:3 +DA:56,0 +FN:56,AttestationProviderMock.getName +FNDA:0,AttestationProviderMock.getName +DA:57,0 +DA:60,0 +FN:60,AttestationProviderMock.getAddress +FNDA:0,AttestationProviderMock.getAddress +DA:61,0 +DA:64,1 +FN:64,AttestationProviderMock.attest +FNDA:1,AttestationProviderMock.attest +DA:69,1 +DA:70,1 +DA:71,1 +DA:72,2 +DA:75,1 +DA:76,1 +DA:77,1 +DA:79,1 +DA:80,1 +DA:81,2 +DA:82,2 +DA:83,2 +DA:85,1 +BRDA:85,0,0,- +DA:86,0 +DA:90,1 +FN:90,AttestationProviderMock.lastRecipientsLength +FNDA:1,AttestationProviderMock.lastRecipientsLength +DA:91,1 +DA:94,2 +FN:94,AttestationProviderMock.lastRecipientAt +FNDA:2,AttestationProviderMock.lastRecipientAt +DA:95,2 +DA:98,0 +FN:98,AttestationProviderMock.verify +FNDA:0,AttestationProviderMock.verify +DA:99,0 +DA:106,1 +FN:106,AssetRegistryMock.register +FNDA:1,AssetRegistryMock.register +DA:107,1 +DA:110,0 +FN:110,AssetRegistryMock.revoke +FNDA:0,AssetRegistryMock.revoke +DA:111,0 +DA:114,0 +FN:114,AssetRegistryMock.transfer +FNDA:0,AssetRegistryMock.transfer +DA:115,0 +DA:127,1 +FN:127,PolicyBaseHarness.managerPing +FNDA:1,PolicyBaseHarness.managerPing +DA:128,1 +DA:131,1 +FN:131,PolicyBaseHarness.authorizerPing +FNDA:1,PolicyBaseHarness.authorizerPing +DA:132,1 +DA:135,1 +FN:135,PolicyBaseHarness.exposeCommit +FNDA:1,PolicyBaseHarness.exposeCommit +DA:140,1 +DA:143,1 +FN:143,PolicyBaseHarness.exposeSetAttestation +FNDA:1,PolicyBaseHarness.exposeSetAttestation +DA:144,1 +DA:147,1 +FN:147,PolicyBaseHarness.exposeHolder +FNDA:1,PolicyBaseHarness.exposeHolder +DA:148,1 +DA:151,0 +FN:151,PolicyBaseHarness.setup +FNDA:0,PolicyBaseHarness.setup +DA:153,0 +FN:153,PolicyBaseHarness.enforce +FNDA:0,PolicyBaseHarness.enforce +DA:157,0 +DA:160,0 +FN:160,PolicyBaseHarness.isAccessAllowed +FNDA:0,PolicyBaseHarness.isAccessAllowed +DA:161,0 +DA:164,0 +FN:164,PolicyBaseHarness.resolveTerms +FNDA:0,PolicyBaseHarness.resolveTerms +DA:166,0 +FN:166,PolicyBaseHarness.name +FNDA:0,PolicyBaseHarness.name +DA:167,0 +DA:170,0 +FN:170,PolicyBaseHarness.description +FNDA:0,PolicyBaseHarness.description +DA:171,0 +FNF:27 +FNH:9 +LF:65 +LH:30 +BRF:1 +BRH:0 end_of_record TN: SF:test/primitives/AccessControlledUpgradeable.t.sol -DA:15,13 +DA:15,7 FN:15,AccessControlledHarness.initialize -FNDA:13,AccessControlledHarness.initialize -DA:16,13 -DA:19,16079 +FNDA:7,AccessControlledHarness.initialize +DA:16,7 +DA:19,1 FN:19,AccessControlledHarness.adminAction -FNDA:16079,AccessControlledHarness.adminAction -DA:20,16079 -DA:21,16079 -DA:24,252 +FNDA:1,AccessControlledHarness.adminAction +DA:20,1 +DA:21,1 +DA:24,2 FN:24,AccessControlledHarness.opsAction -FNDA:252,AccessControlledHarness.opsAction -DA:25,252 -DA:26,252 -DA:29,601 +FNDA:2,AccessControlledHarness.opsAction +DA:25,2 +DA:26,2 +DA:29,2 FN:29,AccessControlledHarness.isPaused -FNDA:601,AccessControlledHarness.isPaused -DA:30,601 -DA:33,916 +FNDA:2,AccessControlledHarness.isPaused +DA:30,2 +DA:33,3 FN:33,AccessControlledHarness.hasRoleView -FNDA:916,AccessControlledHarness.hasRoleView -DA:34,916 -DA:192,2 -FN:192,AccessControlledHandler.constructor -FNDA:2,AccessControlledHandler.constructor -DA:193,2 -DA:194,2 -DA:195,2 -DA:197,2 -DA:198,6 -DA:202,15928 -FN:202,AccessControlledHandler.grantOpsRole -FNDA:15928,AccessControlledHandler.grantOpsRole -DA:203,15928 -DA:204,500 -DA:205,500 -DA:206,500 -DA:209,15740 -FN:209,AccessControlledHandler.revokeOpsRole -FNDA:15740,AccessControlledHandler.revokeOpsRole -DA:210,15740 -DA:211,422 -DA:212,422 -DA:213,152 -DA:214,152 -DA:217,16078 -FN:217,AccessControlledHandler.callAdminAction -FNDA:16078,AccessControlledHandler.callAdminAction -DA:218,16078 -DA:219,16078 -DA:220,16078 -DA:223,16076 -FN:223,AccessControlledHandler.callOpsAction -FNDA:16076,AccessControlledHandler.callOpsAction -DA:224,16076 -DA:225,490 -DA:226,490 -DA:227,112 -DA:228,112 -DA:229,112 -DA:232,16174 -FN:232,AccessControlledHandler.pause -FNDA:16174,AccessControlledHandler.pause -DA:234,8710 -DA:235,8710 -DA:236,8710 -DA:239,16386 -FN:239,AccessControlledHandler.unpause -FNDA:16386,AccessControlledHandler.unpause -DA:240,16386 -DA:241,7714 -DA:242,7714 -DA:243,7714 -DA:246,0 -FN:246,AccessControlledHandler.actorsLength -FNDA:0,AccessControlledHandler.actorsLength -DA:247,0 -DA:250,0 -FN:250,AccessControlledHandler.actorAt -FNDA:0,AccessControlledHandler.actorAt -DA:251,0 -DA:254,0 -FN:254,AccessControlledHandler.expectedCounterValue -FNDA:0,AccessControlledHandler.expectedCounterValue -DA:255,0 -DA:258,0 -FN:258,AccessControlledHandler.expectedPausedState -FNDA:0,AccessControlledHandler.expectedPausedState -DA:259,0 -FNF:16 -FNH:12 -LF:57 -LH:49 +FNDA:3,AccessControlledHarness.hasRoleView +DA:34,3 +FNF:5 +FNH:5 +LF:12 +LH:12 BRF:0 BRH:0 end_of_record TN: SF:test/primitives/AllowanceOperatorUpgradeable.t.sol -DA:12,13 +DA:12,8 FN:12,AllowanceOperatorHarness.initialize -FNDA:13,AllowanceOperatorHarness.initialize +FNDA:8,AllowanceOperatorHarness.initialize DA:13,0 -DA:16,32067 +DA:16,3 FN:16,AllowanceOperatorHarness.boostLedger -FNDA:32067,AllowanceOperatorHarness.boostLedger -DA:17,32067 -DA:21,1609 -FN:21,AllowanceOperatorHarness.approve -FNDA:1609,AllowanceOperatorHarness.approve -DA:22,1609 -DA:25,320 -FN:25,AllowanceOperatorHarness.revoke -FNDA:320,AllowanceOperatorHarness.revoke -DA:26,320 -DA:29,318 -FN:29,AllowanceOperatorHarness.collect -FNDA:318,AllowanceOperatorHarness.collect -DA:30,318 -DA:185,2 -FN:185,AllowanceHandler.constructor -FNDA:2,AllowanceHandler.constructor -DA:186,2 -DA:187,2 -DA:188,6 -DA:192,1052233 -FN:192,AllowanceHandler.seedLedger -FNDA:1052233,AllowanceHandler.seedLedger -DA:193,1052233 -DA:194,31808 -DA:195,31808 -DA:196,31808 -DA:197,31808 -DA:200,1051770 -FN:200,AllowanceHandler.approve -FNDA:1051770,AllowanceHandler.approve -DA:201,1051770 -DA:202,1087 -DA:203,1087 -DA:204,1087 -DA:206,1087 -DA:207,1087 -DA:209,1087 -DA:210,1087 -DA:213,1053095 -FN:213,AllowanceHandler.revoke -FNDA:1053095,AllowanceHandler.revoke -DA:214,1053095 -DA:215,1107 -DA:216,1107 -DA:217,1107 -DA:218,1107 -DA:219,1107 -DA:220,62 -DA:222,62 -DA:223,62 -DA:224,62 -DA:227,1054374 -FN:227,AllowanceHandler.collect -FNDA:1054374,AllowanceHandler.collect -DA:228,1054374 -DA:229,1029 -DA:230,1029 -DA:231,1029 -DA:232,1029 -DA:233,1029 -DA:234,1029 -DA:235,57 -DA:236,57 -DA:238,57 -DA:239,57 -DA:241,57 -DA:242,57 -DA:243,57 -DA:246,0 -FN:246,AllowanceHandler.accountsLength -FNDA:0,AllowanceHandler.accountsLength -DA:247,0 -DA:250,0 -FN:250,AllowanceHandler.accountAt -FNDA:0,AllowanceHandler.accountAt -DA:251,0 -DA:254,0 -FN:254,AllowanceHandler.expectedLedger -FNDA:0,AllowanceHandler.expectedLedger -DA:255,0 -DA:258,0 -FN:258,AllowanceHandler.expectedAllowance -FNDA:0,AllowanceHandler.expectedAllowance -DA:259,0 -DA:262,0 -FN:262,AllowanceHandler.token -FNDA:0,AllowanceHandler.token -DA:263,0 -FNF:15 -FNH:10 -LF:65 -LH:54 +FNDA:3,AllowanceOperatorHarness.boostLedger +DA:17,3 +DA:20,10 +FN:20,AllowanceOperatorHarness.approve +FNDA:10,AllowanceOperatorHarness.approve +DA:21,10 +DA:24,3 +FN:24,AllowanceOperatorHarness.revoke +FNDA:3,AllowanceOperatorHarness.revoke +DA:25,3 +DA:28,5 +FN:28,AllowanceOperatorHarness.collect +FNDA:5,AllowanceOperatorHarness.collect +DA:29,5 +DA:32,5 +FN:32,AllowanceOperatorHarness.allowance +FNDA:5,AllowanceOperatorHarness.allowance +DA:33,5 +FNF:6 +FNH:6 +LF:12 +LH:11 BRF:0 BRH:0 end_of_record TN: SF:test/primitives/BalanceOperatorUpgradeable.t.sol -DA:16,24587 -FN:16,BalanceOperatorHarness.deposit -FNDA:24587,BalanceOperatorHarness.deposit -DA:17,24587 -DA:20,15200 -FN:20,BalanceOperatorHarness.withdraw -FNDA:15200,BalanceOperatorHarness.withdraw -DA:21,15200 -DA:24,1021 -FN:24,BalanceOperatorHarness.transfer -FNDA:1021,BalanceOperatorHarness.transfer -DA:25,1021 -DA:257,2 -FN:257,BalanceOperatorHandler.constructor -FNDA:2,BalanceOperatorHandler.constructor -DA:258,2 -DA:259,2 -DA:261,2 -DA:262,20 -DA:266,2 -FN:266,BalanceOperatorHandler.getActors -FNDA:2,BalanceOperatorHandler.getActors -DA:267,2 -DA:270,582752 -FN:270,BalanceOperatorHandler.deposit -FNDA:582752,BalanceOperatorHandler.deposit -DA:271,582752 -DA:272,24395 -DA:273,24395 -DA:274,24395 -DA:275,24065 -DA:277,24065 -DA:278,24065 -DA:279,24065 -DA:280,24065 -DA:282,24065 -DA:285,583341 -FN:285,BalanceOperatorHandler.withdraw -FNDA:583341,BalanceOperatorHandler.withdraw -DA:286,583341 -DA:287,24374 -DA:288,24374 -DA:289,24374 -DA:290,14938 -DA:292,14938 -DA:293,14938 -DA:294,14938 -DA:297,583194 -FN:297,BalanceOperatorHandler.transfer -FNDA:583194,BalanceOperatorHandler.transfer -DA:298,583194 -DA:299,23803 -DA:300,1640 -DA:302,1281 -DA:303,1281 -DA:304,1281 -DA:305,1281 -DA:306,757 -DA:308,757 -DA:309,757 -FNF:8 -FNH:8 -LF:44 -LH:44 -BRF:0 +DA:23,0 +FN:23,MockToken.totalSupply +FNDA:0,MockToken.totalSupply +DA:24,0 +DA:27,8 +FN:27,MockToken.balanceOf +FNDA:8,MockToken.balanceOf +DA:28,8 +DA:31,3 +FN:31,MockToken.transfer +FNDA:3,MockToken.transfer +DA:32,3 +DA:33,3 +DA:36,7 +FN:36,MockToken.allowance +FNDA:7,MockToken.allowance +DA:37,7 +DA:40,6 +FN:40,MockToken.approve +FNDA:6,MockToken.approve +DA:41,6 +DA:42,6 +DA:43,0 +DA:46,6 +FN:46,MockToken.transferFrom +FNDA:6,MockToken.transferFrom +DA:47,6 +DA:48,6 +BRDA:48,0,0,- +BRDA:48,0,1,- +DA:49,6 +DA:50,6 +DA:51,0 +DA:54,14 +FN:54,MockToken.mint +FNDA:14,MockToken.mint +DA:55,14 +DA:56,14 +DA:57,14 +DA:60,9 +FN:60,MockToken._transfer +FNDA:9,MockToken._transfer +DA:61,9 +BRDA:61,1,0,- +BRDA:61,1,1,- +DA:62,9 +BRDA:62,2,0,- +BRDA:62,2,1,- +DA:63,9 +DA:64,9 +DA:65,9 +DA:70,7 +FN:70,BalanceOperatorHarness.deposit +FNDA:7,BalanceOperatorHarness.deposit +DA:71,7 +DA:74,4 +FN:74,BalanceOperatorHarness.withdraw +FNDA:4,BalanceOperatorHarness.withdraw +DA:75,4 +DA:78,4 +FN:78,BalanceOperatorHarness.transfer +FNDA:4,BalanceOperatorHarness.transfer +DA:79,4 +FNF:11 +FNH:10 +LF:35 +LH:31 +BRF:6 BRH:0 end_of_record TN: SF:test/primitives/LedgerUpgradeable.t.sol -DA:9,5 +DA:9,6 FN:9,LedgerUpgradeableHarness.initialize -FNDA:5,LedgerUpgradeableHarness.initialize +FNDA:6,LedgerUpgradeableHarness.initialize DA:10,0 -DA:13,8730 +DA:13,7 FN:13,LedgerUpgradeableHarness.setEntry -FNDA:8730,LedgerUpgradeableHarness.setEntry -DA:14,8730 -DA:17,8643 +FNDA:7,LedgerUpgradeableHarness.setEntry +DA:14,7 +DA:17,3 FN:17,LedgerUpgradeableHarness.sumEntry -FNDA:8643,LedgerUpgradeableHarness.sumEntry -DA:18,8643 -DA:21,368 +FNDA:3,LedgerUpgradeableHarness.sumEntry +DA:18,3 +DA:21,3 FN:21,LedgerUpgradeableHarness.subEntry -FNDA:368,LedgerUpgradeableHarness.subEntry -DA:22,368 -DA:93,1 -FN:93,LedgerUpgradeableHandler.constructor -FNDA:1,LedgerUpgradeableHandler.constructor -DA:94,1 -DA:97,8475 -FN:97,LedgerUpgradeableHandler.setEntry -FNDA:8475,LedgerUpgradeableHandler.setEntry -DA:98,8475 -DA:99,8471 -DA:101,8471 -DA:102,8471 -BRDA:102,1,0,8471 -DA:103,8471 -DA:104,8471 -DA:106,8471 -DA:109,8399 -FN:109,LedgerUpgradeableHandler.sumEntry -FNDA:8399,LedgerUpgradeableHandler.sumEntry -DA:110,8399 -DA:112,8386 -DA:113,8386 -DA:114,0 -DA:116,8386 -DA:118,8386 -BRDA:118,3,0,8386 -DA:119,8386 -DA:120,8386 -DA:122,8386 -DA:125,8151 -FN:125,LedgerUpgradeableHandler.subEntry -FNDA:8151,LedgerUpgradeableHandler.subEntry -DA:126,8151 -DA:128,8137 -DA:129,8137 -DA:130,8137 -DA:132,111 -DA:134,111 -BRDA:134,6,0,111 -DA:135,111 -DA:136,111 -DA:138,111 -DA:141,0 -FN:141,LedgerUpgradeableHandler.keysLength -FNDA:0,LedgerUpgradeableHandler.keysLength -DA:142,0 -DA:145,0 -FN:145,LedgerUpgradeableHandler.keyAt -FNDA:0,LedgerUpgradeableHandler.keyAt -DA:146,0 -DA:149,0 -FN:149,LedgerUpgradeableHandler.expectedBalance -FNDA:0,LedgerUpgradeableHandler.expectedBalance -DA:150,0 -DA:151,0 -FNF:11 -FNH:8 -LF:45 -LH:36 -BRF:3 -BRH:3 +FNDA:3,LedgerUpgradeableHarness.subEntry +DA:22,3 +FNF:4 +FNH:4 +LF:8 +LH:7 +BRF:0 +BRH:0 end_of_record TN: SF:test/primitives/LockOperatorUpgradeable.t.sol -DA:16,13 +DA:16,8 FN:16,LockOperatorHarness.initialize -FNDA:13,LockOperatorHarness.initialize +FNDA:8,LockOperatorHarness.initialize DA:17,0 -DA:20,21336 -FN:20,LockOperatorHarness.boostLedger -FNDA:21336,LockOperatorHarness.boostLedger -DA:21,21336 -DA:24,6249 +DA:20,7 +FN:20,LockOperatorHarness.seedLedger +FNDA:7,LockOperatorHarness.seedLedger +DA:21,7 +DA:24,9 FN:24,LockOperatorHarness.lock -FNDA:6249,LockOperatorHarness.lock -DA:25,6249 -DA:28,1934 +FNDA:9,LockOperatorHarness.lock +DA:25,9 +DA:28,3 FN:28,LockOperatorHarness.release -FNDA:1934,LockOperatorHarness.release -DA:29,1934 -DA:32,310 +FNDA:3,LockOperatorHarness.release +DA:29,3 +DA:32,3 FN:32,LockOperatorHarness.claim -FNDA:310,LockOperatorHarness.claim -DA:33,310 -DA:36,517 +FNDA:3,LockOperatorHarness.claim +DA:33,3 +DA:36,4 FN:36,LockOperatorHarness.lockedBalance -FNDA:517,LockOperatorHarness.lockedBalance -DA:37,517 -DA:38,517 +FNDA:4,LockOperatorHarness.lockedBalance +DA:37,4 +DA:38,4 DA:40,0 DA:41,0 DA:42,0 @@ -4234,317 +3413,259 @@ DA:44,0 DA:45,0 DA:46,0 DA:48,0 -DA:253,3 -FN:253,LockOperatorHandler.constructor -FNDA:3,LockOperatorHandler.constructor -DA:254,3 -DA:255,3 -DA:256,9 -DA:260,692242 -FN:260,LockOperatorHandler.seedLedger -FNDA:692242,LockOperatorHandler.seedLedger -DA:261,692242 -DA:262,20817 -DA:263,20817 -DA:264,20817 -DA:265,20817 -DA:268,692334 -FN:268,LockOperatorHandler.lock -FNDA:692334,LockOperatorHandler.lock -DA:269,692334 -DA:270,20769 -DA:271,20769 -DA:272,20769 -DA:274,5728 -DA:275,5728 -DA:277,5728 -DA:278,5728 -DA:281,692567 -FN:281,LockOperatorHandler.release -FNDA:692567,LockOperatorHandler.release -DA:282,692567 -DA:283,20848 -DA:284,20848 -DA:285,20848 -DA:287,1677 -DA:288,1677 -DA:290,1677 -DA:291,1677 -DA:294,692932 -FN:294,LockOperatorHandler.claim -FNDA:692932,LockOperatorHandler.claim -DA:295,692932 -DA:296,611 -DA:297,611 -DA:298,611 -DA:299,611 -DA:301,50 -DA:302,50 -DA:304,50 -DA:305,50 -DA:308,0 -FN:308,LockOperatorHandler.accountsLength -FNDA:0,LockOperatorHandler.accountsLength -DA:309,0 -DA:312,0 -FN:312,LockOperatorHandler.accountAt -FNDA:0,LockOperatorHandler.accountAt -DA:313,0 -DA:316,0 -FN:316,LockOperatorHandler.expectedLedger -FNDA:0,LockOperatorHandler.expectedLedger -DA:317,0 -DA:320,0 -FN:320,LockOperatorHandler.expectedLocked -FNDA:0,LockOperatorHandler.expectedLocked -DA:321,0 -DA:324,0 -FN:324,LockOperatorHandler.token -FNDA:0,LockOperatorHandler.token -DA:325,0 -FNF:16 -FNH:11 -LF:68 -LH:50 +FNF:6 +FNH:6 +LF:20 +LH:12 BRF:0 BRH:0 end_of_record TN: SF:test/primitives/QuorumUpgradeable.t.sol -DA:10,15 +DA:10,11 FN:10,QuorumUpgradeableHarness.initialize -FNDA:15,QuorumUpgradeableHarness.initialize +FNDA:11,QuorumUpgradeableHarness.initialize DA:11,0 -DA:14,50824 +DA:14,6 FN:14,QuorumUpgradeableHarness.statusOf -FNDA:50824,QuorumUpgradeableHarness.statusOf -DA:15,50824 -DA:18,10616 +FNDA:6,QuorumUpgradeableHarness.statusOf +DA:15,6 +DA:18,7 FN:18,QuorumUpgradeableHarness.register -FNDA:10616,QuorumUpgradeableHarness.register -DA:19,10616 -DA:22,308 +FNDA:7,QuorumUpgradeableHarness.register +DA:19,7 +DA:22,3 FN:22,QuorumUpgradeableHarness.approve -FNDA:308,QuorumUpgradeableHarness.approve -DA:23,308 -DA:26,38 +FNDA:3,QuorumUpgradeableHarness.approve +DA:23,3 +DA:26,2 FN:26,QuorumUpgradeableHarness.blockEntry -FNDA:38,QuorumUpgradeableHarness.blockEntry -DA:27,38 -DA:30,290 +FNDA:2,QuorumUpgradeableHarness.blockEntry +DA:27,2 +DA:30,2 FN:30,QuorumUpgradeableHarness.quit -FNDA:290,QuorumUpgradeableHarness.quit -DA:31,290 +FNDA:2,QuorumUpgradeableHarness.quit +DA:31,2 DA:34,2 FN:34,QuorumUpgradeableHarness.revoke FNDA:2,QuorumUpgradeableHarness.revoke DA:35,2 -DA:138,2 -FN:138,QuorumHandler.constructor -FNDA:2,QuorumHandler.constructor -DA:139,2 -DA:142,10140 -FN:142,QuorumHandler.register -FNDA:10140,QuorumHandler.register -DA:143,10140 -DA:144,10140 -DA:145,10097 -DA:146,10097 -DA:149,9810 -FN:149,QuorumHandler.approve -FNDA:9810,QuorumHandler.approve -DA:150,9810 -DA:151,9810 -DA:152,49 -DA:153,49 -DA:156,10024 -FN:156,QuorumHandler.quit -FNDA:10024,QuorumHandler.quit -DA:157,10024 -DA:158,10024 -DA:159,32 -DA:160,32 -DA:163,10104 -FN:163,QuorumHandler.blockEntry -FNDA:10104,QuorumHandler.blockEntry -DA:164,10104 -DA:165,10104 -DA:166,36 -DA:167,36 -DA:170,9972 -FN:170,QuorumHandler.revoke -FNDA:9972,QuorumHandler.revoke -DA:171,9972 -DA:172,9972 -DA:173,0 -DA:174,0 -DA:177,0 -FN:177,QuorumHandler.trackedLength -FNDA:0,QuorumHandler.trackedLength -DA:178,0 -DA:181,0 -FN:181,QuorumHandler.trackedAt -FNDA:0,QuorumHandler.trackedAt -DA:182,0 -DA:185,0 -FN:185,QuorumHandler.expectedStatus -FNDA:0,QuorumHandler.expectedStatus -DA:186,0 -DA:189,10214 -FN:189,QuorumHandler._update -FNDA:10214,QuorumHandler._update -DA:190,10214 -BRDA:190,5,0,10097 -DA:191,10097 -DA:192,10097 -DA:194,10214 -DA:197,50050 -FN:197,QuorumHandler._normalize -FNDA:50050,QuorumHandler._normalize -DA:198,50050 -FNF:18 -FNH:15 -LF:54 -LH:45 -BRF:1 -BRH:1 +FNF:7 +FNH:7 +LF:14 +LH:13 +BRF:0 +BRH:0 end_of_record TN: SF:test/rights/RightsPolicyAuthorizer.t.sol +DA:18,0 +FN:18,DummyAttestationProvider.getName +FNDA:0,DummyAttestationProvider.getName +DA:19,0 +DA:22,0 +FN:22,DummyAttestationProvider.getAddress +FNDA:0,DummyAttestationProvider.getAddress DA:23,0 -FN:23,PolicyMock.configureRevert -FNDA:0,PolicyMock.configureRevert -DA:24,0 -DA:28,9684 -FN:28,PolicyMock.setup -FNDA:9684,PolicyMock.setup -DA:29,0 -BRDA:29,0,0,- -DA:30,9684 -DA:31,9684 +DA:26,0 +FN:26,DummyAttestationProvider.attest +FNDA:0,DummyAttestationProvider.attest +DA:31,0 +DA:34,0 +FN:34,DummyAttestationProvider.verify +FNDA:0,DummyAttestationProvider.verify DA:35,0 -FN:35,PolicyMock.enforce -FNDA:0,PolicyMock.enforce -DA:36,0 -DA:40,0 -FN:40,PolicyMock.isAccessAllowed -FNDA:0,PolicyMock.isAccessAllowed -DA:41,0 -DA:45,0 -FN:45,PolicyMock.getLicense -FNDA:0,PolicyMock.getLicense -DA:46,0 -DA:50,0 -FN:50,PolicyMock.resolveTerms -FNDA:0,PolicyMock.resolveTerms -DA:51,0 -DA:55,0 -FN:55,PolicyMock.getAttestationProvider -FNDA:0,PolicyMock.getAttestationProvider -DA:56,0 -DA:60,0 -FN:60,PolicyMock.name -FNDA:0,PolicyMock.name -DA:61,0 -DA:65,0 -FN:65,PolicyMock.description -FNDA:0,PolicyMock.description -DA:66,0 -DA:69,36807 -FN:69,PolicyMock.supportsInterface -FNDA:36807,PolicyMock.supportsInterface -DA:70,36807 -DA:75,1 -FN:75,PolicyNoDataRevertMock.setup -FNDA:1,PolicyNoDataRevertMock.setup -DA:77,0 -DA:87,1 -FN:87,ReentrantPolicyMock.constructor -FNDA:1,ReentrantPolicyMock.constructor +DA:50,777 +FN:50,PolicyBaseAuthorizerHarness.constructor +FNDA:777,PolicyBaseAuthorizerHarness.constructor +DA:53,777 +DA:56,1 +FN:56,PolicyBaseAuthorizerHarness.setSetupRevert +FNDA:1,PolicyBaseAuthorizerHarness.setSetupRevert +DA:57,1 +DA:60,1 +FN:60,PolicyBaseAuthorizerHarness.setSetupRevertNoData +FNDA:1,PolicyBaseAuthorizerHarness.setSetupRevertNoData +DA:61,1 +DA:64,1 +FN:64,PolicyBaseAuthorizerHarness.setTriggerReentrancy +FNDA:1,PolicyBaseAuthorizerHarness.setTriggerReentrancy +DA:65,1 +DA:66,1 +DA:69,1 +FN:69,PolicyBaseAuthorizerHarness.lastHolder +FNDA:1,PolicyBaseAuthorizerHarness.lastHolder +DA:70,1 +DA:73,1 +FN:73,PolicyBaseAuthorizerHarness.lastInit +FNDA:1,PolicyBaseAuthorizerHarness.lastInit +DA:74,1 +DA:77,366 +FN:77,PolicyBaseAuthorizerHarness.setup +FNDA:366,PolicyBaseAuthorizerHarness.setup +DA:78,1 +BRDA:78,0,0,1 +DA:79,1 +BRDA:79,1,0,1 +BRDA:79,1,1,- +DA:81,0 +DA:84,0 +DA:87,365 +BRDA:87,2,0,1 DA:88,1 -DA:91,1 -FN:91,ReentrantPolicyMock.setup -FNDA:1,ReentrantPolicyMock.setup -DA:93,1 -DA:94,1 +DA:89,1 +DA:91,364 +DA:92,364 DA:95,0 -DA:382,2 -FN:382,RightsPolicyAuthorizerHandler.constructor -FNDA:2,RightsPolicyAuthorizerHandler.constructor -DA:383,2 -DA:384,2 -DA:385,2 -DA:386,2 -DA:388,2 -DA:389,6 -DA:390,6 -DA:391,6 -DA:395,25052 -FN:395,RightsPolicyAuthorizerHandler._audit -FNDA:25052,RightsPolicyAuthorizerHandler._audit -DA:398,11370 -DA:399,11370 -BRDA:399,1,0,11370 -DA:401,11370 -DA:402,11370 -BRDA:402,2,0,11370 -DA:403,6 -DA:406,11370 -BRDA:406,3,0,- -DA:407,0 -DA:411,0 -FN:411,RightsPolicyAuthorizerHandler.policiesLength -FNDA:0,RightsPolicyAuthorizerHandler.policiesLength -DA:412,0 -DA:415,0 -FN:415,RightsPolicyAuthorizerHandler.policyAt -FNDA:0,RightsPolicyAuthorizerHandler.policyAt -DA:416,0 -DA:419,0 -FN:419,RightsPolicyAuthorizerHandler.isAuthorized -FNDA:0,RightsPolicyAuthorizerHandler.isAuthorized -DA:420,0 -DA:423,16746 -FN:423,RightsPolicyAuthorizerHandler.authorize -FNDA:16746,RightsPolicyAuthorizerHandler.authorize -DA:424,16746 -DA:425,16746 -DA:427,16746 -DA:428,16746 -DA:430,9172 -DA:431,9172 -BRDA:431,5,0,9172 -DA:432,5681 -DA:436,16716 -FN:436,RightsPolicyAuthorizerHandler.revoke -FNDA:16716,RightsPolicyAuthorizerHandler.revoke -DA:437,16716 -DA:438,16716 -DA:439,16716 -DA:441,3287 -DA:442,3287 -BRDA:442,7,0,3287 -DA:443,3287 -DA:447,16588 -FN:447,RightsPolicyAuthorizerHandler.toggleAudit -FNDA:16588,RightsPolicyAuthorizerHandler.toggleAudit -DA:448,16588 -DA:449,16588 -DA:451,8300 -BRDA:451,8,0,8300 -BRDA:451,8,1,- -DA:452,8300 -DA:453,4552 -BRDA:453,9,0,4552 -DA:454,4552 -DA:455,4552 -BRDA:455,10,0,4552 -DA:456,4552 -DA:457,4552 -FNF:21 +FN:95,PolicyBaseAuthorizerHarness.enforce +FNDA:0,PolicyBaseAuthorizerHarness.enforce +DA:96,0 +DA:99,0 +FN:99,PolicyBaseAuthorizerHarness.isAccessAllowed +FNDA:0,PolicyBaseAuthorizerHarness.isAccessAllowed +DA:100,0 +DA:104,0 +FN:104,PolicyBaseAuthorizerHarness.resolveTerms +FNDA:0,PolicyBaseAuthorizerHarness.resolveTerms +DA:106,0 +FN:106,PolicyBaseAuthorizerHarness.name +FNDA:0,PolicyBaseAuthorizerHarness.name +DA:107,0 +DA:110,0 +FN:110,PolicyBaseAuthorizerHarness.description +FNDA:0,PolicyBaseAuthorizerHarness.description +DA:111,0 +FNF:16 +FNH:7 +LF:40 +LH:21 +BRF:4 +BRH:3 +end_of_record +TN: +SF:test/rights/RightsPolicyManager.t.sol +DA:35,494 +FN:35,ConfigurableAttestationProvider.setNextAttestationIds +FNDA:494,ConfigurableAttestationProvider.setNextAttestationIds +DA:36,494 +DA:37,494 +DA:38,494 +DA:39,495 +DA:43,0 +FN:43,ConfigurableAttestationProvider.getName +FNDA:0,ConfigurableAttestationProvider.getName +DA:44,0 +DA:47,0 +FN:47,ConfigurableAttestationProvider.getAddress +FNDA:0,ConfigurableAttestationProvider.getAddress +DA:48,0 +DA:51,494 +FN:51,ConfigurableAttestationProvider.attest +FNDA:494,ConfigurableAttestationProvider.attest +DA:56,494 +DA:57,494 +DA:58,494 +DA:59,495 +DA:62,494 +DA:63,494 +DA:64,494 +DA:66,494 +DA:67,494 +DA:69,494 +BRDA:69,1,0,494 +BRDA:69,1,1,- +DA:70,494 +BRDA:70,2,0,- +BRDA:70,2,1,- +DA:71,494 +DA:72,495 +DA:74,494 +DA:76,0 +DA:77,0 +DA:81,494 +DA:82,495 +DA:84,0 +DA:87,0 +FN:87,ConfigurableAttestationProvider.verify +FNDA:0,ConfigurableAttestationProvider.verify +DA:88,0 +DA:91,0 +FN:91,ConfigurableAttestationProvider.lastRecipientsLength +FNDA:0,ConfigurableAttestationProvider.lastRecipientsLength +DA:92,0 +DA:95,0 +FN:95,ConfigurableAttestationProvider.lastRecipientAt +FNDA:0,ConfigurableAttestationProvider.lastRecipientAt +DA:96,0 +DA:118,0 +FN:118,PolicyBaseManagerHarness.setSetupRevert +FNDA:0,PolicyBaseManagerHarness.setSetupRevert +DA:119,0 +DA:122,5 +FN:122,PolicyBaseManagerHarness.setAccessAllowed +FNDA:5,PolicyBaseManagerHarness.setAccessAllowed +DA:123,5 +DA:126,1 +FN:126,PolicyBaseManagerHarness.setAccessRevert +FNDA:1,PolicyBaseManagerHarness.setAccessRevert +DA:127,1 +DA:130,1 +FN:130,PolicyBaseManagerHarness.setEnforceRevert +FNDA:1,PolicyBaseManagerHarness.setEnforceRevert +DA:131,1 +DA:134,1 +FN:134,PolicyBaseManagerHarness.lastHolder +FNDA:1,PolicyBaseManagerHarness.lastHolder +DA:135,1 +DA:138,0 +FN:138,PolicyBaseManagerHarness.lastSetupData +FNDA:0,PolicyBaseManagerHarness.lastSetupData +DA:139,0 +DA:142,1 +FN:142,PolicyBaseManagerHarness.getLastAgreement +FNDA:1,PolicyBaseManagerHarness.getLastAgreement +DA:143,1 +DA:146,266 +FN:146,PolicyBaseManagerHarness.setup +FNDA:266,PolicyBaseManagerHarness.setup +DA:147,0 +BRDA:147,0,0,- +DA:148,266 +DA:149,266 +DA:152,495 +FN:152,PolicyBaseManagerHarness.enforce +FNDA:495,PolicyBaseManagerHarness.enforce +DA:156,1 +BRDA:156,1,0,1 +DA:157,494 +DA:158,494 +DA:160,494 +DA:161,494 +DA:163,494 +DA:164,494 +DA:165,494 +DA:166,495 +DA:170,6 +FN:170,PolicyBaseManagerHarness.isAccessAllowed +FNDA:6,PolicyBaseManagerHarness.isAccessAllowed +DA:171,1 +BRDA:171,2,0,1 +DA:172,5 +DA:175,0 +FN:175,PolicyBaseManagerHarness.resolveTerms +FNDA:0,PolicyBaseManagerHarness.resolveTerms +DA:177,0 +FN:177,PolicyBaseManagerHarness.name +FNDA:0,PolicyBaseManagerHarness.name +DA:178,0 +DA:181,0 +FN:181,PolicyBaseManagerHarness.description +FNDA:0,PolicyBaseManagerHarness.description +DA:182,0 +FNF:20 FNH:10 -LF:78 -LH:52 -BRF:10 -BRH:7 +LF:71 +LH:48 +BRF:7 +BRH:3 end_of_record diff --git a/packages/protocol/package.json b/packages/protocol/package.json index 8cd6eb4..6d3f0ff 100644 --- a/packages/protocol/package.json +++ b/packages/protocol/package.json @@ -1,6 +1,6 @@ { "name": "@synaps3/protocol", - "version": "1.10.13", + "version": "1.10.16", "description": "Core contracts for the Synapse Protocol", "homepage": "https://github.com/Synaps3Protocol/protocol-core-v1#readme", "license": "BUSL-1.1", diff --git a/packages/types/package.json b/packages/types/package.json index 61cf82e..24f3851 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@synaps3/types", - "version": "1.10.11", + "version": "1.10.12", "description": "Essential interfaces and types for Synapse Protocol.", "homepage": "https://github.com/Synaps3Protocol/protocol-core-v1#readme", "license": "BUSL-1.1", diff --git a/script/orchestration/01_Orchestrate_ProtocolHydration.s.sol b/script/orchestration/01_Orchestrate_ProtocolHydration.s.sol index 426a17e..7918e62 100644 --- a/script/orchestration/01_Orchestrate_ProtocolHydration.s.sol +++ b/script/orchestration/01_Orchestrate_ProtocolHydration.s.sol @@ -14,6 +14,7 @@ import { getGovPermissions as AssetReferendumGovPermissions } from "script/permi import { getModPermissions as PolicyAuditorModPermissions } from "script/permissions/Permissions_PolicyAuditor.sol"; import { getOpsPermissions as LedgerVaultOpsPermissions } from "script/permissions/Permissions_LedgerVault.sol"; import { getModPermissions as HooksModPermissions } from "script/permissions/Permissions_HookRegistry.sol"; +import { getPauserPermissions as PauserPermissions } from "script/permissions/Permissions_AccessControlled.sol"; contract OrchestrateProtocolHydration is Script { function run() external { @@ -22,6 +23,7 @@ contract OrchestrateProtocolHydration is Script { address treasuryAddress = vm.envAddress("TREASURY"); address auditorAddress = vm.envAddress("POLICY_AUDIT"); address accessManager = vm.envAddress("ACCESS_MANAGER"); + address assetRegistry = vm.envAddress("ASSET_REGISTRY"); address assetReferendum = vm.envAddress("ASSET_REFERENDUM"); address agreementManager = vm.envAddress("AGREEMENT_MANAGER"); address agreementSettler = vm.envAddress("AGREEMENT_SETTLER"); @@ -35,28 +37,41 @@ contract OrchestrateProtocolHydration is Script { // initially the admin will be the mod to setup policies address adminAddress = vm.addr(admin); IAccessManager authority = IAccessManager(accessManager); + // the governor is set to admin to handle initial setup.. - // after this can be revoked and assign the governance as governor + // after this can be revoked and assign the governance timelock as governor + // https://docs.openzeppelin.com/contracts/5.x/access-control#role-admins-and-guardians authority.grantRole(C.GOV_ROLE, adminAddress, 0); + authority.grantRole(C.OPS_ROLE, agreementManager, 0); + authority.grantRole(C.OPS_ROLE, agreementSettler, 0); + // assign governance permissions + bytes4[] memory pauserAllowed = PauserPermissions(); + bytes4[] memory vaultAllowed = LedgerVaultOpsPermissions(); bytes4[] memory tollgateAllowed = TollgateGovPermissions(); bytes4[] memory treasuryAllowed = TreasuryGovPermissions(); + bytes4[] memory auditorAllowed = PolicyAuditorModPermissions(); bytes4[] memory assetReferendumAllowed = AssetReferendumGovPermissions(); bytes4[] memory custodianReferendumAllowed = CustodianReferendumGovPermissions(); + // pausable list of contracts + authority.setTargetFunctionRole(assetRegistry, pauserAllowed, C.SEC_ROLE); + authority.setTargetFunctionRole(ledgerVault, pauserAllowed, C.SEC_ROLE); + authority.setTargetFunctionRole(treasuryAddress, pauserAllowed, C.SEC_ROLE); + authority.setTargetFunctionRole(custodianReferendum, pauserAllowed, C.SEC_ROLE); + authority.setTargetFunctionRole(tollgateAddress, tollgateAllowed, C.GOV_ROLE); authority.setTargetFunctionRole(treasuryAddress, treasuryAllowed, C.GOV_ROLE); + + authority.setTargetFunctionRole(treasuryAddress, treasuryAllowed, C.TREASURER_ROLE); authority.setTargetFunctionRole(assetReferendum, assetReferendumAllowed, C.CONTENT_COUNCIL_ROLE); authority.setTargetFunctionRole(custodianReferendum, custodianReferendumAllowed, C.CUSTODY_COUNCIL_ROLE); - // assign operations permissions - authority.grantRole(C.OPS_ROLE, agreementManager, 0); - authority.grantRole(C.OPS_ROLE, agreementSettler, 0); - bytes4[] memory vaultAllowed = LedgerVaultOpsPermissions(); authority.setTargetFunctionRole(ledgerVault, vaultAllowed, C.OPS_ROLE); - - + authority.setTargetFunctionRole(auditorAddress, auditorAllowed, C.ADMIN_ROLE); + // bytes4[] memory hookModAllowed = HooksModPermissions(); + // authority.setTargetFunctionRole(auditorAddress, hookModAllowed, C.MOD_ROLE); // 2 set mmc as the initial currency and fees uint256 agrFee = vm.envUint("AGREEMENT_FEES"); // 5% 500 bps diff --git a/script/permissions/Permissions_AccessControlled.sol b/script/permissions/Permissions_AccessControlled.sol new file mode 100644 index 0000000..741c361 --- /dev/null +++ b/script/permissions/Permissions_AccessControlled.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; +import { AccessControlledUpgradeable } from "contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol"; +import { AssetRegistry } from "contracts/assets/AssetRegistry.sol"; + +function getPauserPermissions() pure returns (bytes4[] memory) { + // AssetReferendum grant access to governance + bytes4[] memory accessControlled = new bytes4[](3); + accessControlled[0] = AccessControlledUpgradeable.pause.selector; + accessControlled[0] = AccessControlledUpgradeable.unpause.selector; + return accessControlled; +} + diff --git a/test/BaseTest.t.sol b/test/BaseTest.t.sol index d1f1b07..842258a 100644 --- a/test/BaseTest.t.sol +++ b/test/BaseTest.t.sol @@ -18,6 +18,7 @@ import { DeployAgreementManager } from "script/deployment/07_Deploy_Financial_Ag import { DeployAgreementSettler } from "script/deployment/08_Deploy_Financial_AgreementSettler.s.sol"; import { DeployRightsAssetCustodian } from "script/deployment/15_Deploy_RightsManager_AssetCustodian.s.sol"; import { DeployRightsPolicyAuthorizer } from "script/deployment/18_Deploy_RightsManager_PolicyAuthorizer.s.sol"; +import { DeployRightsPolicyManager } from "script/deployment/17_Deploy_RightsManager_PolicyManager.s.sol"; import { DeployPolicyAudit } from "script/deployment/14_Deploy_Policies_PolicyAudit.s.sol"; import { getGovPermissions as TollgateGovPermissions } from "script/permissions/Permissions_Tollgate.sol"; @@ -230,6 +231,14 @@ abstract contract BaseTest is Test { : rightsPolicyAuthorizer; } + function deployRightsPolicyManager() public { + deployAgreementSettler(); + deployRightsPolicyAuthorizer(); + + DeployRightsPolicyManager rightsManagerDeployer = new DeployRightsPolicyManager(); + rightsPolicyManager = rightsPolicyManager == address(0) ? rightsManagerDeployer.run() : rightsPolicyManager; + } + function _setContentCouncilPermissions(address target, bytes4[] memory allowed) public { vm.startPrank(admin); IAccessManager authority = IAccessManager(accessManager); diff --git a/test/assets/AssetReferendum.t.sol b/test/assets/AssetReferendum.t.sol index 6b900f3..5631814 100644 --- a/test/assets/AssetReferendum.t.sol +++ b/test/assets/AssetReferendum.t.sol @@ -6,109 +6,11 @@ import { IAssetReferendumRegistrable } from "contracts/core/interfaces/assets/IA import { IAssetReferendumRevokable } from "contracts/core/interfaces/assets/IAssetReferendumRevokable.sol"; import { IAssetReferendumVerifiable } from "contracts/core/interfaces/assets/IAssetReferendumVerifiable.sol"; import { AssetReferendum } from "contracts/assets/AssetReferendum.sol"; +import { IAccessManager } from "contracts/core/interfaces/access/IAccessManager.sol"; +import { C } from "contracts/core/primitives/Constants.sol"; import { BaseTest } from "test/BaseTest.t.sol"; -contract AssetReferendumHandler is Test { - enum Status { - None, - Submitted, - Approved, - Rejected, - Revoked - } - - struct AssetState { - Status status; - address submitter; - } - - address public immutable referendum; - address public immutable council; - - address[] public actors; - - uint256[] private _trackedAssets; - mapping(uint256 => AssetState) private _assets; - - constructor(address referendum_, address council_) { - referendum = referendum_; - council = council_; - - for (uint256 i = 0; i < 6; i++) { - actors.push(vm.addr(i + 111)); - } - } - - function submit(uint256 assetSeed, uint256 actorSeed) external { - if (actors.length == 0) return; - - uint256 assetId = bound(assetSeed, 1, type(uint128).max); - AssetState storage state = _assets[assetId]; - if (state.status != Status.None) return; - - address submitter = actors[actorSeed % actors.length]; - - vm.prank(submitter); - IAssetReferendumRegistrable(referendum).submit(assetId); - - state.status = Status.Submitted; - state.submitter = submitter; - _trackedAssets.push(assetId); - } - - function approve(uint256 assetSeed) external { - if (_trackedAssets.length == 0) return; - - uint256 assetId = _trackedAssets[assetSeed % _trackedAssets.length]; - AssetState storage state = _assets[assetId]; - if (state.status != Status.Submitted) return; - - vm.prank(council); - IAssetReferendumRegistrable(referendum).approve(assetId); - - state.status = Status.Approved; - } - - function reject(uint256 assetSeed) external { - if (_trackedAssets.length == 0) return; - - uint256 assetId = _trackedAssets[assetSeed % _trackedAssets.length]; - AssetState storage state = _assets[assetId]; - if (state.status != Status.Submitted) return; - - vm.prank(council); - IAssetReferendumRevokable(referendum).reject(assetId); - - state.status = Status.Rejected; - } - - function revoke(uint256 assetSeed) external { - if (_trackedAssets.length == 0) return; - - uint256 assetId = _trackedAssets[assetSeed % _trackedAssets.length]; - AssetState storage state = _assets[assetId]; - if (state.status != Status.Approved) return; - - vm.prank(council); - IAssetReferendumRevokable(referendum).revoke(assetId); - - state.status = Status.Revoked; - } - - function trackedLength() external view returns (uint256) { - return _trackedAssets.length; - } - - function trackedAt(uint256 index) external view returns (uint256) { - return _trackedAssets[index]; - } - - function stateOf(uint256 assetId) external view returns (AssetState memory) { - return _assets[assetId]; - } -} - contract AssetReferendumTest is BaseTest { function setUp() public initialize { // setup the access manager to use during tests.. @@ -130,6 +32,15 @@ contract AssetReferendumTest is BaseTest { assertFalse(referendum.isApproved(user, 1), "Asset should not be approved yet"); } + function test_Submit_RevertsWhenDuplicate() public { + uint256 assetId = 22; + _submitContentAsUser(assetId); + + vm.prank(user); + vm.expectRevert(abi.encodeWithSelector(AssetReferendum.SubmissionFailed.selector, user, assetId)); + IAssetReferendumRegistrable(assetReferendum).submit(assetId); + } + function test_Approve_ApprovedEventEmitted() public { uint256 assetId = 1; _submitContentAsUser(assetId); @@ -255,6 +166,17 @@ contract AssetReferendumTest is BaseTest { assertFalse(referendum.isApproved(submitter, assetId), "Revoked asset should not be approved"); } + function test_IsApproved_ReturnsTrueForVerifiedAccount() public { + address verified = vm.addr(77); + IAccessManager authority = IAccessManager(accessManager); + + vm.prank(governor); + authority.grantRole(C.VER_ROLE, verified, 0); + + IAssetReferendumVerifiable referendum = IAssetReferendumVerifiable(assetReferendum); + assertTrue(referendum.isApproved(verified, 999), "Verified account should bypass submission requirement"); + } + function _submitAndApproveContent(uint256 assetId) internal { _submitContentAsUser(assetId); vm.warp(1641070805); @@ -268,60 +190,3 @@ contract AssetReferendumTest is BaseTest { IAssetReferendumRegistrable(assetReferendum).submit(assetId); } } - -contract AssetReferendumInvariantTest is BaseTest { - AssetReferendumHandler handler; - - function setUp() public initialize { - deployAssetReferendum(); - - handler = new AssetReferendumHandler(assetReferendum, contentCouncil); - targetContract(address(handler)); - } - - function invariant_StateAlignment() external view { - IAssetReferendumVerifiable referendum = IAssetReferendumVerifiable(assetReferendum); - uint256 len = handler.trackedLength(); - - for (uint256 i = 0; i < len; i++) { - uint256 assetId = handler.trackedAt(i); - AssetReferendumHandler.AssetState memory state = handler.stateOf(assetId); - - if (state.status == AssetReferendumHandler.Status.None) { - continue; - } - - bool isActive = referendum.isActive(assetId); - bool isApproved = referendum.isApproved(state.submitter, assetId); - - if (state.status == AssetReferendumHandler.Status.Submitted) { - assertFalse(isActive, "Submitted asset should be inactive"); - assertFalse(isApproved, "Submitted asset should not be approved"); - } else if (state.status == AssetReferendumHandler.Status.Approved) { - assertTrue(isActive, "Approved asset should be active"); - assertTrue(isApproved, "Approved asset should be approved for submitter"); - } else if (state.status == AssetReferendumHandler.Status.Rejected) { - assertFalse(isActive, "Rejected asset should be inactive"); - assertFalse(isApproved, "Rejected asset should not be approved"); - } else if (state.status == AssetReferendumHandler.Status.Revoked) { - assertFalse(isActive, "Revoked asset should be inactive"); - assertFalse(isApproved, "Revoked asset should not be approved"); - } - } - } - - function invariant_NoApprovedWithoutSubmitter() external view { - IAssetReferendumVerifiable referendum = IAssetReferendumVerifiable(assetReferendum); - uint256 len = handler.trackedLength(); - - for (uint256 i = 0; i < len; i++) { - uint256 assetId = handler.trackedAt(i); - AssetReferendumHandler.AssetState memory state = handler.stateOf(assetId); - - if (state.status == AssetReferendumHandler.Status.Approved) { - assertTrue(state.submitter != address(0), "Approved asset must track submitter"); - assertTrue(referendum.isApproved(state.submitter, assetId), "Approved asset must stay approved"); - } - } - } -} diff --git a/test/assets/AssetRegistry.t.sol b/test/assets/AssetRegistry.t.sol index 6d084d0..80134c3 100644 --- a/test/assets/AssetRegistry.t.sol +++ b/test/assets/AssetRegistry.t.sol @@ -6,119 +6,10 @@ import { AssetRegistry } from "contracts/assets/AssetRegistry.sol"; import { IAssetRegistry } from "contracts/core/interfaces/assets/IAssetRegistry.sol"; import { IAssetReferendumRegistrable } from "contracts/core/interfaces/assets/IAssetReferendumRegistrable.sol"; import { IERC721StatefulVerifiable } from "contracts/core/interfaces/token/erc721/IERC721StatefulVerifiable.sol"; +import { IAccessManaged } from "@openzeppelin/contracts/access/manager/IAccessManaged.sol"; import { BaseTest } from "test/BaseTest.t.sol"; -contract AssetRegistryHandler is Test { - struct AssetInfo { - bool exists; - bool revoked; - bool active; - address owner; - } - - AssetRegistry public registry; - address public referendum; - address public contentCouncil; - address public admin; - address[] public actors; - - uint256[] private _assetIds; - mapping(uint256 => AssetInfo) private _assets; - - constructor(address registry_, address referendum_, address contentCouncil_, address admin_) { - registry = AssetRegistry(registry_); - referendum = referendum_; - contentCouncil = contentCouncil_; - admin = admin_; - - actors.push(contentCouncil_); - for (uint256 i = 0; i < 5; i++) { - actors.push(vm.addr(i + 100)); - } - } - - function register(uint256 assetSeed, uint256 actorSeed) external { - if (actors.length == 0) return; - - uint256 assetId = bound(assetSeed, 1, type(uint128).max); - AssetInfo storage info = _assets[assetId]; - if (info.exists) return; - - address submitter = actors[actorSeed % actors.length]; - - vm.prank(submitter); - IAssetReferendumRegistrable(referendum).submit(assetId); - - vm.prank(contentCouncil); - IAssetReferendumRegistrable(referendum).approve(assetId); - - vm.prank(submitter); - registry.register(submitter, assetId); - - info.exists = true; - info.revoked = false; - info.active = true; - info.owner = submitter; - _assetIds.push(assetId); - } - - function transfer(uint256 tokenSeed, uint256 targetSeed) external { - if (_assetIds.length == 0) return; - - uint256 assetId = _assetIds[tokenSeed % _assetIds.length]; - AssetInfo storage info = _assets[assetId]; - if (!info.exists || info.revoked) return; - - address newOwner = actors[targetSeed % actors.length]; - if (newOwner == address(0) || newOwner == info.owner) return; - - vm.prank(info.owner); - registry.transfer(newOwner, assetId); - - info.owner = newOwner; - } - - function switchState(uint256 tokenSeed) external { - if (_assetIds.length == 0) return; - - uint256 assetId = _assetIds[tokenSeed % _assetIds.length]; - AssetInfo storage info = _assets[assetId]; - if (!info.exists || info.revoked) return; - - vm.prank(info.owner); - bool newState = registry.switchState(assetId); - info.active = newState; - } - - function revoke(uint256 tokenSeed) external { - if (_assetIds.length == 0) return; - - uint256 assetId = _assetIds[tokenSeed % _assetIds.length]; - AssetInfo storage info = _assets[assetId]; - if (!info.exists || info.revoked) return; - - vm.prank(admin); - registry.revoke(assetId); - - info.revoked = true; - info.active = false; - info.owner = address(0); - } - - function assetIdsLength() external view returns (uint256) { - return _assetIds.length; - } - - function assetIdAt(uint256 index) external view returns (uint256) { - return _assetIds[index]; - } - - function getAssetInfo(uint256 assetId) external view returns (AssetInfo memory) { - return _assets[assetId]; - } -} - contract AssetRegistryTest is BaseTest { function setUp() public initialize { // setup the access manager to use during tests.. @@ -140,7 +31,9 @@ contract AssetRegistryTest is BaseTest { IAssetRegistry(assetRegistry).register(user, assetId); assertEq(IAssetRegistry(assetRegistry).ownerOf(assetId), user, "Invalid unexpected owner"); - assertEq(IERC721StatefulVerifiable(assetRegistry).isActive(assetId), true, "Asset must be active"); + assertTrue(IERC721StatefulVerifiable(assetRegistry).isActive(assetId), "Asset must be active"); + assertEq(AssetRegistry(assetRegistry).totalSupply(), 1, "Total supply should reflect minted asset"); + assertEq(IAssetRegistry(assetRegistry).balanceOf(user), 1, "Owner balance should increment"); } function test_Register_RevertWhen_NotApproved() public { @@ -151,21 +44,6 @@ contract AssetRegistryTest is BaseTest { IAssetRegistry(assetRegistry).register(user, assetId); } - function testFuzz_Register_SetsOwnerAndActivates(address to, uint256 assetId) public { - vm.assume(to != address(0)); - assetId = bound(assetId, 1, type(uint128).max); - - _submitAndApproveAsset(to, assetId); - - vm.prank(to); - IAssetRegistry(assetRegistry).register(to, assetId); - - assertEq(IAssetRegistry(assetRegistry).ownerOf(assetId), to, "Unexpected owner after register"); - assertTrue(IERC721StatefulVerifiable(assetRegistry).isActive(assetId), "Asset should be active"); - assertEq(IAssetRegistry(assetRegistry).balanceOf(to), 1, "Balance should account for minted asset"); - assertEq(AssetRegistry(assetRegistry).totalSupply(), 1, "Total supply should match minted assets"); - } - function test_Register_RevertWhen_DuplicateAsset() public { uint256 assetId = 21; _submitAndApproveAsset(user, assetId); @@ -234,6 +112,24 @@ contract AssetRegistryTest is BaseTest { assertTrue(IERC721StatefulVerifiable(assetRegistry).isActive(assetId), "Asset should be active again"); } + function test_SwitchState_RevertWhen_NotOwner() public { + uint256 assetId = 52; + address stranger = vm.addr(777); + + _submitAndApproveAsset(user, assetId); + vm.prank(user); + IAssetRegistry(assetRegistry).register(user, assetId); + + vm.expectRevert( + abi.encodeWithSignature( + "InvalidUnauthorizedOperation(string)", + "Only the asset owner can modify its state." + ) + ); + vm.prank(stranger); + AssetRegistry(assetRegistry).switchState(assetId); + } + function test_Revoke_DisablesAndBurns() public { uint256 assetId = 61; _submitAndApproveAsset(user, assetId); @@ -254,6 +150,18 @@ contract AssetRegistryTest is BaseTest { IAssetRegistry(assetRegistry).ownerOf(assetId); } + function test_Revoke_RevertWhen_NotAdmin() public { + uint256 assetId = 71; + _submitAndApproveAsset(user, assetId); + + vm.prank(user); + IAssetRegistry(assetRegistry).register(user, assetId); + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, user)); + vm.prank(user); + AssetRegistry(assetRegistry).revoke(assetId); + } + function _submitAndApproveAsset(address submitter, uint256 assetId) private { vm.prank(submitter); IAssetReferendumRegistrable(assetReferendum).submit(assetId); @@ -262,66 +170,3 @@ contract AssetRegistryTest is BaseTest { IAssetReferendumRegistrable(assetReferendum).approve(assetId); } } - -contract AssetRegistryInvariantTest is BaseTest { - AssetRegistryHandler handler; - - function setUp() public initialize { - deployAssetRegistry(); - - handler = new AssetRegistryHandler(assetRegistry, assetReferendum, contentCouncil, admin); - targetContract(address(handler)); - } - - function invariant_TotalSupplyMatchesTracked() external view { - uint256 len = handler.assetIdsLength(); - uint256 expectedSupply = 0; - - for (uint256 i = 0; i < len; i++) { - uint256 assetId = handler.assetIdAt(i); - AssetRegistryHandler.AssetInfo memory info = handler.getAssetInfo(assetId); - if (info.exists && !info.revoked) { - expectedSupply++; - } - } - - assertEq(AssetRegistry(assetRegistry).totalSupply(), expectedSupply, "Total supply mismatch"); - } - - function invariant_TrackedOwnerMatchesRegistry() external view { - uint256 len = handler.assetIdsLength(); - - for (uint256 i = 0; i < len; i++) { - uint256 assetId = handler.assetIdAt(i); - AssetRegistryHandler.AssetInfo memory info = handler.getAssetInfo(assetId); - - if (!info.exists || info.revoked) { - continue; - } - - assertEq(info.owner, IAssetRegistry(assetRegistry).ownerOf(assetId), "Tracked owner mismatch"); - assertTrue(info.owner != address(0), "Active asset cannot have zero owner"); - } - } - - function invariant_ActiveFlagMatchesRegistryState() external view { - uint256 len = handler.assetIdsLength(); - - for (uint256 i = 0; i < len; i++) { - uint256 assetId = handler.assetIdAt(i); - AssetRegistryHandler.AssetInfo memory info = handler.getAssetInfo(assetId); - - if (!info.exists) { - continue; - } - - bool isActiveOnChain = IERC721StatefulVerifiable(assetRegistry).isActive(assetId); - - if (info.revoked) { - assertFalse(isActiveOnChain, "Revoked asset should be inactive on chain"); - } else { - assertEq(isActiveOnChain, info.active, "Active flag mismatch"); - } - } - } -} diff --git a/test/assets/AssetSafe.t.sol b/test/assets/AssetSafe.t.sol index ae166cf..9c7d0b4 100644 --- a/test/assets/AssetSafe.t.sol +++ b/test/assets/AssetSafe.t.sol @@ -10,136 +10,10 @@ import { AssetSafe } from "contracts/assets/AssetSafe.sol"; import { BaseTest } from "test/BaseTest.t.sol"; import { T } from "contracts/core/primitives/Types.sol"; -contract AssetSafeHandler is Test { - address public immutable safe; - address public immutable registry; - address public immutable referendum; - address public immutable contentCouncil; - - address[] public actors; - - uint256[] private _assetIds; - mapping(uint256 => bool) private _isTracked; - mapping(uint256 => address) private _owners; - mapping(uint256 => mapping(uint8 => bytes)) private _content; - mapping(uint256 => mapping(uint8 => bool)) private _hasContent; - mapping(uint256 => uint8) private _latestCipher; - mapping(uint256 => bool) private _hasLatestCipher; - - constructor(address safe_, address registry_, address referendum_, address contentCouncil_) { - safe = safe_; - registry = registry_; - referendum = referendum_; - contentCouncil = contentCouncil_; - - for (uint256 i = 0; i < 6; i++) { - actors.push(vm.addr(i + 501)); - } - } - - function registerAsset(uint256 assetSeed, uint256 actorSeed) external { - if (actors.length == 0) return; - - uint256 assetId = bound(assetSeed, 1, type(uint128).max); - if (_isTracked[assetId]) return; - - address owner = actors[actorSeed % actors.length]; - if (owner == address(0)) return; - - vm.prank(owner); - IAssetReferendumRegistrable(referendum).submit(assetId); - - vm.prank(contentCouncil); - IAssetReferendumRegistrable(referendum).approve(assetId); - - vm.prank(owner); - IAssetRegistry(registry).register(owner, assetId); - - _isTracked[assetId] = true; - _owners[assetId] = owner; - _assetIds.push(assetId); - } - - function transferAsset(uint256 assetSeed, uint256 actorSeed) external { - if (_assetIds.length == 0) return; - - uint256 assetId = _assetIds[assetSeed % _assetIds.length]; - if (!_isTracked[assetId]) return; - - address currentOwner = _owners[assetId]; - if (currentOwner == address(0)) return; - - address newOwner = actors[actorSeed % actors.length]; - if (newOwner == address(0) || newOwner == currentOwner) return; - - vm.prank(currentOwner); - IAssetRegistry(registry).transfer(newOwner, assetId); - - _owners[assetId] = newOwner; - } - - function setContent(uint256 assetSeed, uint8 cipherSeed, uint256 dataSeed) external { - if (_assetIds.length == 0) return; - - uint256 assetId = _assetIds[assetSeed % _assetIds.length]; - if (!_isTracked[assetId]) return; - - address owner = _owners[assetId]; - if (owner == address(0)) return; - - uint8 cipherIndex = uint8(bound(cipherSeed, 1, uint8(T.Cipher.EC))); - T.Cipher cipher = T.Cipher(cipherIndex); - bytes memory data = abi.encode(dataSeed); - - vm.prank(owner); - IAssetSafe(safe).setContent(assetId, cipher, data); - - _content[assetId][cipherIndex] = data; - _hasContent[assetId][cipherIndex] = true; - _latestCipher[assetId] = cipherIndex; - _hasLatestCipher[assetId] = true; - } - - function trackedLength() external view returns (uint256) { - return _assetIds.length; - } - - function trackedAt(uint256 index) external view returns (uint256) { - return _assetIds[index]; - } - - function ownerOf(uint256 assetId) external view returns (address) { - return _owners[assetId]; - } - - function isTracked(uint256 assetId) external view returns (bool) { - return _isTracked[assetId]; - } - - function hasContent(uint256 assetId, uint8 cipherIndex) external view returns (bool) { - return _hasContent[assetId][cipherIndex]; - } - - function contentOf(uint256 assetId, uint8 cipherIndex) external view returns (bytes memory) { - return _content[assetId][cipherIndex]; - } - - function hasLatestCipher(uint256 assetId) external view returns (bool) { - return _hasLatestCipher[assetId]; - } - - function latestCipher(uint256 assetId) external view returns (uint8) { - return _latestCipher[assetId]; - } -} - contract AssetSafeTest is BaseTest { - - function setUp() public initialize { // setup the access manager to use during tests.. deployAssetSafe(); - } function test_SetContent_ValidOwner() public { @@ -175,6 +49,27 @@ contract AssetSafeTest is BaseTest { safe.setContent(assetId, T.Cipher.LIT, ""); } + function test_SetContent_MultipleCiphersUpdatesTypeOnly() public { + uint256 assetId = 222; + _registerAndApproveAsset(user, assetId); + IAssetSafe safe = IAssetSafe(assetSafe); + + bytes memory litData = bytes("first"); + vm.prank(user); + safe.setContent(assetId, T.Cipher.LIT, litData); + + bytes memory ecData = bytes("second"); + vm.prank(user); + safe.setContent(assetId, T.Cipher.EC, ecData); + + // Latest cipher should be EC + assertEq(uint8(safe.getType(assetId)), uint8(T.Cipher.EC), "Cipher type should reflect last write"); + // New cipher data stored + assertEq(keccak256(safe.getContent(assetId, T.Cipher.EC)), keccak256(ecData), "EC payload mismatch"); + // Previous cipher data remains accessible + assertEq(keccak256(safe.getContent(assetId, T.Cipher.LIT)), keccak256(litData), "LIT payload should remain"); + } + function test_SetContent_ValidScheme() public { vm.warp(1641070800); uint256 assetId = 123456; @@ -214,6 +109,12 @@ contract AssetSafeTest is BaseTest { assertEq(keccak256(abi.encodePacked(expected)), keccak256(abi.encodePacked(b64)), "Content should match the expected data"); } + function test_GetContent_ReturnsEmptyWhenNotSet() public view { + IAssetSafe safe = IAssetSafe(assetSafe); + bytes memory raw = safe.getContent(98765, T.Cipher.LIT); + assertEq(raw.length, 0, "Unset content should return empty bytes"); + } + function testFuzz_SetContent_StoresData( address owner, uint256 assetId, @@ -266,68 +167,3 @@ contract AssetSafeTest is BaseTest { IAssetRegistry(assetRegistry).register(to, assetId); } } - -contract AssetSafeInvariantTest is BaseTest { - AssetSafeHandler handler; - uint8 private constant MAX_CIPHER = uint8(T.Cipher.EC); - - function setUp() public initialize { - deployAssetSafe(); - - handler = new AssetSafeHandler(assetSafe, assetRegistry, assetReferendum, contentCouncil); - targetContract(address(handler)); - } - - function invariant_OwnerMatchesRegistry() external view { - IAssetRegistry registryContract = IAssetRegistry(assetRegistry); - uint256 len = handler.trackedLength(); - - for (uint256 i = 0; i < len; i++) { - uint256 assetId = handler.trackedAt(i); - if (!handler.isTracked(assetId)) { - continue; - } - - address expectedOwner = handler.ownerOf(assetId); - if (expectedOwner == address(0)) { - continue; - } - - assertEq(registryContract.ownerOf(assetId), expectedOwner, "Handler owner should match registry owner"); - } - } - - function invariant_ContentMatchesStored() external view { - IAssetSafe safeContract = IAssetSafe(assetSafe); - uint256 len = handler.trackedLength(); - - for (uint256 i = 0; i < len; i++) { - uint256 assetId = handler.trackedAt(i); - - for (uint8 cipherIndex = 1; cipherIndex <= MAX_CIPHER; cipherIndex++) { - if (!handler.hasContent(assetId, cipherIndex)) { - continue; - } - - bytes memory expected = handler.contentOf(assetId, cipherIndex); - bytes memory actual = safeContract.getContent(assetId, T.Cipher(cipherIndex)); - assertEq(keccak256(actual), keccak256(expected), "Stored content should match handler state"); - } - } - } - - function invariant_LatestCipherMatchesType() external view { - IAssetSafe safeContract = IAssetSafe(assetSafe); - uint256 len = handler.trackedLength(); - - for (uint256 i = 0; i < len; i++) { - uint256 assetId = handler.trackedAt(i); - if (!handler.hasLatestCipher(assetId)) { - continue; - } - - uint8 expected = handler.latestCipher(assetId); - assertEq(uint8(safeContract.getType(assetId)), expected, "Latest cipher should match stored type"); - } - } -} diff --git a/test/economics/Tollgate.t.sol b/test/economics/Tollgate.t.sol index be04601..a70911e 100644 --- a/test/economics/Tollgate.t.sol +++ b/test/economics/Tollgate.t.sol @@ -6,6 +6,7 @@ import { BaseTest } from "test/BaseTest.t.sol"; import { Tollgate } from "contracts/economics/Tollgate.sol"; import { ITollgate } from "contracts/core/interfaces/economics/ITollgate.sol"; import { T } from "contracts/core/primitives/Types.sol"; +import { IAccessManaged } from "@openzeppelin/contracts/access/manager/IAccessManaged.sol"; contract TargetA {} @@ -23,90 +24,6 @@ contract TargetD { } } -contract TollgateHandler is Test { - struct FeeState { - bool exists; - uint256 fee; - } - - address public immutable tollgate; - address public immutable governor; - address[] public targets; - address[] public currencies; - - mapping(address => T.Scheme) private _schemes; - mapping(address => mapping(address => FeeState)) private _fees; - mapping(address => address[]) private _targetCurrencies; - mapping(address => mapping(address => bool)) private _currencyTracked; - - constructor(address tollgate_, address governor_, address token_) { - tollgate = tollgate_; - governor = governor_; - - targets.push(address(new TargetA())); - targets.push(address(new TargetB())); - targets.push(address(new TargetC())); - targets.push(address(new TargetD())); - - _schemes[targets[0]] = T.Scheme.FLAT; - _schemes[targets[1]] = T.Scheme.NOMINAL; - _schemes[targets[2]] = T.Scheme.BPS; - _schemes[targets[3]] = T.Scheme.FLAT; - - currencies.push(token_); - currencies.push(vm.addr(910)); - currencies.push(vm.addr(911)); - } - - function setFees(uint256 targetSeed, uint256 currencySeed, uint256 feeSeed) external { - if (targets.length == 0) return; - address target = targets[targetSeed % targets.length]; - address currency = currencies[currencySeed % currencies.length]; - T.Scheme scheme = _schemes[target]; - - uint256 fee; - if (scheme == T.Scheme.FLAT) { - fee = bound(feeSeed, 1, type(uint96).max); - } else if (scheme == T.Scheme.NOMINAL) { - fee = bound(feeSeed, 1, 100); - } else { - fee = bound(feeSeed, 1, 10_000); - } - - vm.prank(governor); - ITollgate(tollgate).setFees(scheme, target, fee, currency); - - FeeState storage state = _fees[target][currency]; - state.exists = true; - state.fee = fee; - - if (!_currencyTracked[target][currency]) { - _currencyTracked[target][currency] = true; - _targetCurrencies[target].push(currency); - } - } - - function targetsLength() external view returns (uint256) { - return targets.length; - } - - function targetAt(uint256 index) external view returns (address) { - return targets[index]; - } - - function schemeOf(address target) external view returns (T.Scheme) { - return _schemes[target]; - } - - function currenciesFor(address target) external view returns (address[] memory) { - return _targetCurrencies[target]; - } - - function feeState(address target, address currency) external view returns (FeeState memory) { - return _fees[target][currency]; - } -} - contract TollgateTest is BaseTest { function setUp() public initialize { deployTollgate(); @@ -160,6 +77,19 @@ contract TollgateTest is BaseTest { ITollgate(tollgate).setFees(T.Scheme.NOMINAL, target, invalidFees, token); } + function test_SetFees_RevertWhen_UnauthorizedCaller() public { + address target = address(new TargetA()); + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, user)); + vm.prank(user); + ITollgate(tollgate).setFees(T.Scheme.FLAT, target, 1, token); + } + + function test_SetFees_RevertWhen_TargetZero() public { + vm.prank(governor); + vm.expectRevert(abi.encodeWithSignature("InvalidTargetScheme(address)", address(0))); + ITollgate(tollgate).setFees(T.Scheme.FLAT, address(0), 1, token); + } + function test_SetFees_RevertIf_NotSupportedSchemeByTarget() public { vm.startPrank(governor); // expected revert if not valid allowance @@ -217,130 +147,4 @@ contract TollgateTest is BaseTest { // only one expected since the set avoid dupes.. assertEq(got, expected, "Expected supported currencies should match"); } - - function testFuzz_SetFees_Flat(uint256 fee, address currency) public { - vm.assume(currency != address(0)); - address target = address(new TargetA()); - fee = bound(fee, 1, type(uint96).max); - - vm.prank(governor); - ITollgate(tollgate).setFees(T.Scheme.FLAT, target, fee, currency); - - (uint256 stored, T.Scheme scheme) = ITollgate(tollgate).getFees(target, currency); - assertEq(stored, fee, "Flat fee should match"); - assertEq(uint256(scheme), uint256(T.Scheme.FLAT), "Scheme should be FLAT"); - } - - function testFuzz_SetFees_Nominal(uint256 fee, address currency) public { - vm.assume(currency != address(0)); - address target = address(new TargetB()); - fee = bound(fee, 1, 100); - - vm.prank(governor); - ITollgate(tollgate).setFees(T.Scheme.NOMINAL, target, fee, currency); - - (uint256 stored, T.Scheme scheme) = ITollgate(tollgate).getFees(target, currency); - assertEq(stored, fee, "Nominal fee should match"); - assertEq(uint256(scheme), uint256(T.Scheme.NOMINAL), "Scheme should be NOMINAL"); - } - - function testFuzz_SetFees_Bps(uint256 fee, address currency) public { - vm.assume(currency != address(0)); - address target = address(new TargetC()); - fee = bound(fee, 1, 10_000); - - vm.prank(governor); - ITollgate(tollgate).setFees(T.Scheme.BPS, target, fee, currency); - - (uint256 stored, T.Scheme scheme) = ITollgate(tollgate).getFees(target, currency); - assertEq(stored, fee, "BPS fee should match"); - assertEq(uint256(scheme), uint256(T.Scheme.BPS), "Scheme should be BPS"); - } - - function testFuzz_SupportedCurrencies_NoDuplicates( - uint256 feeA, - uint256 feeB, - address currency - ) public { - vm.assume(currency != address(0)); - address target = address(new TargetA()); - feeA = bound(feeA, 1, type(uint96).max); - feeB = bound(feeB, 1, type(uint96).max); - - vm.prank(governor); - ITollgate(tollgate).setFees(T.Scheme.FLAT, target, feeA, currency); - - vm.prank(governor); - ITollgate(tollgate).setFees(T.Scheme.FLAT, target, feeB, currency); - - address[] memory supported = ITollgate(tollgate).supportedCurrencies(target); - assertEq(supported.length, 1, "Supported currencies should not duplicate entries"); - assertEq(supported[0], currency, "Supported currency should match input"); - } -} - -contract TollgateInvariantTest is BaseTest { - TollgateHandler handler; - - function setUp() public initialize { - deployTollgate(); - - handler = new TollgateHandler(tollgate, governor, token); - targetContract(address(handler)); - } - - function invariant_FeesMatchHandlerState() external view { - ITollgate tollgateContract = ITollgate(tollgate); - uint256 len = handler.targetsLength(); - - for (uint256 i = 0; i < len; i++) { - address target = handler.targetAt(i); - address[] memory currenciesList = handler.currenciesFor(target); - T.Scheme scheme = handler.schemeOf(target); - - for (uint256 j = 0; j < currenciesList.length; j++) { - address currency = currenciesList[j]; - TollgateHandler.FeeState memory state = handler.feeState(target, currency); - if (!state.exists) continue; - - (uint256 fee, T.Scheme storedScheme) = tollgateContract.getFees(target, currency); - assertEq(fee, state.fee, "Fee must align with handler state"); - assertEq(uint256(storedScheme), uint256(scheme), "Scheme must align with handler state"); - } - } - } - - function invariant_SupportedCurrenciesAligned() external view { - ITollgate tollgateContract = ITollgate(tollgate); - uint256 len = handler.targetsLength(); - - for (uint256 i = 0; i < len; i++) { - address target = handler.targetAt(i); - address[] memory handlerCurrencies = handler.currenciesFor(target); - address[] memory supported = tollgateContract.supportedCurrencies(target); - - uint256 expectedCount = 0; - for (uint256 j = 0; j < handlerCurrencies.length; j++) { - TollgateHandler.FeeState memory state = handler.feeState(target, handlerCurrencies[j]); - if (state.exists) expectedCount++; - } - - assertEq(supported.length, expectedCount, "Supported currency count mismatch"); - - for (uint256 j = 0; j < handlerCurrencies.length; j++) { - address currency = handlerCurrencies[j]; - TollgateHandler.FeeState memory state = handler.feeState(target, currency); - if (!state.exists) continue; - - bool found = false; - for (uint256 k = 0; k < supported.length; k++) { - if (supported[k] == currency) { - found = true; - break; - } - } - assertTrue(found, "Supported currency missing from Tollgate state"); - } - } - } } diff --git a/test/finance/AgreementManager.t.sol b/test/finance/AgreementManager.t.sol index 5155e5e..6ea110a 100644 --- a/test/finance/AgreementManager.t.sol +++ b/test/finance/AgreementManager.t.sol @@ -118,258 +118,91 @@ contract AgreementManagerTest is BaseTest { IAgreementManager(agreementManager).createAgreement(amount, token, arbiter, parties, ""); } - function test_CreateAgreement_WithPenalizationLocksAmount() public { - uint256 partiesLen = IAgreementManagerExtended(agreementManager).maxParties() + 2; - address[] memory parties = _buildParties(partiesLen); - uint256 amount = 100 * 1e18; + function test_CreateAgreement_ComputesFeesForBpsScheme() public { + vm.prank(governor); + ITollgate(tollgate).setFees(T.Scheme.BPS, arbiter, 500, token); + + uint256 amount = 200 * 1e18; + address[] memory parties = _buildParties(1); vm.prank(user); uint256 proof = IAgreementManager(agreementManager).createAgreement(amount, token, arbiter, parties, ""); T.Agreement memory stored = IAgreementManager(agreementManager).getAgreement(proof); - uint256 penaltyBps = _penaltyBps(partiesLen, IAgreementManagerExtended(agreementManager).maxParties()); - uint256 expectedLocked = amount + ((amount * penaltyBps) / C.BPS_MAX); - - assertEq(stored.locked, expectedLocked, "Locked amount mismatch"); - - uint256 userLedger = ILedgerVerifiable(ledger).getLedgerBalance(user, token); - assertEq(userLedger, INITIAL_DEPOSIT - stored.locked, "Ledger balance should reflect locked amount"); + uint256 expectedFee = (amount * 500) / C.BPS_MAX; // 500 bps configured in setUp + assertEq(stored.fees, expectedFee, "BPS fee mismatch"); } - function test_PreviewAgreement_Penalization() public { - uint256 partiesLen = 9; - address[] memory parties = _buildParties(partiesLen); - uint256 amount = 100 * 1e18; + function test_CreateAgreement_ComputesFeesForNominalScheme() public { + vm.prank(governor); + ITollgate(tollgate).setFees(T.Scheme.NOMINAL, arbiter, 25, token); // 25% nominal + + uint256 amount = 80 * 1e18; + address[] memory parties = _buildParties(2); vm.prank(user); - T.Agreement memory agreement = IAgreementManager(agreementManager).previewAgreement(amount, token, arbiter, parties, ""); + uint256 proof = IAgreementManager(agreementManager).createAgreement(amount, token, arbiter, parties, ""); - uint256 exceed = partiesLen - IAgreementManagerExtended(agreementManager).maxParties(); - uint256 expectedPercentage = (exceed * (exceed + 1)) / 2; - uint256 expectedPenalization = (amount * expectedPercentage * 100) / C.BPS_MAX; + T.Agreement memory stored = IAgreementManager(agreementManager).getAgreement(proof); + uint256 expectedFee = (amount * 25 * 100) / C.BPS_MAX; // nominal converted to bps internally + assertEq(stored.fees, expectedFee, "Nominal fee mismatch"); - assertEq(agreement.locked, amount + expectedPenalization, "Penalization mismatch"); + vm.prank(governor); + ITollgate(tollgate).setFees(T.Scheme.BPS, arbiter, 500, token); } - function testFuzz_CreateAgreement_RevertWhen_UnsupportedScheme(uint256 amountSeed) public { - address unsupportedArbiter = address(new AgreementManagerMockArbiter()); - uint256 amount = bound(amountSeed, 1e18, 100 * 1e18); + function test_CreateAgreement_RevertWhen_ExceedsMaxPartiesPenaltyCap() public { + uint256 maxParties = IAgreementManagerExtended(agreementManager).maxParties(); + uint256 partiesLen = maxParties + 15; // ensures penalty bps > 10_000 + address[] memory parties = _buildParties(partiesLen); vm.prank(user); - vm.expectRevert(abi.encodeWithSelector(AgreementManager.UnsupportedAgreementTarget.selector, unsupportedArbiter, token)); - IAgreementManager(agreementManager).createAgreement(amount, token, unsupportedArbiter, new address[](0), ""); + vm.expectRevert(AgreementManager.ExceedsMaxParties.selector); + IAgreementManager(agreementManager).createAgreement(10 * 1e18, token, arbiter, parties, ""); } - function testFuzz_PreviewAgreement_MatchesPenalty(uint256 partiesLen) public { + function test_PreviewAgreement_NoPenalizationWhenWithinLimit() public { + uint256 amount = 60 * 1e18; uint256 maxParties = IAgreementManagerExtended(agreementManager).maxParties(); - partiesLen = bound(partiesLen, 0, maxParties + 10); - address[] memory parties = _buildParties(partiesLen); - uint256 amount = 25 * 1e18; + address[] memory parties = _buildParties(maxParties); vm.prank(user); - T.Agreement memory agreement = IAgreementManager(agreementManager).previewAgreement(amount, token, arbiter, parties, ""); + T.Agreement memory preview = IAgreementManager(agreementManager).previewAgreement(amount, token, arbiter, parties, ""); - uint256 penalty = _penaltyBps(partiesLen, maxParties); - uint256 expectedLocked = amount + ((amount * penalty) / C.BPS_MAX); - assertEq(agreement.locked, expectedLocked, "Locked value should include penalty"); + assertEq(preview.locked, amount, "Locked amount should equal total when within limit"); } - function testFuzz_CreateAgreement_MatchesPreview(uint256 amountSeed, uint8 partiesSeed) public { - uint256 maxParties = IAgreementManagerExtended(agreementManager).maxParties(); - uint256 partiesLen = uint256(partiesSeed) % (maxParties + 6); + function test_CreateAgreement_WithPenalizationLocksAmount() public { + uint256 partiesLen = IAgreementManagerExtended(agreementManager).maxParties() + 2; address[] memory parties = _buildParties(partiesLen); - uint256 available = ILedgerVerifiable(ledger).getLedgerBalance(user, token); - uint256 penaltyBps = _penaltyBps(partiesLen, maxParties); - - uint256 maxAmount = available; - if (penaltyBps > 0) { - maxAmount = (available * C.BPS_MAX) / (C.BPS_MAX + penaltyBps); - } - if (maxAmount < 1e18) return; - - uint256 amount = bound(amountSeed, 1e18, maxAmount); - bytes memory payload = abi.encode(amountSeed, partiesSeed); + uint256 amount = 100 * 1e18; vm.prank(user); - T.Agreement memory preview = IAgreementManager(agreementManager).previewAgreement(amount, token, arbiter, parties, payload); - - vm.startPrank(user); - uint256 proof = IAgreementManager(agreementManager).createAgreement(amount, token, arbiter, parties, payload); - vm.stopPrank(); + uint256 proof = IAgreementManager(agreementManager).createAgreement(amount, token, arbiter, parties, ""); T.Agreement memory stored = IAgreementManager(agreementManager).getAgreement(proof); - assertEq(stored.total, preview.total, "Total mismatch"); - assertEq(stored.fees, preview.fees, "Fees mismatch"); - assertEq(stored.locked, preview.locked, "Locked mismatch"); - } -} + uint256 penaltyBps = _penaltyBps(partiesLen, IAgreementManagerExtended(agreementManager).maxParties()); + uint256 expectedLocked = amount + ((amount * penaltyBps) / C.BPS_MAX); -contract AgreementManagerHandler is Test { - struct AgreementInfo { - bool exists; - uint256 total; - uint256 fees; - uint256 locked; - } + assertEq(stored.locked, expectedLocked, "Locked amount mismatch"); - IAgreementManagerExtended public immutable manager; - ILedgerVerifiable public immutable vault; - address public immutable token; - address public immutable initiator; - address public immutable arbiter; - address public immutable admin; - uint256 public immutable initialDeposit; - - uint256[] private _proofs; - mapping(uint256 => AgreementInfo) private _agreements; - uint256 private _totalLocked; - uint256 private _nonce; - - constructor( - address manager_, - address vault_, - address token_, - address initiator_, - address arbiter_, - address admin_, - uint256 initialDeposit_ - ) { - manager = IAgreementManagerExtended(manager_); - vault = ILedgerVerifiable(vault_); - token = token_; - initiator = initiator_; - arbiter = arbiter_; - admin = admin_; - initialDeposit = initialDeposit_; + uint256 userLedger = ILedgerVerifiable(ledger).getLedgerBalance(user, token); + assertEq(userLedger, INITIAL_DEPOSIT - stored.locked, "Ledger balance should reflect locked amount"); } - function createAgreement(uint256 amountSeed, uint8 partiesSeed) external { - uint256 available = vault.getLedgerBalance(initiator, token); - if (available < 1e18) return; - - uint256 maxParties = manager.maxParties(); - uint256 partiesLen = uint256(partiesSeed) % (maxParties + 6); - uint256 penaltyBps = _penaltyBps(partiesLen, maxParties); - if (penaltyBps > C.BPS_MAX) return; - - uint256 maxAmount = available; - if (penaltyBps > 0) { - maxAmount = (available * C.BPS_MAX) / (C.BPS_MAX + penaltyBps); - } - if (maxAmount < 1e18) return; - - uint256 amount = bound(amountSeed, 1e18, maxAmount); + function test_PreviewAgreement_Penalization() public { + uint256 partiesLen = 9; address[] memory parties = _buildParties(partiesLen); - bytes memory payload = abi.encode(amountSeed, partiesSeed, _nonce++); - - vm.prank(initiator); - uint256 proof = manager.createAgreement(amount, token, arbiter, parties, payload); - - if (_agreements[proof].exists) return; - - T.Agreement memory agreement = manager.getAgreement(proof); - _agreements[proof] = AgreementInfo({ exists: true, total: agreement.total, fees: agreement.fees, locked: agreement.locked }); - _totalLocked += agreement.locked; - _proofs.push(proof); - } - - function setMaxParties(uint256 newMax) external { - uint256 value = bound(newMax, 1, 10); - vm.prank(admin); - manager.setMaxParties(value); - } - - function proofsLength() external view returns (uint256) { - return _proofs.length; - } - - function proofAt(uint256 index) external view returns (uint256) { - return _proofs[index]; - } - - function info(uint256 proof) external view returns (AgreementInfo memory) { - return _agreements[proof]; - } - - function totalLocked() external view returns (uint256) { - return _totalLocked; - } - - function recomputeLocked() external view returns (uint256 lockedSum) { - uint256 len = _proofs.length; - for (uint256 i = 0; i < len; i++) { - AgreementInfo memory info = _agreements[_proofs[i]]; - if (!info.exists) continue; - lockedSum += info.locked; - } - } - - function _buildParties(uint256 len) private view returns (address[] memory parties) { - parties = new address[](len); - for (uint256 i = 0; i < len; i++) { - parties[i] = vm.addr(500 + i); - } - } - - function _penaltyBps(uint256 partiesLen, uint256 maxParties) private pure returns (uint256) { - if (partiesLen <= maxParties) return 0; - uint256 excess = partiesLen - maxParties; - return ((excess * (excess + 1)) / 2) * 100; - } -} - -contract AgreementManagerInvariantTest is BaseTest { - AgreementManagerHandler handler; - address internal arbiter; - uint256 internal constant INITIAL_DEPOSIT = 5_000 * 1e18; - - function setUp() public initialize { - deployAgreementManager(); - arbiter = address(new AgreementManagerMockArbiter()); - - vm.prank(governor); - ITollgate(tollgate).setFees(T.Scheme.BPS, arbiter, 400, token); - - vm.startPrank(admin); - IERC20(token).approve(ledger, INITIAL_DEPOSIT); - ILedgerVault(ledger).deposit(user, INITIAL_DEPOSIT, token); - vm.stopPrank(); + uint256 amount = 100 * 1e18; - handler = new AgreementManagerHandler( - agreementManager, - ledger, - token, - user, - arbiter, - admin, - INITIAL_DEPOSIT - ); - - targetContract(address(handler)); - } + vm.prank(user); + T.Agreement memory agreement = IAgreementManager(agreementManager).previewAgreement(amount, token, arbiter, parties, ""); - function invariant_AgreementsStoredMatchHandler() external view { - uint256 len = handler.proofsLength(); - for (uint256 i = 0; i < len; i++) { - uint256 proof = handler.proofAt(i); - AgreementManagerHandler.AgreementInfo memory info = handler.info(proof); - if (!info.exists) continue; - - T.Agreement memory agreement = IAgreementManager(agreementManager).getAgreement(proof); - assertEq(agreement.total, info.total, "Total mismatch"); - assertEq(agreement.fees, info.fees, "Fees mismatch"); - assertEq(agreement.locked, info.locked, "Locked mismatch"); - assertEq(agreement.arbiter, arbiter, "Arbiter mismatch"); - assertEq(agreement.initiator, user, "Initiator mismatch"); - } - } + uint256 exceed = partiesLen - IAgreementManagerExtended(agreementManager).maxParties(); + uint256 expectedPercentage = (exceed * (exceed + 1)) / 2; + uint256 expectedPenalization = (amount * expectedPercentage * 100) / C.BPS_MAX; - function invariant_UserLedgerPlusLockedEqualsInitial() external view { - uint256 ledgerBalance = ILedgerVerifiable(ledger).getLedgerBalance(user, token); - assertEq(ledgerBalance + handler.totalLocked(), INITIAL_DEPOSIT, "Ledger accounting mismatch"); + assertEq(agreement.locked, amount + expectedPenalization, "Penalization mismatch"); } - function invariant_LockedTotalsConsistent() external view { - assertEq(handler.totalLocked(), handler.recomputeLocked(), "Tracked locked total mismatch"); - } } diff --git a/test/finance/AgreementSettler.t.sol b/test/finance/AgreementSettler.t.sol index 1b8e6a2..41b0bbf 100644 --- a/test/finance/AgreementSettler.t.sol +++ b/test/finance/AgreementSettler.t.sol @@ -130,11 +130,24 @@ contract AgreementSettlerTest is BaseTest { "User ledger mismatch" ); - vm.expectRevert(AgreementSettler.AgreementAlreadySettled.selector); vm.prank(user); + vm.expectRevert(AgreementSettler.AgreementAlreadySettled.selector); IAgreementSettlerExtended(agreementSettler).quitAgreement(proof); } + function test_SettleAgreement_RevertWhen_AlreadySettled() public { + uint256 amount = 60 * 1e18; + (uint256 proof, ) = _createAgreement(amount, 2); + address counterparty = vm.addr(7001); + + vm.prank(address(arbiter)); + IAgreementSettlerExtended(agreementSettler).settleAgreement(proof, counterparty); + + vm.expectRevert(AgreementSettler.AgreementAlreadySettled.selector); + vm.prank(address(arbiter)); + IAgreementSettlerExtended(agreementSettler).settleAgreement(proof, counterparty); + } + function test_QuitAgreement_RevertWhen_NotInitiator() public { uint256 amount = 30 * 1e18; (uint256 proof, ) = _createAgreement(amount, 1); @@ -144,265 +157,16 @@ contract AgreementSettlerTest is BaseTest { IAgreementSettlerExtended(agreementSettler).quitAgreement(proof); } - function testFuzz_SettleAgreement_LedgerConsistency(uint256 amountSeed, uint8 partiesSeed) public { - uint256 partiesLen = uint256(partiesSeed) % (IAgreementManagerExtended(agreementManager).maxParties() + 5); - uint256 amount = _boundedAmount(amountSeed, partiesLen); - if (amount == 0) return; + function test_QuitAgreement_RevertWhen_AlreadySettled() public { + uint256 amount = 90 * 1e18; + (uint256 proof, ) = _createAgreement(amount, 2); - (uint256 proof, ) = _createAgreement(amount, partiesLen); - address counterparty = vm.addr(9000 + partiesLen); vm.prank(address(arbiter)); - T.Agreement memory settled = IAgreementSettlerExtended(agreementSettler).settleAgreement(proof, counterparty); - - uint256 available = settled.total - settled.fees; - uint256 protocolTake = settled.fees + (settled.locked - settled.total); - - assertEq(ILedgerVerifiable(ledger).getLedgerBalance(counterparty, token), available, "Counterparty ledger mismatch"); - assertEq(ILedgerVerifiable(ledger).getLedgerBalance(agreementSettler, token), protocolTake, "Settler ledger mismatch"); - } - - function testFuzz_QuitAgreement_LedgerConsistency(uint256 amountSeed, uint8 partiesSeed) public { - uint256 partiesLen = uint256(partiesSeed) % (IAgreementManagerExtended(agreementManager).maxParties() + 5); - uint256 amount = _boundedAmount(amountSeed, partiesLen); - if (amount == 0) return; - - (uint256 proof, T.Agreement memory agreement) = _createAgreement(amount, partiesLen); - uint256 protocolTake = agreement.fees + (agreement.locked - agreement.total); + IAgreementSettlerExtended(agreementSettler).settleAgreement(proof, vm.addr(9000)); + vm.expectRevert(AgreementSettler.AgreementAlreadySettled.selector); vm.prank(user); IAgreementSettlerExtended(agreementSettler).quitAgreement(proof); - - assertEq(ILedgerVerifiable(ledger).getLedgerBalance(agreementSettler, token), protocolTake, "Protocol take ledger mismatch"); - assertEq( - ILedgerVerifiable(ledger).getLedgerBalance(user, token), - INITIAL_DEPOSIT - protocolTake, - "User ledger mismatch after quit" - ); - } -} - -contract AgreementSettlerHandler is Test { - IAgreementSettlerExtended public immutable settler; - IAgreementManagerExtended public immutable manager; - ILedgerVerifiable public immutable vault; - address public immutable token; - address public immutable initiator; - SettlerMockArbiter public immutable arbiter; - - struct ProofState { - bool exists; - bool settled; - bool cancelled; - uint256 total; - uint256 fees; - uint256 locked; - uint256 protocolTake; - uint256 available; - } - - uint256[] private _proofs; - mapping(uint256 => ProofState) private _states; - uint256 private _activeLocked; - uint256 private _protocolTake; - uint256 private _payout; - uint256 private _nonce; - - constructor( - address settler_, - address manager_, - address vault_, - address token_, - address initiator_, - address arbiter_ - ) { - settler = IAgreementSettlerExtended(settler_); - manager = IAgreementManagerExtended(manager_); - vault = ILedgerVerifiable(vault_); - token = token_; - initiator = initiator_; - arbiter = SettlerMockArbiter(arbiter_); - } - - function createAgreement(uint256 amountSeed, uint8 partiesSeed) external { - uint256 partiesLen = uint256(partiesSeed) % (manager.maxParties() + 5); - uint256 penaltyBps = _penaltyBps(partiesLen, manager.maxParties()); - uint256 available = vault.getLedgerBalance(initiator, token); - if (available < 1e18) return; - - uint256 maxAmount = available; - if (penaltyBps > 0) { - maxAmount = (available * C.BPS_MAX) / (C.BPS_MAX + penaltyBps); - } - if (maxAmount < 1e18) return; - - uint256 amount = bound(amountSeed, 1e18, maxAmount); - address[] memory parties = _buildParties(partiesLen); - bytes memory payload = abi.encode(_nonce++); - vm.prank(initiator); - uint256 proof = manager.createAgreement(amount, token, address(arbiter), parties, payload); - if (_states[proof].exists) return; - - T.Agreement memory agreement = manager.getAgreement(proof); - _states[proof] = ProofState({ - exists: true, - settled: false, - cancelled: false, - total: agreement.total, - fees: agreement.fees, - locked: agreement.locked, - protocolTake: 0, - available: agreement.total - agreement.fees - }); - _activeLocked += agreement.locked; - _proofs.push(proof); - } - - function settle(uint256 proofSeed, address counterpartySeed) external { - if (_proofs.length == 0) return; - uint256 proof = _proofs[proofSeed % _proofs.length]; - ProofState storage state = _states[proof]; - if (!state.exists || state.settled || state.cancelled) return; - - address counterParty = counterpartySeed; - while (counterParty == address(0) || counterParty == initiator || counterParty == address(settler)) { - counterParty = vm.addr(uint256(uint160(counterParty)) + 1); - } - - vm.prank(address(arbiter)); - T.Agreement memory settled = settler.settleAgreement(proof, counterParty); - uint256 protocolTake = settled.fees + (settled.locked - settled.total); - uint256 available = settled.total - settled.fees; - - state.settled = true; - state.protocolTake = protocolTake; - state.available = available; - - _activeLocked -= settled.locked; - _protocolTake += protocolTake; - _payout += available; - } - - function quit(uint256 proofSeed) external { - if (_proofs.length == 0) return; - uint256 proof = _proofs[proofSeed % _proofs.length]; - ProofState storage state = _states[proof]; - if (!state.exists || state.settled || state.cancelled) return; - - vm.prank(initiator); - T.Agreement memory cancelled = settler.quitAgreement(proof); - uint256 protocolTake = cancelled.fees + (cancelled.locked - cancelled.total); - - state.cancelled = true; - state.protocolTake = protocolTake; - - _activeLocked -= cancelled.locked; - _protocolTake += protocolTake; - } - - function proofsLength() external view returns (uint256) { - return _proofs.length; } - function proofAt(uint256 index) external view returns (uint256) { - return _proofs[index]; - } - - function stateOf(uint256 proof) external view returns (ProofState memory) { - return _states[proof]; - } - - function activeLocked() external view returns (uint256) { - return _activeLocked; - } - - function totalProtocolTake() external view returns (uint256) { - return _protocolTake; - } - - function totalPayout() external view returns (uint256) { - return _payout; - } - - function recomputeActiveLocked() external view returns (uint256 sum) { - uint256 len = _proofs.length; - for (uint256 i = 0; i < len; i++) { - ProofState memory state = _states[_proofs[i]]; - if (!state.exists || state.settled || state.cancelled) continue; - sum += state.locked; - } - } - - function _buildParties(uint256 len) private view returns (address[] memory parties) { - parties = new address[](len); - for (uint256 i = 0; i < len; i++) { - parties[i] = vm.addr(1_500 + i); - } - } - - function _penaltyBps(uint256 partiesLen, uint256 maxParties) private pure returns (uint256) { - if (partiesLen <= maxParties) return 0; - uint256 excess = partiesLen - maxParties; - return ((excess * (excess + 1)) / 2) * 100; - } -} - -contract AgreementSettlerInvariantTest is BaseTest { - AgreementSettlerHandler handler; - SettlerMockArbiter arbiter; - uint256 internal constant INITIAL_DEPOSIT = 8_000 * 1e18; - - function setUp() public initialize { - deployAgreementSettler(); - arbiter = new SettlerMockArbiter(agreementSettler); - - vm.prank(governor); - ITollgate(tollgate).setFees(T.Scheme.BPS, address(arbiter), 350, token); - - vm.startPrank(admin); - IERC20(token).approve(ledger, INITIAL_DEPOSIT); - ILedgerVault(ledger).deposit(user, INITIAL_DEPOSIT, token); - vm.stopPrank(); - - handler = new AgreementSettlerHandler( - agreementSettler, - agreementManager, - ledger, - token, - user, - address(arbiter) - ); - - targetContract(address(handler)); - } - - function invariant_SettlerLedgerMatchesProtocolTake() external view { - uint256 settlerLedger = ILedgerVerifiable(ledger).getLedgerBalance(agreementSettler, token); - assertEq(settlerLedger, handler.totalProtocolTake(), "Settler ledger mismatch"); - } - - function invariant_UserLedgerAccountingHolds() external view { - uint256 userLedger = ILedgerVerifiable(ledger).getLedgerBalance(user, token); - uint256 total = userLedger + handler.activeLocked() + handler.totalProtocolTake() + handler.totalPayout(); - assertEq(total, INITIAL_DEPOSIT, "Ledger accounting must balance"); - } - - function invariant_ActiveLockedConsistency() external view { - assertEq(handler.activeLocked(), handler.recomputeActiveLocked(), "Active locked tracking mismatch"); - } - - function invariant_AgreementStateMatchesManager() external view { - uint256 len = handler.proofsLength(); - for (uint256 i = 0; i < len; i++) { - uint256 proof = handler.proofAt(i); - AgreementSettlerHandler.ProofState memory state = handler.stateOf(proof); - if (!state.exists) continue; - - T.Agreement memory agreement = IAgreementManager(agreementManager).getAgreement(proof); - assertEq(agreement.total, state.total, "Agreement total mismatch"); - assertEq(agreement.fees, state.fees, "Agreement fees mismatch"); - assertEq(agreement.locked, state.locked, "Agreement locked mismatch"); - assertEq(agreement.arbiter, address(arbiter), "Arbiter mismatch"); - assertEq(agreement.initiator, user, "Initiator mismatch"); - } - } } diff --git a/test/finance/LedgerVault.t.sol b/test/finance/LedgerVault.t.sol index 992a558..026cded 100644 --- a/test/finance/LedgerVault.t.sol +++ b/test/finance/LedgerVault.t.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.26; import "forge-std/Test.sol"; import { AccessManager } from "@openzeppelin/contracts/access/manager/AccessManager.sol"; +import { IAccessManaged } from "@openzeppelin/contracts/access/manager/IAccessManaged.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; @@ -151,6 +152,12 @@ contract LedgerVaultTest is Test { 40 ether, "User ledger after transfer" ); + assertEq( + ILedgerVerifiable(address(vault)).getLedgerBalance(admin, address(token)) + + ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(token)), + 100 ether, + "Ledger totals must conserve balance" + ); } function test_Transfer_RevertWhen_Self() public { @@ -218,6 +225,24 @@ contract LedgerVaultTest is Test { ); } + function test_Lock_RevertWhen_Unauthorized() public { + _deposit(user, 30 ether); + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, user)); + vm.prank(user); + vault.lock(user, 10 ether, address(token)); + } + + function test_Claim_RevertWhen_Unauthorized() public { + _deposit(user, 50 ether); + vm.prank(operator); + vault.lock(user, 20 ether, address(token)); + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, other)); + vm.prank(other); + vault.claim(user, 5 ether, address(token)); + } + function test_Pause_BlocksStateChanging() public { _deposit(admin, 10 ether); vm.prank(admin); @@ -258,9 +283,8 @@ contract LedgerVaultTest is Test { ); } - function testFuzz_DepositWithdraw(uint256 amount) public { - amount = bound(amount, 1 ether, 1_000 ether); - token.mint(user, amount); + function test_DepositWithdraw_FullAmountRestoresState() public { + uint256 amount = 250 ether; _deposit(user, amount); vm.prank(user); @@ -269,244 +293,25 @@ contract LedgerVaultTest is Test { assertEq( ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(token)), 0, - "Ledger should be zero" + "Ledger balance should return to zero" ); + assertEq(token.balanceOf(address(vault)), 0, "Vault should hold no tokens"); } - function testFuzz_TransferMaintainsLedger(uint256 depositAmount, uint256 transferAmount) public { - depositAmount = bound(depositAmount, 2 ether, 1_000 ether); - transferAmount = bound(transferAmount, 1 ether, depositAmount - 1 ether); - token.mint(user, depositAmount); - _deposit(user, depositAmount); - - vm.prank(user); - vault.transfer(other, transferAmount, address(token)); - - uint256 ledgerUser = ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(token)); - uint256 ledgerOther = ILedgerVerifiable(address(vault)).getLedgerBalance(other, address(token)); - assertEq(ledgerUser + ledgerOther, depositAmount, "Ledger conservation failed"); - } -} - -contract LedgerVaultHandler is Test { - LedgerVaultHarness public immutable vault; - MockToken public immutable token; - address public immutable operator; - address public immutable claimer; - address[] internal accounts; - - mapping(address => uint256) internal expectedLedger; - mapping(address => uint256) internal expectedLocked; - - constructor( - LedgerVaultHarness vault_, - MockToken token_, - address operator_, - address claimer_, - address[] memory actors - ) { - vault = vault_; - token = token_; - operator = operator_; - claimer = claimer_; - for (uint256 i = 0; i < actors.length; i++) { - accounts.push(actors[i]); - } - } - - function accountsLength() external view returns (uint256) { - return accounts.length; - } - - function accountAt(uint256 idx) external view returns (address) { - return accounts[idx]; - } - - function expectedLedgerOf(address account) external view returns (uint256) { - return expectedLedger[account]; - } - - function expectedLockedOf(address account) external view returns (uint256) { - return expectedLocked[account]; - } - - function _boundAmount(address account, uint256 amount) internal view returns (uint256) { - uint256 balance = token.balanceOf(account); - if (balance == 0) return 0; - return bound(amount, 1, balance); - } - - function deposit(uint256 idx, uint256 amount) external { - vm.assume(idx < accounts.length); - address account = accounts[idx]; - amount = _boundAmount(account, amount); - if (amount == 0) return; - - vm.startPrank(account); - token.approve(address(vault), amount); - uint256 confirmed = vault.deposit(account, amount, address(token)); - vm.stopPrank(); - - expectedLedger[account] += confirmed; - } - - function withdraw(uint256 idx, uint256 amount) external { - vm.assume(idx < accounts.length); - address account = accounts[idx]; - uint256 available = expectedLedger[account]; - vm.assume(available > 0); - amount = bound(amount, 1, available); - - vm.prank(account); - uint256 confirmed = vault.withdraw(account, amount, address(token)); - expectedLedger[account] = available - confirmed; - } - - function transfer(uint256 fromIdx, uint256 toIdx, uint256 amount) external { - vm.assume(fromIdx < accounts.length && toIdx < accounts.length); - vm.assume(fromIdx != toIdx); - address from = accounts[fromIdx]; - address to = accounts[toIdx]; - uint256 available = expectedLedger[from]; - vm.assume(available > 0); - amount = bound(amount, 1, available); - - vm.prank(from); - vault.transfer(to, amount, address(token)); - - expectedLedger[from] = available - amount; - expectedLedger[to] += amount; - } - - function lock(uint256 idx, uint256 amount) external { - vm.assume(idx < accounts.length); - address account = accounts[idx]; - uint256 available = expectedLedger[account]; - vm.assume(available > 0); - amount = bound(amount, 1, available); - + function test_LedgerAndLockedBalancesMatchVaultHoldings() public { + _deposit(user, 300 ether); vm.prank(operator); - vault.lock(account, amount, address(token)); - - expectedLedger[account] = available - amount; - expectedLocked[account] += amount; - } - - function release(uint256 idx, uint256 amount) external { - vm.assume(idx < accounts.length); - address account = accounts[idx]; - uint256 locked = expectedLocked[account]; - vm.assume(locked > 0); - amount = bound(amount, 1, locked); - - vm.prank(operator); - vault.release(account, amount, address(token)); - - expectedLocked[account] = locked - amount; - expectedLedger[account] += amount; - } - - function claim(uint256 idx, uint256 amount) external { - vm.assume(idx < accounts.length); - address account = accounts[idx]; - uint256 locked = expectedLocked[account]; - vm.assume(locked > 0); - amount = bound(amount, 1, locked); - + vault.lock(user, 120 ether, address(token)); vm.prank(claimer); - vault.claim(account, amount, address(token)); - - expectedLocked[account] = locked - amount; - expectedLedger[claimer] += amount; - } -} - -contract LedgerVaultInvariantTest is Test { - LedgerVaultHarness vault; - AccessManager manager; - MockToken token; - LedgerVaultHandler handler; - - address admin = vm.addr(11); - address operator = vm.addr(12); - address claimer = vm.addr(13); - address[] accounts; - - function setUp() public { - token = new MockToken(); - manager = new AccessManager(admin); - - LedgerVaultHarness implementation = new LedgerVaultHarness(); - ERC1967Proxy proxy = new ERC1967Proxy( - address(implementation), - abi.encodeWithSignature("initialize(address)", address(manager)) - ); - vault = LedgerVaultHarness(address(proxy)); - - vm.startPrank(admin); - bytes4[] memory adminSelectors = new bytes4[](2); - adminSelectors[0] = AccessControlledUpgradeable.pause.selector; - adminSelectors[1] = AccessControlledUpgradeable.unpause.selector; - manager.setTargetFunctionRole(address(vault), adminSelectors, C.ADMIN_ROLE); - - bytes4[] memory opsSelectors = new bytes4[](3); - opsSelectors[0] = LedgerVault.lock.selector; - opsSelectors[1] = LedgerVault.release.selector; - opsSelectors[2] = LedgerVault.claim.selector; - manager.setTargetFunctionRole(address(vault), opsSelectors, C.OPS_ROLE); - manager.setRoleAdmin(C.OPS_ROLE, C.ADMIN_ROLE); - manager.grantRole(C.OPS_ROLE, operator, 0); - manager.grantRole(C.OPS_ROLE, claimer, 0); - vm.stopPrank(); - - accounts = new address[](5); - for (uint256 i = 0; i < accounts.length; i++) { - accounts[i] = vm.addr(20 + i); - token.mint(accounts[i], 1_000_000 ether); - } - - handler = new LedgerVaultHandler(vault, token, operator, claimer, accounts); - targetContract(address(handler)); - } - - function _aggregateLedgerAndLocked() - internal - view - returns (uint256 ledgerSum, uint256 lockedSum) - { - uint256 len = handler.accountsLength(); - for (uint256 i = 0; i < len; i++) { - address account = handler.accountAt(i); - ledgerSum += ILedgerVerifiable(address(vault)).getLedgerBalance(account, address(token)); - lockedSum += vault.lockedBalance(account, address(token)); - assertEq( - handler.expectedLedgerOf(account), - ILedgerVerifiable(address(vault)).getLedgerBalance(account, address(token)), - "Ledger expectation mismatch" - ); - assertEq( - handler.expectedLockedOf(account), - vault.lockedBalance(account, address(token)), - "Locked expectation mismatch" - ); - } + vault.claim(user, 40 ether, address(token)); + vm.prank(operator); + vault.release(user, 50 ether, address(token)); - ledgerSum += ILedgerVerifiable(address(vault)).getLedgerBalance(claimer, address(token)); - lockedSum += vault.lockedBalance(claimer, address(token)); - assertEq( - handler.expectedLedgerOf(claimer), - ILedgerVerifiable(address(vault)).getLedgerBalance(claimer, address(token)), - "Claimer ledger mismatch" - ); - assertEq( - handler.expectedLockedOf(claimer), - vault.lockedBalance(claimer, address(token)), - "Claimer locked mismatch" - ); - } + uint256 ledgerUser = ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(token)); + uint256 ledgerClaimer = ILedgerVerifiable(address(vault)).getLedgerBalance(claimer, address(token)); + uint256 lockedUser = vault.lockedBalance(user, address(token)); + uint256 vaultBalance = token.balanceOf(address(vault)); - function invariant_LedgerAndLockedBalance() external view { - (uint256 ledgerSum, uint256 lockedSum) = _aggregateLedgerAndLocked(); - assertEq(ledgerSum + lockedSum, token.balanceOf(address(vault)), "Ledger + locked must match vault balance"); + assertEq(ledgerUser + ledgerClaimer + lockedUser, vaultBalance, "Vault balance must equal ledger + locked"); } } diff --git a/test/libraries/FeesOps.t.sol b/test/libraries/FeesOps.t.sol index 19ddcae..b2f7f64 100644 --- a/test/libraries/FeesOps.t.sol +++ b/test/libraries/FeesOps.t.sol @@ -66,72 +66,16 @@ contract FeesOpsTest is Test { assertEq(harness.calcBps(per), per * C.SCALE_FACTOR, "calcBps mismatch"); } - function testFuzz_PerOfMatchesManual(uint256 amount, uint256 bps) public { - amount = bound(amount, 0, type(uint128).max); - bps = bound(bps, 0, C.BPS_MAX); - - uint256 expected = (amount * bps) / C.BPS_MAX; - assertEq(harness.perOf(amount, bps), expected, "Fuzz percentage mismatch"); - } - - function testFuzz_CalcBpsInverse(uint256 per) public { - per = bound(per, 0, 1_000_000); - uint256 bps = harness.calcBps(per); - assertEq(bps / C.SCALE_FACTOR, per, "calcBps inverse mismatch"); - } -} - -contract FeesOpsHandler is Test { - FeesOpsHarness public immutable harness; - - uint256 internal _totalAmount; - uint256 internal _lastCalcBps; - - constructor(FeesOpsHarness harness_) { - harness = harness_; - } - - function recordPerOf(uint256 amount, uint256 bps) external { - bps = bound(bps, 0, C.BPS_MAX); - amount = bound(amount, 0, type(uint128).max); - uint256 result = harness.perOf(amount, bps); - _totalAmount += result; - } - - function recordCalcBps(uint256 per) external { - per = bound(per, 0, 1_000_000); - _lastCalcBps = harness.calcBps(per); - } - - function reset() external { - _totalAmount = 0; - _lastCalcBps = 0; - } - - function totalAmount() external view returns (uint256) { - return _totalAmount; - } - - function lastCalcBps() external view returns (uint256) { - return _lastCalcBps; - } -} - -contract FeesOpsInvariantTest is Test { - FeesOpsHarness harness; - FeesOpsHandler handler; - - function setUp() public { - harness = new FeesOpsHarness(); - handler = new FeesOpsHandler(harness); - targetContract(address(handler)); + function test_PerOf_ReturnsZeroWhenAmountZero() public { + assertEq(harness.perOf(0, 1_000), 0, "Zero amount should produce zero result"); } - function invariant_TotalAmountWithinBounds() external view { - assertLe(handler.totalAmount(), type(uint256).max, "Total amount overflowed"); + function test_PerOf_ReturnsZeroWhenBpsZero() public { + assertEq(harness.perOf(1_000 ether, 0), 0, "Zero bps should produce zero result"); } - function invariant_LastPercentageValid() external view { - assertEq(handler.lastCalcBps() % C.SCALE_FACTOR, 0, "calcBps outputs should be multiples of scale factor"); + function test_CalcBps_LargePercentage() public { + uint256 per = 1_000_000; // 1000000% + assertEq(harness.calcBps(per), per * C.SCALE_FACTOR, "Large percentage scaling mismatch"); } } diff --git a/test/libraries/FinancialOps.t.sol b/test/libraries/FinancialOps.t.sol index 10f4683..f6f122e 100644 --- a/test/libraries/FinancialOps.t.sol +++ b/test/libraries/FinancialOps.t.sol @@ -82,13 +82,13 @@ contract FinancialOpsTest is Test { function test_SafeDepositNative_RevertWhen_Mismatch() public { uint256 amount = 3 ether; vm.prank(alice); - vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringDeposit.selector, "Amount exceeds balance sent.")); + vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringDeposit.selector, "Invalid expected sent balance.")); harness.depositNative{ value: amount - 1 }(amount); } function test_SafeDepositNative_RevertWhen_Zero() public { vm.prank(alice); - vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringDeposit.selector, "Invalid zero amount.")); + vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringDeposit.selector, "Invalid amount or sender.")); harness.depositNative{ value: 0 }(0); } @@ -113,7 +113,7 @@ contract FinancialOpsTest is Test { function test_SafeDepositERC20_RevertWhen_Zero() public { vm.prank(alice); - vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringDeposit.selector, "Invalid zero amount.")); + vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringDeposit.selector, "Invalid amount or sender.")); harness.depositToken(alice, 0, address(token)); } @@ -126,57 +126,32 @@ contract FinancialOpsTest is Test { uint256 bobBefore = bob.balance; harness.transferFunds(bob, transferAmount, address(0)); - assertEq(address(harness).balance, amount - transferAmount, "Harness native after transfer"); + assertEq(address(harness).balance, amount - transferAmount, "Harness native balance mismatch"); assertEq(bob.balance, bobBefore + transferAmount, "Bob native balance mismatch"); } - function test_TransferNative_RevertWhen_Zero() public { - vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringTransfer.selector, "Invalid zero amount to transfer.")); - harness.transferFunds(bob, 0, address(0)); - } - - function test_TransferNative_RevertWhen_InsufficientBalance() public { - uint256 amount = 1 ether; - vm.prank(alice); - harness.depositNative{ value: amount }(amount); - - vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringTransfer.selector, "Insufficient balance.")); - harness.transferFunds(bob, amount + 1 ether, address(0)); - } - function test_TransferERC20_Succeeds() public { - uint256 amount = 4e21; + uint256 amount = 1e22; vm.startPrank(alice); token.approve(address(harness), amount); harness.depositToken(alice, amount, address(token)); vm.stopPrank(); - uint256 transferAmount = 1e21; + uint256 transferAmount = 3e21; uint256 bobBefore = token.balanceOf(bob); harness.transferFunds(bob, transferAmount, address(token)); - assertEq(token.balanceOf(address(harness)), amount - transferAmount, "Harness token after transfer"); + assertEq(token.balanceOf(address(harness)), amount - transferAmount, "Harness token balance mismatch"); assertEq(token.balanceOf(bob), bobBefore + transferAmount, "Bob token balance mismatch"); } - function test_TransferERC20_RevertWhen_Zero() public { - vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringTransfer.selector, "Invalid zero amount to transfer.")); - harness.transferFunds(bob, 0, address(token)); - } - - function test_TransferERC20_RevertWhen_InsufficientBalance() public { - uint256 amount = 5e21; - vm.startPrank(alice); - token.approve(address(harness), amount); - harness.depositToken(alice, amount, address(token)); - vm.stopPrank(); - - vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringTransfer.selector, "Insufficient balance.")); - harness.transferFunds(bob, amount + 1, address(token)); + function test_Transfer_RevertWhen_InvalidAmount() public { + vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringTransfer.selector, "Invalid amount or recipient.")); + harness.transferFunds(address(0), 1, address(token)); } function test_IncreaseAllowance_Succeeds() public { - uint256 allowanceAmount = 7e20; + uint256 allowanceAmount = 5e20; harness.increaseTokenAllowance(carol, allowanceAmount, address(token)); assertEq(token.allowance(address(harness), carol), allowanceAmount, "Allowance mismatch"); } @@ -247,180 +222,24 @@ contract FinancialOpsTest is Test { assertEq(token.balanceOf(carol), 3e21, "Carol token balance mismatch"); } - function testFuzz_NativeDepositTransferConservation(uint256 depositAmount, uint256 transferAmount) public { - depositAmount = bound(depositAmount, 1 wei, 50 ether); - transferAmount = bound(transferAmount, 0, depositAmount); - + function test_DepositWithdrawFullyRestoresBalances() public { + uint256 amount = 12 ether; vm.prank(alice); - harness.depositNative{ value: depositAmount }(depositAmount); - - uint256 bobBefore = bob.balance; - if (transferAmount > 0) { - harness.transferFunds(bob, transferAmount, address(0)); - } - - assertEq(address(harness).balance, depositAmount - transferAmount, "Harness native conservation"); - assertEq(bob.balance, bobBefore + transferAmount, "Bob native gain mismatch"); - } - - function testFuzz_ERC20DepositTransferConservation(uint256 depositAmount, uint256 transferAmount) public { - depositAmount = bound(depositAmount, 1, INITIAL_TOKEN_ALLOCATION); - transferAmount = bound(transferAmount, 0, depositAmount); - - vm.startPrank(alice); - token.approve(address(harness), depositAmount); - harness.depositToken(alice, depositAmount, address(token)); - vm.stopPrank(); - - uint256 bobBefore = token.balanceOf(bob); - if (transferAmount > 0) { - harness.transferFunds(bob, transferAmount, address(token)); - } - - assertEq(token.balanceOf(address(harness)), depositAmount - transferAmount, "Harness token conservation"); - assertEq(token.balanceOf(bob), bobBefore + transferAmount, "Bob token gain mismatch"); - } -} - -contract FinancialOpsHandler is Test { - FinancialOpsHarness public immutable harness; - TestToken public immutable token; - - address[] internal accounts; - uint256 internal constant INITIAL_NATIVE_BALANCE = 80 ether; - uint256 internal constant INITIAL_TOKEN_BALANCE = 5e21; - - uint256 internal expectedHarnessNative; - uint256 internal expectedHarnessToken; - uint256 internal aggregateNativeInitial; - uint256 internal aggregateTokenInitial; - - constructor(FinancialOpsHarness harness_, TestToken token_) { - harness = harness_; - token = token_; - - for (uint256 i = 0; i < 3; i++) { - address account = vm.addr(i + 10); - accounts.push(account); - vm.deal(account, INITIAL_NATIVE_BALANCE); - token.mint(account, INITIAL_TOKEN_BALANCE); - aggregateNativeInitial += INITIAL_NATIVE_BALANCE; - aggregateTokenInitial += INITIAL_TOKEN_BALANCE; - } - } - - function depositNative(uint256 accountIdx, uint256 amount) external { - vm.assume(accountIdx < accounts.length); - address account = accounts[accountIdx]; - uint256 balance = account.balance; - if (balance == 0) return; - amount = bound(amount, 1, balance); - - vm.prank(account); harness.depositNative{ value: amount }(amount); - expectedHarnessNative += amount; - } - - function transferNative(uint256 accountIdx, uint256 amount) external { - vm.assume(accountIdx < accounts.length); - if (expectedHarnessNative == 0) return; - amount = bound(amount, 1, expectedHarnessNative); - address recipient = accounts[accountIdx]; - harness.transferFunds(recipient, amount, address(0)); - expectedHarnessNative -= amount; + vm.prank(alice); + harness.transferFunds(alice, amount, address(0)); + assertEq(address(harness).balance, 0, "Harness native balance should be zero"); } - function depositToken(uint256 accountIdx, uint256 amount) external { - vm.assume(accountIdx < accounts.length); - address account = accounts[accountIdx]; - uint256 balance = token.balanceOf(account); - if (balance == 0) return; - amount = bound(amount, 1, balance); - - vm.startPrank(account); + function test_TokenDepositWithdrawFullyRestoresBalances() public { + uint256 amount = 4e21; + vm.startPrank(alice); token.approve(address(harness), amount); - harness.depositToken(account, amount, address(token)); + harness.depositToken(alice, amount, address(token)); vm.stopPrank(); - expectedHarnessToken += amount; - } - - function transferToken(uint256 accountIdx, uint256 amount) external { - vm.assume(accountIdx < accounts.length); - if (expectedHarnessToken == 0) return; - amount = bound(amount, 1, expectedHarnessToken); - address recipient = accounts[accountIdx]; - - harness.transferFunds(recipient, amount, address(token)); - expectedHarnessToken -= amount; - } - - function accountsLength() external view returns (uint256) { - return accounts.length; - } - - function accountAt(uint256 idx) external view returns (address) { - return accounts[idx]; - } - - function expectedHarnessNativeBalance() external view returns (uint256) { - return expectedHarnessNative; - } - - function expectedHarnessTokenBalance() external view returns (uint256) { - return expectedHarnessToken; - } - - function nativeInitialTotal() external view returns (uint256) { - return aggregateNativeInitial; - } - - function tokenInitialTotal() external view returns (uint256) { - return aggregateTokenInitial; - } -} - -contract FinancialOpsInvariantTest is Test { - FinancialOpsHarness internal harness; - TestToken internal token; - FinancialOpsHandler internal handler; - - function setUp() public { - harness = new FinancialOpsHarness(); - token = new TestToken("Mock Token", "MOCK"); - handler = new FinancialOpsHandler(harness, token); - targetContract(address(handler)); - } - - function invariant_HarnessBalancesMatchExpectations() external view { - assertEq( - address(harness).balance, - handler.expectedHarnessNativeBalance(), - "Harness native expectation mismatch" - ); - assertEq( - token.balanceOf(address(harness)), - handler.expectedHarnessTokenBalance(), - "Harness token expectation mismatch" - ); - } - - function invariant_TotalTokenConserved() external view { - uint256 total = token.balanceOf(address(harness)); - uint256 len = handler.accountsLength(); - for (uint256 i = 0; i < len; i++) { - total += token.balanceOf(handler.accountAt(i)); - } - assertEq(total, handler.tokenInitialTotal(), "Token conservation failed"); - } - - function invariant_TotalNativeConserved() external view { - uint256 total = address(harness).balance; - uint256 len = handler.accountsLength(); - for (uint256 i = 0; i < len; i++) { - total += handler.accountAt(i).balance; - } - assertEq(total, handler.nativeInitialTotal(), "Native conservation failed"); + harness.transferFunds(alice, amount, address(token)); + assertEq(token.balanceOf(address(harness)), 0, "Harness token balance should be zero"); } } diff --git a/test/libraries/RollingOps.t.sol b/test/libraries/RollingOps.t.sol index 98b27b8..450b712 100644 --- a/test/libraries/RollingOps.t.sol +++ b/test/libraries/RollingOps.t.sol @@ -40,7 +40,6 @@ contract RollingOpsHarness { } contract RollingOpsTest is Test { - uint256 internal constant MAX_WINDOW = 20; RollingOpsHarness harness; function setUp() public { @@ -129,102 +128,4 @@ contract RollingOpsTest is Test { assertEq(harness.at(1), c, "Second element should be latest rolled"); assertFalse(harness.contains(a), "Rolled out element should not be contained"); } - - function testFuzz_RollRespectsWindow(uint256 windowSize, uint256 count) public { - windowSize = bound(windowSize, 1, MAX_WINDOW); - count = bound(count, 1, 60); - harness.configure(windowSize); - - address[] memory inserted = new address[](count); - for (uint256 i = 0; i < count; i++) { - inserted[i] = vm.addr(i + 1); - harness.roll(inserted[i]); - } - - uint256 expectedLength = count < windowSize ? count : windowSize; - assertEq(harness.length(), expectedLength, "Length should never exceed window"); - - for (uint256 i = 0; i < expectedLength; i++) { - assertEq(harness.at(i), inserted[count - expectedLength + i], "Order mismatch after rolling"); - } - } - - function testFuzz_RollContainsMostRecent(address seed, uint256 windowSize) public { - windowSize = bound(windowSize, 1, MAX_WINDOW); - harness.configure(windowSize); - - for (uint256 i = 0; i < windowSize; i++) { - address current = address(uint160(uint256(keccak256(abi.encode(seed, i))))); - harness.roll(current); - assertTrue(harness.contains(current), "Recently rolled address should be contained"); - } - } -} - -contract RollingOpsHandler is Test { - using RollingOps for RollingOps.AddressArray; - - RollingOpsHarness public immutable harness; - address[] internal snapshot; - - constructor(RollingOpsHarness harness_) { - harness = harness_; - } - - uint256 internal constant MAX_WINDOW = 20; - - function configure(uint256 windowSeed) external { - uint256 window = bound(windowSeed, 1, MAX_WINDOW); - harness.configure(window); - _rebuildSnapshot(); - } - - function roll(address value) external { - harness.roll(value); - _rebuildSnapshot(); - } - - function maxWindow() external pure returns (uint256) { - return MAX_WINDOW; - } - - function snapshotLength() external view returns (uint256) { - return snapshot.length; - } - - function snapshotAt(uint256 index) external view returns (address) { - return snapshot[index]; - } - - function _rebuildSnapshot() private { - delete snapshot; - address[] memory vals = harness.values(); - for (uint256 i = 0; i < vals.length; i++) { - snapshot.push(vals[i]); - } - } -} - -contract RollingOpsInvariantTest is Test { - RollingOpsHarness harness; - RollingOpsHandler handler; - - function setUp() public { - harness = new RollingOpsHarness(); - handler = new RollingOpsHandler(harness); - targetContract(address(handler)); - } - - function invariant_LengthWithinBound() external view { - assertLe(harness.length(), handler.maxWindow(), "Length exceeds handler max window"); - } - - function invariant_StateMatchesSnapshot() external view { - uint256 len = handler.snapshotLength(); - assertEq(harness.length(), len, "Length mismatch between harness and snapshot"); - - for (uint256 i = 0; i < len; i++) { - assertEq(harness.at(i), handler.snapshotAt(i), "Snapshot divergence detected"); - } - } } diff --git a/test/policies/PolicyAudit.t.sol b/test/policies/PolicyAudit.t.sol index 5e0c9fa..7bb7a79 100644 --- a/test/policies/PolicyAudit.t.sol +++ b/test/policies/PolicyAudit.t.sol @@ -2,9 +2,7 @@ pragma solidity 0.8.26; import "forge-std/Test.sol"; - import { PolicyAudit } from "contracts/policies/PolicyAudit.sol"; -import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import { AccessControlledUpgradeable } from "contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol"; import { QuorumUpgradeable } from "contracts/core/primitives/upgradeable/QuorumUpgradeable.sol"; import { IPolicy } from "contracts/core/interfaces/policies/IPolicy.sol"; @@ -51,23 +49,13 @@ contract MockPolicy is ERC165, IPolicy { contract NotPolicy {} -contract PolicyAuditHarness is PolicyAudit { - function status(address policy) external view returns (T.Status) { - return _status(uint160(policy)); - } -} - contract PolicyAuditTest is BaseTest { - PolicyAuditHarness internal audit; + PolicyAudit internal audit; address internal nonAdmin; function setUp() public initialize { - PolicyAuditHarness implementation = new PolicyAuditHarness(); - ERC1967Proxy proxy = new ERC1967Proxy( - address(implementation), - abi.encodeCall(PolicyAudit.initialize, accessManager) - ); - audit = PolicyAuditHarness(address(proxy)); + deployPolicyAudit(); + audit = PolicyAudit(policyAudit); nonAdmin = vm.addr(77); } @@ -82,8 +70,9 @@ contract PolicyAuditTest is BaseTest { vm.expectEmit(true, true, false, true, address(audit)); emit PolicyAudit.PolicySubmitted(address(policy), address(this)); audit.submit(address(policy)); - assertEq(uint8(audit.status(address(policy))), uint8(T.Status.Waiting), "Status should be waiting"); - assertFalse(audit.isAudited(address(policy)), "Policy should not be active yet"); + assertTrue(audit.isPending(address(policy)), "Policy should be pending approval"); + assertFalse(audit.isRejected(address(policy)), "Policy should not be rejected"); + assertFalse(audit.isApproved(address(policy)), "Policy should not be approved yet"); } function test_Submit_RevertWhen_AlreadySubmitted() public { @@ -101,8 +90,9 @@ contract PolicyAuditTest is BaseTest { emit PolicyAudit.PolicyApproved(address(policy), admin); vm.prank(admin); audit.approve(address(policy)); - assertEq(uint8(audit.status(address(policy))), uint8(T.Status.Active), "Policy not active"); - assertTrue(audit.isAudited(address(policy)), "isAudited should be true"); + assertTrue(audit.isApproved(address(policy)), "Policy should be approved"); + assertFalse(audit.isRejected(address(policy)), "Policy should not be rejected"); + assertFalse(audit.isPending(address(policy)), "Policy should not remain pending"); } function test_Approve_RevertWhen_NotWaiting() public { @@ -122,11 +112,13 @@ contract PolicyAuditTest is BaseTest { emit PolicyAudit.PolicyRevoked(address(policy), admin); vm.prank(admin); audit.reject(address(policy)); - assertEq(uint8(audit.status(address(policy))), uint8(T.Status.Blocked), "Policy not blocked"); - assertFalse(audit.isAudited(address(policy)), "isAudited should be false after revoke"); + assertFalse(audit.isApproved(address(policy)), "Policy should no longer be approved"); + assertTrue(audit.isRejected(address(policy)), "Policy should be rejected"); + assertFalse(audit.isPending(address(policy)), "Rejected policy should not be pending"); + vm.startPrank(admin); vm.expectRevert(QuorumUpgradeable.NotWaitingApproval.selector); - vm.prank(admin); audit.approve(address(policy)); + vm.stopPrank(); } function test_Reject_RevertWhen_NotActive() public { @@ -167,118 +159,11 @@ contract PolicyAuditTest is BaseTest { vm.prank(admin); audit.reject(address(policy2)); - assertTrue(audit.isAudited(address(policy1)), "Policy1 should be active"); - assertFalse(audit.isAudited(address(policy2)), "Policy2 should be blocked"); - assertEq(uint8(audit.status(address(policy3))), uint8(T.Status.Waiting), "Policy3 should remain waiting"); - } - - function testFuzz_SubmitMultiple(uint8 count) public { - count = uint8(bound(count, 1, 25)); - for (uint8 i = 0; i < count; i++) { - MockPolicy policy = new MockPolicy(); - audit.submit(address(policy)); - assertEq(uint8(audit.status(address(policy))), uint8(T.Status.Waiting), "Status should be waiting"); - } - } - - function testFuzz_SubmitApprove(uint8 count) public { - count = uint8(bound(count, 1, 20)); - for (uint8 i = 0; i < count; i++) { - MockPolicy policy = new MockPolicy(); - audit.submit(address(policy)); - vm.prank(admin); - audit.approve(address(policy)); - assertTrue(audit.isAudited(address(policy)), "Policy should be active"); - } - } -} - -contract PolicyAuditHandler is Test { - PolicyAuditHarness public immutable audit; - address public immutable admin; - address[] internal policies; - mapping(address => T.Status) internal statusStore; - - constructor(PolicyAuditHarness audit_, address admin_) { - audit = audit_; - admin = admin_; - } - - function submitPolicy() external { - MockPolicy policy = new MockPolicy(); - try audit.submit(address(policy)) { - policies.push(address(policy)); - statusStore[address(policy)] = T.Status.Waiting; - } catch {} - } - - function approvePolicy(uint256 idx) external { - if (policies.length == 0) return; - address policy = policies[idx % policies.length]; - if (statusStore[policy] != T.Status.Waiting) return; - - vm.prank(admin); - try audit.approve(policy) { - statusStore[policy] = T.Status.Active; - } catch {} - } - - function rejectPolicy(uint256 idx) external { - if (policies.length == 0) return; - address policy = policies[idx % policies.length]; - if (statusStore[policy] != T.Status.Active) return; - - vm.prank(admin); - try audit.reject(policy) { - statusStore[policy] = T.Status.Blocked; - } catch {} - } - - function policiesLength() external view returns (uint256) { - return policies.length; - } - - function policyAt(uint256 idx) external view returns (address) { - return policies[idx]; - } - - function storedStatus(address policy) external view returns (T.Status) { - return statusStore[policy]; - } -} - -contract PolicyAuditInvariantTest is BaseTest { - PolicyAuditHarness audit; - PolicyAuditHandler handler; - - function setUp() public initialize { - PolicyAuditHarness implementation = new PolicyAuditHarness(); - ERC1967Proxy proxy = new ERC1967Proxy( - address(implementation), - abi.encodeCall(PolicyAudit.initialize, accessManager) - ); - audit = PolicyAuditHarness(address(proxy)); - - handler = new PolicyAuditHandler(audit, admin); - targetContract(address(handler)); - } - - function invariant_StatusSynchronization() external view { - uint256 len = handler.policiesLength(); - for (uint256 i = 0; i < len; i++) { - address policy = handler.policyAt(i); - T.Status expected = handler.storedStatus(policy); - assertEq(uint8(audit.status(policy)), uint8(expected), "Status mismatch"); - } - } - - function invariant_IsAuditedMatchesActive() external view { - uint256 len = handler.policiesLength(); - for (uint256 i = 0; i < len; i++) { - address policy = handler.policyAt(i); - bool audited = audit.isAudited(policy); - bool expected = handler.storedStatus(policy) == T.Status.Active; - assertEq(audited, expected, "isAudited mismatch"); - } + assertTrue(audit.isApproved(address(policy1)), "Policy1 should be active"); + assertFalse(audit.isApproved(address(policy2)), "Policy2 should be blocked"); + assertTrue(audit.isRejected(address(policy2)), "Policy2 should be rejected"); + assertFalse(audit.isApproved(address(policy3)), "Policy3 should remain unapproved"); + assertFalse(audit.isRejected(address(policy3)), "Policy3 should not be rejected"); + assertTrue(audit.isPending(address(policy3)), "Policy3 should remain pending"); } } diff --git a/test/policies/PolicyBase.t.sol b/test/policies/PolicyBase.t.sol new file mode 100644 index 0000000..628a80e --- /dev/null +++ b/test/policies/PolicyBase.t.sol @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import "forge-std/Test.sol"; + +import { PolicyBase } from "contracts/policies/PolicyBase.sol"; +import { IPolicy } from "contracts/core/interfaces/policies/IPolicy.sol"; +import { IAttestationProvider } from "contracts/core/interfaces/base/IAttestationProvider.sol"; +import { IAssetRegistry } from "contracts/core/interfaces/assets/IAssetRegistry.sol"; +import { IRightsPolicyManagerVerifiable } from "contracts/core/interfaces/rights/IRightsPolicyManagerVerifiable.sol"; +import { IRightsPolicyAuthorizerVerifiable } from "contracts/core/interfaces/rights/IRightsPolicyAuthorizerVerifiable.sol"; +import { T } from "contracts/core/primitives/Types.sol"; + +import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; + +contract RightsPolicyManagerVerifiableMock is IRightsPolicyManagerVerifiable { + function getPolicies(address) external pure override returns (address[] memory policies) { + policies = new address[](0); + } + + function getActivePolicy(address, bytes memory) external pure override returns (bool active, address policyAddress) { + return (false, address(0)); + } + + function getActivePolicies(address, bytes memory) external pure override returns (address[] memory policies) { + policies = new address[](0); + } + + function isActivePolicy(address, address, bytes calldata) external pure override returns (bool) { + return false; + } + + function isRegisteredPolicy(address, address) external pure override returns (bool) { + return false; + } +} + +contract RightsPolicyAuthorizerVerifiableMock is IRightsPolicyAuthorizerVerifiable { + function getAuthorizedPolicies(address) external pure override returns (address[] memory policies) { + policies = new address[](0); + } + + function isPolicyAuthorized(address, address) external pure override returns (bool) { + return false; + } +} + +contract AttestationProviderMock is IAttestationProvider { + address[] internal _lastRecipients; + uint256 public lastExpireAt; + bytes public lastData; + uint256 public attestCalls; + uint256 private _nextId = 1; + mapping(address => mapping(uint256 => bool)) internal _issued; + + function getName() external pure returns (string memory) { + return "mock"; + } + + function getAddress() external view returns (address) { + return address(this); + } + + function attest( + address[] calldata recipients, + uint256 expireAt, + bytes calldata data + ) external override returns (uint256[] memory attestationIds) { + delete _lastRecipients; + uint256 len = recipients.length; + for (uint256 i = 0; i < len; i++) { + _lastRecipients.push(recipients[i]); + } + + lastExpireAt = expireAt; + lastData = data; + attestCalls++; + + attestationIds = new uint256[](len); + for (uint256 i = 0; i < len; i++) { + uint256 id = _nextId++; + attestationIds[i] = id; + _issued[recipients[i]][id] = true; + } + if (len == 0) { + _nextId++; + } + } + + function lastRecipientsLength() external view returns (uint256) { + return _lastRecipients.length; + } + + function lastRecipientAt(uint256 index) external view returns (address) { + return _lastRecipients[index]; + } + + function verify(uint256 attestationId, address recipient) external view returns (bool) { + return _issued[recipient][attestationId]; + } +} + +contract AssetRegistryMock is ERC721, IAssetRegistry { + constructor() ERC721("MockRegistry", "MREG") {} + + function register(address to, uint256 assetId) external override { + _mint(to, assetId); + } + + function revoke(uint256 assetId) external override { + _burn(assetId); + } + + function transfer(address to, uint256 assetId) external override { + safeTransferFrom(msg.sender, to, assetId); + } +} + +contract PolicyBaseHarness is PolicyBase { + constructor( + address rightsPolicyManager, + address rightsAuthorizer, + address assetRegistry, + address attestationProvider + ) PolicyBase(rightsPolicyManager, rightsAuthorizer, assetRegistry, attestationProvider) {} + + function managerPing() external onlyPolicyManager returns (bool) { + return true; + } + + function authorizerPing() external onlyPolicyAuthorizer returns (bool) { + return true; + } + + function exposeCommit( + address holder, + T.Agreement calldata agreement, + uint256 expireAt + ) external returns (uint256[] memory) { + return _commit(holder, agreement, expireAt); + } + + function exposeSetAttestation(address account, bytes memory context, uint256 attestationId) external { + _setAttestation(account, context, attestationId); + } + + function exposeHolder(uint256 assetId) external view returns (address) { + return _getHolder(assetId); + } + + function setup(address, bytes calldata) external pure override {} + + function enforce( + address, + T.Agreement calldata agreement + ) external pure override returns (uint256[] memory result) { + result = new uint256[](agreement.parties.length); + } + + function isAccessAllowed(address, bytes calldata) external pure override returns (bool) { + return true; + } + + function resolveTerms(bytes calldata) external pure override returns (T.Terms memory terms) {} + + function name() external pure override returns (string memory) { + return "PolicyBaseHarness"; + } + + function description() external pure override returns (string memory) { + return "Policy base test harness"; + } +} + +contract PolicyBaseTest is Test { + RightsPolicyManagerVerifiableMock internal manager; + RightsPolicyAuthorizerVerifiableMock internal authorizer; + AssetRegistryMock internal registry; + AttestationProviderMock internal attestation; + PolicyBaseHarness internal policy; + + address internal holder = address(0xBEEF); + address internal keeper = address(0xCAFE); + + function setUp() public { + manager = new RightsPolicyManagerVerifiableMock(); + authorizer = new RightsPolicyAuthorizerVerifiableMock(); + registry = new AssetRegistryMock(); + attestation = new AttestationProviderMock(); + policy = new PolicyBaseHarness(address(manager), address(authorizer), address(registry), address(attestation)); + } + + function test_GetAttestationProvider_ReturnsConfiguredAddress() public { + assertEq(policy.getAttestationProvider(), address(attestation), "Unexpected attestation provider address"); + } + + function test_SupportsInterface_ForIPolicy() public { + assertTrue(policy.supportsInterface(type(IPolicy).interfaceId), "IPolicy interface support missing"); + assertFalse(policy.supportsInterface(bytes4(0xdeadbeef)), "Unexpected interface should be unsupported"); + } + + function test_OnlyPolicyManager_AllowsManagerAddress() public { + vm.expectRevert( + abi.encodeWithSelector(PolicyBase.InvalidUnauthorizedCall.selector, "Only rights policy manager allowed.") + ); + policy.managerPing(); + + vm.prank(address(manager)); + assertTrue(policy.managerPing(), "Manager call should succeed"); + } + + function test_OnlyPolicyAuthorizer_AllowsAuthorizerAddress() public { + vm.expectRevert( + abi.encodeWithSelector(PolicyBase.InvalidUnauthorizedCall.selector, "Only rights policy authorizer allowed.") + ); + policy.authorizerPing(); + + vm.prank(address(authorizer)); + assertTrue(policy.authorizerPing(), "Authorizer call should succeed"); + } + + function test_SetAttestationStoresAndEmits() public { + address account = address(0xA11CE); + bytes memory context = abi.encodePacked(uint256(1)); + uint256 attestationId = 321; + bytes32 composedKey = keccak256(abi.encodePacked(account, context)); + + vm.expectEmit(true, true, true, true); + emit PolicyBase.AttestedAgreement(composedKey, account, attestationId); + + policy.exposeSetAttestation(account, context, attestationId); + assertEq(policy.getLicense(account, context), attestationId, "Stored attestation mismatch"); + } + + function test_CommitCreatesAttestations() public { + address[] memory parties = new address[](2); + parties[0] = holder; + parties[1] = keeper; + + T.Agreement memory agreement = T.Agreement({ + arbiter: address(0xAB), + currency: address(0xCD), + initiator: address(0xEF), + total: 1_000, + fees: 100, + locked: 900, + parties: parties, + payload: abi.encode("payload") + }); + + uint256 expireAt = block.timestamp + 1 days; + + vm.expectEmit(true, false, false, true); + emit PolicyBase.AgreementCommitted(holder, parties.length, agreement.total, agreement.fees); + + uint256[] memory attestationIds = policy.exposeCommit(holder, agreement, expireAt); + + assertEq(attestationIds.length, parties.length, "Attestation length mismatch"); + assertEq(attestationIds[0], 1, "First attestation id mismatch"); + assertEq(attestationIds[1], 2, "Second attestation id mismatch"); + assertEq(attestation.attestCalls(), 1, "Attest should be invoked once"); + assertEq(attestation.lastExpireAt(), expireAt, "Expire timestamp mismatch"); + assertEq(attestation.lastRecipientsLength(), parties.length, "Recipients length mismatch"); + assertEq(attestation.lastRecipientAt(0), holder, "First recipient mismatch"); + assertEq(attestation.lastRecipientAt(1), keeper, "Second recipient mismatch"); + } + + function test_GetHolderReadsFromRegistry() public { + uint256 assetId = 42; + registry.register(holder, assetId); + assertEq(policy.exposeHolder(assetId), holder, "Holder should come from registry"); + } +} diff --git a/test/primitives/AccessControlledUpgradeable.t.sol b/test/primitives/AccessControlledUpgradeable.t.sol index a51ddf9..7dc0d77 100644 --- a/test/primitives/AccessControlledUpgradeable.t.sol +++ b/test/primitives/AccessControlledUpgradeable.t.sol @@ -76,14 +76,11 @@ contract AccessControlledUpgradeableTest is Test { fresh.initialize(address(0)); } - function test_AdminAction_AllowsAdmin() public { + function test_AdminAction_AllowsOnlyAdmin() public { vm.prank(admin); uint256 result = harness.adminAction(); assertEq(result, 1, "Admin action should increment counter"); - assertEq(harness.counter(), 1, "Counter mismatch after admin action"); - } - function test_AdminAction_RevertsForNonAdmin() public { vm.expectRevert( abi.encodeWithSelector( AccessControlledUpgradeable.InvalidUnauthorizedOperation.selector, @@ -94,32 +91,20 @@ contract AccessControlledUpgradeableTest is Test { harness.adminAction(); } - function test_HasRole_ReflectsAssignments() public { - assertTrue(harness.hasRoleView(C.ADMIN_ROLE, admin), "Admin should have admin role"); - assertFalse(harness.hasRoleView(C.ADMIN_ROLE, operator), "Operator should not have admin role"); - - vm.prank(admin); - manager.grantRole(C.ADMIN_ROLE, operator, 0); - - assertTrue(harness.hasRoleView(C.ADMIN_ROLE, operator), "Operator admin role not reflected"); - } - function test_OpsAction_AllowsOperator() public { vm.prank(operator); uint256 result = harness.opsAction(); assertEq(result, 1, "Ops action should increment counter"); - } - function test_OpsAction_RevertsForUnauthorized() public { vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, stranger)); vm.prank(stranger); harness.opsAction(); } - function test_PauseBlocksOpsActionUntilUnpaused() public { + function test_PauseAndUnpauseControlOps() public { vm.prank(admin); harness.pause(); - assertTrue(harness.isPaused(), "Contract should be paused"); + assertTrue(harness.isPaused(), "Harness should be paused"); vm.expectRevert(PausableUpgradeable.EnforcedPause.selector); vm.prank(operator); @@ -127,185 +112,34 @@ contract AccessControlledUpgradeableTest is Test { vm.prank(admin); harness.unpause(); - assertFalse(harness.isPaused(), "Contract should be unpaused"); + assertFalse(harness.isPaused(), "Harness should be unpaused"); vm.prank(operator); uint256 result = harness.opsAction(); - assertEq(result, 1, "Ops action should succeed after unpause"); + assertEq(result, 1, "Ops action should work after unpause"); } - function test_Integration_GrantRevokeFlow() public { - vm.prank(operator); - harness.opsAction(); - assertEq(harness.counter(), 1, "Counter should increment after ops action"); + function test_RoleAssignmentsVisible() public { + assertTrue(harness.hasRoleView(C.ADMIN_ROLE, admin), "Admin should have admin role"); + assertTrue(harness.hasRoleView(C.OPS_ROLE, operator), "Operator should have ops role"); vm.prank(admin); manager.revokeRole(C.OPS_ROLE, operator); assertFalse(harness.hasRoleView(C.OPS_ROLE, operator), "Operator role should be revoked"); - - vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, operator)); - vm.prank(operator); - harness.opsAction(); } - function testFuzz_AdminAction_RevertsForNonAdmin(address caller) public { - vm.assume(caller != admin && caller != address(manager)); + function test_RolesCannotBeStolen() public { vm.expectRevert( abi.encodeWithSelector( AccessControlledUpgradeable.InvalidUnauthorizedOperation.selector, "Only admin can perform this action." ) ); - vm.prank(caller); - harness.adminAction(); - } - - function testFuzz_OpsAction_HonorsPause(bool pauseBeforeCall) public { - if (pauseBeforeCall && !harness.isPaused()) { - vm.prank(admin); - harness.pause(); - } - - if (harness.isPaused()) { - vm.expectRevert(PausableUpgradeable.EnforcedPause.selector); - vm.prank(operator); - harness.opsAction(); - - vm.prank(admin); - harness.unpause(); - } else { - vm.prank(operator); - harness.opsAction(); - } - } -} - -contract AccessControlledHandler is Test { - AccessControlledHarness public immutable harness; - AccessManager public immutable manager; - address public immutable admin; - address[] internal actors; - - uint256 internal expectedCounter; - bool internal expectedPaused; - - constructor(AccessControlledHarness harness_, AccessManager manager_, address admin_, address[] memory actors_) { - harness = harness_; - manager = manager_; - admin = admin_; - - for (uint256 i = 0; i < actors_.length; i++) { - actors.push(actors_[i]); - } - } - - function grantOpsRole(uint256 actorIdx) external { - vm.assume(actorIdx < actors.length); - address actor = actors[actorIdx]; - vm.prank(admin); - manager.grantRole(C.OPS_ROLE, actor, 0); - } - - function revokeOpsRole(uint256 actorIdx) external { - vm.assume(actorIdx < actors.length); - address actor = actors[actorIdx]; - if (!harness.hasRoleView(C.OPS_ROLE, actor)) return; - vm.prank(admin); - manager.revokeRole(C.OPS_ROLE, actor); - } - - function callAdminAction() external { - vm.prank(admin); + vm.prank(stranger); harness.adminAction(); - expectedCounter += 1; - } - function callOpsAction(uint256 actorIdx) external { - vm.assume(actorIdx < actors.length); - address actor = actors[actorIdx]; - if (!harness.hasRoleView(C.OPS_ROLE, actor) || harness.isPaused()) return; - vm.prank(actor); + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, stranger)); + vm.prank(stranger); harness.opsAction(); - expectedCounter += 1; } - - function pause() external { - if (expectedPaused) return; - vm.prank(admin); - harness.pause(); - expectedPaused = true; - } - - function unpause() external { - if (!expectedPaused) return; - vm.prank(admin); - harness.unpause(); - expectedPaused = false; - } - - function actorsLength() external view returns (uint256) { - return actors.length; - } - - function actorAt(uint256 idx) external view returns (address) { - return actors[idx]; - } - - function expectedCounterValue() external view returns (uint256) { - return expectedCounter; - } - - function expectedPausedState() external view returns (bool) { - return expectedPaused; - } -} - -contract AccessControlledInvariantTest is Test { - AccessManager internal manager; - AccessControlledHarness internal harness; - AccessControlledHandler internal handler; - - address internal admin = vm.addr(11); - address[] internal actors; - - function setUp() public { - manager = new AccessManager(admin); - harness = new AccessControlledHarness(); - - vm.prank(admin); - harness.initialize(address(manager)); - - vm.startPrank(admin); - bytes4[] memory adminSelectors = new bytes4[](3); - adminSelectors[0] = AccessControlledUpgradeable.pause.selector; - adminSelectors[1] = AccessControlledUpgradeable.unpause.selector; - adminSelectors[2] = AccessControlledHarness.adminAction.selector; - manager.setTargetFunctionRole(address(harness), adminSelectors, C.ADMIN_ROLE); - - bytes4[] memory opsSelectors = new bytes4[](1); - opsSelectors[0] = AccessControlledHarness.opsAction.selector; - manager.setTargetFunctionRole(address(harness), opsSelectors, C.OPS_ROLE); - manager.setRoleAdmin(C.OPS_ROLE, C.ADMIN_ROLE); - vm.stopPrank(); - - actors = new address[](3); - for (uint256 i = 0; i < actors.length; i++) { - actors[i] = vm.addr(12 + i); - } - - vm.prank(admin); - manager.grantRole(C.OPS_ROLE, actors[0], 0); - - handler = new AccessControlledHandler(harness, manager, admin, actors); - targetContract(address(handler)); - } - - function invariant_CounterMatchesExpectations() external view { - assertEq(harness.counter(), handler.expectedCounterValue(), "Counter expectation mismatch"); - } - - function invariant_PauseStateMatches() external view { - assertEq(harness.isPaused(), handler.expectedPausedState(), "Pause state mismatch"); - } - } diff --git a/test/primitives/AllowanceOperatorUpgradeable.t.sol b/test/primitives/AllowanceOperatorUpgradeable.t.sol index 7c9ada7..bbd2e43 100644 --- a/test/primitives/AllowanceOperatorUpgradeable.t.sol +++ b/test/primitives/AllowanceOperatorUpgradeable.t.sol @@ -17,7 +17,6 @@ contract AllowanceOperatorHarness is AllowanceOperatorUpgradeable { _sumLedgerEntry(account, amount, currency); } - // IAllowanceOperator interface function approve(address to, uint256 amount, address currency) external override returns (uint256) { return _approve(to, amount, currency); } @@ -30,34 +29,33 @@ contract AllowanceOperatorHarness is AllowanceOperatorUpgradeable { return _collect(from, amount, currency); } - + function allowance(address owner, address spender, address currency) external view returns (uint256) { + return getApprovedAmount(owner, spender, currency); + } } -contract AllowanceOperatorTest is Test { - AllowanceOperatorHarness harness; +contract AllowanceOperatorUpgradeableTest is Test { + AllowanceOperatorHarness internal harness; address internal constant TOKEN = address(0xC0FFEE); - address alice; - address bob; - address carol; + address internal alice = vm.addr(1); + address internal bob = vm.addr(2); + address internal carol = vm.addr(3); function setUp() public { harness = new AllowanceOperatorHarness(); harness.initialize(); - alice = vm.addr(1); - bob = vm.addr(2); - carol = vm.addr(3); } - function test_Approve_SetsAllowanceAndEmitsEvent() public { + function test_ApproveStoresAllowanceAndEmits() public { vm.prank(alice); vm.expectEmit(true, true, false, true, address(harness)); - emit IAllowanceApprovable.FundsApproved(alice, bob, 10, TOKEN); - harness.approve(bob, 10, TOKEN); + emit IAllowanceApprovable.FundsApproved(alice, bob, 25 ether, TOKEN); + harness.approve(bob, 25 ether, TOKEN); - assertEq(harness.getApprovedAmount(alice, bob, TOKEN), 10, "Allowance mismatch"); + assertEq(harness.allowance(alice, bob, TOKEN), 25 ether, "Allowance mismatch"); } - function test_Approve_RevertWhen_InvalidParams() public { + function test_Approve_RevertWhen_InvalidParameters() public { vm.prank(alice); vm.expectRevert(bytes4(keccak256("InvalidOperationParameters()"))); harness.approve(address(0), 10, TOKEN); @@ -65,241 +63,90 @@ contract AllowanceOperatorTest is Test { vm.prank(alice); vm.expectRevert(bytes4(keccak256("InvalidOperationParameters()"))); harness.approve(bob, 0, TOKEN); - } - function test_Approve_RevertWhen_SelfApproval() public { vm.prank(alice); vm.expectRevert(bytes4(keccak256("InvalidOperationParameters()"))); - harness.approve(alice, 1, TOKEN); + harness.approve(alice, 5, TOKEN); } - function test_Revoke_RemovesAllowance() public { + function test_RevokeReducesAllowance() public { vm.startPrank(alice); - harness.approve(bob, 20, TOKEN); - harness.revoke(bob, 5, TOKEN); + harness.approve(bob, 40 ether, TOKEN); + uint256 revoked = harness.revoke(bob, 15 ether, TOKEN); vm.stopPrank(); - assertEq(harness.getApprovedAmount(alice, bob, TOKEN), 15, "Allowance after revoke mismatch"); + assertEq(revoked, 15 ether, "Revoked amount mismatch"); + assertEq(harness.allowance(alice, bob, TOKEN), 25 ether, "Remaining allowance mismatch"); } - function test_Revoke_RevertWhen_ExceedsAllowance() public { + function test_Revoke_RevertWhen_InsufficientAllowance() public { vm.startPrank(alice); - harness.approve(bob, 5, TOKEN); + harness.approve(bob, 10 ether, TOKEN); vm.expectRevert(bytes4(keccak256("NoFundsToRevoke()"))); - harness.revoke(bob, 6, TOKEN); + harness.revoke(bob, 12 ether, TOKEN); vm.stopPrank(); } - function test_Collect_TransfersApprovedFunds() public { + function test_CollectTransfersLedgerBetweenAccounts() public { + harness.boostLedger(alice, 60 ether, TOKEN); vm.prank(alice); - harness.approve(bob, 40, TOKEN); - harness.boostLedger(alice, 40, TOKEN); + harness.approve(bob, 45 ether, TOKEN); - vm.prank(bob); vm.expectEmit(true, true, false, true, address(harness)); - emit IAllowanceCollectable.FundsCollected(alice, bob, 35, TOKEN); - harness.collect(alice, 35, TOKEN); + emit IAllowanceCollectable.FundsCollected(alice, bob, 30 ether, TOKEN); + vm.prank(bob); + harness.collect(alice, 30 ether, TOKEN); - assertEq(harness.getApprovedAmount(alice, bob, TOKEN), 5, "Remaining allowance mismatch"); - assertEq(ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN), 5, "Alice ledger mismatch"); - assertEq(ILedgerVerifiable(address(harness)).getLedgerBalance(bob, TOKEN), 35, "Bob ledger mismatch"); + ILedgerVerifiable ledger = ILedgerVerifiable(address(harness)); + assertEq(harness.allowance(alice, bob, TOKEN), 15 ether, "Allowance should decrease"); + assertEq(ledger.getLedgerBalance(alice, TOKEN), 30 ether, "Alice ledger mismatch"); + assertEq(ledger.getLedgerBalance(bob, TOKEN), 30 ether, "Bob ledger mismatch"); } - function test_Collect_RevertWhen_NoApproval() public { - harness.boostLedger(alice, 20, TOKEN); - + function test_Collect_RevertWhen_NoAllowance() public { + harness.boostLedger(alice, 20 ether, TOKEN); vm.prank(bob); vm.expectRevert(bytes4(keccak256("NoFundsToCollect()"))); - harness.collect(alice, 10, TOKEN); + harness.collect(alice, 10 ether, TOKEN); } - function test_Collect_RevertWhen_InsufficientBalance() public { + function test_Collect_RevertWhen_InsufficientLedger() public { vm.prank(alice); - harness.approve(bob, 10, TOKEN); - + harness.approve(bob, 10 ether, TOKEN); vm.prank(bob); vm.expectRevert(bytes4(keccak256("NoFundsToCollect()"))); - harness.collect(alice, 5, TOKEN); + harness.collect(alice, 5 ether, TOKEN); } - function test_Integration_MultiRecipientFlow() public { - vm.prank(alice); - harness.approve(bob, 30, TOKEN); - vm.prank(alice); - harness.approve(carol, 15, TOKEN); - harness.boostLedger(alice, 45, TOKEN); + function test_Integration_ApproveCollectRevokeFlow() public { + harness_boostAndApprove(alice, bob, 80 ether, 60 ether); + harness_boostAndApprove(alice, carol, 80 ether, 15 ether); vm.prank(bob); - harness.collect(alice, 20, TOKEN); + harness.collect(alice, 30 ether, TOKEN); vm.prank(carol); - harness.collect(alice, 10, TOKEN); - - assertEq(harness.getApprovedAmount(alice, bob, TOKEN), 10, "Bob remaining allowance"); - assertEq(harness.getApprovedAmount(alice, carol, TOKEN), 5, "Carol remaining allowance"); - assertEq(ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN), 15, "Alice ledger balance"); - assertEq(ILedgerVerifiable(address(harness)).getLedgerBalance(bob, TOKEN), 20, "Bob ledger balance"); - assertEq(ILedgerVerifiable(address(harness)).getLedgerBalance(carol, TOKEN), 10, "Carol ledger balance"); - } - - function testFuzz_ApproveRevokeCycle(uint256 amount, uint256 revokeAmount) public { - amount = bound(amount, 1, 1e24); - revokeAmount = bound(revokeAmount, 1, amount); - - vm.prank(alice); - harness.approve(bob, amount, TOKEN); - - vm.prank(alice); - harness.revoke(bob, revokeAmount, TOKEN); - - assertEq(harness.getApprovedAmount(alice, bob, TOKEN), amount - revokeAmount, "Allowance after fuzz revoke mismatch"); - } - - function testFuzz_CollectMaintainsLedger(uint256 deposit, uint256 collectAmount) public { - deposit = bound(deposit, 1e18, 1e24); - collectAmount = bound(collectAmount, 1e18, deposit); - - vm.prank(alice); - harness.approve(bob, deposit, TOKEN); - harness.boostLedger(alice, deposit, TOKEN); - - vm.prank(bob); - harness.collect(alice, collectAmount, TOKEN); - - uint256 total = - ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN) + - ILedgerVerifiable(address(harness)).getLedgerBalance(bob, TOKEN); - assertEq(total, deposit, "Ledger conservation failed"); - } -} - -contract AllowanceHandler is Test { - AllowanceOperatorHarness public immutable harness; - address[] internal accounts; - address internal constant TOKEN = address(0xC0FFEE); - uint256 internal constant MAX_TEST_AMOUNT = 1e24; - - mapping(address => uint256) internal ledgerExpectation; - mapping(bytes32 => uint256) internal allowanceExpectation; - - constructor(AllowanceOperatorHarness operator) { - harness = operator; - for (uint256 i = 0; i < 3; i++) { - accounts.push(vm.addr(i + 10)); - } - } + harness.collect(alice, 10 ether, TOKEN); - function seedLedger(uint256 index, uint256 amount) external { - vm.assume(index < accounts.length); - address account = accounts[index]; - amount = bound(amount, 1, MAX_TEST_AMOUNT); - harness.boostLedger(account, amount, TOKEN); - ledgerExpectation[account] += amount; - } - - function approve(uint256 fromIdx, uint256 toIdx, uint256 amount) external { - vm.assume(fromIdx < accounts.length && toIdx < accounts.length && fromIdx != toIdx); - address from = accounts[fromIdx]; - address to = accounts[toIdx]; - amount = bound(amount, 1, MAX_TEST_AMOUNT); - - vm.prank(from); - harness.approve(to, amount, TOKEN); - - bytes32 key = keccak256(abi.encode(from, to)); - allowanceExpectation[key] += amount; - } - - function revoke(uint256 fromIdx, uint256 toIdx, uint256 amount) external { - vm.assume(fromIdx < accounts.length && toIdx < accounts.length && fromIdx != toIdx); - address from = accounts[fromIdx]; - address to = accounts[toIdx]; - bytes32 key = keccak256(abi.encode(from, to)); - uint256 expected = allowanceExpectation[key]; - if (expected == 0) return; - amount = bound(amount, 1, expected); - - vm.prank(from); - harness.revoke(to, amount, TOKEN); - allowanceExpectation[key] = expected - amount; - } - - function collect(uint256 fromIdx, uint256 toIdx, uint256 amount) external { - vm.assume(fromIdx < accounts.length && toIdx < accounts.length && fromIdx != toIdx); - address from = accounts[fromIdx]; - address to = accounts[toIdx]; - bytes32 key = keccak256(abi.encode(from, to)); - uint256 allowance = allowanceExpectation[key]; - uint256 availableLedger = ledgerExpectation[from]; - if (allowance == 0 || availableLedger == 0) return; - uint256 maxCollect = allowance < availableLedger ? allowance : availableLedger; - amount = bound(amount, 1, maxCollect); - - vm.prank(to); - harness.collect(from, amount, TOKEN); - - allowanceExpectation[key] = allowance - amount; - ledgerExpectation[from] -= amount; - ledgerExpectation[to] += amount; - } - - function accountsLength() external view returns (uint256) { - return accounts.length; - } - - function accountAt(uint256 idx) external view returns (address) { - return accounts[idx]; - } - - function expectedLedger(address account) external view returns (uint256) { - return ledgerExpectation[account]; - } - - function expectedAllowance(address from, address to) external view returns (uint256) { - return allowanceExpectation[keccak256(abi.encode(from, to))]; - } - - function token() external pure returns (address) { - return TOKEN; - } -} - -contract AllowanceOperatorInvariantTest is Test { - AllowanceOperatorHarness harness; - AllowanceHandler handler; - - function setUp() public { - harness = new AllowanceOperatorHarness(); - harness.initialize(); - handler = new AllowanceHandler(harness); - targetContract(address(handler)); - } + vm.startPrank(alice); + harness.revoke(bob, 10 ether, TOKEN); + vm.stopPrank(); - function invariant_LedgerBalancesMatchExpectation() external view { - uint256 len = handler.accountsLength(); - for (uint256 i = 0; i < len; i++) { - address account = handler.accountAt(i); - assertEq( - ILedgerVerifiable(address(harness)).getLedgerBalance(account, handler.token()), - handler.expectedLedger(account), - "Ledger balance mismatch" - ); - } + ILedgerVerifiable ledger = ILedgerVerifiable(address(harness)); + assertEq(ledger.getLedgerBalance(alice, TOKEN), 80 ether - 40 ether, "Alice residual ledger mismatch"); + assertEq(ledger.getLedgerBalance(bob, TOKEN), 30 ether, "Bob ledger mismatch"); + assertEq(ledger.getLedgerBalance(carol, TOKEN), 10 ether, "Carol ledger mismatch"); + assertEq(harness.allowance(alice, bob, TOKEN), 20 ether, "Bob allowance mismatch"); + assertEq(harness.allowance(alice, carol, TOKEN), 5 ether, "Carol allowance mismatch"); } - function invariant_AllowancesMatchExpectation() external view { - uint256 len = handler.accountsLength(); - for (uint256 i = 0; i < len; i++) { - address from = handler.accountAt(i); - for (uint256 j = 0; j < len; j++) { - address to = handler.accountAt(j); - if (from == to) continue; - assertEq( - harness.getApprovedAmount(from, to, handler.token()), - handler.expectedAllowance(from, to), - "Allowance mismatch" - ); - } + function harness_boostAndApprove(address owner, address spender, uint256 seedAmount, uint256 allowanceAmount) internal { + ILedgerVerifiable ledger = ILedgerVerifiable(address(harness)); + uint256 currentBalance = ledger.getLedgerBalance(owner, TOKEN); + if (currentBalance < seedAmount) { + harness.boostLedger(owner, seedAmount - currentBalance, TOKEN); } + vm.prank(owner); + harness.approve(spender, allowanceAmount, TOKEN); } } diff --git a/test/primitives/BalanceOperatorUpgradeable.t.sol b/test/primitives/BalanceOperatorUpgradeable.t.sol index 0b8dc5e..1178ca1 100644 --- a/test/primitives/BalanceOperatorUpgradeable.t.sol +++ b/test/primitives/BalanceOperatorUpgradeable.t.sol @@ -2,347 +2,200 @@ pragma solidity 0.8.26; import "forge-std/Test.sol"; -import { BaseTest } from "test/BaseTest.t.sol"; -import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; -import { ILedgerVerifiable } from "contracts/core/interfaces/base/ILedgerVerifiable.sol"; + +import { BalanceOperatorUpgradeable } from "contracts/core/primitives/upgradeable/BalanceOperatorUpgradeable.sol"; import { IBalanceDepositor } from "contracts/core/interfaces/base/IBalanceDepositor.sol"; -import { IBalanceVerifiable } from "contracts/core/interfaces/base/IBalanceVerifiable.sol"; -import { IBalanceTransferable } from "contracts/core/interfaces/base/IBalanceTransferable.sol"; import { IBalanceWithdrawable } from "contracts/core/interfaces/base/IBalanceWithdrawable.sol"; -import { BalanceOperatorUpgradeable } from "contracts/core/primitives/upgradeable/BalanceOperatorUpgradeable.sol"; - -/// @notice Thin wrapper to expose BalanceOperatorUpgradeable internal entrypoints for testing. -contract BalanceOperatorHarness is BalanceOperatorUpgradeable { - function deposit(address recipient, uint256 amount, address currency) external payable returns (uint256) { - return _deposit(recipient, amount, currency); - } - - function withdraw(address recipient, uint256 amount, address currency) external returns (uint256) { - return _withdraw(recipient, amount, currency); - } - - function transfer(address recipient, uint256 amount, address currency) external returns (uint256) { - return _transfer(recipient, amount, currency); - } -} - - -contract BalanceOperatorUpgradeableTest is BaseTest { - BalanceOperatorHarness operator; - address opAddress; - - function setUp() public initialize { - deployToken(); - operator = new BalanceOperatorHarness(); - opAddress = address(operator); - } +import { IBalanceTransferable } from "contracts/core/interfaces/base/IBalanceTransferable.sol"; +import { IBalanceVerifiable } from "contracts/core/interfaces/base/IBalanceVerifiable.sol"; +import { ILedgerVerifiable } from "contracts/core/interfaces/base/ILedgerVerifiable.sol"; +import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; - function test_Deposit_ValidDeposit() public { - // 100 MMC - uint256 amount = 100 * 1e18; - vm.startPrank(admin); - uint256 prevBalance = IERC20(token).balanceOf(admin); - uint256 confirmed = _validDeposit(admin, amount); - uint256 afterBalance = IERC20(token).balanceOf(admin); +contract MockToken is IERC20 { + string public constant name = "MockToken"; + string public constant symbol = "MOCK"; + uint8 public constant decimals = 18; - uint256 balance = ILedgerVerifiable(opAddress).getLedgerBalance(admin, token); - uint256 contractBalance = IBalanceVerifiable(opAddress).getBalance(token); - vm.stopPrank(); + mapping(address => uint256) private _balances; + mapping(address => mapping(address => uint256)) private _allowances; + uint256 private _totalSupply; - assertEq(confirmed, balance, "Confirmed amount should match ledger balance"); - assertEq(contractBalance, confirmed, "Contract balance should match confirmed amount"); - assertEq(afterBalance, prevBalance - confirmed, "Admin balance should decrease by confirmed amount"); + function totalSupply() external view override returns (uint256) { + return _totalSupply; } - function test_Deposit_FundsDepositedEventEmitted() public { - uint256 amount = 100 * 1e18; - vm.startPrank(admin); - IERC20(token).approve(opAddress, amount); - - vm.expectEmit(true, true, false, true, address(opAddress)); - emit IBalanceDepositor.FundsDeposited(admin, admin, amount, token); - IBalanceDepositor(opAddress).deposit(admin, amount, token); - vm.stopPrank(); + function balanceOf(address account) external view override returns (uint256) { + return _balances[account]; } - function test_Deposit_RevertWhen_InvalidApproval() public { - vm.expectRevert(abi.encodeWithSignature("FailDuringDeposit(string)", "Amount exceeds allowance.")); - IBalanceDepositor(opAddress).deposit(admin, 100 * 1e18, token); + function transfer(address to, uint256 amount) external override returns (bool) { + _transfer(msg.sender, to, amount); + return true; } - function test_Deposit_RevertIf_InvalidParams() public { - uint256 amount = 0; - address account = address(0); - bytes4 err = bytes4(keccak256("InvalidOperationParameters()")); - // must fail if account = address(0) or amount == 0 - vm.expectRevert(err); - IBalanceDepositor(opAddress).deposit(admin, amount, token); - - vm.expectRevert(err); - IBalanceDepositor(opAddress).deposit(account, 1 * 1e18, token); - } - - function test_Withdraw_ValidWithdraw() public { - // 100 MMC - uint256 amount = 100 * 1e18; - vm.startPrank(admin); - uint256 prevBalance = IERC20(token).balanceOf(admin); - uint256 deposited = _validDeposit(admin, amount); - uint256 afterBalance = IERC20(token).balanceOf(admin); - - uint256 confirmed = IBalanceWithdrawable(opAddress).withdraw(admin, deposited, token); - uint256 balance = ILedgerVerifiable(opAddress).getLedgerBalance(admin, token); - uint256 contractBalance = IBalanceVerifiable(opAddress).getBalance(token); - vm.stopPrank(); - - assertEq(confirmed, deposited, "Confirmed amount should match deposited amount"); - assertEq(prevBalance, afterBalance + confirmed, "Admin balance should increase by confirmed amount"); - assertEq(contractBalance, 0, "Contract balance should be zero after withdrawal"); - assertEq(balance, 0, "Ledger balance should be zero after withdrawal"); + function allowance(address owner, address spender) external view override returns (uint256) { + return _allowances[owner][spender]; } - function test_Withdraw_FundsWithdrawnEventEmitted() public { - uint256 amount = 100 * 1e18; - vm.startPrank(admin); - _validDeposit(admin, amount); - - vm.expectEmit(true, true, false, true, address(opAddress)); - emit IBalanceWithdrawable.FundsWithdrawn(admin, admin, amount, token); - IBalanceWithdrawable(opAddress).withdraw(admin, amount, token); - vm.stopPrank(); + function approve(address spender, uint256 amount) external override returns (bool) { + _allowances[msg.sender][spender] = amount; + emit Approval(msg.sender, spender, amount); + return true; } - function test_Withdraw_RevertIf_NoFunds() public { - vm.expectRevert(bytes4(keccak256("NoFundsToWithdraw()"))); - IBalanceWithdrawable(opAddress).withdraw(admin, 1 * 1e18, token); + function transferFrom(address from, address to, uint256 amount) external override returns (bool) { + uint256 currentAllowance = _allowances[from][msg.sender]; + require(currentAllowance >= amount, "insufficient allowance"); + _allowances[from][msg.sender] = currentAllowance - amount; + _transfer(from, to, amount); + return true; } - function test_Withdraw_RevertIf_InvalidParams() public { - uint256 amount = 0; - address account = address(0); - bytes4 err = bytes4(keccak256("InvalidOperationParameters()")); - // must fail if account = address(0) or amount == 0 - vm.expectRevert(err); - IBalanceWithdrawable(opAddress).withdraw(admin, amount, token); - - vm.expectRevert(err); - IBalanceWithdrawable(opAddress).withdraw(account, 1 * 1e18, token); + function mint(address to, uint256 amount) external { + _balances[to] += amount; + _totalSupply += amount; + emit Transfer(address(0), to, amount); } - function test_Transfer_ValidTransfer() public { - // 100 MMC - uint256 amount = 100 * 1e18; - uint256 expectedAfter = amount / 2; - address user = vm.addr(7); - - vm.startPrank(admin); - _validDeposit(admin, amount); - // transfer the haft of the balance to user - uint256 confirmed = IBalanceTransferable(opAddress).transfer(user, expectedAfter, token); - uint256 contractBalance = IBalanceVerifiable(opAddress).getBalance(token); - vm.stopPrank(); - - ILedgerVerifiable verifier = ILedgerVerifiable(opAddress); - uint256 balanceAdmin = verifier.getLedgerBalance(admin, token); - uint256 balanceUser = verifier.getLedgerBalance(user, token); - - assertEq(contractBalance, amount, "Contract balance should match initial deposit"); - assertEq(balanceAdmin, expectedAfter, "Admin balance should be half after transfer"); - assertEq(balanceUser, confirmed, "User balance should match transferred amount"); + function _transfer(address from, address to, uint256 amount) private { + require(to != address(0), "invalid to"); + require(_balances[from] >= amount, "insufficient balance"); + _balances[from] -= amount; + _balances[to] += amount; + emit Transfer(from, to, amount); } +} - function test_Transfer_FundsTransferredEventEmitted() public { - // 100 MMC - uint256 amount = 100 * 1e18; - address user = vm.addr(7); - - vm.startPrank(admin); - _validDeposit(admin, amount); - // transfer the haft of the balance to user - vm.expectEmit(true, true, false, true, address(opAddress)); - emit IBalanceTransferable.FundsTransferred(user, admin, amount, token); - IBalanceTransferable(opAddress).transfer(user, amount, token); - vm.stopPrank(); +contract BalanceOperatorHarness is BalanceOperatorUpgradeable { + function deposit(address recipient, uint256 amount, address currency) external payable returns (uint256) { + return _deposit(recipient, amount, currency); } - function test_Transfer_RevertIf_NoFunds() public { - vm.expectRevert(bytes4(keccak256("NoFundsToTransfer()"))); - IBalanceTransferable(opAddress).transfer(vm.addr(7), 1 * 1e18, token); + function withdraw(address recipient, uint256 amount, address currency) external returns (uint256) { + return _withdraw(recipient, amount, currency); } - function test_Transfer_RevertIf_InvalidParams() public { - uint256 amount = 0; - address account = address(0); - bytes4 err = bytes4(keccak256("InvalidOperationParameters()")); - // must fail if account = address(0) or amount == 0 - vm.expectRevert(err); - IBalanceTransferable(opAddress).transfer(admin, amount, token); - - vm.expectRevert(err); - IBalanceTransferable(opAddress).transfer(account, 1 * 1e18, token); - - vm.prank(admin); - vm.expectRevert(err); - // sender cannot be the recipient - IBalanceTransferable(opAddress).transfer(admin, 1 * 1e18, token); + function transfer(address recipient, uint256 amount, address currency) external returns (uint256) { + return _transfer(recipient, amount, currency); } +} - function test_Integration_DepositTransferWithdrawFlow() public { - uint256 depositAmount = 250 * 1e18; - address recipient = vm.addr(8); +contract BalanceOperatorUpgradeableTest is Test { + BalanceOperatorHarness internal operator; + MockToken internal token; + address internal op; + address internal alice; + address internal bob; - vm.startPrank(admin); - _validDeposit(admin, depositAmount); - IBalanceTransferable(opAddress).transfer(recipient, 40 * 1e18, token); - IBalanceTransferable(opAddress).transfer(vm.addr(9), 60 * 1e18, token); - uint256 withdrawn = IBalanceWithdrawable(opAddress).withdraw(admin, 90 * 1e18, token); - vm.stopPrank(); + function setUp() public { + operator = new BalanceOperatorHarness(); + token = new MockToken(); + op = address(operator); + alice = vm.addr(1); + bob = vm.addr(2); - ILedgerVerifiable verifier = ILedgerVerifiable(opAddress); - assertEq(withdrawn, 90 * 1e18, "Withdrawn amount mismatch"); - assertEq(verifier.getLedgerBalance(admin, token), 60 * 1e18, "Admin residual ledger mismatch"); - assertEq(verifier.getLedgerBalance(recipient, token), 40 * 1e18, "Recipient ledger mismatch"); - assertEq( - IBalanceVerifiable(opAddress).getBalance(token), - depositAmount - withdrawn, - "Contract balance mismatch" - ); + token.mint(alice, 1_000 ether); + token.mint(bob, 500 ether); } - function testFuzz_DepositWithdrawMaintainsLedger(uint256 amount) public { - amount = bound(amount, 1e18, 1_000 * 1e18); - - vm.startPrank(admin); - uint256 deposited = _validDeposit(admin, amount); - uint256 withdrawn = IBalanceWithdrawable(opAddress).withdraw(admin, deposited, token); + function _deposit(address account, uint256 amount) internal returns (uint256) { + vm.startPrank(account); + token.approve(op, amount); + uint256 confirmed = IBalanceDepositor(op).deposit(account, amount, address(token)); vm.stopPrank(); - - assertEq(deposited, withdrawn, "Mismatch between deposit and withdrawal"); - assertEq(ILedgerVerifiable(opAddress).getLedgerBalance(admin, token), 0, "Admin ledger should be zero"); - assertEq(IBalanceVerifiable(opAddress).getBalance(token), 0, "Contract balance should be zero"); + return confirmed; } - function testFuzz_TransferDistributesLedger(uint256 depositAmount, uint256 transferAmount) public { - depositAmount = bound(depositAmount, 2e18, 1_000 * 1e18); - transferAmount = bound(transferAmount, 1e18, depositAmount - 1); - address recipient = vm.addr(10); - - vm.startPrank(admin); - _validDeposit(admin, depositAmount); - IBalanceTransferable(opAddress).transfer(recipient, transferAmount, token); - vm.stopPrank(); + function test_Deposit_UpdatesLedgerAndVault() public { + uint256 amount = 200 ether; + uint256 confirmed = _deposit(alice, amount); - ILedgerVerifiable verifier = ILedgerVerifiable(opAddress); + assertEq(confirmed, amount, "Confirmed amount mismatch"); assertEq( - verifier.getLedgerBalance(admin, token) + verifier.getLedgerBalance(recipient, token), - depositAmount, - "Ledger conservation failed" + ILedgerVerifiable(op).getLedgerBalance(alice, address(token)), + amount, + "Ledger should reflect deposit" ); + assertEq(IBalanceVerifiable(op).getBalance(address(token)), amount, "Vault balance mismatch"); + assertEq(token.balanceOf(alice), 800 ether, "Token balance should decrease"); } - function _validDeposit(address account, uint256 amount) private returns (uint256) { - IERC20(token).approve(opAddress, amount); - return IBalanceDepositor(opAddress).deposit(account, amount, token); + function test_Deposit_RevertWhen_NoAllowance() public { + vm.expectRevert(abi.encodeWithSignature("FailDuringDeposit(string)", "Amount exceeds allowance.")); + IBalanceDepositor(op).deposit(alice, 1 ether, address(token)); } -} - -contract BalanceOperatorHandler is Test { - IERC20 internal immutable token; - BalanceOperatorHarness internal immutable operator; + function test_Withdraw_ReturnsFundsAndClearsLedger() public { + uint256 amount = 150 ether; + _deposit(alice, amount); - uint256 public totalDeposited; - address[] public actors; + vm.prank(alice); + uint256 withdrawn = IBalanceWithdrawable(op).withdraw(alice, amount, address(token)); - constructor(BalanceOperatorHarness op, address currency) { - operator = op; - token = IERC20(currency); - - for (uint256 i = 0; i < 10; i++) { - actors.push(vm.addr(i + 1)); - } + assertEq(withdrawn, amount, "Withdrawn amount mismatch"); + assertEq(ILedgerVerifiable(op).getLedgerBalance(alice, address(token)), 0, "Ledger should be zero"); + assertEq(IBalanceVerifiable(op).getBalance(address(token)), 0, "Vault balance should be zero"); + assertEq(token.balanceOf(alice), 1_000 ether, "Token balance should be restored"); } - function getActors() external view returns (address[] memory) { - return actors; + function test_Withdraw_RevertWhen_InsufficientLedger() public { + _deposit(alice, 10 ether); + vm.expectRevert(bytes4(keccak256("NoFundsToWithdraw()"))); + vm.prank(alice); + IBalanceWithdrawable(op).withdraw(alice, 20 ether, address(token)); } - function deposit(uint256 actorIndex, uint256 amount) external { - vm.assume(actorIndex < actors.length); - address actor = actors[actorIndex]; - uint256 balance = token.balanceOf(actor); - if (balance == 0) return; - amount = bound(amount, 1, balance); + function test_Transfer_MovesLedgerBalances() public { + uint256 amount = 120 ether; + _deposit(alice, amount); - vm.startPrank(actor); - token.approve(address(operator), amount); - uint256 confirmed = operator.deposit(actor, amount, address(token)); - vm.stopPrank(); + vm.prank(alice); + uint256 moved = IBalanceTransferable(op).transfer(bob, 45 ether, address(token)); - totalDeposited += confirmed; - } - - function withdraw(uint256 actorIndex, uint256 amount) external { - vm.assume(actorIndex < actors.length); - address actor = actors[actorIndex]; - uint256 available = operator.getLedgerBalance(actor, address(token)); - if (available == 0) return; - amount = bound(amount, 1, available); - - vm.prank(actor); - uint256 confirmed = operator.withdraw(actor, amount, address(token)); - totalDeposited -= confirmed; + assertEq(moved, 45 ether, "Transfer amount mismatch"); + ILedgerVerifiable ledger = ILedgerVerifiable(op); + assertEq(ledger.getLedgerBalance(alice, address(token)), 75 ether, "Alice ledger mismatch"); + assertEq(ledger.getLedgerBalance(bob, address(token)), 45 ether, "Bob ledger mismatch"); + assertEq( + ledger.getLedgerBalance(alice, address(token)) + ledger.getLedgerBalance(bob, address(token)), + amount, + "Ledger totals should conserve value" + ); } - function transfer(uint256 actorIndex, uint256 actorIndexB, uint256 amount) external { - vm.assume(actorIndex < actors.length); - vm.assume(actorIndexB < actors.length); - vm.assume(actorIndex != actorIndexB); + function test_Transfer_RevertWhen_SelfOrZero() public { + _deposit(alice, 50 ether); - address from = actors[actorIndex]; - address to = actors[actorIndexB]; - uint256 balance = operator.getLedgerBalance(from, address(token)); - if (balance == 0) return; - amount = bound(amount, 1, balance); + vm.expectRevert(bytes4(keccak256("InvalidOperationParameters()"))); + vm.prank(alice); + IBalanceTransferable(op).transfer(alice, 10 ether, address(token)); - vm.prank(from); - operator.transfer(to, amount, address(token)); + vm.expectRevert(bytes4(keccak256("InvalidOperationParameters()"))); + vm.prank(alice); + IBalanceTransferable(op).transfer(bob, 0, address(token)); } -} - -contract BalanceOperatorInvariantTest is BaseTest { - BalanceOperatorHarness internal operator; - BalanceOperatorHandler internal handler; - address internal opAddress; - - function setUp() public initialize { - deployToken(); - operator = new BalanceOperatorHarness(); - handler = new BalanceOperatorHandler(operator, token); - opAddress = address(operator); - address[] memory actors = handler.getActors(); - uint256 len = actors.length; - for (uint256 i = 0; i < len; i++) { - vm.prank(admin); - IERC20(token).transfer(actors[i], 100 * 1e18); - } + function test_Integration_DepositTransferWithdraw() public { + uint256 amount = 300 ether; + _deposit(alice, amount); - targetContract(address(handler)); - } - - function invariant_TotalDepositsMatchVault() external { - assertEq(handler.totalDeposited(), IBalanceVerifiable(opAddress).getBalance(token), "Deposit ledger mismatch"); - } + vm.prank(alice); + IBalanceTransferable(op).transfer(bob, 100 ether, address(token)); - function invariant_SumOfLedgersEqualsVaultBalance() external { - uint256 aggregate; - address[] memory actors = handler.getActors(); - uint256 len = actors.length; - for (uint256 i = 0; i < len; i++) { - aggregate += ILedgerVerifiable(opAddress).getLedgerBalance(actors[i], token); - } + vm.prank(bob); + uint256 withdrawnBob = IBalanceWithdrawable(op).withdraw(bob, 60 ether, address(token)); + vm.prank(alice); + uint256 withdrawnAlice = IBalanceWithdrawable(op).withdraw(alice, 200 ether, address(token)); - assertEq(aggregate, IBalanceVerifiable(opAddress).getBalance(token), "Ledger aggregation mismatch"); + ILedgerVerifiable ledger = ILedgerVerifiable(op); + assertEq(withdrawnBob, 60 ether, "Bob withdrawal mismatch"); + assertEq(withdrawnAlice, 200 ether, "Alice withdrawal mismatch"); + assertEq(ledger.getLedgerBalance(alice, address(token)), 0, "Alice ledger should be zero"); + assertEq(ledger.getLedgerBalance(bob, address(token)), 40 ether, "Bob remaining ledger mismatch"); + assertEq( + IBalanceVerifiable(op).getBalance(address(token)), + 40 ether, + "Vault balance should equal remaining ledger" + ); } } diff --git a/test/primitives/LedgerUpgradeable.t.sol b/test/primitives/LedgerUpgradeable.t.sol index fdec3a0..7d21ca5 100644 --- a/test/primitives/LedgerUpgradeable.t.sol +++ b/test/primitives/LedgerUpgradeable.t.sol @@ -24,7 +24,10 @@ contract LedgerUpgradeableHarness is LedgerUpgradeable { } contract LedgerUpgradeableTest is Test { - LedgerUpgradeableHarness harness; + LedgerUpgradeableHarness internal harness; + address internal alice = vm.addr(11); + address internal bob = vm.addr(12); + address internal currency = vm.addr(33); function setUp() public { harness = new LedgerUpgradeableHarness(); @@ -32,144 +35,43 @@ contract LedgerUpgradeableTest is Test { } function test_SetEntry_SetsBalance() public { - address account = address(0xBEEF); - address currency = address(0xCAFE); - uint256 amount = 123 ether; - - harness.setEntry(account, amount, currency); - - assertEq(harness.getLedgerBalance(account, currency), amount, "Ledger should equal set amount"); - } - - function test_SumEntry_Accumulates() public { - address account = address(0xA11CE); - address currency = address(0xC0FFEE); - - harness.setEntry(account, 10 ether, currency); - harness.sumEntry(account, 5 ether, currency); - - assertEq(harness.getLedgerBalance(account, currency), 15 ether, "Sum should increase balance"); - } - - function test_SubEntry_Decrements() public { - address account = address(0xDEAD); - address currency = address(0xBADDAD); - - harness.setEntry(account, 20 ether, currency); - harness.subEntry(account, 7 ether, currency); - - assertEq(harness.getLedgerBalance(account, currency), 13 ether, "Sub should decrease balance"); + harness.setEntry(alice, 50 ether, currency); + assertEq(harness.getLedgerBalance(alice, currency), 50 ether, "Set should override balance"); } - function testFuzz_SetAndAdjust(uint256 amount, uint256 addAmount, uint256 subAmount) public { - amount = bound(amount, 1, type(uint96).max); - addAmount = bound(addAmount, 0, type(uint96).max - amount); - subAmount = bound(subAmount, 0, amount + addAmount); - - address account = vm.addr(111); - address currency = vm.addr(222); - - harness.setEntry(account, amount, currency); - harness.sumEntry(account, addAmount, currency); - harness.subEntry(account, subAmount, currency); - - uint256 expected = amount + addAmount - subAmount; - assertEq(harness.getLedgerBalance(account, currency), expected, "Ledger after adjustments mismatch"); + function test_SumEntry_IncrementsBalance() public { + harness.setEntry(alice, 10 ether, currency); + harness.sumEntry(alice, 5 ether, currency); + assertEq(harness.getLedgerBalance(alice, currency), 15 ether, "Sum should add amount"); } -} - -contract LedgerUpgradeableHandler is Test { - LedgerUpgradeableHarness public immutable harness; - struct Key { - address account; - address currency; + function test_SubEntry_DecrementsBalance() public { + harness.setEntry(alice, 20 ether, currency); + harness.subEntry(alice, 7 ether, currency); + assertEq(harness.getLedgerBalance(alice, currency), 13 ether, "Sub should remove amount"); } - Key[] private _keys; - mapping(bytes32 => bool) private _tracked; - mapping(bytes32 => uint256) private _expected; - - constructor(LedgerUpgradeableHarness harness_) { - harness = harness_; + function test_SubEntry_AllowsReducingToZero() public { + harness.setEntry(alice, 8 ether, currency); + harness.subEntry(alice, 8 ether, currency); + assertEq(harness.getLedgerBalance(alice, currency), 0, "Balance should reach zero"); } - function setEntry(address account, address currency, uint256 amount) external { - if (account == address(0) || currency == address(0)) return; - harness.setEntry(account, amount, currency); + function test_SetEntry_IsolatedPerAccountAndCurrency() public { + harness.setEntry(alice, 15 ether, currency); + harness.setEntry(bob, 30 ether, vm.addr(44)); - bytes32 key = keccak256(abi.encode(account, currency)); - if (!_tracked[key]) { - _tracked[key] = true; - _keys.push(Key({ account: account, currency: currency })); - } - _expected[key] = amount; + assertEq(harness.getLedgerBalance(alice, currency), 15 ether, "Alice balance mismatch"); + assertEq(harness.getLedgerBalance(bob, vm.addr(44)), 30 ether, "Bob balance mismatch"); + assertEq(harness.getLedgerBalance(bob, currency), 0, "Cross account balances should stay zero"); } - function sumEntry(address account, address currency, uint256 amount) external { - if (account == address(0) || currency == address(0)) return; - - bytes32 key = keccak256(abi.encode(account, currency)); - uint256 current = _tracked[key] ? _expected[key] : harness.getLedgerBalance(account, currency); - uint256 newBalance = current + amount; - - harness.sumEntry(account, amount, currency); + function test_SequentialOperationsConserveMath() public { + harness.setEntry(alice, 40 ether, currency); + harness.sumEntry(alice, 12 ether, currency); + harness.subEntry(alice, 5 ether, currency); + harness.sumEntry(alice, 3 ether, currency); - if (!_tracked[key]) { - _tracked[key] = true; - _keys.push(Key({ account: account, currency: currency })); - } - _expected[key] = newBalance; - } - - function subEntry(address account, address currency, uint256 amount) external { - if (account == address(0) || currency == address(0)) return; - - bytes32 key = keccak256(abi.encode(account, currency)); - uint256 current = _tracked[key] ? _expected[key] : harness.getLedgerBalance(account, currency); - if (amount > current) return; // avoid underflow - - harness.subEntry(account, amount, currency); - - if (!_tracked[key]) { - _tracked[key] = true; - _keys.push(Key({ account: account, currency: currency })); - } - _expected[key] = current - amount; - } - - function keysLength() external view returns (uint256) { - return _keys.length; - } - - function keyAt(uint256 index) external view returns (Key memory) { - return _keys[index]; - } - - function expectedBalance(address account, address currency) external view returns (uint256) { - bytes32 key = keccak256(abi.encode(account, currency)); - return _expected[key]; + assertEq(harness.getLedgerBalance(alice, currency), 50 ether, "Sequential math mismatch"); } } - -contract LedgerUpgradeableInvariantTest is Test { - LedgerUpgradeableHarness harness; - LedgerUpgradeableHandler handler; - - function setUp() public { - harness = new LedgerUpgradeableHarness(); - harness.initialize(); - handler = new LedgerUpgradeableHandler(harness); - targetContract(address(handler)); - } - - function invariant_LedgerMatchesExpected() external view { - uint256 len = handler.keysLength(); - for (uint256 i = 0; i < len; i++) { - LedgerUpgradeableHandler.Key memory key = handler.keyAt(i); - uint256 expected = handler.expectedBalance(key.account, key.currency); - assertEq(harness.getLedgerBalance(key.account, key.currency), expected, "Ledger mismatch"); - } - } -} - diff --git a/test/primitives/LockOperatorUpgradeable.t.sol b/test/primitives/LockOperatorUpgradeable.t.sol index ea08e4e..31f0973 100644 --- a/test/primitives/LockOperatorUpgradeable.t.sol +++ b/test/primitives/LockOperatorUpgradeable.t.sol @@ -17,7 +17,7 @@ contract LockOperatorHarness is LockOperatorUpgradeable { __LockOperator_init(); } - function boostLedger(address account, uint256 amount, address currency) external { + function seedLedger(address account, uint256 amount, address currency) external { _sumLedgerEntry(account, amount, currency); } @@ -51,334 +51,101 @@ contract LockOperatorHarness is LockOperatorUpgradeable { } contract LockOperatorUpgradeableTest is Test { - LockOperatorHarness harness; + LockOperatorHarness internal harness; address internal constant TOKEN = address(0xC0FFEE); - address operator; - address alice; - address bob; - address claimer; + address internal alice = vm.addr(1); + address internal bob = vm.addr(2); + address internal claimer = vm.addr(3); function setUp() public { harness = new LockOperatorHarness(); harness.initialize(); - operator = vm.addr(1); - alice = vm.addr(2); - bob = vm.addr(3); - claimer = vm.addr(4); } - function test_Lock_ReducesLedgerAndTracksLocked() public { - uint256 amount = 50 ether; - harness.boostLedger(alice, 100 ether, TOKEN); + function test_LockDeductsLedgerAndTracksLocked() public { + harness.seedLedger(alice, 120 ether, TOKEN); - vm.prank(operator); vm.expectEmit(true, true, false, true, address(harness)); - emit ILockLocker.FundsLocked(operator, alice, amount, TOKEN); - harness.lock(alice, amount, TOKEN); - - assertEq( - ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN), - 50 ether, - "Ledger should reflect locked deduction" - ); - assertEq(harness.lockedBalance(alice, TOKEN), amount, "Locked balance mismatch"); + emit ILockLocker.FundsLocked(address(this), alice, 40 ether, TOKEN); + harness.lock(alice, 40 ether, TOKEN); + + assertEq(ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN), 80 ether, "Ledger deduction mismatch"); + assertEq(harness.lockedBalance(alice, TOKEN), 40 ether, "Locked balance mismatch"); + } + + function test_Lock_RevertWhen_NoFunds() public { + vm.expectRevert(ILockLocker.NoFundsToLock.selector); + harness.lock(alice, 1 ether, TOKEN); } function test_Lock_RevertWhen_InvalidParams() public { - harness.boostLedger(alice, 10 ether, TOKEN); + harness.seedLedger(alice, 10 ether, TOKEN); bytes4 err = bytes4(keccak256("InvalidOperationParameters()")); - vm.prank(operator); vm.expectRevert(err); harness.lock(address(0), 1 ether, TOKEN); - vm.prank(operator); vm.expectRevert(err); harness.lock(alice, 0, TOKEN); } - function test_Lock_RevertWhen_InsufficientLedgerBalance() public { - vm.prank(operator); - vm.expectRevert(ILockLocker.NoFundsToLock.selector); - harness.lock(alice, 1 ether, TOKEN); - } - function test_Release_RestoresLedger() public { - harness.boostLedger(alice, 80 ether, TOKEN); - - vm.prank(operator); + harness.seedLedger(alice, 90 ether, TOKEN); harness.lock(alice, 60 ether, TOKEN); - vm.prank(operator); vm.expectEmit(true, true, false, true, address(harness)); - emit ILockReleaser.FundsReleased(operator, alice, 20 ether, TOKEN); - harness.release(alice, 20 ether, TOKEN); - - assertEq(harness.lockedBalance(alice, TOKEN), 40 ether, "Locked balance after release"); - assertEq( - ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN), - 40 ether, - "Ledger should regain released amount" - ); + emit ILockReleaser.FundsReleased(address(this), alice, 25 ether, TOKEN); + harness.release(alice, 25 ether, TOKEN); + + assertEq(harness.lockedBalance(alice, TOKEN), 35 ether, "Locked after release mismatch"); + assertEq(ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN), 55 ether, "Ledger after release mismatch"); } function test_Release_RevertWhen_InsufficientLocked() public { - harness.boostLedger(alice, 40 ether, TOKEN); - vm.prank(operator); - harness.lock(alice, 30 ether, TOKEN); - - vm.prank(operator); + harness.seedLedger(alice, 20 ether, TOKEN); + harness.lock(alice, 10 ether, TOKEN); vm.expectRevert(ILockReleaser.NoFundsToRelease.selector); - harness.release(alice, 40 ether, TOKEN); + harness.release(alice, 15 ether, TOKEN); } function test_Claim_MovesLockedToClaimerLedger() public { - harness.boostLedger(alice, 90 ether, TOKEN); - vm.prank(operator); - harness.lock(alice, 60 ether, TOKEN); + harness.seedLedger(alice, 70 ether, TOKEN); + harness.lock(alice, 30 ether, TOKEN); - vm.prank(claimer); vm.expectEmit(true, true, false, true, address(harness)); - emit ILockClaimer.FundsClaimed(claimer, alice, 25 ether, TOKEN); - harness.claim(alice, 25 ether, TOKEN); - - assertEq(harness.lockedBalance(alice, TOKEN), 35 ether, "Locked balance after claim"); - assertEq( - ILedgerVerifiable(address(harness)).getLedgerBalance(claimer, TOKEN), - 25 ether, - "Claimer ledger should increase" - ); - } - - function test_Claim_RevertWhen_InsufficientLocked() public { + emit ILockClaimer.FundsClaimed(claimer, alice, 18 ether, TOKEN); vm.prank(claimer); - vm.expectRevert(ILockClaimer.NoFundsToClaim.selector); - harness.claim(alice, 1 ether, TOKEN); - } - - function test_Integration_MultiAccountFlow() public { - harness.boostLedger(alice, 100 ether, TOKEN); - harness.boostLedger(bob, 90 ether, TOKEN); + harness.claim(alice, 18 ether, TOKEN); - vm.prank(operator); - harness.lock(alice, 60 ether, TOKEN); - - vm.prank(operator); - harness.lock(bob, 45 ether, TOKEN); - - vm.prank(operator); - harness.release(alice, 20 ether, TOKEN); - - vm.prank(claimer); - harness.claim(alice, 10 ether, TOKEN); - - vm.prank(claimer); - harness.claim(bob, 15 ether, TOKEN); - - assertEq(harness.lockedBalance(alice, TOKEN), 30 ether, "Alice locked mismatch"); - assertEq(harness.lockedBalance(bob, TOKEN), 30 ether, "Bob locked mismatch"); - assertEq( - ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN), - 60 ether, - "Alice ledger mismatch" - ); - assertEq( - ILedgerVerifiable(address(harness)).getLedgerBalance(bob, TOKEN), - 45 ether, - "Bob ledger mismatch" - ); - assertEq( - ILedgerVerifiable(address(harness)).getLedgerBalance(claimer, TOKEN), - 25 ether, - "Claimer ledger aggregate mismatch" - ); + ILedgerVerifiable ledger = ILedgerVerifiable(address(harness)); + assertEq(harness.lockedBalance(alice, TOKEN), 12 ether, "Locked remainder mismatch"); + assertEq(ledger.getLedgerBalance(claimer, TOKEN), 18 ether, "Claimer ledger mismatch"); + assertEq(ledger.getLedgerBalance(alice, TOKEN), 40 ether, "Alice ledger should reflect lock deduction"); } - function testFuzz_LockReleaseCycle(uint256 seedAmount, uint256 lockAmount, uint256 releaseAmount) public { - seedAmount = bound(seedAmount, 1 ether, 1e24); - lockAmount = bound(lockAmount, 1 ether, seedAmount); - releaseAmount = bound(releaseAmount, 0, lockAmount); - - harness.boostLedger(alice, seedAmount, TOKEN); - - vm.prank(operator); - harness.lock(alice, lockAmount, TOKEN); - - if (releaseAmount > 0) { - vm.prank(operator); - harness.release(alice, releaseAmount, TOKEN); - } - - uint256 expectedLocked = lockAmount - releaseAmount; - uint256 expectedLedger = seedAmount - lockAmount + releaseAmount; + function test_Claim_RevertWhen_InsufficientLocked() public { + harness.seedLedger(alice, 30 ether, TOKEN); + harness.lock(alice, 10 ether, TOKEN); - assertEq(harness.lockedBalance(alice, TOKEN), expectedLocked, "Fuzz locked mismatch"); - assertEq( - ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN), - expectedLedger, - "Fuzz ledger mismatch" - ); - assertEq(expectedLocked + expectedLedger, seedAmount, "Conservation after release"); + vm.expectRevert(ILockClaimer.NoFundsToClaim.selector); + harness.claim(alice, 12 ether, TOKEN); } - function testFuzz_ClaimMaintainsConservation(uint256 seedAmount, uint256 lockAmount, uint256 claimAmount) public { - seedAmount = bound(seedAmount, 1 ether, 1e24); - lockAmount = bound(lockAmount, 1 ether, seedAmount); - claimAmount = bound(claimAmount, 1 ether, lockAmount); - - harness.boostLedger(alice, seedAmount, TOKEN); - vm.prank(operator); - harness.lock(alice, lockAmount, TOKEN); - + function test_Integration_LockReleaseClaimFlow() public { + harness.seedLedger(alice, 200 ether, TOKEN); + harness.lock(alice, 120 ether, TOKEN); + harness.release(alice, 30 ether, TOKEN); vm.prank(claimer); - harness.claim(alice, claimAmount, TOKEN); - - uint256 lockedLeft = lockAmount - claimAmount; - uint256 ledgerAlice = ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN); - uint256 ledgerClaimer = ILedgerVerifiable(address(harness)).getLedgerBalance(claimer, TOKEN); - - assertEq(harness.lockedBalance(alice, TOKEN), lockedLeft, "Locked left mismatch"); - assertEq(ledgerAlice + lockedLeft + ledgerClaimer, seedAmount, "Seed conservation broken"); - } -} - -contract LockOperatorHandler is Test { - LockOperatorHarness public immutable harness; - address[] internal accounts; - address internal constant TOKEN = address(0xC0FFEE); - - mapping(address => uint256) internal ledgerExpectation; - mapping(address => uint256) internal lockedExpectation; - - constructor(LockOperatorHarness operator) { - harness = operator; - for (uint256 i = 0; i < 3; i++) { - accounts.push(vm.addr(i + 10)); - } - } - - function seedLedger(uint256 index, uint256 amount) external { - vm.assume(index < accounts.length); - amount = bound(amount, 1, 1e27); - address account = accounts[index]; - harness.boostLedger(account, amount, TOKEN); - ledgerExpectation[account] += amount; - } - - function lock(uint256 index, uint256 amount) external { - vm.assume(index < accounts.length); - address account = accounts[index]; - uint256 available = ledgerExpectation[account]; - vm.assume(amount > 0 && amount <= available); - - vm.prank(account); - harness.lock(account, amount, TOKEN); - - ledgerExpectation[account] = available - amount; - lockedExpectation[account] += amount; - } + harness.claim(alice, 50 ether, TOKEN); - function release(uint256 index, uint256 amount) external { - vm.assume(index < accounts.length); - address account = accounts[index]; - uint256 locked = lockedExpectation[account]; - vm.assume(amount > 0 && amount <= locked); - - vm.prank(account); - harness.release(account, amount, TOKEN); - - lockedExpectation[account] = locked - amount; - ledgerExpectation[account] += amount; - } - - function claim(uint256 lockedIdx, uint256 claimerIdx, uint256 amount) external { - vm.assume(lockedIdx < accounts.length && claimerIdx < accounts.length && lockedIdx != claimerIdx); - address account = accounts[lockedIdx]; - address claimerAccount = accounts[claimerIdx]; - uint256 locked = lockedExpectation[account]; - vm.assume(amount > 0 && amount <= locked); - - vm.prank(claimerAccount); - harness.claim(account, amount, TOKEN); - - lockedExpectation[account] = locked - amount; - ledgerExpectation[claimerAccount] += amount; - } - - function accountsLength() external view returns (uint256) { - return accounts.length; - } - - function accountAt(uint256 idx) external view returns (address) { - return accounts[idx]; - } - - function expectedLedger(address account) external view returns (uint256) { - return ledgerExpectation[account]; - } - - function expectedLocked(address account) external view returns (uint256) { - return lockedExpectation[account]; - } - - function token() external pure returns (address) { - return TOKEN; - } -} - -contract LockOperatorUpgradeableInvariantTest is Test { - LockOperatorHarness harness; - LockOperatorHandler handler; - - function setUp() public { - harness = new LockOperatorHarness(); - harness.initialize(); - handler = new LockOperatorHandler(harness); - targetContract(address(handler)); - } - - function invariant_LedgerBalancesMatchExpectation() external { - uint256 len = handler.accountsLength(); - for (uint256 i = 0; i < len; i++) { - address account = handler.accountAt(i); - assertEq( - ILedgerVerifiable(address(harness)).getLedgerBalance(account, handler.token()), - handler.expectedLedger(account), - "Ledger expectation mismatch" - ); - } - } - - function invariant_LockedBalancesMatchExpectation() external { - uint256 len = handler.accountsLength(); - for (uint256 i = 0; i < len; i++) { - address account = handler.accountAt(i); - assertEq( - harness.lockedBalance(account, handler.token()), - handler.expectedLocked(account), - "Locked expectation mismatch" - ); - } - } - - function invariant_TotalConservationHolds() external { - uint256 len = handler.accountsLength(); - uint256 expectedLedgerSum; - uint256 expectedLockedSum; - uint256 actualLedgerSum; - uint256 actualLockedSum; - address tokenAddress = handler.token(); - - for (uint256 i = 0; i < len; i++) { - address account = handler.accountAt(i); - expectedLedgerSum += handler.expectedLedger(account); - expectedLockedSum += handler.expectedLocked(account); - actualLedgerSum += ILedgerVerifiable(address(harness)).getLedgerBalance(account, tokenAddress); - actualLockedSum += harness.lockedBalance(account, tokenAddress); - } + uint256 locked = harness.lockedBalance(alice, TOKEN); + ILedgerVerifiable ledger = ILedgerVerifiable(address(harness)); + uint256 aliceLedger = ledger.getLedgerBalance(alice, TOKEN); + uint256 claimerLedger = ledger.getLedgerBalance(claimer, TOKEN); - assertEq(actualLedgerSum, expectedLedgerSum, "Aggregated ledger mismatch"); - assertEq(actualLockedSum, expectedLockedSum, "Aggregated locked mismatch"); - assertEq(actualLedgerSum + actualLockedSum, expectedLedgerSum + expectedLockedSum, "Total conservation mismatch"); + assertEq(locked, 40 ether, "Final locked mismatch"); + assertEq(aliceLedger, 110 ether, "Alice ledger mismatch"); + assertEq(claimerLedger, 50 ether, "Claimer ledger mismatch"); + assertEq(locked + aliceLedger + claimerLedger, 200 ether, "Total conservation mismatch"); } } diff --git a/test/primitives/QuorumUpgradeable.t.sol b/test/primitives/QuorumUpgradeable.t.sol index 7b19f41..417d5ef 100644 --- a/test/primitives/QuorumUpgradeable.t.sol +++ b/test/primitives/QuorumUpgradeable.t.sol @@ -37,200 +37,70 @@ contract QuorumUpgradeableHarness is QuorumUpgradeable { } contract QuorumUpgradeableTest is Test { - QuorumUpgradeableHarness harness; + QuorumUpgradeableHarness internal harness; function setUp() public { harness = new QuorumUpgradeableHarness(); harness.initialize(); } - function test_DefaultStatusIsPending() public { - assertEq(uint256(harness.statusOf(1)), uint256(T.Status.Pending), "Default should be pending"); + function test_StatusDefaultsToPending() public { + assertEq(uint256(harness.statusOf(1)), uint256(T.Status.Pending), "Default status should be pending"); } - function test_Register_FromPendingMovesToWaiting() public { - harness.register(1); - assertEq(uint256(harness.statusOf(1)), uint256(T.Status.Waiting), "Should move to waiting"); + function test_RegisterMovesToWaiting() public { + harness.register(42); + assertEq(uint256(harness.statusOf(42)), uint256(T.Status.Waiting), "Register should move to waiting"); } function test_Register_RevertWhen_NotPending() public { - harness.register(1); + harness.register(10); vm.expectRevert(QuorumUpgradeable.NotPendingApproval.selector); - harness.register(1); + harness.register(10); } - function test_Approve_FromWaitingMovesToActive() public { - harness.register(1); - harness.approve(1); - assertEq(uint256(harness.statusOf(1)), uint256(T.Status.Active), "Should be active"); + function test_ApproveMovesToActive() public { + harness.register(7); + harness.approve(7); + assertEq(uint256(harness.statusOf(7)), uint256(T.Status.Active), "Approve should activate entry"); } function test_Approve_RevertWhen_NotWaiting() public { vm.expectRevert(QuorumUpgradeable.NotWaitingApproval.selector); - harness.approve(1); + harness.approve(99); } - function test_Block_FromWaitingMovesToBlocked() public { - harness.register(1); - harness.blockEntry(1); - assertEq(uint256(harness.statusOf(1)), uint256(T.Status.Blocked), "Should be blocked"); + function test_BlockMovesToBlocked() public { + harness.register(5); + harness.blockEntry(5); + assertEq(uint256(harness.statusOf(5)), uint256(T.Status.Blocked), "Block should mark entry blocked"); } function test_Block_RevertWhen_NotWaiting() public { vm.expectRevert(QuorumUpgradeable.NotWaitingApproval.selector); - harness.blockEntry(1); + harness.blockEntry(12); } - function test_Quit_FromWaitingReturnsPending() public { - harness.register(1); - harness.quit(1); - assertEq(uint256(harness.statusOf(1)), uint256(T.Status.Pending), "Should return to pending"); + function test_QuitReturnsPending() public { + harness.register(3); + harness.quit(3); + assertEq(uint256(harness.statusOf(3)), uint256(T.Status.Pending), "Quit should restore pending state"); } function test_Quit_RevertWhen_NotWaiting() public { vm.expectRevert(QuorumUpgradeable.NotWaitingApproval.selector); - harness.quit(1); + harness.quit(4); } - function test_Revoke_FromActiveMovesToBlocked() public { - harness.register(1); - harness.approve(1); - harness.revoke(1); - assertEq(uint256(harness.statusOf(1)), uint256(T.Status.Blocked), "Active should move to blocked"); + function test_RevokeMovesActiveToBlocked() public { + harness.register(8); + harness.approve(8); + harness.revoke(8); + assertEq(uint256(harness.statusOf(8)), uint256(T.Status.Blocked), "Revoke should block active entry"); } function test_Revoke_RevertWhen_NotActive() public { vm.expectRevert(QuorumUpgradeable.InvalidInactiveState.selector); - harness.revoke(1); - } - - function testFuzz_RegisterApproveCycle(uint256 entry) public { - entry = bound(entry, 0, type(uint64).max); - - harness.register(entry); - assertEq(uint256(harness.statusOf(entry)), uint256(T.Status.Waiting)); - - harness.approve(entry); - assertEq(uint256(harness.statusOf(entry)), uint256(T.Status.Active)); - } - - function testFuzz_RegisterQuitKeepsPending(uint256 entry) public { - entry = bound(entry, 0, type(uint64).max); - - harness.register(entry); - harness.quit(entry); - - assertEq(uint256(harness.statusOf(entry)), uint256(T.Status.Pending)); - } -} - -contract QuorumHandler is Test { - QuorumUpgradeableHarness public immutable harness; - - struct EntryState { - bool tracked; - T.Status status; - } - - mapping(uint256 => EntryState) private _entries; - uint256[] private _trackedEntries; - - constructor(QuorumUpgradeableHarness harness_) { - harness = harness_; - } - - function register(uint256 entry) external { - entry = _normalize(entry); - if (harness.statusOf(entry) != T.Status.Pending) return; - harness.register(entry); - _update(entry, T.Status.Waiting); - } - - function approve(uint256 entry) external { - entry = _normalize(entry); - if (harness.statusOf(entry) != T.Status.Waiting) return; - harness.approve(entry); - _update(entry, T.Status.Active); - } - - function quit(uint256 entry) external { - entry = _normalize(entry); - if (harness.statusOf(entry) != T.Status.Waiting) return; - harness.quit(entry); - _update(entry, T.Status.Pending); - } - - function blockEntry(uint256 entry) external { - entry = _normalize(entry); - if (harness.statusOf(entry) != T.Status.Waiting) return; - harness.blockEntry(entry); - _update(entry, T.Status.Blocked); - } - - function revoke(uint256 entry) external { - entry = _normalize(entry); - if (harness.statusOf(entry) != T.Status.Active) return; - harness.revoke(entry); - _update(entry, T.Status.Blocked); - } - - function trackedLength() external view returns (uint256) { - return _trackedEntries.length; - } - - function trackedAt(uint256 index) external view returns (uint256) { - return _trackedEntries[index]; - } - - function expectedStatus(uint256 entry) external view returns (T.Status) { - return _entries[entry].status; - } - - function _update(uint256 entry, T.Status newStatus) private { - if (!_entries[entry].tracked) { - _entries[entry].tracked = true; - _trackedEntries.push(entry); - } - _entries[entry].status = newStatus; - } - - function _normalize(uint256 entry) private pure returns (uint256) { - return entry % 1_000; - } -} - -contract QuorumUpgradeableInvariantTest is Test { - QuorumUpgradeableHarness harness; - QuorumHandler handler; - - function setUp() public { - harness = new QuorumUpgradeableHarness(); - harness.initialize(); - handler = new QuorumHandler(harness); - targetContract(address(handler)); - } - - function invariant_StatusMatchesHandler() external view { - uint256 len = handler.trackedLength(); - for (uint256 i = 0; i < len; i++) { - uint256 entry = handler.trackedAt(i); - assertEq(uint256(harness.statusOf(entry)), uint256(handler.expectedStatus(entry)), "Status mismatch"); - } - } - - function invariant_StatusWithinEnum() external view { - uint256 len = handler.trackedLength(); - for (uint256 i = 0; i < len; i++) { - uint256 entry = handler.trackedAt(i); - T.Status status = harness.statusOf(entry); - assertTrue( - status == T.Status.Pending || - status == T.Status.Waiting || - status == T.Status.Active || - status == T.Status.Blocked, - "Invalid status value" - ); - } + harness.revoke(6); } } - diff --git a/test/rights/RightsPolicyAuthorizer.t.sol b/test/rights/RightsPolicyAuthorizer.t.sol index ee3b76f..3a04a70 100644 --- a/test/rights/RightsPolicyAuthorizer.t.sol +++ b/test/rights/RightsPolicyAuthorizer.t.sol @@ -4,95 +4,111 @@ pragma solidity 0.8.26; import "forge-std/Test.sol"; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; -import { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; import { RightsPolicyAuthorizer } from "contracts/rights/RightsPolicyAuthorizer.sol"; import { IRightsPolicyAuthorizer } from "contracts/core/interfaces/rights/IRightsPolicyAuthorizer.sol"; -import { IPolicy } from "contracts/core/interfaces/policies/IPolicy.sol"; import { IPolicyAuditor } from "contracts/core/interfaces/policies/IPolicyAuditor.sol"; +import { PolicyBase } from "contracts/policies/PolicyBase.sol"; +import { IAttestationProvider } from "contracts/core/interfaces/base/IAttestationProvider.sol"; import { T } from "contracts/core/primitives/Types.sol"; import { BaseTest } from "test/BaseTest.t.sol"; -/// @dev Minimal policy mock exposing setup side-effects for assertions. -contract PolicyMock is ERC165, IPolicy { - address public lastHolder; - bytes public lastInit; - bool public shouldRevert; - - function configureRevert(bool status) external { - shouldRevert = status; +contract DummyAttestationProvider is IAttestationProvider { + function getName() external pure returns (string memory) { + return "DummyAttestationProvider"; } - /// @inheritdoc IPolicy - function setup(address holder, bytes calldata init) public virtual override { - if (shouldRevert) revert("policy setup failed"); - lastHolder = holder; - lastInit = init; + function getAddress() external view returns (address) { + return address(this); } - /// @inheritdoc IPolicy - function enforce(address, T.Agreement calldata) external pure override returns (uint256[] memory result) { - return result; + function attest( + address[] calldata recipients, + uint256, + bytes calldata + ) external pure override returns (uint256[] memory attestationIds) { + attestationIds = new uint256[](recipients.length); } - /// @inheritdoc IPolicy - function isAccessAllowed(address, bytes calldata) external pure override returns (bool) { + function verify(uint256, address) external pure returns (bool) { return false; } +} + +/// @dev Policy harness leveraging PolicyBase for authorizer testing. +contract PolicyBaseAuthorizerHarness is PolicyBase { + IRightsPolicyAuthorizer public immutable AUTHORIZE_GATE; + address private _lastHolder; + bytes private _lastInitData; - /// @inheritdoc IPolicy - function getLicense(address, bytes calldata) external pure override returns (uint256) { - return 0; + bool public setupShouldRevert; + bool public setupRevertNoData; + bool public triggerReentrancy; + bool private _reentrancyExecuted; + + constructor(address rightsAuthorizer, address attestationProvider) + PolicyBase(address(0), rightsAuthorizer, address(0), attestationProvider) + { + AUTHORIZE_GATE = IRightsPolicyAuthorizer(rightsAuthorizer); } - /// @inheritdoc IPolicy - function resolveTerms(bytes calldata) external pure override returns (T.Terms memory terms) { - return terms; + function setSetupRevert(bool status) external { + setupShouldRevert = status; } - /// @inheritdoc IPolicy - function getAttestationProvider() external pure override returns (address) { - return address(0); + function setSetupRevertNoData(bool status) external { + setupRevertNoData = status; } - /// @inheritdoc IPolicy - function name() external pure override returns (string memory) { - return "MockPolicy"; + function setTriggerReentrancy(bool status) external { + triggerReentrancy = status; + _reentrancyExecuted = false; } - /// @inheritdoc IPolicy - function description() external pure override returns (string memory) { - return "Mock policy used for testing"; + function lastHolder() external view returns (address) { + return _lastHolder; } - function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { - return interfaceId == type(IPolicy).interfaceId || super.supportsInterface(interfaceId); + function lastInit() external view returns (bytes memory) { + return _lastInitData; } -} -contract PolicyNoDataRevertMock is PolicyMock { - function setup(address, bytes calldata) public pure override { - assembly { - revert(0, 0) + function setup(address holder, bytes calldata init) external virtual override { + if (setupShouldRevert) { + if (setupRevertNoData) { + assembly { + revert(0, 0) + } + } else { + revert("policy setup failed"); + } + } + if (triggerReentrancy && !_reentrancyExecuted) { + _reentrancyExecuted = true; + AUTHORIZE_GATE.authorizePolicy(address(this), init); } + _lastHolder = holder; + _lastInitData = init; } -} -/// @dev Policy mock exercising reentrancy protection. -contract ReentrantPolicyMock is PolicyMock { - IRightsPolicyAuthorizer public immutable authorizer; - bool private triggered; + function enforce(address, T.Agreement calldata agreement) external pure override returns (uint256[] memory result) { + result = new uint256[](agreement.parties.length); + } - constructor(IRightsPolicyAuthorizer authorizer_) { - authorizer = authorizer_; + function isAccessAllowed(address, bytes calldata) external pure override returns (bool) { + return true; } - function setup(address holder, bytes calldata init) public override { - if (triggered) return; - triggered = true; - authorizer.authorizePolicy(address(this), init); - super.setup(holder, init); + + function resolveTerms(bytes calldata) external pure override returns (T.Terms memory terms) {} + + function name() external pure override returns (string memory) { + return "PolicyBaseAuthorizerHarness"; + } + + function description() external pure override returns (string memory) { + return "Policy base authorizer harness"; } } @@ -113,6 +129,14 @@ contract RightsPolicyAuthorizerTest is BaseTest { holder = user; } + function _createPolicy() + internal + returns (PolicyBaseAuthorizerHarness policy, DummyAttestationProvider provider) + { + provider = new DummyAttestationProvider(); + policy = new PolicyBaseAuthorizerHarness(address(authorizer), address(provider)); + } + function _auditPolicy(address policy) internal { if (audited[policy]) return; @@ -124,7 +148,7 @@ contract RightsPolicyAuthorizerTest is BaseTest { audited[policy] = true; } catch {} - if (!audited[policy] && auditor.isAudited(policy)) { + if (!audited[policy] && auditor.isApproved(policy)) { audited[policy] = true; } } @@ -137,7 +161,7 @@ contract RightsPolicyAuthorizerTest is BaseTest { audited[policy] = false; } catch {} - if (audited[policy] && !auditor.isAudited(policy)) { + if (audited[policy] && !auditor.isApproved(policy)) { audited[policy] = false; } } @@ -149,7 +173,7 @@ contract RightsPolicyAuthorizerTest is BaseTest { } function test_AuthorizePolicy_SucceedsForAuditedPolicy() public { - PolicyMock policy = new PolicyMock(); + (PolicyBaseAuthorizerHarness policy, ) = _createPolicy(); _auditPolicy(address(policy)); bytes memory initData = abi.encode(uint256(1)); @@ -165,7 +189,9 @@ contract RightsPolicyAuthorizerTest is BaseTest { } function test_AuthorizePolicy_RevertsWhenPolicyNotAudited() public { - PolicyMock policy = new PolicyMock(); + (PolicyBaseAuthorizerHarness policy, ) = _createPolicy(); + + assertFalse(authorizer.isPolicyAuthorized(address(policy), holder), "Policy should start unauthorized"); vm.expectRevert(abi.encodeWithSelector(RightsPolicyAuthorizer.InvalidNotAuditedPolicy.selector, address(policy))); vm.prank(holder); @@ -173,7 +199,9 @@ contract RightsPolicyAuthorizerTest is BaseTest { } function test_AuthorizePolicy_RevertsWhenSetupFails() public { - PolicyNoDataRevertMock policy = new PolicyNoDataRevertMock(); + (PolicyBaseAuthorizerHarness policy, ) = _createPolicy(); + policy.setSetupRevert(true); + policy.setSetupRevertNoData(true); _auditPolicy(address(policy)); vm.expectRevert( @@ -187,24 +215,26 @@ contract RightsPolicyAuthorizerTest is BaseTest { } function test_AuthorizePolicy_ReentrancyIsBlocked() public { - ReentrantPolicyMock policy = new ReentrantPolicyMock(authorizer); + (PolicyBaseAuthorizerHarness policy, ) = _createPolicy(); + policy.setTriggerReentrancy(true); _auditPolicy(address(policy)); + vm.expectRevert( + abi.encodeWithSelector( + RightsPolicyAuthorizer.InvalidPolicyInitialization.selector, + "Error during policy initialization call" + ) + ); vm.prank(holder); authorizer.authorizePolicy(address(policy), "data"); address[] memory holderPolicies = authorizer.getAuthorizedPolicies(holder); - assertEq(holderPolicies.length, 1, "Holder should keep a single authorized policy"); - assertEq(holderPolicies[0], address(policy), "Unexpected policy stored for holder"); - - assertFalse( - authorizer.isPolicyAuthorized(address(policy), address(policy)), - "Reentrancy guard should prevent policy self-authorization" - ); + assertEq(holderPolicies.length, 0, "Reentrant attempt should not authorize policy"); + assertFalse(authorizer.isPolicyAuthorized(address(policy), holder), "Policy should remain unauthorized"); } function test_RevokePolicy_RemovesAuthorization() public { - PolicyMock policy = new PolicyMock(); + (PolicyBaseAuthorizerHarness policy, ) = _createPolicy(); _auditPolicy(address(policy)); vm.prank(holder); @@ -220,7 +250,7 @@ contract RightsPolicyAuthorizerTest is BaseTest { } function test_RevokePolicy_RevertsWhenNotAuthorized() public { - PolicyMock policy = new PolicyMock(); + (PolicyBaseAuthorizerHarness policy, ) = _createPolicy(); vm.expectRevert(abi.encodeWithSelector(RightsPolicyAuthorizer.RevocationFailed.selector, holder, address(policy))); vm.prank(holder); @@ -228,7 +258,7 @@ contract RightsPolicyAuthorizerTest is BaseTest { } function test_AuthorizePolicy_RevertsOnDuplicate() public { - PolicyMock policy = new PolicyMock(); + (PolicyBaseAuthorizerHarness policy, ) = _createPolicy(); _auditPolicy(address(policy)); vm.startPrank(holder); @@ -244,48 +274,9 @@ contract RightsPolicyAuthorizerTest is BaseTest { vm.stopPrank(); } - function test_GetAuthorizedPolicies_FiltersOutNonAudited() public { - PolicyMock policy = new PolicyMock(); - _auditPolicy(address(policy)); - - vm.prank(holder); - authorizer.authorizePolicy(address(policy), ""); - - address[] memory authorizedBefore = authorizer.getAuthorizedPolicies(holder); - assertEq(authorizedBefore.length, 1, "Authorized list should include policy"); - - _revokeAudit(address(policy)); - - address[] memory authorizedAfter = authorizer.getAuthorizedPolicies(holder); - assertEq(authorizedAfter.length, 0, "Non-audited policies must be filtered out"); - } - - function test_GetAuthorizedPolicies_ReturnsUniqueAuthorizedEntries() public { - PolicyMock policyA = new PolicyMock(); - PolicyMock policyB = new PolicyMock(); - _auditPolicy(address(policyA)); - _auditPolicy(address(policyB)); - - vm.startPrank(holder); - authorizer.authorizePolicy(address(policyA), "A"); - authorizer.authorizePolicy(address(policyB), "B"); - vm.stopPrank(); - - address[] memory authorized = authorizer.getAuthorizedPolicies(holder); - assertEq(authorized.length, 2, "Two policies expected"); - assertTrue(authorized[0] != authorized[1], "Duplicate entries detected"); - } - - function test_IsPolicyAuthorized_ReturnsFalseWhenNeverAuthorized() public { - PolicyMock policy = new PolicyMock(); - _auditPolicy(address(policy)); - - assertFalse(authorizer.isPolicyAuthorized(address(policy), holder), "Policy should not be authorized"); - } - function test_Integration_AuthorizeRevokeAndAuditFlow() public { - PolicyMock policyA = new PolicyMock(); - PolicyMock policyB = new PolicyMock(); + (PolicyBaseAuthorizerHarness policyA, ) = _createPolicy(); + (PolicyBaseAuthorizerHarness policyB, ) = _createPolicy(); _auditPolicy(address(policyA)); _auditPolicy(address(policyB)); @@ -296,6 +287,7 @@ contract RightsPolicyAuthorizerTest is BaseTest { address[] memory list = authorizer.getAuthorizedPolicies(holder); assertEq(list.length, 2, "Both policies should be present"); + assertTrue(list[0] != list[1], "Duplicate entries detected"); vm.prank(holder); authorizer.revokePolicy(address(policyB)); @@ -308,17 +300,18 @@ contract RightsPolicyAuthorizerTest is BaseTest { } function testFuzz_AuthorizePoliciesMaintainsConsistency(bytes32 salt) public { - PolicyMock[3] memory policies; + PolicyBaseAuthorizerHarness[3] memory policies; bool[3] memory expectedAuthorized; bool[3] memory expectedAudited; for (uint256 i = 0; i < policies.length; i++) { - policies[i] = new PolicyMock(); + (PolicyBaseAuthorizerHarness policy, ) = _createPolicy(); + policies[i] = policy; _auditPolicy(address(policies[i])); expectedAudited[i] = true; } - uint256 steps = 12; + uint256 steps = 6; for (uint256 step = 0; step < steps; step++) { uint8 op = uint8(uint256(keccak256(abi.encode(salt, step)))) % 3; uint8 idx = uint8(uint256(keccak256(abi.encode(salt, step, "IDX")))) % uint8(policies.length); @@ -367,133 +360,5 @@ contract RightsPolicyAuthorizerTest is BaseTest { assertTrue(found, "Expected policy missing"); } } -} - -contract RightsPolicyAuthorizerHandler is Test { - IRightsPolicyAuthorizer public immutable authorizer; - IPolicyAuditor public immutable auditor; - address public immutable holder; - address public immutable admin; - - PolicyMock[] internal policies; - mapping(address => bool) internal authorized; - mapping(address => bool) internal audited; - - constructor(IRightsPolicyAuthorizer authorizer_, IPolicyAuditor auditor_, address holder_, address admin_) { - authorizer = authorizer_; - auditor = auditor_; - holder = holder_; - admin = admin_; - - for (uint256 i = 0; i < 3; i++) { - PolicyMock policy = new PolicyMock(); - policies.push(policy); - _audit(address(policy)); - } - } - function _audit(address policy) internal { - if (audited[policy]) return; - - vm.prank(holder); - try auditor.submit(policy) {} catch {} - - vm.prank(admin); - try auditor.approve(policy) { - audited[policy] = true; - } catch {} - - if (!audited[policy] && auditor.isAudited(policy)) { - audited[policy] = true; - } - } - - function policiesLength() external view returns (uint256) { - return policies.length; - } - - function policyAt(uint256 idx) external view returns (address) { - return address(policies[idx]); - } - - function isAuthorized(address policy) external view returns (bool) { - return authorized[policy] && audited[policy] && auditor.isAudited(policy); - } - - function authorize(uint256 seed) external { - PolicyMock policy = policies[seed % policies.length]; - address addr = address(policy); - - _audit(addr); - if (!audited[addr]) return; - - vm.prank(holder); - try authorizer.authorizePolicy(addr, abi.encode(seed)) { - authorized[addr] = true; - } catch {} - } - - function revoke(uint256 seed) external { - PolicyMock policy = policies[seed % policies.length]; - address addr = address(policy); - if (!authorized[addr]) return; - - vm.prank(holder); - try authorizer.revokePolicy(addr) { - authorized[addr] = false; - } catch {} - } - - function toggleAudit(uint256 seed, bool status) external { - PolicyMock policy = policies[seed % policies.length]; - address addr = address(policy); - - if (status) { - _audit(addr); - } else if (audited[addr]) { - vm.prank(admin); - try auditor.reject(addr) { - audited[addr] = false; - authorized[addr] = false; - } catch {} - } - } -} - -contract RightsPolicyAuthorizerInvariantTest is BaseTest { - IRightsPolicyAuthorizer internal authorizer; - IPolicyAuditor internal auditor; - RightsPolicyAuthorizerHandler internal handler; - - function setUp() public initialize { - deployRightsPolicyAuthorizer(); - authorizer = IRightsPolicyAuthorizer(rightsPolicyAuthorizer); - auditor = IPolicyAuditor(policyAudit); - - handler = new RightsPolicyAuthorizerHandler(authorizer, auditor, user, admin); - targetContract(address(handler)); - } - - function invariant_NoZeroOrUnauditedPoliciesInSet() external { - address[] memory list = authorizer.getAuthorizedPolicies(user); - - for (uint256 i = 0; i < list.length; i++) { - address policy = list[i]; - assertTrue(policy != address(0), "Authorized list should not contain zero address"); - assertTrue(auditor.isAudited(policy), "Authorized list should only include audited policies"); - - for (uint256 j = 0; j < i; j++) { - require(list[j] != policy, "Authorized list should contain unique policies"); - } - } - } - - function invariant_AuthorizationReflectsHandlerState() external { - for (uint256 i = 0; i < handler.policiesLength(); i++) { - address policy = handler.policyAt(i); - bool expected = handler.isAuthorized(policy); - bool actual = authorizer.isPolicyAuthorized(policy, user); - assertEq(actual, expected, "Authorization state mismatch"); - } - } } diff --git a/test/rights/RightsPolicyManager.t.sol b/test/rights/RightsPolicyManager.t.sol new file mode 100644 index 0000000..fedea9f --- /dev/null +++ b/test/rights/RightsPolicyManager.t.sol @@ -0,0 +1,506 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.26; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { AgreementSettler } from "contracts/financial/AgreementSettler.sol"; +import { RightsPolicyManager } from "contracts/rights/RightsPolicyManager.sol"; +import { PolicyBase } from "contracts/policies/PolicyBase.sol"; + +import { BaseTest } from "test/BaseTest.t.sol"; +import { IRightsPolicyAuthorizer } from "contracts/core/interfaces/rights/IRightsPolicyAuthorizer.sol"; +import { IAgreementManager } from "contracts/core/interfaces/financial/IAgreementManager.sol"; +import { ITollgate } from "contracts/core/interfaces/economics/ITollgate.sol"; +import { ILedgerVault } from "contracts/core/interfaces/financial/ILedgerVault.sol"; +import { IPolicyAuditor } from "contracts/core/interfaces/policies/IPolicyAuditor.sol"; +import { IAttestationProvider } from "contracts/core/interfaces/base/IAttestationProvider.sol"; +import { T } from "contracts/core/primitives/Types.sol"; + +uint256 constant DEFAULT_TOLLGATE_BPS = 500; +uint256 constant DEFAULT_AGREEMENT_AMOUNT = 100 ether; +uint256 constant INITIAL_LEDGER_DEPOSIT = 1_000_000 ether; +bytes constant DEFAULT_PAYLOAD = "payload"; + +/// @dev Attestation provider stub allowing configurable attestation ids. +contract ConfigurableAttestationProvider is IAttestationProvider { + address[] internal _lastRecipients; + uint256 public lastExpireAt; + bytes public lastData; + uint256 public attestCalls; + + uint256[] internal _nextIds; + uint256 private _counter = 1; + mapping(address => mapping(uint256 => bool)) internal _issued; + + function setNextAttestationIds(uint256[] memory ids) external { + delete _nextIds; + uint256 len = ids.length; + for (uint256 i = 0; i < len; i++) { + _nextIds.push(ids[i]); + } + } + + function getName() external pure returns (string memory) { + return "ConfigurableAttestationProvider"; + } + + function getAddress() external view returns (address) { + return address(this); + } + + function attest( + address[] calldata recipients, + uint256 expireAt, + bytes calldata data + ) external override returns (uint256[] memory attestationIds) { + delete _lastRecipients; + uint256 len = recipients.length; + for (uint256 i = 0; i < len; i++) { + _lastRecipients.push(recipients[i]); + } + + lastExpireAt = expireAt; + lastData = data; + attestCalls++; + + attestationIds = new uint256[](len); + if (len == 0) return attestationIds; + + if (_nextIds.length != 0) { + require(_nextIds.length == len, "Attestation length mismatch"); + for (uint256 i = 0; i < len; i++) { + attestationIds[i] = _nextIds[i]; + } + delete _nextIds; + } else { + for (uint256 i = 0; i < len; i++) { + attestationIds[i] = _counter++; + } + } + + for (uint256 i = 0; i < len; i++) { + _issued[recipients[i]][attestationIds[i]] = true; + } + return attestationIds; + } + + function verify(uint256 attestationId, address recipient) external view returns (bool) { + return _issued[recipient][attestationId]; + } + + function lastRecipientsLength() external view returns (uint256) { + return _lastRecipients.length; + } + + function lastRecipientAt(uint256 index) external view returns (address) { + return _lastRecipients[index]; + } +} + +/// @dev Policy harness leveraging PolicyBase for realistic behaviour. +contract PolicyBaseManagerHarness is PolicyBase { + address private _lastHolder; + bytes private _lastSetupData; + T.Agreement private _lastAgreement; + + bool public setupShouldRevert; + bool public enforceShouldRevert; + bool public accessAllowed = true; + bool public accessShouldRevert; + + constructor( + address rightsPolicyManager, + address rightsAuthorizer, + address assetRegistry, + address attestationProvider + ) PolicyBase(rightsPolicyManager, rightsAuthorizer, assetRegistry, attestationProvider) {} + + function setSetupRevert(bool status) external { + setupShouldRevert = status; + } + + function setAccessAllowed(bool status) external { + accessAllowed = status; + } + + function setAccessRevert(bool status) external { + accessShouldRevert = status; + } + + function setEnforceRevert(bool status) external { + enforceShouldRevert = status; + } + + function lastHolder() external view returns (address) { + return _lastHolder; + } + + function lastSetupData() external view returns (bytes memory) { + return _lastSetupData; + } + + function getLastAgreement() external view returns (T.Agreement memory) { + return _lastAgreement; + } + + function setup(address holder, bytes calldata init) external override { + if (setupShouldRevert) revert("policy setup failed"); + _lastHolder = holder; + _lastSetupData = init; + } + + function enforce( + address holder, + T.Agreement calldata agreement + ) external override returns (uint256[] memory attestationIds) { + if (enforceShouldRevert) revert("enforce failure"); + _lastHolder = holder; + _lastAgreement = agreement; + + uint256 expireAt = block.timestamp + 1; + attestationIds = _commit(holder, agreement, expireAt); + + uint256 len = agreement.parties.length; + bytes memory context = abi.encode(holder); + for (uint256 i = 0; i < len; i++) { + _setAttestation(agreement.parties[i], context, attestationIds[i]); + } + } + + function isAccessAllowed(address, bytes calldata) external view override returns (bool) { + if (accessShouldRevert) revert("access check failed"); + return accessAllowed; + } + + function resolveTerms(bytes calldata) external pure override returns (T.Terms memory terms) {} + + function name() external pure override returns (string memory) { + return "PolicyBaseManagerHarness"; + } + + function description() external pure override returns (string memory) { + return "Policy base test harness"; + } +} + +contract RightsPolicyManagerTest is BaseTest { + RightsPolicyManager internal manager; + IRightsPolicyAuthorizer internal authorizer; + IAgreementManager internal agreements; + IPolicyAuditor internal auditor; + ITollgate internal tollgateContract; + ILedgerVault internal ledgerVault; + IERC20 internal currency; + + address internal holder; + + mapping(address => bool) internal auditedPolicies; + mapping(address => bool) internal authorizedPolicies; + + event Registered(address indexed account, uint256 indexed proof, uint256 attestationId, address policy); + + function setUp() public initialize { + holder = user; + + deployRightsPolicyManager(); + + manager = RightsPolicyManager(rightsPolicyManager); + authorizer = IRightsPolicyAuthorizer(rightsPolicyAuthorizer); + agreements = IAgreementManager(agreementManager); + auditor = IPolicyAuditor(policyAudit); + tollgateContract = ITollgate(tollgate); + ledgerVault = ILedgerVault(ledger); + currency = IERC20(token); + + _configureTollgate(); + _seedLedgerBalance(holder, INITIAL_LEDGER_DEPOSIT); + } + + function _configureTollgate() internal { + vm.prank(governor); + tollgateContract.setFees(T.Scheme.BPS, address(manager), DEFAULT_TOLLGATE_BPS, address(currency)); + } + + function _seedLedgerBalance(address account, uint256 amount) internal { + vm.startPrank(admin); + currency.approve(address(ledgerVault), amount); + ledgerVault.deposit(account, amount, address(currency)); + vm.stopPrank(); + } + + function _deployPolicy() + internal + returns (PolicyBaseManagerHarness policy, ConfigurableAttestationProvider provider) + { + provider = new ConfigurableAttestationProvider(); + policy = new PolicyBaseManagerHarness(address(manager), address(authorizer), assetRegistry, address(provider)); + } + + function _authorizePolicy(PolicyBaseManagerHarness policy, bytes memory data) internal { + _auditPolicy(address(policy)); + if (authorizedPolicies[address(policy)]) return; + + vm.prank(holder); + authorizer.authorizePolicy(address(policy), data); + authorizedPolicies[address(policy)] = true; + } + + function _auditPolicy(address policy) internal { + if (auditedPolicies[policy]) return; + + vm.prank(holder); + try auditor.submit(policy) {} catch {} + + vm.prank(admin); + try auditor.approve(policy) { + auditedPolicies[policy] = true; + } catch {} + + if (!auditedPolicies[policy] && auditor.isApproved(policy)) { + auditedPolicies[policy] = true; + } + } + + function _createAgreement( + address[] memory parties + ) internal returns (uint256 proof, T.Agreement memory agreement) { + vm.roll(block.number + 1); + vm.startPrank(holder); + proof = agreements.createAgreement( + DEFAULT_AGREEMENT_AMOUNT, + address(currency), + address(manager), + parties, + DEFAULT_PAYLOAD + ); + vm.stopPrank(); + agreement = agreements.getAgreement(proof); + } + + function _createAgreementWithArbiter( + address arbiter, + address[] memory parties + ) internal returns (uint256 proof, T.Agreement memory agreement) { + vm.roll(block.number + 1); + vm.prank(governor); + tollgateContract.setFees(T.Scheme.BPS, arbiter, DEFAULT_TOLLGATE_BPS, address(currency)); + + vm.startPrank(holder); + proof = agreements.createAgreement(DEFAULT_AGREEMENT_AMOUNT, address(currency), arbiter, parties, DEFAULT_PAYLOAD); + vm.stopPrank(); + agreement = agreements.getAgreement(proof); + } + + function _collectedFees(T.Agreement memory agreement) internal pure returns (uint256) { + return agreement.fees + (agreement.locked - agreement.total); + } + + function test_RegisterPolicy_SucceedsForAuthorizedPolicy() public { + (PolicyBaseManagerHarness policy, ConfigurableAttestationProvider provider) = _deployPolicy(); + _authorizePolicy(policy, abi.encode(uint256(1))); + + address[] memory parties = new address[](2); + parties[0] = vm.addr(11); + parties[1] = vm.addr(12); + (uint256 proof, T.Agreement memory agreement) = _createAgreement(parties); + + uint256[] memory attestationIds = new uint256[](2); + attestationIds[0] = 777; + attestationIds[1] = 888; + provider.setNextAttestationIds(attestationIds); + + vm.expectEmit(true, true, true, true, agreementSettler); + emit AgreementSettler.AgreementSettled(address(manager), holder, proof, _collectedFees(agreement)); + + vm.expectEmit(true, true, true, true); + emit Registered(parties[0], proof, attestationIds[0], address(policy)); + vm.expectEmit(true, true, true, true); + emit Registered(parties[1], proof, attestationIds[1], address(policy)); + + uint256[] memory result = manager.registerPolicy(proof, holder, address(policy)); + assertEq(result.length, attestationIds.length, "Unexpected attestation array length"); + for (uint256 i = 0; i < result.length; i++) { + assertEq(result[i], attestationIds[i], "Attestation id mismatch"); + } + + assertEq(policy.lastHolder(), holder, "Holder mismatch recorded in policy"); + address retrievedArbiter; + address[] memory enforcedParties; + bytes memory payload; + T.Agreement memory enforced = policy.getLastAgreement(); + retrievedArbiter = enforced.arbiter; + enforcedParties = enforced.parties; + payload = enforced.payload; + assertEq(retrievedArbiter, agreement.arbiter, "Stored agreement arbiter mismatch"); + assertEq(enforcedParties.length, agreement.parties.length, "Stored agreement parties mismatch"); + + address[] memory holderPolicies = manager.getPolicies(parties[0]); + assertEq(holderPolicies.length, 1, "First party should have one policy"); + assertEq(holderPolicies[0], address(policy), "Unexpected policy stored for first party"); + + holderPolicies = manager.getPolicies(parties[1]); + assertEq(holderPolicies.length, 1, "Second party should have one policy"); + assertEq(holderPolicies[0], address(policy), "Unexpected policy stored for second party"); + } + + function test_RegisterPolicy_RevertsWhenPolicyNotAuthorized() public { + (PolicyBaseManagerHarness policy, ) = _deployPolicy(); + + address[] memory parties = new address[](1); + parties[0] = vm.addr(101); + (uint256 proof, ) = _createAgreement(parties); + + vm.expectRevert(abi.encodeWithSelector(RightsPolicyManager.RightsNotDelegated.selector, address(policy), holder)); + manager.registerPolicy(proof, holder, address(policy)); + } + + function test_RegisterPolicy_RevertsWhenAgreementHasNoParties() public { + (PolicyBaseManagerHarness policy, ) = _deployPolicy(); + _authorizePolicy(policy, ""); + + address[] memory parties = new address[](0); + (uint256 proof, ) = _createAgreement(parties); + + vm.expectRevert( + abi.encodeWithSelector( + RightsPolicyManager.EnforcementFailed.selector, + "No parties in agreement: at least one party is required." + ) + ); + manager.registerPolicy(proof, holder, address(policy)); + } + + function test_RegisterPolicy_RevertsWhenEnforceFails() public { + (PolicyBaseManagerHarness policy, ) = _deployPolicy(); + policy.setEnforceRevert(true); + _authorizePolicy(policy, ""); + + address[] memory parties = new address[](1); + parties[0] = vm.addr(99); + (uint256 proof, ) = _createAgreement(parties); + + vm.expectRevert( + abi.encodeWithSelector( + RightsPolicyManager.EnforcementFailed.selector, + "Error during policy enforcement call" + ) + ); + manager.registerPolicy(proof, holder, address(policy)); + } + + function test_RegisterPolicy_RevertsWhenSettlerFails() public { + (PolicyBaseManagerHarness policy, ) = _deployPolicy(); + _authorizePolicy(policy, ""); + + address[] memory parties = new address[](1); + parties[0] = vm.addr(77); + (uint256 proof, ) = _createAgreementWithArbiter(address(this), parties); + + vm.expectRevert(AgreementSettler.UnauthorizedEscrowAgent.selector); + manager.registerPolicy(proof, holder, address(policy)); + } + + function test_GetActivePolicy_ReturnsFirstMatchingPolicy() public { + address account = vm.addr(222); + address[] memory parties = new address[](1); + parties[0] = account; + + (PolicyBaseManagerHarness inactivePolicy, ConfigurableAttestationProvider inactiveProvider) = _deployPolicy(); + inactivePolicy.setAccessAllowed(false); + _authorizePolicy(inactivePolicy, ""); + inactiveProvider.setNextAttestationIds(_singleAttestation(1)); + (uint256 inactiveProof, ) = _createAgreement(parties); + manager.registerPolicy(inactiveProof, holder, address(inactivePolicy)); + + (PolicyBaseManagerHarness activePolicy, ConfigurableAttestationProvider activeProvider) = _deployPolicy(); + activePolicy.setAccessAllowed(true); + _authorizePolicy(activePolicy, ""); + activeProvider.setNextAttestationIds(_singleAttestation(2)); + (uint256 activeProof, ) = _createAgreement(parties); + manager.registerPolicy(activeProof, holder, address(activePolicy)); + + (bool found, address policyAddress) = manager.getActivePolicy(account, abi.encode("criteria")); + assertTrue(found, "An active policy should be found"); + assertEq(policyAddress, address(activePolicy), "Expected the active policy to be returned"); + } + + function test_GetActivePolicies_FiltersInactiveOnes() public { + address account = vm.addr(333); + address[] memory parties = new address[](1); + parties[0] = account; + + (PolicyBaseManagerHarness policyA, ConfigurableAttestationProvider providerA) = _deployPolicy(); + policyA.setAccessAllowed(true); + _authorizePolicy(policyA, ""); + providerA.setNextAttestationIds(_singleAttestation(101)); + (uint256 proofA, ) = _createAgreement(parties); + manager.registerPolicy(proofA, holder, address(policyA)); + + (PolicyBaseManagerHarness policyB, ConfigurableAttestationProvider providerB) = _deployPolicy(); + policyB.setAccessAllowed(false); + _authorizePolicy(policyB, ""); + providerB.setNextAttestationIds(_singleAttestation(102)); + (uint256 proofB, ) = _createAgreement(parties); + manager.registerPolicy(proofB, holder, address(policyB)); + + (PolicyBaseManagerHarness policyC, ConfigurableAttestationProvider providerC) = _deployPolicy(); + policyC.setAccessAllowed(true); + _authorizePolicy(policyC, ""); + providerC.setNextAttestationIds(_singleAttestation(103)); + (uint256 proofC, ) = _createAgreement(parties); + manager.registerPolicy(proofC, holder, address(policyC)); + + address[] memory activePolicies = manager.getActivePolicies(account, ""); + assertEq(activePolicies.length, 2, "Only active policies should be returned"); + assertEq(activePolicies[0], address(policyA), "First active policy mismatch"); + assertEq(activePolicies[1], address(policyC), "Second active policy mismatch"); + } + + function test_IsActivePolicy_ReturnsFalseWhenAccessCheckReverts() public { + (PolicyBaseManagerHarness policy, ConfigurableAttestationProvider provider) = _deployPolicy(); + _authorizePolicy(policy, ""); + policy.setAccessRevert(true); + + address[] memory parties = new address[](1); + parties[0] = vm.addr(404); + provider.setNextAttestationIds(_singleAttestation(9)); + + assertFalse(manager.isActivePolicy(parties[0], address(policy), ""), "Unknown policy should be inactive"); + + (uint256 proof, ) = _createAgreement(parties); + manager.registerPolicy(proof, holder, address(policy)); + + assertFalse(manager.isActivePolicy(parties[0], address(policy), ""), "Reverting policy should be treated as inactive"); + } + + function testFuzz_RegisterPolicy_StoresPolicyOnce( + address account, + uint256 proofSeed, + uint256 attestation + ) public { + vm.assume(account != address(0)); + + (PolicyBaseManagerHarness policy, ConfigurableAttestationProvider provider) = _deployPolicy(); + _authorizePolicy(policy, abi.encode(proofSeed)); + + address[] memory parties = new address[](1); + parties[0] = account; + + uint8 repeats = uint8(bound(proofSeed, 1, 3)); + uint256 baseAttestation = bound(attestation, 1, type(uint256).max - repeats); + for (uint8 i = 0; i < repeats; i++) { + provider.setNextAttestationIds(_singleAttestation(baseAttestation + i)); + (uint256 proof, ) = _createAgreement(parties); + manager.registerPolicy(proof, holder, address(policy)); + } + + address[] memory policies = manager.getPolicies(account); + assertEq(policies.length, 1, "Policy should be registered once"); + assertEq(policies[0], address(policy), "Stored policy mismatch"); + } + + function _singleAttestation(uint256 value) internal pure returns (uint256[] memory attestationIds) { + attestationIds = new uint256[](1); + attestationIds[0] = value; + } +} From ee01f1473f28e5e8b630ccee18f1cdaed5a6390d Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Mon, 13 Oct 2025 12:03:13 -0600 Subject: [PATCH 22/33] test: right policy managet + authorizer --- SYNAPSE_AUDIT_DOC.md | 170 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 SYNAPSE_AUDIT_DOC.md diff --git a/SYNAPSE_AUDIT_DOC.md b/SYNAPSE_AUDIT_DOC.md new file mode 100644 index 0000000..bf09db7 --- /dev/null +++ b/SYNAPSE_AUDIT_DOC.md @@ -0,0 +1,170 @@ +## Synapse Protocol – Auditor Documentation (v1) + +> **Scope**: Assets, Policy & Rights Enforcement, Finance (Escrow & Settlements), Economics, Governance, Access Control +> **Out of Scope**: Custodian Network (DePIN), DWRR routing, replication/delivery infrastructure + +--- + +### 1. Overview + +Synapse Protocol delivers a deterministic coordination layer for digital asset registration, licensing, and monetization. Programmable access rules are executed on-chain, governed by role-based permissions and quorum-driven workflows. This document captures architecture, module summaries, interdependencies, and audit checkpoints. + +--- + +### 2. Layered System Architecture + +| Layer | Purpose | Key Components | Notes | +| --- | --- | --- | --- | +| **Blockchain Layer** | Anchors protocol state on EVM networks, executes verifiable rights and settlement logic. | Deployed contracts for Assets, Rights, Policies, Finance, Governance, Access Control. | Stateless interactions via calldata; deterministic execution supports audits & integrations. | +| **Coordination Layer** | Core execution environment managing registries, policies, governance, fees. | Asset & policy registries, rights authorizers, settlement engines. | Primary audit scope; ensures modules compose deterministically. | +| **Integration Layer** | Bridges external applications, attestation services, marketplaces. | `IAttestationProvider` implementations, future SEP integrations. | Currently minimal; attestations pluggable through `PolicyBase`. | + +--- + +### 3. Smart Contract Summary + +| Module | Description & Logic | Core Contracts | Critical Functions | Relationships & Dependencies | +| --- | --- | --- | --- | --- | +| **Assets** | ERC-721 asset lifecycle with governance-gated approval, activation, transfer. | `AssetRegistry`, `AssetReferendum`, `AssetSafe` | `AssetRegistry.register`, `revoke`, `transfer`, `switchState`; `AssetReferendum.submit`, `approve`, `reject`, `revoke`, `isApproved` | `AssetRegistry` invokes `IAssetReferendumVerifiable.isApproved`; inherits `AccessControlledUpgradeable`. `AssetReferendum` extends `QuorumUpgradeable`. | +| **Rights** | Authorizes policies and enforces access rights; orchestrates agreement settlement. | `RightsPolicyAuthorizer`, `RightsPolicyManager`, `RightsAssetCustodian` | `RightsPolicyAuthorizer.authorizePolicy`, `revokePolicy`, `isPolicyAuthorized`, `getAuthorizedPolicies`; `RightsPolicyManager.registerPolicy`, `getActivePolicy`, `getActivePolicies`, `getPolicies`, `isActivePolicy` | Authorizer consults `PolicyAudit.isApproved`, uses `AccessManager` roles. Manager interacts with `IAgreementSettler`, `IAgreementManager`, `IRightsPolicyAuthorizerVerifiable`, and policy contracts (via `PolicyBase`). | +| **Policies** | Provides reusable policy logic, attestation workflow, and auditing pipeline. | `PolicyBase` (abstract), `PolicyAudit`, policy implementations | `PolicyBase.setup`, `enforce`, `_commit`, `_setAttestation`, `getLicense`; `PolicyAudit.submit`, `approve`, `reject`, `isApproved`, `isRejected`, `isPending` | `PolicyBase` keeps immutable refs to `RightsPolicyManager`, `RightsPolicyAuthorizer`, `IAssetRegistry`, `IAttestationProvider`. `PolicyAudit` extends `QuorumUpgradeable`, consumed by authorizer. | +| **Finance** | Agreement creation, escrow, fee calculation, settlement, ledger operations. | `AgreementManager`, `AgreementSettler`, `LedgerVault`, `Tollgate`, `Treasury` | `AgreementManager.createAgreement`, `previewAgreement`, `setMaxParties`; `AgreementSettler.settleAgreement`, `quitAgreement`; `LedgerVault.deposit`, `release`, `claim`; `Tollgate.setFees`, `getFees`, `supportedCurrencies` | `AgreementManager` relies on `Tollgate` & `LedgerVault`. `AgreementSettler` releases funds to counterparties and calls policy enforcement. Libraries `FinancialOps`, `FeesOps`. | +| **Governance** | Quorum-based approval for assets and policies, enforcing state machines. | `AssetReferendum`, `PolicyAudit`, `QuorumUpgradeable` base | Module-specific `submit`, `approve`, `reject`, `revoke`, `isApproved`, `isPending`. | Governed via `AccessManager` roles. Emits domain events (`Submitted`, `PolicyApproved`, etc.). | +| **Access Control** | Central role matrix enabling per-target permissioning and pauses; governs upgrades. | `AccessManager`, `AccessControlledUpgradeable` | `grantRole`, `revokeRole`, `setTargetFunctionRole`, `setRoleAdmin`, `setTargetClosed`, `_authorizeUpgrade` | All modules import `AccessControlledUpgradeable`. Roles (`ADMIN_ROLE`, `GOV_ROLE`, `OPS_ROLE`, etc.) defined in `C`. Uses OpenZeppelin `AccessManagerUpgradeable` + UUPS pattern. | + +--- + +### 4. Module Topology & Flow + +**Narrative Flow** +1. `AccessManager` assigns roles; governance modules operate via quorum FSM. +2. Asset creators submit proposals to `AssetReferendum`; upon approval, `AssetRegistry.register` mints tokens. +3. Policies must pass `PolicyAudit`; rights holders call `RightsPolicyAuthorizer.authorizePolicy` to delegate rights. +4. `RightsPolicyManager.registerPolicy` settles agreements via `AgreementSettler`, triggers `PolicyBase.enforce`, stores licensed policies per account. +5. Financial modules manage escrow deposits (`LedgerVault`), fee validation (`Tollgate`), and payouts (`AgreementSettler`, `Treasury`). +6. Governance intercepts at content approval, policy auditing, fee updates, and contract upgrades. + +**ASCII Diagram** +``` +[AccessManager / Role Control] + | + v + [AssetReferendum] --> approves --> [AssetRegistry] + | | + v v + [PolicyAudit] --(isApproved)--> [RightsPolicyAuthorizer] + | | + | v + | [RightsPolicyManager] + | | + | (settle) v + | [AgreementSettler] + | | + | [LedgerVault/Treasury] + | + governance oversight, upgrades, fee settings +``` + +--- + +### 5. Contract Relationships + +| Relationship | Direction | Description | Events / Standards | +| --- | --- | --- | --- | +| Role Assignment | `AccessManager` → All modules | Configures privileged functions, pausing, upgrades. | OpenZeppelin Access Manager, UUPS. | +| Content Approval | `AssetReferendum` → `AssetRegistry` | `register` gated by referendum approval. | `Submitted`, `Approved`, `RegisteredAsset`. | +| Policy Auditing | `PolicyAudit` → `RightsPolicyAuthorizer` | `authorizePolicy` allowed only if `isApproved`. | `PolicyApproved`, `PolicyRevoked`. | +| Rights Enforcement | `RightsPolicyAuthorizer` → `PolicyBase.setup` | Holder-driven authorization; `RightsPolicyManager` checks `onlyAuthorizedPolicy`. | `RightsGranted`, `RightsRevoked`. | +| Policy Registration | `RightsPolicyManager` → `AgreementSettler` → `PolicyBase.enforce` | Settles agreements, obtains attestations, registers policies. | `AgreementSettled`, `Registered`, `AttestedAgreement`. | +| Escrow & Fees | `AgreementManager` ↔ `Tollgate` / `LedgerVault` | Validates fees, stores collateral, handles releases. | ERC-20 operations (via `FinancialOps`). | +| Attestation Integration | `PolicyBase` → `IAttestationProvider` | Issues attestations per agreement; recorded for access checks. | Custom provider interface; future SEP integration noted. | +| Upgrade Authorization | `AccessControlledUpgradeable` → `AccessManager` | `_authorizeUpgrade` restricted to admin. | UUPS proxy. | +| Standards & TODOs | Future compatibility (ERC-1271, ERC-404, ERC-2981, ERC-4804). | Documented in TODO comments. | n/a | + +--- + +### 6. Critical Invariants & Controls + +- **Access Control**: All privileged functions are guarded (`restricted`, `onlyAdmin`, target function roles). Misconfigurations in `AccessManager` propagate system-wide. +- **Quorum FSM**: `QuorumUpgradeable` enforces state transitions (`Pending → Waiting → Active/Blocked`) for referendums and audits. +- **Policy Authorization**: `_authorizing` guard inside `RightsPolicyAuthorizer` prevents recursive `authorizePolicy` calls; reentrancy tests confirm failure paths. +- **Settlement Integrity**: `RightsPolicyManager.registerPolicy` halts if `AgreementSettler` or policy enforcement fails, preventing partial state updates. +- **Attestation Lifecycle**: `PolicyBase._commit` ensures attestation count matches parties; `_setAttestation` binds context to attestation IDs. +- **Financial Safety**: `FinancialOps`/`FeesOps` validate inputs (non-zero amounts/recipients, sufficient balances); auditors should inspect misuse scenarios. +- **Upgrade Safety**: Each UUPS contract restricts upgrades via `onlyAdmin`; verify governance processes around upgrade execution. +- **Event Traceability**: Domain events (`RegisteredAsset`, `PolicyApproved`, `AgreementSettled`, etc.) provide auditable off-chain records. + +--- + +### 7. Financial Escrow Sequence Diagram + +```mermaid +sequenceDiagram + participant Holder + participant AgreementManager + participant Tollgate + participant LedgerVault + participant RightsPolicyManager + participant AgreementSettler + participant Treasury + + Holder->>AgreementManager: createAgreement(amount, currency, arbiter, parties, payload) + AgreementManager->>Tollgate: getFees(arbiter, currency) + Tollgate-->>AgreementManager: feeScheme, feeAmount + AgreementManager->>LedgerVault: deposit(holder, totalToLock, currency) + LedgerVault-->>AgreementManager: receipt + AgreementManager->>AgreementManager: store agreement & emit AgreementCreated + AgreementManager-->>Holder: proof (agreementId) + + RightsPolicyManager->>AgreementSettler: settleAgreement(proof, holder) + AgreementSettler->>AgreementManager: getAgreement(proof) + AgreementSettler->>LedgerVault: claim(protocolTake, currency) + AgreementSettler->>Treasury: forward fees + AgreementSettler->>LedgerVault: release(counterparty amounts) + LedgerVault-->>AgreementSettler: settlement confirmation + AgreementSettler-->>RightsPolicyManager: attestationIds, agreement + AgreementSettler->>AgreementSettler: emit AgreementSettled +``` + +**Notes** +- `totalToLock = amount + penalization` (penalization enforces honest participation). +- Protocol take = fees + penalization; residual funds released to parties from `LedgerVault`. +- `AgreementSettled` is consumed by `RightsPolicyManager` and downstream analytics for compliance tracking. + +### 8. Audit Checklist + +1. **AccessManager Configuration** + - Validate role assignments and target function role mappings. + - Confirm pause/unpause permissions and guardianship settings. +2. **Governance FSM** + - Check `QuorumUpgradeable` invariants in `AssetReferendum` & `PolicyAudit`. + - Verify state transitions and emitted events. +3. **Policy & Rights Flow** + - Inspect `RightsPolicyAuthorizer.authorizePolicy` reentrancy guard behavior. + - Ensure `PolicyBase.setup` and `enforce` revert paths leave system consistent. + - Test scenario coverage for duplicate authorizations and revocations. +4. **Financial Settlement** + - Validate fee calculations (`Tollgate`, `AgreementManager.previewAgreement`). + - Review `AgreementSettler.quitAgreement`, penalties, and ledger rollbacks. + - Confirm `LedgerVault` balances vs emitted events. +5. **Attestation Providers** + - Review any concrete `IAttestationProvider` deployed; ensure attestations cannot be spoofed or double-issued. +6. **Upgrade & Pause Controls** + - Ensure `_authorizeUpgrade` restrictions and governance processes are documented. + - Confirm modules can be paused/resumed by appropriate roles without bypasses. + +--- + +### 9. References & Notes + +- **Libraries & Standards**: OpenZeppelin Upgradeable suite, custom `FinancialOps`, `FeesOps`, `QuorumUpgradeable`. +- **External Standards (planned)**: ERC-1271 (custodian signatures), ERC-404 (fractionalization), ERC-2981 (royalties), ERC-4804 (on-chain URLs), SEP-001/002 (assets standards). +- **Event Catalog**: + - Assets: `RegisteredAsset`, `RevokedAsset`, `AssetEnabled`, `AssetDisabled`. + - Policies: `PolicySubmitted`, `PolicyApproved`, `PolicyRevoked`, `AttestedAgreement`, `AgreementCommitted`. + - Rights: `RightsGranted`, `RightsRevoked`, `Registered`. + - Finance: `AgreementCreated`, `AgreementSettled`, fee events in `Tollgate`. + +--- + +Prepared for Synapse Protocol auditors to assess the deterministic coordination layer, focusing on module architecture, invariants, inter-module dependencies, and governance controls. Omitted modules (Custodian Network / DePIN, DWRR routing) are out of current scope. For full coverage, extend review to attestation provider implementations and future standards once integrated. From ca69fc15914b8cf791da4d04acc9f4c57b37fbe3 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Mon, 13 Oct 2025 12:03:23 -0600 Subject: [PATCH 23/33] test: right policy managet + authorizer --- SYNAPSE_AUDIT_DOC.md | 170 ------------------------------------------- 1 file changed, 170 deletions(-) delete mode 100644 SYNAPSE_AUDIT_DOC.md diff --git a/SYNAPSE_AUDIT_DOC.md b/SYNAPSE_AUDIT_DOC.md deleted file mode 100644 index bf09db7..0000000 --- a/SYNAPSE_AUDIT_DOC.md +++ /dev/null @@ -1,170 +0,0 @@ -## Synapse Protocol – Auditor Documentation (v1) - -> **Scope**: Assets, Policy & Rights Enforcement, Finance (Escrow & Settlements), Economics, Governance, Access Control -> **Out of Scope**: Custodian Network (DePIN), DWRR routing, replication/delivery infrastructure - ---- - -### 1. Overview - -Synapse Protocol delivers a deterministic coordination layer for digital asset registration, licensing, and monetization. Programmable access rules are executed on-chain, governed by role-based permissions and quorum-driven workflows. This document captures architecture, module summaries, interdependencies, and audit checkpoints. - ---- - -### 2. Layered System Architecture - -| Layer | Purpose | Key Components | Notes | -| --- | --- | --- | --- | -| **Blockchain Layer** | Anchors protocol state on EVM networks, executes verifiable rights and settlement logic. | Deployed contracts for Assets, Rights, Policies, Finance, Governance, Access Control. | Stateless interactions via calldata; deterministic execution supports audits & integrations. | -| **Coordination Layer** | Core execution environment managing registries, policies, governance, fees. | Asset & policy registries, rights authorizers, settlement engines. | Primary audit scope; ensures modules compose deterministically. | -| **Integration Layer** | Bridges external applications, attestation services, marketplaces. | `IAttestationProvider` implementations, future SEP integrations. | Currently minimal; attestations pluggable through `PolicyBase`. | - ---- - -### 3. Smart Contract Summary - -| Module | Description & Logic | Core Contracts | Critical Functions | Relationships & Dependencies | -| --- | --- | --- | --- | --- | -| **Assets** | ERC-721 asset lifecycle with governance-gated approval, activation, transfer. | `AssetRegistry`, `AssetReferendum`, `AssetSafe` | `AssetRegistry.register`, `revoke`, `transfer`, `switchState`; `AssetReferendum.submit`, `approve`, `reject`, `revoke`, `isApproved` | `AssetRegistry` invokes `IAssetReferendumVerifiable.isApproved`; inherits `AccessControlledUpgradeable`. `AssetReferendum` extends `QuorumUpgradeable`. | -| **Rights** | Authorizes policies and enforces access rights; orchestrates agreement settlement. | `RightsPolicyAuthorizer`, `RightsPolicyManager`, `RightsAssetCustodian` | `RightsPolicyAuthorizer.authorizePolicy`, `revokePolicy`, `isPolicyAuthorized`, `getAuthorizedPolicies`; `RightsPolicyManager.registerPolicy`, `getActivePolicy`, `getActivePolicies`, `getPolicies`, `isActivePolicy` | Authorizer consults `PolicyAudit.isApproved`, uses `AccessManager` roles. Manager interacts with `IAgreementSettler`, `IAgreementManager`, `IRightsPolicyAuthorizerVerifiable`, and policy contracts (via `PolicyBase`). | -| **Policies** | Provides reusable policy logic, attestation workflow, and auditing pipeline. | `PolicyBase` (abstract), `PolicyAudit`, policy implementations | `PolicyBase.setup`, `enforce`, `_commit`, `_setAttestation`, `getLicense`; `PolicyAudit.submit`, `approve`, `reject`, `isApproved`, `isRejected`, `isPending` | `PolicyBase` keeps immutable refs to `RightsPolicyManager`, `RightsPolicyAuthorizer`, `IAssetRegistry`, `IAttestationProvider`. `PolicyAudit` extends `QuorumUpgradeable`, consumed by authorizer. | -| **Finance** | Agreement creation, escrow, fee calculation, settlement, ledger operations. | `AgreementManager`, `AgreementSettler`, `LedgerVault`, `Tollgate`, `Treasury` | `AgreementManager.createAgreement`, `previewAgreement`, `setMaxParties`; `AgreementSettler.settleAgreement`, `quitAgreement`; `LedgerVault.deposit`, `release`, `claim`; `Tollgate.setFees`, `getFees`, `supportedCurrencies` | `AgreementManager` relies on `Tollgate` & `LedgerVault`. `AgreementSettler` releases funds to counterparties and calls policy enforcement. Libraries `FinancialOps`, `FeesOps`. | -| **Governance** | Quorum-based approval for assets and policies, enforcing state machines. | `AssetReferendum`, `PolicyAudit`, `QuorumUpgradeable` base | Module-specific `submit`, `approve`, `reject`, `revoke`, `isApproved`, `isPending`. | Governed via `AccessManager` roles. Emits domain events (`Submitted`, `PolicyApproved`, etc.). | -| **Access Control** | Central role matrix enabling per-target permissioning and pauses; governs upgrades. | `AccessManager`, `AccessControlledUpgradeable` | `grantRole`, `revokeRole`, `setTargetFunctionRole`, `setRoleAdmin`, `setTargetClosed`, `_authorizeUpgrade` | All modules import `AccessControlledUpgradeable`. Roles (`ADMIN_ROLE`, `GOV_ROLE`, `OPS_ROLE`, etc.) defined in `C`. Uses OpenZeppelin `AccessManagerUpgradeable` + UUPS pattern. | - ---- - -### 4. Module Topology & Flow - -**Narrative Flow** -1. `AccessManager` assigns roles; governance modules operate via quorum FSM. -2. Asset creators submit proposals to `AssetReferendum`; upon approval, `AssetRegistry.register` mints tokens. -3. Policies must pass `PolicyAudit`; rights holders call `RightsPolicyAuthorizer.authorizePolicy` to delegate rights. -4. `RightsPolicyManager.registerPolicy` settles agreements via `AgreementSettler`, triggers `PolicyBase.enforce`, stores licensed policies per account. -5. Financial modules manage escrow deposits (`LedgerVault`), fee validation (`Tollgate`), and payouts (`AgreementSettler`, `Treasury`). -6. Governance intercepts at content approval, policy auditing, fee updates, and contract upgrades. - -**ASCII Diagram** -``` -[AccessManager / Role Control] - | - v - [AssetReferendum] --> approves --> [AssetRegistry] - | | - v v - [PolicyAudit] --(isApproved)--> [RightsPolicyAuthorizer] - | | - | v - | [RightsPolicyManager] - | | - | (settle) v - | [AgreementSettler] - | | - | [LedgerVault/Treasury] - | - governance oversight, upgrades, fee settings -``` - ---- - -### 5. Contract Relationships - -| Relationship | Direction | Description | Events / Standards | -| --- | --- | --- | --- | -| Role Assignment | `AccessManager` → All modules | Configures privileged functions, pausing, upgrades. | OpenZeppelin Access Manager, UUPS. | -| Content Approval | `AssetReferendum` → `AssetRegistry` | `register` gated by referendum approval. | `Submitted`, `Approved`, `RegisteredAsset`. | -| Policy Auditing | `PolicyAudit` → `RightsPolicyAuthorizer` | `authorizePolicy` allowed only if `isApproved`. | `PolicyApproved`, `PolicyRevoked`. | -| Rights Enforcement | `RightsPolicyAuthorizer` → `PolicyBase.setup` | Holder-driven authorization; `RightsPolicyManager` checks `onlyAuthorizedPolicy`. | `RightsGranted`, `RightsRevoked`. | -| Policy Registration | `RightsPolicyManager` → `AgreementSettler` → `PolicyBase.enforce` | Settles agreements, obtains attestations, registers policies. | `AgreementSettled`, `Registered`, `AttestedAgreement`. | -| Escrow & Fees | `AgreementManager` ↔ `Tollgate` / `LedgerVault` | Validates fees, stores collateral, handles releases. | ERC-20 operations (via `FinancialOps`). | -| Attestation Integration | `PolicyBase` → `IAttestationProvider` | Issues attestations per agreement; recorded for access checks. | Custom provider interface; future SEP integration noted. | -| Upgrade Authorization | `AccessControlledUpgradeable` → `AccessManager` | `_authorizeUpgrade` restricted to admin. | UUPS proxy. | -| Standards & TODOs | Future compatibility (ERC-1271, ERC-404, ERC-2981, ERC-4804). | Documented in TODO comments. | n/a | - ---- - -### 6. Critical Invariants & Controls - -- **Access Control**: All privileged functions are guarded (`restricted`, `onlyAdmin`, target function roles). Misconfigurations in `AccessManager` propagate system-wide. -- **Quorum FSM**: `QuorumUpgradeable` enforces state transitions (`Pending → Waiting → Active/Blocked`) for referendums and audits. -- **Policy Authorization**: `_authorizing` guard inside `RightsPolicyAuthorizer` prevents recursive `authorizePolicy` calls; reentrancy tests confirm failure paths. -- **Settlement Integrity**: `RightsPolicyManager.registerPolicy` halts if `AgreementSettler` or policy enforcement fails, preventing partial state updates. -- **Attestation Lifecycle**: `PolicyBase._commit` ensures attestation count matches parties; `_setAttestation` binds context to attestation IDs. -- **Financial Safety**: `FinancialOps`/`FeesOps` validate inputs (non-zero amounts/recipients, sufficient balances); auditors should inspect misuse scenarios. -- **Upgrade Safety**: Each UUPS contract restricts upgrades via `onlyAdmin`; verify governance processes around upgrade execution. -- **Event Traceability**: Domain events (`RegisteredAsset`, `PolicyApproved`, `AgreementSettled`, etc.) provide auditable off-chain records. - ---- - -### 7. Financial Escrow Sequence Diagram - -```mermaid -sequenceDiagram - participant Holder - participant AgreementManager - participant Tollgate - participant LedgerVault - participant RightsPolicyManager - participant AgreementSettler - participant Treasury - - Holder->>AgreementManager: createAgreement(amount, currency, arbiter, parties, payload) - AgreementManager->>Tollgate: getFees(arbiter, currency) - Tollgate-->>AgreementManager: feeScheme, feeAmount - AgreementManager->>LedgerVault: deposit(holder, totalToLock, currency) - LedgerVault-->>AgreementManager: receipt - AgreementManager->>AgreementManager: store agreement & emit AgreementCreated - AgreementManager-->>Holder: proof (agreementId) - - RightsPolicyManager->>AgreementSettler: settleAgreement(proof, holder) - AgreementSettler->>AgreementManager: getAgreement(proof) - AgreementSettler->>LedgerVault: claim(protocolTake, currency) - AgreementSettler->>Treasury: forward fees - AgreementSettler->>LedgerVault: release(counterparty amounts) - LedgerVault-->>AgreementSettler: settlement confirmation - AgreementSettler-->>RightsPolicyManager: attestationIds, agreement - AgreementSettler->>AgreementSettler: emit AgreementSettled -``` - -**Notes** -- `totalToLock = amount + penalization` (penalization enforces honest participation). -- Protocol take = fees + penalization; residual funds released to parties from `LedgerVault`. -- `AgreementSettled` is consumed by `RightsPolicyManager` and downstream analytics for compliance tracking. - -### 8. Audit Checklist - -1. **AccessManager Configuration** - - Validate role assignments and target function role mappings. - - Confirm pause/unpause permissions and guardianship settings. -2. **Governance FSM** - - Check `QuorumUpgradeable` invariants in `AssetReferendum` & `PolicyAudit`. - - Verify state transitions and emitted events. -3. **Policy & Rights Flow** - - Inspect `RightsPolicyAuthorizer.authorizePolicy` reentrancy guard behavior. - - Ensure `PolicyBase.setup` and `enforce` revert paths leave system consistent. - - Test scenario coverage for duplicate authorizations and revocations. -4. **Financial Settlement** - - Validate fee calculations (`Tollgate`, `AgreementManager.previewAgreement`). - - Review `AgreementSettler.quitAgreement`, penalties, and ledger rollbacks. - - Confirm `LedgerVault` balances vs emitted events. -5. **Attestation Providers** - - Review any concrete `IAttestationProvider` deployed; ensure attestations cannot be spoofed or double-issued. -6. **Upgrade & Pause Controls** - - Ensure `_authorizeUpgrade` restrictions and governance processes are documented. - - Confirm modules can be paused/resumed by appropriate roles without bypasses. - ---- - -### 9. References & Notes - -- **Libraries & Standards**: OpenZeppelin Upgradeable suite, custom `FinancialOps`, `FeesOps`, `QuorumUpgradeable`. -- **External Standards (planned)**: ERC-1271 (custodian signatures), ERC-404 (fractionalization), ERC-2981 (royalties), ERC-4804 (on-chain URLs), SEP-001/002 (assets standards). -- **Event Catalog**: - - Assets: `RegisteredAsset`, `RevokedAsset`, `AssetEnabled`, `AssetDisabled`. - - Policies: `PolicySubmitted`, `PolicyApproved`, `PolicyRevoked`, `AttestedAgreement`, `AgreementCommitted`. - - Rights: `RightsGranted`, `RightsRevoked`, `Registered`. - - Finance: `AgreementCreated`, `AgreementSettled`, fee events in `Tollgate`. - ---- - -Prepared for Synapse Protocol auditors to assess the deterministic coordination layer, focusing on module architecture, invariants, inter-module dependencies, and governance controls. Omitted modules (Custodian Network / DePIN, DWRR routing) are out of current scope. For full coverage, extend review to attestation provider implementations and future standards once integrated. From 6a603d42a7f24dad404f22f9d2f3f19321792504 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Mon, 13 Oct 2025 15:38:31 -0600 Subject: [PATCH 24/33] docs: pre-audits review doc --- docs/SYNAPSE_AUDIT_DOC.md | 370 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 docs/SYNAPSE_AUDIT_DOC.md diff --git a/docs/SYNAPSE_AUDIT_DOC.md b/docs/SYNAPSE_AUDIT_DOC.md new file mode 100644 index 0000000..f791965 --- /dev/null +++ b/docs/SYNAPSE_AUDIT_DOC.md @@ -0,0 +1,370 @@ +## Synapse Protocol – Auditor Documentation (v1) + +> **Scope**: Assets, Rights & Policies, Finance (Escrow & Settlements), Economics, Governance, Access Control +> **Out of Scope**: Custodian Network (DePIN), DWRR routing, replication/delivery infrastructure + +--- + +### 1. Overview + +Synapse Protocol provides a deterministic coordination layer for digital asset registration, licensing, and monetization. Creators define programmable access rules enforced on-chain, with all state transitions governed by role-based permissions and quorum-driven governance. This document summarizes architecture, modules, dependencies, and key audit checkpoints. + +--- + +### 2. Layered System Architecture + +| Layer | Purpose | Key Components | Notes | +| --- | --- | --- | --- | +| **Blockchain Layer** | Anchors protocol state on EVM networks; executes verifiable rights and settlement logic. | Deployed contracts for Assets, Rights, Policies, Finance, Economics, Governance, Access Control. | Deterministic calldata interactions enable auditability and integrations. | +| **Coordination Layer** | Core execution environment managing registries, policies, governance, and economics modules. | Asset registry, referendum, policy authorizer/manager, settlement engines, economics controllers (fees/tollgate, treasury). | Primary audit focus; ensures modules compose deterministically. | +| **Integration Layer / Peripheral Layer** | Bridges external applications, attestation services, marketplaces. | Peripheral contracts such as `SubscriptionPolicy`, `IAttestationProvider` adapters (e.g., EAS), future SEP integrations. | Minimal in current scope; policies/attestors plug into the coordination layer via `PolicyBase`. | + +--- + +### 3. Smart Contract Summary + +| Module | Description & Logic | Core Contracts | Critical Functions | Relationships & Dependencies | +| --- | --- | --- | --- | --- | +| **Access Control** | Central role matrix, permission routing, pausing, upgrade authorization. | `AccessManager`, `AccessControlledUpgradeable`, OZ `AccessManagerUpgradeable` | `grantRole`, `revokeRole`, `setTargetFunctionRole`, `setRoleAdmin`, `setTargetClosed`, `_authorizeUpgrade` | All upgradeable modules initialize with `__AccessControlled_init(accessManager)`. Roles (`ADMIN_ROLE`, `GOV_ROLE`, `OPS_ROLE`, etc.) defined in `C`. Uses UUPS upgrade pattern. Contracts inheriting this mixin are pausable (`whenNotPaused`, `restricted`) and can be halted via governance-controlled roles. | +| **Governance** | Quorum-based approval pipelines for assets and policies; manages FSM transitions. | `AssetReferendum`, `PolicyAudit`, `QuorumUpgradeable` | `submit`, `approve`, `reject`, `revoke`, `isApproved`, `isRejected`, `isPending` | Governed by `AccessManager` roles; relies on `T.Status` state machine. Emits `Submitted`, `Approved`, `Rejected`, `PolicyApproved`, `PolicyRevoked`. | +| **Assets** | ERC-721 lifecycle management with governance approval and activation controls. | `AssetRegistry`, `AssetReferendum`, `AssetSafe` | `AssetRegistry.register`, `revoke`, `transfer`, `switchState`; `AssetReferendum.submit`, `approve`, `reject`, `revoke`, `isApproved` | `AssetRegistry` queries `IAssetReferendumVerifiable.isApproved`; inherits `AccessControlledUpgradeable`. `AssetReferendum` extends `QuorumUpgradeable`. | +| **Policies** | Reusable policy primitives providing attestation workflows and auditing pipeline. | `PolicyBase` (abstract), `PolicyAudit`, domain policy implementations | `PolicyBase.setup`, `enforce`, `_commit`, `_setAttestation`, `getLicense`; `PolicyAudit.submit`, `approve`, `reject`, `isApproved`, `isRejected`, `isPending` | `PolicyBase` holds immutables for `RightsPolicyManager`, `RightsPolicyAuthorizer`, `IAssetRegistry`, `IAttestationProvider`. `PolicyAudit` is consumed by authorizer via `isApproved`. | +| **Rights** | Authorizes policies and enforces access rights over assets; coordinates settlement process. | `RightsPolicyAuthorizer`, `RightsPolicyManager`, `RightsAssetCustodian` | `RightsPolicyAuthorizer.authorizePolicy`, `revokePolicy`, `isPolicyAuthorized`, `getAuthorizedPolicies`; `RightsPolicyManager.registerPolicy`, `getActivePolicy`, `getActivePolicies`, `getPolicies`, `isActivePolicy` | Authorizer depends on `PolicyAudit` (approval), `AccessManager` roles, internal `_authorizing` guard. Manager interacts with `IAgreementSettler`, `IAgreementManager`, `IRightsPolicyAuthorizerVerifiable`, and policy contracts (via `PolicyBase`). | +| **Finance** | Agreement creation, escrow, settlement, fee routing, ledger management. | `AgreementManager`, `AgreementSettler`, `LedgerVault`, `Treasury` | `AgreementManager.createAgreement`, `previewAgreement`, `setMaxParties`; `AgreementSettler.settleAgreement`, `quitAgreement`; `LedgerVault.deposit`, `release`, `claim`; `Treasury` distribution functions | `AgreementManager` validates fees via `Tollgate`, stores collateral in `LedgerVault`. `AgreementSettler` executes payouts, emits `AgreementSettled`. | +| **Economics** | Configures fees, basis-point schedules, token economics, and treasury flows. | `Tollgate`, `Treasury`, economic permission scripts | `Tollgate.setFees`, `getFees`, `supportedCurrencies`, `updateSupportedCurrency`; `Treasury.withdraw`, `distribute` | Economics modules referenced by `AgreementManager`/`AgreementSettler`. `Tollgate` controlled via governance (`AccessManager` roles). | + +#### Core Directory Components + +| Subdirectory | Purpose | Key Elements | +| --- | --- | --- | +| `contracts/core/interfaces` | Canonical interfaces consumed across modules. | Rights (`IRightsPolicyAuthorizer`), Finance (`IAgreementManager`), Assets (`IAssetReferendumVerifiable`), Attestations (`IAttestationProvider`). | +| `contracts/core/primitives` | Shared primitives (Structs, constants, upgradeable mixins). | `AccessControlledUpgradeable`, `QuorumUpgradeable`, `T` (Types), `C` (Constants). | +| `contracts/core/libraries` | Deterministic utility libraries. | `FinancialOps`, `FeesOps`, `LoopOps`, `CriteriaOps`. | +| `contracts/core/primitives/upgradeable` | UUPS-ready mixins for inheritance. | `AccessControlledUpgradeable`, `ReentrancyGuardTransientUpgradeable`. | + + +--- + +### 4. Governance Structure + +| Role | Description | Responsibilities | Assigned Entities | +| --- | --- | --- | --- | +| `ADMIN_ROLE` | Core administrators controlling upgrades, pause/unpause, and role granting. | `_authorizeUpgrade`, `setTargetFunctionRole`, `setTargetClosed`, emergency actions. | Multisig / governance executor (per deployment). | +| `GOV_ROLE` | Community governance authority. | Approves council compositions, economics changes, policy & asset referendums. | DAO governance process. | +| `CONTENT_COUNCIL_ROLE` | Oversees content curation and asset approvals. | Voting on `AssetReferendum` submissions. | Council multisig. | +| `CUSTODY_COUNCIL_ROLE` | Manages custodial operations and related referendums. | Approving custodial contracts, emergency custodial actions. | Custody council. | +| `OPS_ROLE` | Operational role granted to trusted system contracts. | Invoke restricted functions (`restricted` modifier), handle automated flows. | Contracts like `AgreementManager`, `RightsPolicyManager`, etc. | +| `SEC_ROLE` | Security guardianship (if implemented). | Fast emergency responses (pause, disable assets). | Security council. | +| `TREASURER_ROLE` | Treasury management. | `Treasury` withdrawals/distributions, economic adjustments. | Treasury multisig. | +| `VER_ROLE` | Verified creators/participants. | Bypass certain checks (e.g., asset verification) when designated. | Trusted creators or nodes. | + +*Hierarchy*: `GOV_ROLE` (community governance) → councils (`CONTENT_COUNCIL_ROLE`, `CUSTODY_COUNCIL_ROLE`, `TREASURER_ROLE`) → ops roles (`OPS_ROLE`, `SEC_ROLE`) → contracts/users. `ADMIN_ROLE` executes governance-approved actions (upgrades, role assignments) within `AccessManager`. + + +--- + +### 5. Module Topology & Flow + +**Narrative Flow** +1. `AccessManager` assigns roles; governance modules operate via `QuorumUpgradeable`. +2. Asset creators submit proposals to `AssetReferendum`; `AssetRegistry.register` mints ERC-721 upon approval. +3. Policies pass `PolicyAudit`; rights holders call `RightsPolicyAuthorizer.authorizePolicy`. +4. `AgreementManager` creates escrow-backed agreements (fees via `Tollgate`, collateral into `LedgerVault`), returning a proof. +5. `RightsPolicyManager.registerPolicy` consumes the proof, triggers `AgreementSettler`, and executes `PolicyBase.enforce`, storing policy references. +6. Economics layer (`Tollgate`, `Treasury`) distributes protocol fees during settlement; finance components (`LedgerVault`, `Treasury`) handle balances and payouts. + +**ASCII Diagram** +``` +[AccessManager / Role Control] + | + v + [AssetReferendum] --> approves --> [AssetRegistry] + | | + v v + [PolicyAudit] --(isApproved)--> [RightsPolicyAuthorizer] + | | + | v + | [RightsPolicyManager] + | | + | (settle) v + | [AgreementSettler] + | | + | [Tollgate / Treasury] + | | + | [LedgerVault payouts] + | + governance oversight, upgrades, fee configuration +``` + +--- + +### 6. Contract Relationships + +| Relationship | Direction | Description | Events / Standards | +| --- | --- | --- | --- | +| Role Assignment | `AccessManager` → All modules | Configures privileged functions, pausing, upgrades. | OpenZeppelin Access Manager, UUPS. | +| Content Approval | `AssetReferendum` → `AssetRegistry` | Registration gated by referendum-approved asset ID. | `Submitted`, `Approved`, `RegisteredAsset`. | +| Policy Auditing | `PolicyAudit` → `RightsPolicyAuthorizer` | `authorizePolicy` permitted only if `isApproved`. | `PolicyApproved`, `PolicyRevoked`. | +| Rights Enforcement | `RightsPolicyAuthorizer` → `PolicyBase.setup` & `RightsPolicyManager.registerPolicy` | Holder-driven authorization; manager enforces via authorized policies; reentrancy guard prevents recursion. | `RightsGranted`, `RightsRevoked`, `Registered`. | +| Policy Registration | `RightsPolicyManager` → `AgreementSettler` → `PolicyBase` (`enforce`) | Settles agreements, retrieves attestations, registers policies. | `AgreementSettled`, `AttestedAgreement`. | +| Settlement Execution | `AgreementSettler` → `AgreementManager` / `LedgerVault` / `Treasury` | Reads agreements, claims protocol fees, releases funds to counterparties. | `AgreementSettled`, ledger transfer events. | +| Escrow & Fees | `AgreementManager` ↔ `Tollgate` / `LedgerVault` | Validates fees, stores collateral, handles releases. | ERC-20 operations via `FinancialOps`; events `AgreementCreated`, `AgreementSettled`. | +| Economics Distribution | `Tollgate` / `Treasury` → Finance & Governance | Tollgate manages fee schedules; Treasury receives protocol take after settlement. | Fee events in `Tollgate`; Treasury distributions (if implemented). | +| Attestation Integration | `PolicyBase` → `IAttestationProvider` | Issues attestation IDs for parties; stored for `isActivePolicy`. | Future SEP integration noted. | +| Upgrade Authorization | `AccessControlledUpgradeable` → `AccessManager` | `_authorizeUpgrade` restricted to admin. | UUPS proxy. | +| Standards & TODOs | Future compatibility (ERC-1271, ERC-404, ERC-2981, ERC-4804). | Documented as TODOs in contracts. | n/a | + +--- + +### 7. Critical Invariants & Controls + +- **Access Control**: All privileged functions protected by target function roles (`restricted`, `onlyAdmin`). Contracts inheriting `AccessControlledUpgradeable` are pausable (`whenNotPaused`) and subject to governance-controlled halt/resume. Misconfiguration centralizes risk at `AccessManager`. +- **Quorum FSM**: `QuorumUpgradeable` enforces state transitions (Pending → Waiting → Active/Blocked) for `AssetReferendum` and `PolicyAudit`. +- **Policy Authorization**: `RightsPolicyAuthorizer` uses `_authorizing` guard to prevent recursive `authorizePolicy`; `RightsPolicyManager` relies on `onlyAuthorizedPolicy`. +- **Settlement Integrity**: `RightsPolicyManager.registerPolicy` reverts on settlement or enforcement failure, preventing half-complete state. +- **Attestation Lifecycle**: `PolicyBase._commit` ensures attestation arrays match parties, `_setAttestation` binds context to IDs. +- **Financial Safety**: `FinancialOps`/`FeesOps` check zero amounts, zero recipients, balance sufficiency; auditors should review edge cases and revert behavior. +- **Economics Configuration**: `Tollgate` fee schedules are governance-controlled; verify no fee bypass. `Treasury` distribution flows must match governance rules. +- **Upgrade Safety**: UUPS contracts restrict `_authorizeUpgrade` to admin role; confirm governance process for upgrade proposals/execution. +- **Event Traceability**: Domain events (`RegisteredAsset`, `PolicyApproved`, `AgreementSettled`, fee events) provide verifiable trails. + +--- + +### 8. Sequence Diagrams + +> The diagrams follow the logical lifecycle: asset onboarding → policy vetting → rights registration → content delivery → settlement. + +#### 8.1 Asset Approval & Registration +```mermaid +sequenceDiagram + participant Creator + participant AssetReferendum + participant GovernanceCouncil + participant AssetRegistry + + Creator->>AssetReferendum: submit(assetId) + AssetReferendum->>AssetReferendum: _register(assetId) (Waiting state) + AssetReferendum->>GovernanceCouncil: emit Submitted(assetId) + GovernanceCouncil->>AssetReferendum: approve(assetId) + AssetReferendum-->>Creator: assetId marked Active + Creator->>AssetRegistry: register(to, assetId) + AssetRegistry->>AssetReferendum: isApproved(to, assetId) + AssetReferendum-->>AssetRegistry: true + AssetRegistry->>AssetRegistry: mint & enable asset + AssetRegistry->>Creator: emit RegisteredAsset(to, assetId) +``` + +**Notes** +- `AssetReferendum` uses `QuorumUpgradeable` (Pending → Waiting → Active/Blocked). +- Registration reverts if the referendum status is not Active. + +#### 8.2 Policy Audit & Authorization +```mermaid +sequenceDiagram + participant PolicyDev + participant PolicyAudit + participant GovernanceCouncil + participant Holder + participant RightsPolicyAuthorizer + + PolicyDev->>PolicyAudit: submit(policy) + PolicyAudit->>PolicyAudit: _register(policy) (Waiting state) + PolicyAudit->>GovernanceCouncil: emit PolicySubmitted(policy) + GovernanceCouncil->>PolicyAudit: approve(policy) + PolicyAudit-->>PolicyDev: status = Active + Holder->>RightsPolicyAuthorizer: authorizePolicy(policy, data) + RightsPolicyAuthorizer->>PolicyAudit: isApproved(policy) + PolicyAudit-->>RightsPolicyAuthorizer: true + RightsPolicyAuthorizer->>RightsPolicyAuthorizer: record authorization + RightsPolicyAuthorizer-->>Holder: emit RightsGranted(policy) +``` + +**Notes** +- Policy audit follows the same quorum FSM as asset approval. +- Authorization attempts fail if audit status is not Active or if ownership checks fail. + +#### 8.3 Rights Policy Management (Subscription Example) +```mermaid +sequenceDiagram + participant Holder + participant RightsPolicyAuthorizer + participant SubscriptionPolicy + participant RightsPolicyManager + participant AgreementManager + participant AgreementSettler + participant AttestationProvider + + Holder->>RightsPolicyAuthorizer: authorizePolicy(SubscriptionPolicy, planData) + RightsPolicyAuthorizer->>SubscriptionPolicy: setup(holder, planData) + RightsPolicyAuthorizer-->>Holder: emit RightsGranted + + Holder->>AgreementManager: createAgreement(amount, currency, manager, parties, payload) + AgreementManager-->>Holder: proof + + Holder->>RightsPolicyManager: registerPolicy(proof, holder, SubscriptionPolicy) + RightsPolicyManager->>AgreementSettler: settleAgreement(proof, holder) + AgreementSettler->>AgreementManager: getAgreement(proof) + AgreementSettler->>SubscriptionPolicy: enforce(holder, agreement) + SubscriptionPolicy->>AttestationProvider: attest(parties, expireAt, data) + AttestationProvider-->>SubscriptionPolicy: attestationIds + SubscriptionPolicy->>SubscriptionPolicy: _setAttestation(account, context, id) + SubscriptionPolicy-->>RightsPolicyManager: attestationIds + RightsPolicyManager-->>Holder: emit Registered(account, proof, attestationId, policy) +``` + +**Notes** +- Policies derived from `PolicyBase` call `_commit` to generate attestations aligning parties and plan metadata. +- Registration is idempotent due to `EnumerableSet` storage per account. + +#### 8.4 Content Access Authorization (Delivery Nodes) +```mermaid +sequenceDiagram + participant DeliveryNode + participant RightsPolicyManager + participant SubscriptionPolicy + participant AttestationProvider + + DeliveryNode->>RightsPolicyManager: getActivePolicy(account, criteria) + RightsPolicyManager->>RightsPolicyManager: getPolicies(account) + RightsPolicyManager->>SubscriptionPolicy: isActivePolicy(account, policy, criteria) + SubscriptionPolicy->>SubscriptionPolicy: isRegisteredPolicy(account) + SubscriptionPolicy->>AttestationProvider: verify(attestationId, account) + AttestationProvider-->>SubscriptionPolicy: valid/invalid + SubscriptionPolicy-->>RightsPolicyManager: true/false + RightsPolicyManager-->>DeliveryNode: (found?, policyAddress) +``` + +**Notes** +- Delivery nodes act as content gateways; they query policies to decide whether to serve protected content. +- `criteria` encapsulates context (assetId, holder, plan tier, expiry) for policy evaluation. + +#### 8.5 Financial Escrow & Settlement +```mermaid +sequenceDiagram + participant Holder + participant AgreementManager + participant Tollgate + participant LedgerVault + participant RightsPolicyManager + participant AgreementSettler + participant Treasury + + Holder->>AgreementManager: createAgreement(amount, currency, arbiter, parties, payload) + AgreementManager->>Tollgate: getFees(arbiter, currency) + Tollgate-->>AgreementManager: feeScheme, feeAmount + AgreementManager->>LedgerVault: deposit(holder, totalToLock, currency) + LedgerVault-->>AgreementManager: receipt + AgreementManager->>AgreementManager: store agreement & emit AgreementCreated + AgreementManager-->>Holder: proof (agreementId) + + RightsPolicyManager->>AgreementSettler: settleAgreement(proof, holder) + AgreementSettler->>AgreementManager: getAgreement(proof) + AgreementSettler->>LedgerVault: claim(protocolTake, currency) + AgreementSettler->>Treasury: forward fees + AgreementSettler->>LedgerVault: release(counterparty amounts) + LedgerVault-->>AgreementSettler: settlement confirmation + AgreementSettler-->>RightsPolicyManager: attestationIds, agreement + AgreementSettler->>AgreementSettler: emit AgreementSettled +``` + +**Notes** +- `totalToLock = amount + penalization` enforcing honest participation; protocol take = fees + penalization. +- Treasury handles protocol fees while counterparties receive releases from `LedgerVault`. +- Settlement artifacts (attestation IDs, events) feed into rights verification and compliance analytics. + +### 9. Audit Checklist + +1. **AccessManager Configuration** + - Verify role assignments, target function mappings, pause controls. +2. **Governance FSM** + - Inspect `QuorumUpgradeable` state transitions for assets/policies. +3. **Policy & Rights Flow** + - Test authorization guard, duplicate policy registration, revocations. +4. **Financial Settlement** + - Validate fee calculations, penalties, ledger updates through settlement and quit flows. +5. **Economics Modules** + - Review fee schedule management in `Tollgate`, treasury distribution logic, and permissioning. +6. **Attestation Providers** + - Evaluate deployed `IAttestationProvider` contracts for data integrity and replay protection. +7. **Upgrade & Pause Controls** + - Confirm `_authorizeUpgrade` restrictions and governance oversight; ensure pausable functions behave as expected. + +--- + +### 10. Tooling & Development Environment + +| Category | Tools / Frameworks | Notes | +| --- | --- | --- | +| Smart Contract Development | Foundry (forge/anvil), Solidity ^0.8.26 | Deterministic builds, fuzzing, invariants. | +| Libraries | OpenZeppelin Upgradeable suite, custom Synapse core libraries (`FinancialOps`, `FeesOps`, `QuorumUpgradeable`). | UUPS proxies, access control, quorum FSMs. | +| Testing | Forge standard library (`forge-std`), fuzz/invariant tests under `test/`. | Tests cover unit, fuzz, and integration flows. | +| Deployment | CREATE3 factory scripts (`script/deployment/*.s.sol`), custom orchestrations. | Deterministic addresses via CREATE3 salts. | +| Security | Slither (config in `slither.config.json`), manual audits. | Recommended for static analysis and coverage checks. | +| Attestation Infra | Ethereum Attestation Service (EAS) (planned), `IAttestationProvider` adapters. | Pluggable provider for policy attestations. | + +### 11. Peripheral Implementations + +- Subscription policy (`SubscriptionPolicy`) built atop `PolicyBase`: https://github.com/Synaps3Protocol/protocol-periphery-v1/blob/main/contracts/policies/SubscriptionPolicy.sol +- EAS attestation provider adapter: https://github.com/Synaps3Protocol/protocol-periphery-v1/blob/main/contracts/attestation/Eas.sol + +### 12. Deployment Runbooks + +| Stage | Scripts (order) | Purpose | +| --- | --- | --- | +| Deployment | `deployment/04_Deploy_Economics_Tollgate` → … → `17_Deploy_RightsManager_PolicyManager` | Provision economics, finance, custody, assets, policies, rights modules via CREATE3. | +| Orchestration | `orchestration/01_Orchestrate_ProtocolHydration` → `03_Orchestrate_ProtocolRightsCustodian` | Hydrate protocol with roles, economic parameters, and custodial network. | +| Upgrade | `upgrades/01_Upgrade_Economics_Tollgate` → … → `17_Upgrade_Rights_RightsPolicyManager` | Apply UUPS upgrades in deterministic order. | + +**Pause / Unpause Runbook** +1. `SEC_ROLE` is the designated role to pause affected modules (using exposed `pause()` on `AccessControlledUpgradeable`). +2. Execute pause transactions on required modules (e.g., `RightsPolicyManager.pause()`, `AgreementManager.pause()`, `LedgerVault.pause()` as required). +3. Broadcast incident report; disable user-facing services. +4. Remediation: deploy fixes or configuration changes under audit. +5. Submit proposal to unpause; `SEC_ROLE` executes `unpause()` in reverse order once mitigation is confirmed. +6. Document event, update post-mortem, and notify stakeholders. + +*Run scripts with `make deploy script=` for canonical ordering.* + +### 13. Deployment Addresses (Amoy Testnet) + +| Contract | Address | +| --- | --- | +| AccessManager | `0x8120a8e0688be6b2c0bb469f871e5e7023ca85eb` | +| AssetReferendum | `0x4edf864dc5e7ef1a15b472954e994f4f95e4d1ab` | +| AssetRegistry | `0xb439928f5dd092e010c802228d1191e64431eebf` | +| AssetSafe | `0x4aeb687f491f91234ff6c25170db06fde505014c` | +| RightsPolicyAuthorizer | `0x64c03e378f29d7a39a9cf2c509c4332336e44d5b` | +| RightsPolicyManager | `0xac21c4a4ab26c295856365541dab1b4c8873d109` | +| PolicyAudit | `0xe9ff2342903c5c3975cdae572a937626cbf3d9ed` | +| AgreementManager | `0x7281685b064d6ffbf77df3e5442f65462e945b0e` | +| AgreementSettler | `0x20ee3ad9ed569832b451cf796190349a9d6d673e` | +| LedgerVault | `0x5855f2c385d526e93802123d5cb54465c4e3871c` | +| Treasury | `0x2bef3819db8181e8d86eb1b2fb3e5999b2ebb8d1` | +| Tollgate | `0xbae832ee0bd9c212212f7f0190cc3b8ca8586ed3` | +| RightAssetCustodian | `0xbd67e67756415576002f67856833f9636c24e199` | +| CustodianFactory | `0x2b03c944c50e373124d4f4fa117037215acf084c` | +| CustodianReferendum | `0x31f32d9066257805ccccbfe46cfc2455fddd902c` | +| DefaultCustodian | `0x5b903c9598409a6857056fc8a397f74716a5c71d` | +| MMC Token | `0x3c7deb6feaeb7a82bde580fb73d8d69c401b219e` | +| SubscriptionPolicy | `0x3393520c79e540c963afae6619c2b51e6fb04f61` | +| EAS Attestation Provider | `0xdb33bda43befada78d36cbc4362ac6f240084e7b` | + +**Attestation Provider (example)**: Ethereum Attestation Service (EAS) can serve as the concrete `IAttestationProvider` implementation. + +*Note*: `SubscriptionPolicy` and the EAS adapter operate in the peripheral/integration layer, interfacing with the coordination layer via `PolicyBase` APIs. + + +### 14. References & Notes + +- **Libraries & Standards**: OpenZeppelin Upgradeable suite, custom `FinancialOps`, `FeesOps`, `QuorumUpgradeable`, `ERC721StatefulUpgradeable`. +- **Future Standards (planned)**: ERC-1271 (custodian signatures), ERC-404 (fractionalization), ERC-2981 (royalties), ERC-4804 (on-chain URLs), SEP-001/002 (asset metadata), SEP-004 (license metadata), EAS attestation registry. +- **Event Catalog**: + - Assets: `RegisteredAsset`, `RevokedAsset`, `AssetEnabled`, `AssetDisabled`. + - Policies: `PolicySubmitted`, `PolicyApproved`, `PolicyRevoked`, `AttestedAgreement`, `AgreementCommitted`. + - Rights: `RightsGranted`, `RightsRevoked`, `Registered`. + - Finance/Economics: `AgreementCreated`, `AgreementSettled`, `FeesSet` (Tollgate), treasury distributions. + +--- + + +Prepared for Synapse Protocol auditors to evaluate module architecture, invariants, inter-module dependencies, and governance controls. For comprehensive coverage, integrate attestation provider audits and upcoming economics/custody extensions as they are deployed. From 0b4ab21931aa2a41e6fea32d73a020cc499f15dd Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Mon, 13 Oct 2025 15:44:21 -0600 Subject: [PATCH 25/33] docs: pre-audits review doc --- docs/SYNAPSE_AUDIT_DOC.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/SYNAPSE_AUDIT_DOC.md b/docs/SYNAPSE_AUDIT_DOC.md index f791965..b38e514 100644 --- a/docs/SYNAPSE_AUDIT_DOC.md +++ b/docs/SYNAPSE_AUDIT_DOC.md @@ -112,7 +112,6 @@ Synapse Protocol provides a deterministic coordination layer for digital asset r | Economics Distribution | `Tollgate` / `Treasury` → Finance & Governance | Tollgate manages fee schedules; Treasury receives protocol take after settlement. | Fee events in `Tollgate`; Treasury distributions (if implemented). | | Attestation Integration | `PolicyBase` → `IAttestationProvider` | Issues attestation IDs for parties; stored for `isActivePolicy`. | Future SEP integration noted. | | Upgrade Authorization | `AccessControlledUpgradeable` → `AccessManager` | `_authorizeUpgrade` restricted to admin. | UUPS proxy. | -| Standards & TODOs | Future compatibility (ERC-1271, ERC-404, ERC-2981, ERC-4804). | Documented as TODOs in contracts. | n/a | --- @@ -357,7 +356,7 @@ sequenceDiagram ### 14. References & Notes - **Libraries & Standards**: OpenZeppelin Upgradeable suite, custom `FinancialOps`, `FeesOps`, `QuorumUpgradeable`, `ERC721StatefulUpgradeable`. -- **Future Standards (planned)**: ERC-1271 (custodian signatures), ERC-404 (fractionalization), ERC-2981 (royalties), ERC-4804 (on-chain URLs), SEP-001/002 (asset metadata), SEP-004 (license metadata), EAS attestation registry. +- **Future Standards (planned)**: SEP-001/002 (asset metadata), SEP-004 (license metadata), EAS attestation registry. - **Event Catalog**: - Assets: `RegisteredAsset`, `RevokedAsset`, `AssetEnabled`, `AssetDisabled`. - Policies: `PolicySubmitted`, `PolicyApproved`, `PolicyRevoked`, `AttestedAgreement`, `AgreementCommitted`. From 4c2a6ec96ff11cc3fa5051e56c3f7bef22c8f163 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Mon, 13 Oct 2025 15:44:56 -0600 Subject: [PATCH 26/33] Update SYNAPSE_AUDIT_DOC.md --- docs/SYNAPSE_AUDIT_DOC.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/SYNAPSE_AUDIT_DOC.md b/docs/SYNAPSE_AUDIT_DOC.md index b38e514..3418373 100644 --- a/docs/SYNAPSE_AUDIT_DOC.md +++ b/docs/SYNAPSE_AUDIT_DOC.md @@ -8,9 +8,11 @@ ### 1. Overview Synapse Protocol provides a deterministic coordination layer for digital asset registration, licensing, and monetization. Creators define programmable access rules enforced on-chain, with all state transitions governed by role-based permissions and quorum-driven governance. This document summarizes architecture, modules, dependencies, and key audit checkpoints. +Captura desde 2025-10-13 15-37-56 --- + ### 2. Layered System Architecture | Layer | Purpose | Key Components | Notes | From 43aed7c031e07c2b3a8ee9e061ca45f93616a55a Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Mon, 13 Oct 2025 15:45:14 -0600 Subject: [PATCH 27/33] Update SYNAPSE_AUDIT_DOC.md --- docs/SYNAPSE_AUDIT_DOC.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SYNAPSE_AUDIT_DOC.md b/docs/SYNAPSE_AUDIT_DOC.md index 3418373..7c2f65d 100644 --- a/docs/SYNAPSE_AUDIT_DOC.md +++ b/docs/SYNAPSE_AUDIT_DOC.md @@ -8,7 +8,7 @@ ### 1. Overview Synapse Protocol provides a deterministic coordination layer for digital asset registration, licensing, and monetization. Creators define programmable access rules enforced on-chain, with all state transitions governed by role-based permissions and quorum-driven governance. This document summarizes architecture, modules, dependencies, and key audit checkpoints. -Captura desde 2025-10-13 15-37-56 +Captura desde 2025-10-13 11-59-01 --- From dd3de78732faea65b808185e8febf072ff0bca42 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Mon, 13 Oct 2025 15:45:32 -0600 Subject: [PATCH 28/33] Update SYNAPSE_AUDIT_DOC.md --- docs/SYNAPSE_AUDIT_DOC.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SYNAPSE_AUDIT_DOC.md b/docs/SYNAPSE_AUDIT_DOC.md index 7c2f65d..7929097 100644 --- a/docs/SYNAPSE_AUDIT_DOC.md +++ b/docs/SYNAPSE_AUDIT_DOC.md @@ -8,7 +8,7 @@ ### 1. Overview Synapse Protocol provides a deterministic coordination layer for digital asset registration, licensing, and monetization. Creators define programmable access rules enforced on-chain, with all state transitions governed by role-based permissions and quorum-driven governance. This document summarizes architecture, modules, dependencies, and key audit checkpoints. -Captura desde 2025-10-13 11-59-01 +Captura desde 2025-10-13 11-59-01 --- From d7231702075a2e24e4f815aa08a64d8ea7476384 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Mon, 13 Oct 2025 15:46:38 -0600 Subject: [PATCH 29/33] Update SYNAPSE_AUDIT_DOC.md --- docs/SYNAPSE_AUDIT_DOC.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/SYNAPSE_AUDIT_DOC.md b/docs/SYNAPSE_AUDIT_DOC.md index 7929097..99cd12f 100644 --- a/docs/SYNAPSE_AUDIT_DOC.md +++ b/docs/SYNAPSE_AUDIT_DOC.md @@ -8,6 +8,7 @@ ### 1. Overview Synapse Protocol provides a deterministic coordination layer for digital asset registration, licensing, and monetization. Creators define programmable access rules enforced on-chain, with all state transitions governed by role-based permissions and quorum-driven governance. This document summarizes architecture, modules, dependencies, and key audit checkpoints. + Captura desde 2025-10-13 11-59-01 --- From e1189f6f6d720034659f9da892670d0e49e9cd4b Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Mon, 13 Oct 2025 15:47:51 -0600 Subject: [PATCH 30/33] docs: pre-audits review doc --- docs/SYNAPSE_AUDIT_DOC.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SYNAPSE_AUDIT_DOC.md b/docs/SYNAPSE_AUDIT_DOC.md index 99cd12f..644e2da 100644 --- a/docs/SYNAPSE_AUDIT_DOC.md +++ b/docs/SYNAPSE_AUDIT_DOC.md @@ -19,7 +19,7 @@ Synapse Protocol provides a deterministic coordination layer for digital asset r | Layer | Purpose | Key Components | Notes | | --- | --- | --- | --- | | **Blockchain Layer** | Anchors protocol state on EVM networks; executes verifiable rights and settlement logic. | Deployed contracts for Assets, Rights, Policies, Finance, Economics, Governance, Access Control. | Deterministic calldata interactions enable auditability and integrations. | -| **Coordination Layer** | Core execution environment managing registries, policies, governance, and economics modules. | Asset registry, referendum, policy authorizer/manager, settlement engines, economics controllers (fees/tollgate, treasury). | Primary audit focus; ensures modules compose deterministically. | +| **Coordination Layer** | Core execution environment managing registries, policies, governance, financial ops and economics modules. | Asset registry, referendum, policy authorizer/manager, settlement engines, economics controllers (fees/tollgate, treasury). | Primary audit focus; ensures modules compose deterministically. | | **Integration Layer / Peripheral Layer** | Bridges external applications, attestation services, marketplaces. | Peripheral contracts such as `SubscriptionPolicy`, `IAttestationProvider` adapters (e.g., EAS), future SEP integrations. | Minimal in current scope; policies/attestors plug into the coordination layer via `PolicyBase`. | --- From 332c130da724852cdeb99e8e0028387188a4c6a7 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Tue, 14 Oct 2025 09:13:36 -0600 Subject: [PATCH 31/33] docs: pre-audits review doc --- docs/SYNAPSE_AUDIT_DOC.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SYNAPSE_AUDIT_DOC.md b/docs/SYNAPSE_AUDIT_DOC.md index 644e2da..99c7d33 100644 --- a/docs/SYNAPSE_AUDIT_DOC.md +++ b/docs/SYNAPSE_AUDIT_DOC.md @@ -1,4 +1,4 @@ -## Synapse Protocol – Auditor Documentation (v1) +## Synapse Protocol – Auditor Documentation (draft) > **Scope**: Assets, Rights & Policies, Finance (Escrow & Settlements), Economics, Governance, Access Control > **Out of Scope**: Custodian Network (DePIN), DWRR routing, replication/delivery infrastructure From 560d237f8bfacf83474afc74674e8fccf5bd6e84 Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Tue, 14 Oct 2025 10:03:49 -0600 Subject: [PATCH 32/33] docs: pre-audits review doc --- docs/SYNAPSE_AUDIT_DOC.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/SYNAPSE_AUDIT_DOC.md b/docs/SYNAPSE_AUDIT_DOC.md index 99c7d33..3b618e7 100644 --- a/docs/SYNAPSE_AUDIT_DOC.md +++ b/docs/SYNAPSE_AUDIT_DOC.md @@ -52,7 +52,7 @@ Synapse Protocol provides a deterministic coordination layer for digital asset r | Role | Description | Responsibilities | Assigned Entities | | --- | --- | --- | --- | -| `ADMIN_ROLE` | Core administrators controlling upgrades, pause/unpause, and role granting. | `_authorizeUpgrade`, `setTargetFunctionRole`, `setTargetClosed`, emergency actions. | Multisig / governance executor (per deployment). | +| `ADMIN_ROLE` | Core administrators controlling upgrades, and role granting. | `_authorizeUpgrade`, `setTargetFunctionRole`, `setTargetClosed`, emergency actions. | Multisig / governance executor (per deployment). | | `GOV_ROLE` | Community governance authority. | Approves council compositions, economics changes, policy & asset referendums. | DAO governance process. | | `CONTENT_COUNCIL_ROLE` | Oversees content curation and asset approvals. | Voting on `AssetReferendum` submissions. | Council multisig. | | `CUSTODY_COUNCIL_ROLE` | Manages custodial operations and related referendums. | Approving custodial contracts, emergency custodial actions. | Custody council. | @@ -61,7 +61,7 @@ Synapse Protocol provides a deterministic coordination layer for digital asset r | `TREASURER_ROLE` | Treasury management. | `Treasury` withdrawals/distributions, economic adjustments. | Treasury multisig. | | `VER_ROLE` | Verified creators/participants. | Bypass certain checks (e.g., asset verification) when designated. | Trusted creators or nodes. | -*Hierarchy*: `GOV_ROLE` (community governance) → councils (`CONTENT_COUNCIL_ROLE`, `CUSTODY_COUNCIL_ROLE`, `TREASURER_ROLE`) → ops roles (`OPS_ROLE`, `SEC_ROLE`) → contracts/users. `ADMIN_ROLE` executes governance-approved actions (upgrades, role assignments) within `AccessManager`. +*Hierarchy*: `GOV_ROLE` (community governance) → councils (`ADMIN_ROLE`,`CONTENT_COUNCIL_ROLE`, `CUSTODY_COUNCIL_ROLE`, `TREASURER_ROLE`) → ops roles (`OPS_ROLE`, `SEC_ROLE`) → contracts/users. `ADMIN_ROLE` executes governance-approved actions (upgrades, role assignments) within `AccessManager`. --- From 9a6d038c69accb51f058989e8136fc67184315ed Mon Sep 17 00:00:00 2001 From: Geolffrey Mena Date: Mon, 20 Oct 2025 17:50:55 -0600 Subject: [PATCH 33/33] tests: fix tests --- contracts/access/AccessManager.sol | 2 +- .../core/interfaces/base/ILockOperator.sol | 3 +- .../core/interfaces/base/ILockVerifiable.sol | 13 ++ .../interfaces/financial/ILedgerVault.sol | 14 +- contracts/core/libraries/FinancialOps.sol | 8 +- contracts/core/primitives/Constants.sol | 4 +- .../upgradeable/LockOperatorUpgradeable.sol | 15 +- contracts/economics/Tollgate.sol | 44 +--- contracts/financial/AgreementManager.sol | 9 +- contracts/financial/AgreementSettler.sol | 4 +- contracts/financial/LedgerVault.sol | 101 ++++++++- contracts/policies/PolicyAudit.sol | 6 +- contracts/rights/RightsAssetCustodian.sol | 3 +- foundry.toml | 2 + script/deployment/00_Deploy_Base.s.sol | 2 +- .../deployment/01_Deploy_Base_Create3.s.sol | 2 +- .../02_Deploy_Access_AccessManager.s.sol | 2 +- .../03_Deploy_Economics_Token.s.sol | 2 +- .../04_Deploy_Economics_Tollgate.s.sol | 2 +- .../05_Deploy_Economics_Treasury.s.sol | 2 +- .../06_Deploy_Financial_LedgerVault.s.sol | 2 +- ...07_Deploy_Financial_AgreementManager.s.sol | 2 +- ...08_Deploy_Financial_AgreementSettler.s.sol | 2 +- .../09_Deploy_Custody_CustodianFactory.s.sol | 2 +- ...0_Deploy_Custody_CustodianReferendum.s.sol | 2 +- .../11_Deploy_Assets_AssetReferendum.s.sol | 2 +- .../12_Deploy_Assets_AssetRegistry.s.sol | 2 +- .../13_Deploy_Assets_AssetSafe.s.sol | 2 +- .../14_Deploy_Policies_PolicyAudit.s.sol | 2 +- ..._Deploy_RightsManager_AssetCustodian.s.sol | 2 +- ...eploy_RightsManager_PolicyAuthorizer.s.sol | 2 +- ...7_Deploy_RightsManager_PolicyManager.s.sol | 2 +- ...eploy_RightsManager_PolicyAuthorizer.s.sol | 2 +- .../01_Orchestrate_ProtocolHydration.s.sol | 13 +- ...Orchestrate_ProtocolCustodianNetwork.s.sol | 8 +- ..._Orchestrate_ProtocolRightsCustodian.s.sol | 4 +- .../permissions/Permissions_LedgerVault.sol | 7 + test/BaseTest.t.sol | 67 ++++-- test/assets/AssetRegistry.t.sol | 4 +- test/economics/Tollgate.t.sol | 6 - test/finance/AgreementManager.t.sol | 4 +- test/finance/AgreementSettler.t.sol | 4 +- test/finance/LedgerVault.t.sol | 195 ++++++++---------- .../AccessControlledUpgradeable.t.sol | 145 ------------- test/primitives/LockOperatorUpgradeable.t.sol | 27 +-- test/rights/RightsPolicyManager.t.sol | 2 +- 46 files changed, 352 insertions(+), 400 deletions(-) create mode 100644 contracts/core/interfaces/base/ILockVerifiable.sol delete mode 100644 test/primitives/AccessControlledUpgradeable.t.sol diff --git a/contracts/access/AccessManager.sol b/contracts/access/AccessManager.sol index b8d85b2..fcd1a15 100644 --- a/contracts/access/AccessManager.sol +++ b/contracts/access/AccessManager.sol @@ -136,7 +136,7 @@ contract AccessManager is Initializable, UUPSUpgradeable, AccessManagerUpgradeab // Governance domain controls councils & treasury/community-facing roles: _setRoleAdmin(C.VER_ROLE, C.GOV_ROLE); - // _setRoleAdmin(C.ADMIN_ROLE, C.GOV_ROLE); + _setRoleAdmin(C.ADMIN_ROLE, C.GOV_ROLE); // locked role _setRoleAdmin(C.TREASURER_ROLE, C.GOV_ROLE); _setRoleAdmin(C.CUSTODY_COUNCIL_ROLE, C.GOV_ROLE); _setRoleAdmin(C.CONTENT_COUNCIL_ROLE, C.GOV_ROLE); diff --git a/contracts/core/interfaces/base/ILockOperator.sol b/contracts/core/interfaces/base/ILockOperator.sol index d85f4c2..b68800a 100644 --- a/contracts/core/interfaces/base/ILockOperator.sol +++ b/contracts/core/interfaces/base/ILockOperator.sol @@ -4,8 +4,9 @@ pragma solidity 0.8.26; import { ILockClaimer } from "@synaps3/core/interfaces/base/ILockClaimer.sol"; import { ILockReleaser } from "@synaps3/core/interfaces/base/ILockReleaser.sol"; import { ILockLocker } from "@synaps3/core/interfaces/base/ILockLocker.sol"; +import { ILockVerifiable } from "@synaps3/core/interfaces/base/ILockVerifiable.sol"; /// @title ILockOperator /// @notice Unified interface that composes locker, releaser, and claimer capabilities. /// @dev Adds a common read method to query the locked balance. -interface ILockOperator is ILockClaimer, ILockLocker, ILockReleaser {} +interface ILockOperator is ILockClaimer, ILockLocker, ILockReleaser, ILockVerifiable {} diff --git a/contracts/core/interfaces/base/ILockVerifiable.sol b/contracts/core/interfaces/base/ILockVerifiable.sol new file mode 100644 index 0000000..15b8f3f --- /dev/null +++ b/contracts/core/interfaces/base/ILockVerifiable.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: BUSL-1.1 +// NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html +pragma solidity 0.8.26; + +/// @title ILockVerifiable +/// @notice Exposes read-only access to locked balances. +interface ILockVerifiable { + /// @notice Returns the locked balance for an account and currency. + /// @param account The address whose locked funds are being queried. + /// @param currency The currency associated with the locked funds. + /// @return The amount of locked funds. + function getLockedBalance(address account, address currency) external view returns (uint256); +} diff --git a/contracts/core/interfaces/financial/ILedgerVault.sol b/contracts/core/interfaces/financial/ILedgerVault.sol index 6fcc459..3b61d39 100644 --- a/contracts/core/interfaces/financial/ILedgerVault.sol +++ b/contracts/core/interfaces/financial/ILedgerVault.sol @@ -9,4 +9,16 @@ import { ILockOperator } from "@synaps3/core/interfaces/base/ILockOperator.sol"; /// @title ILedgerVault /// @notice Interface for managing locked funds and their operations. /// @dev Extends IBalanceOperator for managing user balances in a vault-like system. -interface ILedgerVault is IBalanceOperator, IAllowanceOperator, ILockOperator {} +interface ILedgerVault is IBalanceOperator, IAllowanceOperator, ILockOperator { + /// @notice Allows a currency to be used within the ledger operations. + /// @param currency The address of the currency to allow. Use address(0) for the native coin. + function allowCurrency(address currency) external; + + /// @notice Blocks a currency from being used within the ledger operations. + /// @param currency The address of the currency to block. Use address(0) for the native coin. + function blockCurrency(address currency) external; + + /// @notice Returns whether a currency is approved for ledger operations. + /// @param currency The address of the currency to verify. + function isCurrencyAllowed(address currency) external view returns (bool); +} diff --git a/contracts/core/libraries/FinancialOps.sol b/contracts/core/libraries/FinancialOps.sol index f249c5e..cb0ce3a 100644 --- a/contracts/core/libraries/FinancialOps.sol +++ b/contracts/core/libraries/FinancialOps.sol @@ -62,11 +62,17 @@ library FinancialOps { revert FailDuringDeposit("Amount exceeds allowance."); } + // Reconcile balances to block fee-on-transfer tokens that would deliver less than the requested amount. // disable slitter use 'arbitrary transfer form' since the use of `safeDeposit` is handled in a safe manner. // eg. msg.sender.safeDeposit(total, currency); <- Use msg.sender as from in transferFrom. // slither-disable-next-line arbitrary-send-erc20 + uint256 balanceBefore = IERC20(token).balanceOf(address(this)); IERC20(token).safeTransferFrom(from, address(this), amount); - return amount; + uint256 balanceAfter = IERC20(token).balanceOf(address(this)); + + uint256 received = balanceAfter - balanceBefore; + if (received != amount) revert FailDuringDeposit("Token not supported."); + return received; } /// @notice Increases the allowance of a given `spender` for a specified ERC20 `token`. diff --git a/contracts/core/primitives/Constants.sol b/contracts/core/primitives/Constants.sol index 8540b05..90f41ee 100644 --- a/contracts/core/primitives/Constants.sol +++ b/contracts/core/primitives/Constants.sol @@ -22,8 +22,8 @@ library C { /// @dev Encoded as `uint256` value `1`. uint256 internal constant ASSET_CRITERIA = 1; - uint64 internal constant ADMIN_ROLE = 0; // alias type(uint64).min AccessManager - uint64 internal constant GOV_ROLE = 1; // governance role + uint64 internal constant GOV_ROLE = 0; // alias type(uint64).min AccessManager + uint64 internal constant ADMIN_ROLE = 1; // admin role uint64 internal constant OPS_ROLE = 2; // operations roles uint64 internal constant VER_ROLE = 3; // account verified role uint64 internal constant SEC_ROLE = 4; // protocol security council diff --git a/contracts/core/primitives/upgradeable/LockOperatorUpgradeable.sol b/contracts/core/primitives/upgradeable/LockOperatorUpgradeable.sol index 830da9f..50ff807 100644 --- a/contracts/core/primitives/upgradeable/LockOperatorUpgradeable.sol +++ b/contracts/core/primitives/upgradeable/LockOperatorUpgradeable.sol @@ -34,6 +34,15 @@ abstract contract LockOperatorUpgradeable is Initializable, LedgerUpgradeable, I /// slither-disable-next-line naming-convention function __LockOperator_init_unchained() internal onlyInitializing {} + /// @notice Retrieves the locked balance of an account for a specific currency. + /// @dev Returns the value stored in the `_locked` mapping for the given `account` and `currency`. + /// @param account The address of the account whose locked balance is being queried. + /// @param currency The address of the currency to check the locked balance for. + /// @return The locked balance of the specified account for the given currency. + function getLockedBalance(address account, address currency) external view returns (uint256) { + return _getLockedBalance(account, currency); + } + /// @notice Locks a specific amount of funds for a given account. /// @dev The funds are immobilized and cannot be withdrawn or transferred until released. /// Only operator role can handle this methods. @@ -62,7 +71,7 @@ abstract contract LockOperatorUpgradeable is Initializable, LedgerUpgradeable, I uint256 amount, address currency ) internal onlyValidOperation(account, amount) returns (uint256) { - if (_getLockedAmount(account, currency) < amount) revert NoFundsToRelease(); + if (_getLockedBalance(account, currency) < amount) revert NoFundsToRelease(); _subLockedAmount(account, amount, currency); _sumLedgerEntry(account, amount, currency); emit FundsReleased(msg.sender, account, amount, currency); @@ -80,7 +89,7 @@ abstract contract LockOperatorUpgradeable is Initializable, LedgerUpgradeable, I uint256 amount, address currency ) internal onlyValidOperation(account, amount) returns (uint256) { - if (_getLockedAmount(account, currency) < amount) revert NoFundsToClaim(); + if (_getLockedBalance(account, currency) < amount) revert NoFundsToClaim(); _subLockedAmount(account, amount, currency); // _sumLedgerEntry(msg.sender, amount, currency); emit FundsClaimed(msg.sender, account, amount, currency); @@ -112,7 +121,7 @@ abstract contract LockOperatorUpgradeable is Initializable, LedgerUpgradeable, I /// @param account The address of the account whose locked balance is being queried. /// @param currency The address of the currency to check the locked balance for. /// @return The locked balance of the specified account for the given currency. - function _getLockedAmount(address account, address currency) private view returns (uint256) { + function _getLockedBalance(address account, address currency) internal view returns (uint256) { LockOperatorStorage storage $ = _getLockOperatorStorage(); return $._locked[account][currency]; } diff --git a/contracts/economics/Tollgate.sol b/contracts/economics/Tollgate.sol index 6aa6387..57d7f90 100644 --- a/contracts/economics/Tollgate.sol +++ b/contracts/economics/Tollgate.sol @@ -24,10 +24,10 @@ contract Tollgate is Initializable, UUPSUpgradeable, AccessControlledUpgradeable /// @dev Tracks registered currencies for specific targets. /// Uses EnumerableSet for efficient storage and querying of currency addresses. mapping(address => EnumerableSet.AddressSet) private _registeredCurrencies; - /// @dev Stores fees associated with specific target and currencies.. - mapping(bytes32 => uint256) private _currencyFees; - /// @dev Stores the target supported schema. - mapping(address => T.Scheme) private _targetScheme; + /// @dev Stores fees associated with specific target and currencies. + mapping(address => mapping(address => uint256)) private _currencyFees; + /// @dev Stores the target supported scheme per currency. + mapping(address => mapping(address => T.Scheme)) private _targetScheme; /// @notice Emitted when fees are set or updated. /// @param target The address or context where the fee applies. @@ -120,14 +120,8 @@ contract Tollgate is Initializable, UUPSUpgradeable, AccessControlledUpgradeable /// @param currency The address of the currency. /// @return The fee value. function getFees(address target, address currency) external view returns (uint256, T.Scheme) { - // if scheme is supported return the fee and scheme - if (!_isSchemeSupported(target, currency)) { - revert UnsupportedCurrency(target, currency); - } - - T.Scheme scheme = _targetScheme[target]; - bytes32 composedKey = _computeComposedKey(target, currency, scheme); - uint256 fee = _currencyFees[composedKey]; + T.Scheme scheme = _targetScheme[target][currency]; + uint256 fee = _currencyFees[target][currency]; return (fee, scheme); } @@ -142,18 +136,10 @@ contract Tollgate is Initializable, UUPSUpgradeable, AccessControlledUpgradeable uint256 fee, address currency ) external onlySupportedScheme(scheme, target) onlyValidFeeRepresentation(scheme, fee) restricted { - // Compute a unique composed key based on the target, currency, and scheme. - // The composed key uniquely identifies a deterministic combination of these parameters - // in a flat storage mapping. This avoids nested mappings, improving gas efficiency - // and simplifying data access through deterministic association. - // Example: If the target is the policy manager contract, the currency is MMC (ERC20 token), - // and the scheme is NOMINAL, setting a fee of 10% means: - // "In the policy manager contract, for MMC, using a nominal scheme, the fee is 10%." + // Each (target, currency) pair maintains its own scheme and fee entry. if (target == address(0)) revert InvalidTargetScheme(target); - bytes32 composedKey = _computeComposedKey(target, currency, scheme); - - _targetScheme[target] = scheme; // eg: rights manager => FLAT - _currencyFees[composedKey] = fee; // target + currency + scheme = fee + _targetScheme[target][currency] = scheme; // eg: rights manager => FLAT per currency + _currencyFees[target][currency] = fee; // store fee per target/currency _registeredCurrencies[target].add(currency); emit FeesSet(target, currency, scheme, fee); } @@ -167,17 +153,7 @@ contract Tollgate is Initializable, UUPSUpgradeable, AccessControlledUpgradeable /// @param currency The address of the currency to verify. /// @return `true` if the currency is supported, otherwise `false`. function _isSchemeSupported(address target, address currency) private view returns (bool) { - T.Scheme scheme = _targetScheme[target]; - bytes32 composedKey = _computeComposedKey(target, currency, scheme); - return _registeredCurrencies[target].contains(currency) && _currencyFees[composedKey] > 0; + return _registeredCurrencies[target].contains(currency); } - /// @notice Computes a unique key for a currency and scheme combination. - /// @param target The target context. - /// @param currency The currency associated with the fee. - /// @param scheme The fee scheme. - /// @return The computed key as a `bytes32` hash. - function _computeComposedKey(address target, address currency, T.Scheme scheme) private pure returns (bytes32) { - return keccak256(abi.encodePacked(target, currency, scheme)); - } } diff --git a/contracts/financial/AgreementManager.sol b/contracts/financial/AgreementManager.sol index 5b4f563..5fe5c6c 100644 --- a/contracts/financial/AgreementManager.sol +++ b/contracts/financial/AgreementManager.sol @@ -38,6 +38,9 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg /// @notice Maximum allowed number of parties per agreement. /// @dev Can be updated by admin to adapt system limits. uint256 private _maxParties; + /// @notice The incremental number of proofs generated + /// @dev After each proof nonce increments. + uint256 private _proofNonce; /// @dev Holds a bounded key expressing the agreement between the parts. mapping(uint256 => T.Agreement) private _agreementsByProof; @@ -186,7 +189,8 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg /// @dev Generates a unique proof for an agreement using keccak256 hashing. function _createAndStoreProof(T.Agreement memory agreement) private returns (uint256) { // yes, we can encode full struct as abi.encode with extra overhead.. - bytes memory rawProof = abi.encode(agreement, block.number, address(this)); + uint256 nonce = _proofNonce++; // each proof MUST be unique + bytes memory rawProof = abi.encode(agreement, blockhash(block.number - 1), address(this), nonce); uint256 proof = uint256(keccak256(rawProof)); _agreementsByProof[proof] = agreement; return proof; @@ -226,11 +230,12 @@ contract AgreementManager is Initializable, UUPSUpgradeable, AccessControlledUpg /// @param currency The address of the currency for which the fee is being calculated. /// @return The calculated fee amount based on the applicable fee scheme. function _calcFees(uint256 total, address target, address currency) private view returns (uint256) { - // !IMPORTANT if fees manager does not support the currency or the target, will revert.. (uint256 fees, T.Scheme scheme) = TOLLGATE.getFees(target, currency); + if (scheme == T.Scheme.BPS) return total.perOf(fees); // bps calc if (scheme == T.Scheme.NOMINAL) return total.perOf(fees.calcBps()); // nominal to bps if (total < fees) revert FlatFeeExceedsTotal(total, fees); // if flat fee + return fees; // ok flat fee is safe } } diff --git a/contracts/financial/AgreementSettler.sol b/contracts/financial/AgreementSettler.sol index cd030b3..26d4360 100644 --- a/contracts/financial/AgreementSettler.sol +++ b/contracts/financial/AgreementSettler.sol @@ -167,7 +167,7 @@ contract AgreementSettler is _setProofAsSettled(proof); // slither-disable-start unused-return - LEDGER_VAULT.claim(initiator, protocolTake, currency); + if (protocolTake > 0) LEDGER_VAULT.claim(initiator, protocolTake, currency); // part of the agreement locked amount is released to the account if (available > 0) LEDGER_VAULT.release(initiator, available, currency); // slither-disable-end unused-return @@ -202,6 +202,7 @@ contract AgreementSettler is uint256 proof, address counterparty ) public onlyValidAgreement(proof) /**hookExec(counterParty) */ returns (T.Agreement memory) { + // Arbiter contracts encapsulate distribution logic, so the counterparty can be any address the arbiter authorizes. // retrieve the agreement to storage to inactivate it and return it T.Agreement memory agreement = AGREEMENT_MANAGER.getAgreement(proof); if (agreement.arbiter != msg.sender) revert UnauthorizedEscrowAgent(); @@ -219,6 +220,7 @@ contract AgreementSettler is // TODO: Implement a time window to enforce the validity period for agreement settlement. // Once the window expires, the agreement should be marked as invalid or revert, // then quit is only way to close the agreement. + _setProofAsSettled(proof); // locked may include penalization diff --git a/contracts/financial/LedgerVault.sol b/contracts/financial/LedgerVault.sol index 045b4d4..83d805e 100644 --- a/contracts/financial/LedgerVault.sol +++ b/contracts/financial/LedgerVault.sol @@ -27,6 +27,25 @@ contract LedgerVault is LockOperatorUpgradeable, ILedgerVault { + /// @dev Tracks which currencies are approved for ledger operations. + mapping(address => bool) private _approvedCurrencies; + + /// @notice Emitted when a currency approval state changes. + /// @param currency The address of the currency whose approval status changed. + /// @param allowed The new approval status. + /// @param admin The admin that triggered the change. + event CurrencyApprovalUpdated(address indexed currency, bool allowed, address indexed admin); + + /// @notice Error thrown when attempting to use an unapproved currency. + /// @param currency The currency that is not approved. + error CurrencyNotAllowed(address currency); + + /// @dev Ensures that the provided currency has been approved for ledger operations. + modifier onlyAllowedCurrency(address currency) { + if (!_isCurrencyAllowed(currency)) revert CurrencyNotAllowed(currency); + _; + } + /// @custom:oz-upgrades-unsafe-allow constructor constructor() { /// https://forum.openzeppelin.com/t/uupsupgradeable-vulnerability-post-mortem/15680 @@ -55,7 +74,13 @@ contract LedgerVault is address account, uint256 amount, address currency - ) external restricted whenNotPaused onlyValidOperation(account, amount) returns (uint256) { + ) external + restricted + whenNotPaused + onlyValidOperation(account, amount) + onlyAllowedCurrency(currency) + returns (uint256) + { return _lock(account, amount, currency); } @@ -67,7 +92,13 @@ contract LedgerVault is address account, uint256 amount, address currency - ) external restricted whenNotPaused onlyValidOperation(account, amount) returns (uint256) { + ) external + restricted + whenNotPaused + onlyValidOperation(account, amount) + onlyAllowedCurrency(currency) + returns (uint256) + { return _release(account, amount, currency); } @@ -81,7 +112,13 @@ contract LedgerVault is address account, uint256 amount, address currency - ) external restricted whenNotPaused onlyValidOperation(account, amount) returns (uint256) { + ) external + restricted + whenNotPaused + onlyValidOperation(account, amount) + onlyAllowedCurrency(currency) + returns (uint256) + { return _claim(account, amount, currency); } @@ -89,7 +126,11 @@ contract LedgerVault is /// @param to The address of the recipient for whom the funds are being approved. /// @param amount The amount of funds to approve. /// @param currency The address of the ERC20 token to approve. Use `address(0)` for native tokens. - function approve(address to, uint256 amount, address currency) external whenNotPaused returns (uint256) { + function approve( + address to, + uint256 amount, + address currency + ) external whenNotPaused onlyAllowedCurrency(currency) returns (uint256) { return _approve(to, amount, currency); } @@ -97,7 +138,11 @@ contract LedgerVault is /// @param to The address of the recipient whose approval is being revoked. /// @param currency The address of the ERC20 token associated with the approval. Use `address(0)` for native tokens. /// @return The amount of funds that were revoked from the approval. - function revoke(address to, uint256 amount, address currency) external whenNotPaused returns (uint256) { + function revoke( + address to, + uint256 amount, + address currency + ) external whenNotPaused onlyAllowedCurrency(currency) returns (uint256) { return _revoke(to, amount, currency); } @@ -105,7 +150,11 @@ contract LedgerVault is /// @param from The address of the account from which the approved funds are being collected. /// @param amount The amount of funds to collect. /// @param currency The address of the ERC20 token to collect. Use `address(0)` for native tokens. - function collect(address from, uint256 amount, address currency) external whenNotPaused returns (uint256) { + function collect( + address from, + uint256 amount, + address currency + ) external whenNotPaused onlyAllowedCurrency(currency) returns (uint256) { return _collect(from, amount, currency); } @@ -117,7 +166,7 @@ contract LedgerVault is address recipient, uint256 amount, address currency - ) external payable whenNotPaused returns (uint256) { + ) external payable whenNotPaused onlyAllowedCurrency(currency) returns (uint256) { return _deposit(recipient, amount, currency); } @@ -129,7 +178,7 @@ contract LedgerVault is address recipient, uint256 amount, address currency - ) external whenNotPaused nonReentrant returns (uint256) { + ) external whenNotPaused onlyAllowedCurrency(currency) nonReentrant returns (uint256) { return _withdraw(recipient, amount, currency); } @@ -137,12 +186,46 @@ contract LedgerVault is /// @param recipient The address of the account to credit with the transfer. /// @param amount The amount of tokens to transfer. /// @param currency The address of the currency to transfer. Use `address(0)` for the native coin. - function transfer(address recipient, uint256 amount, address currency) external whenNotPaused returns (uint256) { + function transfer( + address recipient, + uint256 amount, + address currency + ) external whenNotPaused onlyAllowedCurrency(currency) returns (uint256) { return _transfer(recipient, amount, currency); } + /// @notice Allows a currency to be used within the ledger operations. + /// @param currency The address of the currency to allow. Use address(0) for the native coin. + function allowCurrency(address currency) external restricted { + _setCurrencyState(currency, true); + } + + /// @notice Blocks a currency from being used within the ledger operations. + /// @param currency The address of the currency to block. Use address(0) for the native coin. + function blockCurrency(address currency) external restricted { + _setCurrencyState(currency, false); + } + + /// @notice Returns whether a currency is approved for ledger operations. + /// @param currency The address of the currency to verify. + function isCurrencyAllowed(address currency) external view returns (bool) { + return _isCurrencyAllowed(currency); + } + /// @notice Function that should revert when msg.sender is not authorized to upgrade the contract. /// @param newImplementation The address of the new implementation contract. /// @dev See https://docs.openzeppelin.com/contracts/4.x/api/proxy#UUPSUpgradeable-_authorizeUpgrade-address- function _authorizeUpgrade(address newImplementation) internal override onlyAdmin {} + + /// @dev Registers the approval status for a currency and emits an event if the value changes. + function _setCurrencyState(address currency, bool allowed) private { + if (_approvedCurrencies[currency] == allowed) return; + _approvedCurrencies[currency] = allowed; + emit CurrencyApprovalUpdated(currency, allowed, msg.sender); + } + + /// @dev Returns true when the currency is currently approved, false otherwise. + function _isCurrencyAllowed(address currency) private view returns (bool) { + return _approvedCurrencies[currency]; + } } diff --git a/contracts/policies/PolicyAudit.sol b/contracts/policies/PolicyAudit.sol index d92120d..a528bd0 100644 --- a/contracts/policies/PolicyAudit.sol +++ b/contracts/policies/PolicyAudit.sol @@ -67,7 +67,7 @@ contract PolicyAudit is Initializable, UUPSUpgradeable, AccessControlledUpgradea /// @notice Submits an audit request for the given policy. /// This registers the policy for audit within the system. /// @param policy The address of the policy to be submitted for auditing. - function submit(address policy) external onlyValidPolicy(policy) { + function submit(address policy) external whenNotPaused onlyValidPolicy(policy) { _register(uint160(policy)); emit PolicySubmitted(policy, msg.sender); } @@ -75,7 +75,7 @@ contract PolicyAudit is Initializable, UUPSUpgradeable, AccessControlledUpgradea /// @notice Approves the audit of a given policy by a specified auditor. /// @param policy The address of the policy to be audited. /// @dev This function emits the PolicyApproved event upon successful audit approval. - function approve(address policy) external onlyAdmin { + function approve(address policy) external whenNotPaused onlyAdmin { _approve(uint160(policy)); emit PolicyApproved(policy, msg.sender); } @@ -83,7 +83,7 @@ contract PolicyAudit is Initializable, UUPSUpgradeable, AccessControlledUpgradea /// @notice Revokes the audit of a given policy by a specified auditor. /// @param policy The address of the policy whose audit is to be revoked. /// @dev This function emits the PolicyRevoked event upon successful audit revocation. - function reject(address policy) external onlyAdmin { + function reject(address policy) external whenNotPaused onlyAdmin { _revoke(uint160(policy)); emit PolicyRevoked(policy, msg.sender); } diff --git a/contracts/rights/RightsAssetCustodian.sol b/contracts/rights/RightsAssetCustodian.sol index 637ab6b..debc743 100644 --- a/contracts/rights/RightsAssetCustodian.sol +++ b/contracts/rights/RightsAssetCustodian.sol @@ -196,6 +196,7 @@ contract RightsAssetCustodian is Initializable, UUPSUpgradeable, AccessControlle /// @notice Selects a custodian for the given holder using weighted randomness. /// @dev Balancing is based on priority, demand, and economic backing (balance). /// Not cryptographically secure randomness; avoid for critical paths. + /// Intended purely as an off-chain hint for frontends or operators, and must not gate on-chain logic. /// @param holder Address of the rights holder. /// @param currency Token used for economic weight evaluation. /// @return chosen The address of the selected custodian. @@ -375,7 +376,7 @@ contract RightsAssetCustodian is Initializable, UUPSUpgradeable, AccessControlle /// @dev Calculates a pseudo-random value based on the block hash, holder address, currency address, /// and a total weight. The randomness is derived using keccak256 hashing and modulo operation. - /// Note: This method is not suitable for secure randomness as it relies on blockhash, which can be influenced. + /// IMPORTANT: This method is not suitable for secure randomness as it relies on blockhash, which can be influenced. /// /// @param holder The address of the holder involved in the calculation. /// @param currency The address of the currency involved in the calculation. diff --git a/foundry.toml b/foundry.toml index 4f8a2af..80ce2d3 100644 --- a/foundry.toml +++ b/foundry.toml @@ -28,9 +28,11 @@ verbosity = 4 [rpc_endpoints] polygon-amoy = "${AMOY_RPC_URL}" +arbitrum-sepolia = "${ARBITRUM_RPC_URL}" [etherscan] polygon-amoy = { key = "${AMOY_API_KEY}", url = "https://www.oklink.com/api/explorer/v1/contract/verify/async/api/polygonAmoy" } +arbitrum-sepolia = { key = "${ETHERSCAN_API_KEY}", url = "https://api.arbiscan.io/api" } [invariant] runs = 1000 diff --git a/script/deployment/00_Deploy_Base.s.sol b/script/deployment/00_Deploy_Base.s.sol index 20f746a..3343e38 100644 --- a/script/deployment/00_Deploy_Base.s.sol +++ b/script/deployment/00_Deploy_Base.s.sol @@ -15,7 +15,7 @@ abstract contract DeployBase is Script { return vm.envAddress("CREATE3_FACTORY"); } - function getAdminPK() public view returns (uint256) { + function getDeployerPK() public view returns (uint256) { return vm.envUint("PRIVATE_KEY"); } diff --git a/script/deployment/01_Deploy_Base_Create3.s.sol b/script/deployment/01_Deploy_Base_Create3.s.sol index f5abc9f..d05156d 100644 --- a/script/deployment/01_Deploy_Base_Create3.s.sol +++ b/script/deployment/01_Deploy_Base_Create3.s.sol @@ -7,7 +7,7 @@ import { CREATE3Factory } from "script/create3/CREATE3Factory.sol"; contract DeployCreate3Factory is DeployBase { function run() external returns (address factory) { - vm.startBroadcast(getAdminPK()); + vm.startBroadcast(getDeployerPK()); bytes32 salt = getSalt("SALT_CREATE3_FACTORY"); bytes memory bytecode = type(CREATE3Factory).creationCode; diff --git a/script/deployment/02_Deploy_Access_AccessManager.s.sol b/script/deployment/02_Deploy_Access_AccessManager.s.sol index d7b2a8a..27b9c22 100644 --- a/script/deployment/02_Deploy_Access_AccessManager.s.sol +++ b/script/deployment/02_Deploy_Access_AccessManager.s.sol @@ -7,7 +7,7 @@ import { AccessManager } from "contracts/access/AccessManager.sol"; contract DeployAccessManager is DeployBase { function run() external returns (address) { - uint256 privateKey = getAdminPK(); + uint256 privateKey = getDeployerPK(); address publicKey = vm.addr(privateKey); vm.startBroadcast(privateKey); diff --git a/script/deployment/03_Deploy_Economics_Token.s.sol b/script/deployment/03_Deploy_Economics_Token.s.sol index 90e20d4..ae9cad0 100644 --- a/script/deployment/03_Deploy_Economics_Token.s.sol +++ b/script/deployment/03_Deploy_Economics_Token.s.sol @@ -6,7 +6,7 @@ import { MMC } from "contracts/economics/MMC.sol"; contract DeployToken is DeployBase { function run() external returns (address) { - uint256 privateKey = getAdminPK(); + uint256 privateKey = getDeployerPK(); address publicKey = vm.addr(privateKey); vm.startBroadcast(privateKey); diff --git a/script/deployment/04_Deploy_Economics_Tollgate.s.sol b/script/deployment/04_Deploy_Economics_Tollgate.s.sol index a2ff4b8..d8b3d62 100644 --- a/script/deployment/04_Deploy_Economics_Tollgate.s.sol +++ b/script/deployment/04_Deploy_Economics_Tollgate.s.sol @@ -8,7 +8,7 @@ import { C } from "contracts/core/primitives/Constants.sol"; contract DeployTollgate is DeployBase { function run() external returns (address) { - vm.startBroadcast(getAdminPK()); + vm.startBroadcast(getDeployerPK()); address impl = address(new Tollgate()); address accessManager = computeCreate3Address("SALT_ACCESS_MANAGER"); bytes memory init = abi.encodeCall(Tollgate.initialize, (accessManager)); diff --git a/script/deployment/05_Deploy_Economics_Treasury.s.sol b/script/deployment/05_Deploy_Economics_Treasury.s.sol index 9f4311a..846d8c2 100644 --- a/script/deployment/05_Deploy_Economics_Treasury.s.sol +++ b/script/deployment/05_Deploy_Economics_Treasury.s.sol @@ -8,7 +8,7 @@ import { C } from "contracts/core/primitives/Constants.sol"; contract DeployTreasury is DeployBase { function run() external returns (address) { - vm.startBroadcast(getAdminPK()); + vm.startBroadcast(getDeployerPK()); address impl = address(new Treasury()); address accessManager = computeCreate3Address("SALT_ACCESS_MANAGER"); bytes memory init = abi.encodeCall(Treasury.initialize, (accessManager)); diff --git a/script/deployment/06_Deploy_Financial_LedgerVault.s.sol b/script/deployment/06_Deploy_Financial_LedgerVault.s.sol index f6bcc8c..772f6b9 100644 --- a/script/deployment/06_Deploy_Financial_LedgerVault.s.sol +++ b/script/deployment/06_Deploy_Financial_LedgerVault.s.sol @@ -7,7 +7,7 @@ import { LedgerVault } from "contracts/financial/LedgerVault.sol"; contract DeployLedgerVault is DeployBase { function run() external returns (address) { - vm.startBroadcast(getAdminPK()); + vm.startBroadcast(getDeployerPK()); address accessManager = computeCreate3Address("SALT_ACCESS_MANAGER"); address impl = address(new LedgerVault()); bytes memory init = abi.encodeCall(LedgerVault.initialize, (accessManager)); diff --git a/script/deployment/07_Deploy_Financial_AgreementManager.s.sol b/script/deployment/07_Deploy_Financial_AgreementManager.s.sol index 8788758..f1acdaf 100644 --- a/script/deployment/07_Deploy_Financial_AgreementManager.s.sol +++ b/script/deployment/07_Deploy_Financial_AgreementManager.s.sol @@ -6,7 +6,7 @@ import { AgreementManager } from "contracts/financial/AgreementManager.sol"; contract DeployAgreementManager is DeployBase { function run() external returns (address) { - vm.startBroadcast(getAdminPK()); + vm.startBroadcast(getDeployerPK()); address tollgate = computeCreate3Address("SALT_TOLLGATE"); address vault = computeCreate3Address("SALT_LEDGER_VAULT"); address accessManager = computeCreate3Address("SALT_ACCESS_MANAGER"); diff --git a/script/deployment/08_Deploy_Financial_AgreementSettler.s.sol b/script/deployment/08_Deploy_Financial_AgreementSettler.s.sol index f94a149..09e3459 100644 --- a/script/deployment/08_Deploy_Financial_AgreementSettler.s.sol +++ b/script/deployment/08_Deploy_Financial_AgreementSettler.s.sol @@ -7,7 +7,7 @@ import { AgreementSettler } from "contracts/financial/AgreementSettler.sol"; contract DeployAgreementSettler is DeployBase { function run() external returns (address) { - vm.startBroadcast(getAdminPK()); + vm.startBroadcast(getDeployerPK()); address treasury = computeCreate3Address("SALT_TREASURY"); address vault = computeCreate3Address("SALT_LEDGER_VAULT"); address agreementManager = computeCreate3Address("SALT_AGREEMENT_MANAGER"); diff --git a/script/deployment/09_Deploy_Custody_CustodianFactory.s.sol b/script/deployment/09_Deploy_Custody_CustodianFactory.s.sol index 7998ba8..9293afe 100644 --- a/script/deployment/09_Deploy_Custody_CustodianFactory.s.sol +++ b/script/deployment/09_Deploy_Custody_CustodianFactory.s.sol @@ -8,7 +8,7 @@ import { CustodianFactory } from "contracts/custody/CustodianFactory.sol"; contract DeployCustodianFactory is DeployBase { function run() public returns (address) { - vm.startBroadcast(getAdminPK()); + vm.startBroadcast(getDeployerPK()); CustodianImpl imp = new CustodianImpl(); // implementation bytes memory creationCode = type(CustodianFactory).creationCode; bytes memory initCode = abi.encodePacked(creationCode, abi.encode(address(imp))); diff --git a/script/deployment/10_Deploy_Custody_CustodianReferendum.s.sol b/script/deployment/10_Deploy_Custody_CustodianReferendum.s.sol index d607a4f..b1d8d6d 100644 --- a/script/deployment/10_Deploy_Custody_CustodianReferendum.s.sol +++ b/script/deployment/10_Deploy_Custody_CustodianReferendum.s.sol @@ -7,7 +7,7 @@ import { C } from "contracts/core/primitives/Constants.sol"; contract DeployCustodianReferendum is DeployBase { function run() external returns (address) { - vm.startBroadcast(getAdminPK()); + vm.startBroadcast(getDeployerPK()); address custodianFactory = computeCreate3Address("SALT_CUSTODIAN_FACTORY"); address accessManager = computeCreate3Address("SALT_ACCESS_MANAGER"); address impl = address(new CustodianReferendum(custodianFactory)); diff --git a/script/deployment/11_Deploy_Assets_AssetReferendum.s.sol b/script/deployment/11_Deploy_Assets_AssetReferendum.s.sol index 70ca6bc..81304c7 100644 --- a/script/deployment/11_Deploy_Assets_AssetReferendum.s.sol +++ b/script/deployment/11_Deploy_Assets_AssetReferendum.s.sol @@ -6,7 +6,7 @@ import { AssetReferendum } from "contracts/assets/AssetReferendum.sol"; contract DeployAssetReferendum is DeployBase { function run() external returns (address) { - vm.startBroadcast(getAdminPK()); + vm.startBroadcast(getDeployerPK()); address impl = address(new AssetReferendum()); address accessManager = computeCreate3Address("SALT_ACCESS_MANAGER"); bytes memory init = abi.encodeCall(AssetReferendum.initialize, (accessManager)); diff --git a/script/deployment/12_Deploy_Assets_AssetRegistry.s.sol b/script/deployment/12_Deploy_Assets_AssetRegistry.s.sol index e3e8bd0..11e2579 100644 --- a/script/deployment/12_Deploy_Assets_AssetRegistry.s.sol +++ b/script/deployment/12_Deploy_Assets_AssetRegistry.s.sol @@ -7,7 +7,7 @@ import { AssetRegistry } from "contracts/assets/AssetRegistry.sol"; contract DeployAssetRegistry is DeployBase { function run() external returns (address) { - vm.startBroadcast(getAdminPK()); + vm.startBroadcast(getDeployerPK()); address accessManager = computeCreate3Address("SALT_ACCESS_MANAGER"); address assetReferendum = computeCreate3Address("SALT_ASSET_REFERENDUM"); address impl = address(new AssetRegistry(assetReferendum)); diff --git a/script/deployment/13_Deploy_Assets_AssetSafe.s.sol b/script/deployment/13_Deploy_Assets_AssetSafe.s.sol index 062e0ae..07de9b7 100644 --- a/script/deployment/13_Deploy_Assets_AssetSafe.s.sol +++ b/script/deployment/13_Deploy_Assets_AssetSafe.s.sol @@ -7,7 +7,7 @@ import { AssetSafe } from "contracts/assets/AssetSafe.sol"; contract DeployAssetSafe is DeployBase { function run() external returns (address) { - vm.startBroadcast(getAdminPK()); + vm.startBroadcast(getDeployerPK()); address accessManager = computeCreate3Address("SALT_ACCESS_MANAGER"); address assetRegistry = computeCreate3Address("SALT_ASSET_REGISTRY"); address impl = address(new AssetSafe(assetRegistry)); diff --git a/script/deployment/14_Deploy_Policies_PolicyAudit.s.sol b/script/deployment/14_Deploy_Policies_PolicyAudit.s.sol index b4bf512..4ea8348 100644 --- a/script/deployment/14_Deploy_Policies_PolicyAudit.s.sol +++ b/script/deployment/14_Deploy_Policies_PolicyAudit.s.sol @@ -8,7 +8,7 @@ import { C } from "contracts/core/primitives/Constants.sol"; contract DeployPolicyAudit is DeployBase { function run() external returns (address) { - vm.startBroadcast(getAdminPK()); + vm.startBroadcast(getDeployerPK()); address impl = address(new PolicyAudit()); address accessManager = computeCreate3Address("SALT_ACCESS_MANAGER"); bytes memory init = abi.encodeCall(PolicyAudit.initialize, (accessManager)); diff --git a/script/deployment/15_Deploy_RightsManager_AssetCustodian.s.sol b/script/deployment/15_Deploy_RightsManager_AssetCustodian.s.sol index 53c8d79..179c033 100644 --- a/script/deployment/15_Deploy_RightsManager_AssetCustodian.s.sol +++ b/script/deployment/15_Deploy_RightsManager_AssetCustodian.s.sol @@ -7,7 +7,7 @@ import { RightsAssetCustodian } from "contracts/rights/RightsAssetCustodian.sol" contract DeployRightsAssetCustodian is DeployBase { function run() external returns (address) { - vm.startBroadcast(getAdminPK()); + vm.startBroadcast(getDeployerPK()); address accessManager = computeCreate3Address("SALT_ACCESS_MANAGER"); address custodianReferendum = computeCreate3Address("SALT_CUSTODIAN_REFERENDUM"); address impl = address(new RightsAssetCustodian(custodianReferendum)); diff --git a/script/deployment/16_Deploy_RightsManager_PolicyAuthorizer.s.sol b/script/deployment/16_Deploy_RightsManager_PolicyAuthorizer.s.sol index c92216e..0a1d249 100644 --- a/script/deployment/16_Deploy_RightsManager_PolicyAuthorizer.s.sol +++ b/script/deployment/16_Deploy_RightsManager_PolicyAuthorizer.s.sol @@ -7,7 +7,7 @@ import { RightsPolicyAuthorizer } from "contracts/rights/RightsPolicyAuthorizer. contract DeployRightsPolicyAuthorizer is DeployBase { function run() external returns (address) { - vm.startBroadcast(getAdminPK()); + vm.startBroadcast(getDeployerPK()); address accessManager = computeCreate3Address("SALT_ACCESS_MANAGER"); address policyAudit = computeCreate3Address("SALT_POLICY_AUDIT"); address impl = address(new RightsPolicyAuthorizer(policyAudit)); diff --git a/script/deployment/17_Deploy_RightsManager_PolicyManager.s.sol b/script/deployment/17_Deploy_RightsManager_PolicyManager.s.sol index f60d560..b99c408 100644 --- a/script/deployment/17_Deploy_RightsManager_PolicyManager.s.sol +++ b/script/deployment/17_Deploy_RightsManager_PolicyManager.s.sol @@ -7,7 +7,7 @@ import { RightsPolicyManager } from "contracts/rights/RightsPolicyManager.sol"; contract DeployRightsPolicyManager is DeployBase { function run() external returns (address) { - vm.startBroadcast(getAdminPK()); + vm.startBroadcast(getDeployerPK()); address accessManager = computeCreate3Address("SALT_ACCESS_MANAGER"); address agreementSettler = computeCreate3Address("SALT_AGREEMENT_SETTLER"); address rightsAuthorizer = computeCreate3Address("SALT_RIGHT_POLICY_AUTHORIZER"); diff --git a/script/deployment/18_Deploy_RightsManager_PolicyAuthorizer.s.sol b/script/deployment/18_Deploy_RightsManager_PolicyAuthorizer.s.sol index c3dc4f2..09dec55 100644 --- a/script/deployment/18_Deploy_RightsManager_PolicyAuthorizer.s.sol +++ b/script/deployment/18_Deploy_RightsManager_PolicyAuthorizer.s.sol @@ -8,7 +8,7 @@ import { RightsPolicyAuthorizer } from "contracts/rights/RightsPolicyAuthorizer. /// @dev Mirrors the production deployment but allows injecting custom dependencies when needed. contract DeployRightsPolicyAuthorizer is DeployBase { function run(address policyAudit, address accessManager) external returns (address) { - vm.startBroadcast(getAdminPK()); + vm.startBroadcast(getDeployerPK()); address implementation = address(new RightsPolicyAuthorizer(policyAudit)); bytes memory initData = abi.encodeCall(RightsPolicyAuthorizer.initialize, accessManager); diff --git a/script/orchestration/01_Orchestrate_ProtocolHydration.s.sol b/script/orchestration/01_Orchestrate_ProtocolHydration.s.sol index 7918e62..aea636f 100644 --- a/script/orchestration/01_Orchestrate_ProtocolHydration.s.sol +++ b/script/orchestration/01_Orchestrate_ProtocolHydration.s.sol @@ -4,6 +4,7 @@ import "forge-std/Script.sol"; import { IAccessManager } from "contracts/core/interfaces/access/IAccessManager.sol"; import { ITollgate } from "contracts/core/interfaces/economics/ITollgate.sol"; +import { ILedgerVault } from "contracts/core/interfaces/financial/ILedgerVault.sol"; import { C } from "contracts/core/primitives/Constants.sol"; import { T } from "contracts/core/primitives/Types.sol"; @@ -18,7 +19,7 @@ import { getPauserPermissions as PauserPermissions } from "script/permissions/Pe contract OrchestrateProtocolHydration is Script { function run() external { - uint256 admin = vm.envUint("PRIVATE_KEY"); + uint256 governor = vm.envUint("PRIVATE_KEY"); address tollgateAddress = vm.envAddress("TOLLGATE"); address treasuryAddress = vm.envAddress("TREASURY"); address auditorAddress = vm.envAddress("POLICY_AUDIT"); @@ -31,17 +32,17 @@ contract OrchestrateProtocolHydration is Script { address custodianReferendum = vm.envAddress("CUSTODIAN_REFERENDUM"); address ledgerVault = vm.envAddress("LEDGER_VAULT"); - vm.startBroadcast(admin); + vm.startBroadcast(governor); // 1 set the initial governor to operate over the protocol configuration // initially the admin will have the role of "governor" // initially the admin will be the mod to setup policies - address adminAddress = vm.addr(admin); + // address adminAddress = vm.addr(governor); IAccessManager authority = IAccessManager(accessManager); // the governor is set to admin to handle initial setup.. // after this can be revoked and assign the governance timelock as governor // https://docs.openzeppelin.com/contracts/5.x/access-control#role-admins-and-guardians - authority.grantRole(C.GOV_ROLE, adminAddress, 0); + // authority.grantRole(C.GOV_ROLE, adminAddress, 0); authority.grantRole(C.OPS_ROLE, agreementManager, 0); authority.grantRole(C.OPS_ROLE, agreementSettler, 0); @@ -78,11 +79,13 @@ contract OrchestrateProtocolHydration is Script { address currency = vm.envAddress("MMC"); ITollgate tollgate = ITollgate(tollgateAddress); + ILedgerVault vault = ILedgerVault(ledgerVault); // assign bps scheme to right policy manager + fees + mmc + vault.allowCurrency(currency); // the currency needs whitelisting tollgate.setFees(T.Scheme.BPS, rightPolicyManager, agrFee, currency); (uint256 feeA, ) = tollgate.getFees(rightPolicyManager, currency); - require(feeA == agrFee); + assert(feeA == agrFee); vm.stopBroadcast(); } } diff --git a/script/orchestration/02_Orchestrate_ProtocolCustodianNetwork.s.sol b/script/orchestration/02_Orchestrate_ProtocolCustodianNetwork.s.sol index e584d35..ddc3a8f 100644 --- a/script/orchestration/02_Orchestrate_ProtocolCustodianNetwork.s.sol +++ b/script/orchestration/02_Orchestrate_ProtocolCustodianNetwork.s.sol @@ -11,14 +11,14 @@ import { IAgreementManager } from "contracts/core/interfaces/financial/IAgreemen contract OrchestrateProtocolCustodianNetwork is DeployBase { function run() external { - uint256 admin = getAdminPK(); + uint256 governor = getDeployerPK(); address mmc = vm.envAddress("MMC"); uint256 fees = vm.envUint("CUSTODY_FEES"); // 100 MMC flat fee address vault = computeCreate3Address("SALT_LEDGER_VAULT"); address custodianFactory = vm.envAddress("CUSTODIAN_FACTORY"); address custodianReferendum = vm.envAddress("CUSTODIAN_REFERENDUM"); - vm.startBroadcast(admin); + vm.startBroadcast(governor); // approve initial custodian address custodian = ICustodianFactory(custodianFactory).create("https://g.watchit.movie"); ICustodianReferendum referendum = ICustodianReferendum(custodianReferendum); @@ -26,12 +26,12 @@ contract OrchestrateProtocolCustodianNetwork is DeployBase { bytes32 got = keccak256(abi.encodePacked(ICustodian(custodian).getEndpoint())); bytes32 expected = keccak256(abi.encodePacked("https://g.watchit.movie")); - require(ICustodian(custodian).getManager() == vm.addr(admin)); + require(ICustodian(custodian).getManager() == vm.addr(governor)); require(got == expected); // deposit funds to register custodian IERC20(mmc).approve(vault, fees); - ILedgerVault(vault).deposit(vm.addr(admin), fees, mmc); + ILedgerVault(vault).deposit(vm.addr(governor), fees, mmc); ILedgerVault(vault).approve(address(referendum), fees, mmc); referendum.register(address(custodian)); diff --git a/script/orchestration/03_Orchestrate_ProtocolRightsCustodian.s.sol b/script/orchestration/03_Orchestrate_ProtocolRightsCustodian.s.sol index 18bb541..e2bbb1a 100644 --- a/script/orchestration/03_Orchestrate_ProtocolRightsCustodian.s.sol +++ b/script/orchestration/03_Orchestrate_ProtocolRightsCustodian.s.sol @@ -6,11 +6,11 @@ import { IRightsAssetCustodian } from "contracts/core/interfaces/rights/IRightsA contract OrchestrateRightsCustodian is Script { function run() external { - uint256 admin = vm.envUint("PRIVATE_KEY"); + uint256 governor = vm.envUint("PRIVATE_KEY"); address rightsCustodian = vm.envAddress("RIGHT_ASSET_CUSTODIAN"); address defaultCustodian = vm.envAddress("DEFAULT_CUSTODIAN_ADDRESS"); - vm.startBroadcast(admin); + vm.startBroadcast(governor); // approve initial custodian IRightsAssetCustodian custodian = IRightsAssetCustodian(rightsCustodian); custodian.grantCustody(defaultCustodian); // assign my content custody to custodian diff --git a/script/permissions/Permissions_LedgerVault.sol b/script/permissions/Permissions_LedgerVault.sol index d223719..e1cc4f1 100644 --- a/script/permissions/Permissions_LedgerVault.sol +++ b/script/permissions/Permissions_LedgerVault.sol @@ -9,3 +9,10 @@ function getOpsPermissions() pure returns (bytes4[] memory) { vaultAllowed[2] = LedgerVault.claim.selector; return vaultAllowed; } + +function getGovPermissions() pure returns (bytes4[] memory) { + bytes4[] memory vaultAllowed = new bytes4[](2); + vaultAllowed[0] = LedgerVault.allowCurrency.selector; + vaultAllowed[1] = LedgerVault.blockCurrency.selector; + return vaultAllowed; +} \ No newline at end of file diff --git a/test/BaseTest.t.sol b/test/BaseTest.t.sol index 842258a..ed56858 100644 --- a/test/BaseTest.t.sol +++ b/test/BaseTest.t.sol @@ -26,9 +26,11 @@ import { getGovPermissions as TreasuryGovPermissions } from "script/permissions/ import { getGovPermissions as CustodianReferendumGovPermissions } from "script/permissions/Permissions_CustodianReferendum.sol"; import { getGovPermissions as AssetReferendumGovPermissions } from "script/permissions/Permissions_AssetReferendum.sol"; import { getOpsPermissions as LedgerVaultOpsPermissions } from "script/permissions/Permissions_LedgerVault.sol"; +import { getGovPermissions as LedgerVaultGovPermissions } from "script/permissions/Permissions_LedgerVault.sol"; import { IAccessManager } from "contracts/core/interfaces/access/IAccessManager.sol"; import { C } from "contracts/core/primitives/Constants.sol"; +import { ILedgerVault } from "contracts/core/interfaces/financial/ILedgerVault.sol"; import { console } from "forge-std/console.sol"; @@ -38,6 +40,7 @@ import { console } from "forge-std/console.sol"; abstract contract BaseTest is Test { address admin; address user; + address sec; address governor; address contentCouncil; address nodesCouncil; @@ -65,11 +68,12 @@ abstract contract BaseTest is Test { modifier initialize() { // setup the admin to operate in tests.. + admin = vm.addr(1); user = vm.addr(2); - governor = vm.addr(1); - contentCouncil = vm.addr(2); - nodesCouncil = vm.addr(2); - admin = vm.addr(vm.envUint("PRIVATE_KEY")); + governor = vm.addr(vm.envUint("PRIVATE_KEY")); + contentCouncil = vm.addr(3); + nodesCouncil = vm.addr(4); + sec = vm.addr(5); deployCreate3Factory(); deployAccessManager(); @@ -101,16 +105,17 @@ abstract contract BaseTest is Test { DeployAccessManager accessManagerDeployer = new DeployAccessManager(); accessManager = accessManager == address(0) ? accessManagerDeployer.run() : accessManager; - vm.prank(admin); + vm.startPrank(governor); // add to governor the gov role IAccessManager authority = IAccessManager(accessManager); - authority.grantRole(C.GOV_ROLE, governor, 0); - - vm.startPrank(governor); + authority.grantRole(C.ADMIN_ROLE, admin, 0); // add to councils the corresponding role authority.grantRole(C.CONTENT_COUNCIL_ROLE, contentCouncil, 0); authority.grantRole(C.CUSTODY_COUNCIL_ROLE, nodesCouncil, 0); vm.stopPrank(); + + vm.prank(admin); + authority.grantRole(C.SEC_ROLE, sec, 0); } // 02_DeployTollgate @@ -130,12 +135,16 @@ abstract contract BaseTest is Test { // set default admin as deployer.. DeployLedgerVault ledgerDeployer = new DeployLedgerVault(); bytes4[] memory ledgerAllowed = LedgerVaultOpsPermissions(); + bytes4[] memory ledgerGovAllowed = LedgerVaultGovPermissions(); ledger = ledger == address(0) ? ledgerDeployer.run() : ledger; - vm.prank(admin); // op role needed to call functions in ledger contract - IAccessManager authority = IAccessManager(accessManager); - authority.setTargetFunctionRole(ledger, ledgerAllowed, C.OPS_ROLE); + _setOpsPermissions(ledger, ledgerAllowed); + _setGovPermissions(ledger, ledgerGovAllowed); + + vm.prank(governor); + ILedgerVault(ledger).allowCurrency(token); + return ledger; } @@ -209,12 +218,13 @@ abstract contract BaseTest is Test { _setNodesCouncilPermissions(custodianReferendum, custodianReferendumAllowed); } - function deployRightsAssetCustodian() public { deployCustodianReferendum(); // set default admin as deployer.. DeployRightsAssetCustodian rightAssetCustodianDeployer = new DeployRightsAssetCustodian(); - rightAssetCustodian = rightAssetCustodian == address(0) ? rightAssetCustodianDeployer.run() : rightAssetCustodian; + rightAssetCustodian = rightAssetCustodian == address(0) + ? rightAssetCustodianDeployer.run() + : rightAssetCustodian; } function deployPolicyAudit() public { @@ -239,8 +249,8 @@ abstract contract BaseTest is Test { rightsPolicyManager = rightsPolicyManager == address(0) ? rightsManagerDeployer.run() : rightsPolicyManager; } - function _setContentCouncilPermissions(address target, bytes4[] memory allowed) public { - vm.startPrank(admin); + function _setContentCouncilPermissions(address target, bytes4[] memory allowed) public { + vm.startPrank(governor); IAccessManager authority = IAccessManager(accessManager); // assign permissions to VAL_ROLE for allowed functions to call in target authority.setTargetFunctionRole(target, allowed, C.CONTENT_COUNCIL_ROLE); @@ -248,25 +258,48 @@ abstract contract BaseTest is Test { } function _setNodesCouncilPermissions(address target, bytes4[] memory allowed) public { - vm.startPrank(admin); + vm.startPrank(governor); IAccessManager authority = IAccessManager(accessManager); // assign permissions to VAL_ROLE for allowed functions to call in target authority.setTargetFunctionRole(target, allowed, C.CUSTODY_COUNCIL_ROLE); vm.stopPrank(); } + function _setOpsPermissions(address target, bytes4[] memory allowed) public { + vm.startPrank(governor); + IAccessManager authority = IAccessManager(accessManager); + // assign permissions to OPS_ROLE for allowed functions to call in target + authority.setTargetFunctionRole(target, allowed, C.OPS_ROLE); + vm.stopPrank(); + } + function _setGovPermissions(address target, bytes4[] memory allowed) public { - vm.startPrank(admin); + vm.startPrank(governor); IAccessManager authority = IAccessManager(accessManager); // assign permissions to GOV_ROLE for allowed functions to call in target authority.setTargetFunctionRole(target, allowed, C.GOV_ROLE); vm.stopPrank(); } + function _setSecPermissions(address target, bytes4[] memory allowed) public { + vm.startPrank(governor); + IAccessManager authority = IAccessManager(accessManager); + // assign permissions to ADMIN_ROLE for allowed functions to call in target + authority.setTargetFunctionRole(target, allowed, C.SEC_ROLE); + vm.stopPrank(); + } + function _assignOpRole(address target) public { vm.startPrank(admin); IAccessManager authority = IAccessManager(accessManager); authority.grantRole(C.OPS_ROLE, target, 0); vm.stopPrank(); } + + function _grantRole(uint64 role, address account) public { + vm.startPrank(admin); + IAccessManager authority = IAccessManager(accessManager); + authority.grantRole(role, account, 0); + vm.stopPrank(); + } } diff --git a/test/assets/AssetRegistry.t.sol b/test/assets/AssetRegistry.t.sol index 80134c3..8e7211a 100644 --- a/test/assets/AssetRegistry.t.sol +++ b/test/assets/AssetRegistry.t.sol @@ -140,8 +140,8 @@ contract AssetRegistryTest is BaseTest { vm.expectEmit(true, true, false, true, assetRegistry); emit AssetRegistry.RevokedAsset(user, assetId); - vm.prank(admin); - AssetRegistry(assetRegistry).revoke(assetId); + vm.prank(governor); + IAssetRegistry(assetRegistry).revoke(assetId); assertFalse(IERC721StatefulVerifiable(assetRegistry).isActive(assetId), "Revoked asset should be inactive"); assertEq(AssetRegistry(assetRegistry).totalSupply(), 0, "Total supply should decrease after burn"); diff --git a/test/economics/Tollgate.t.sol b/test/economics/Tollgate.t.sol index a70911e..b96b41a 100644 --- a/test/economics/Tollgate.t.sol +++ b/test/economics/Tollgate.t.sol @@ -125,12 +125,6 @@ contract TollgateTest is BaseTest { assertEq(uint256(c), 3, "Expected scheme should be BPS"); } - function test_GetFees_RevertWhen_NotSupportedScheme() public { - address invalidTokenAddress = vm.addr(3); - address target = vm.addr(8); - vm.expectRevert(abi.encodeWithSignature("UnsupportedCurrency(address,address)", target, invalidTokenAddress)); - ITollgate(tollgate).getFees(target, invalidTokenAddress); - } function test_SupportedCurrencies_ReturnExpectedCurrencies() public { address target = custodianReferendum; diff --git a/test/finance/AgreementManager.t.sol b/test/finance/AgreementManager.t.sol index 6ea110a..37d1541 100644 --- a/test/finance/AgreementManager.t.sol +++ b/test/finance/AgreementManager.t.sol @@ -28,10 +28,8 @@ contract AgreementManagerTest is BaseTest { deployAgreementManager(); arbiter = address(new AgreementManagerMockArbiter()); - vm.prank(governor); + vm.startPrank(governor); ITollgate(tollgate).setFees(T.Scheme.BPS, arbiter, 500, token); - - vm.startPrank(admin); IERC20(token).approve(ledger, INITIAL_DEPOSIT); ILedgerVault(ledger).deposit(user, INITIAL_DEPOSIT, token); vm.stopPrank(); diff --git a/test/finance/AgreementSettler.t.sol b/test/finance/AgreementSettler.t.sol index 41b0bbf..0b43061 100644 --- a/test/finance/AgreementSettler.t.sol +++ b/test/finance/AgreementSettler.t.sol @@ -42,10 +42,8 @@ contract AgreementSettlerTest is BaseTest { deployAgreementSettler(); arbiter = new SettlerMockArbiter(agreementSettler); - vm.prank(governor); + vm.startPrank(governor); ITollgate(tollgate).setFees(T.Scheme.BPS, address(arbiter), 500, token); - - vm.startPrank(admin); IERC20(token).approve(ledger, INITIAL_DEPOSIT); ILedgerVault(ledger).deposit(user, INITIAL_DEPOSIT, token); vm.stopPrank(); diff --git a/test/finance/LedgerVault.t.sol b/test/finance/LedgerVault.t.sol index 026cded..ee9a941 100644 --- a/test/finance/LedgerVault.t.sol +++ b/test/finance/LedgerVault.t.sol @@ -3,18 +3,16 @@ pragma solidity 0.8.26; import "forge-std/Test.sol"; -import { AccessManager } from "@openzeppelin/contracts/access/manager/AccessManager.sol"; import { IAccessManaged } from "@openzeppelin/contracts/access/manager/IAccessManaged.sol"; -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; -import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import { AccessControlledUpgradeable } from "contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol"; import { LedgerVault } from "contracts/financial/LedgerVault.sol"; -import { C } from "contracts/core/primitives/Constants.sol"; import { ILedgerVerifiable } from "contracts/core/interfaces/base/ILedgerVerifiable.sol"; import { FinancialOps } from "contracts/core/libraries/FinancialOps.sol"; +import { BaseTest } from "test/BaseTest.t.sol"; +import { C } from "contracts/core/primitives/Constants.sol"; contract MockToken is ERC20 { constructor() ERC20("Mock Token", "MOCK") {} @@ -24,74 +22,38 @@ contract MockToken is ERC20 { } } -contract LedgerVaultHarness is LedgerVault { - bytes32 private constant LOCK_SLOT = - 0xece3ff917f3a3127e521e0c3f2f90ff09a3c8199be32f9b40bff79e776960800; +contract LedgerVaultTest is BaseTest { + LedgerVault internal vault; + MockToken internal mockToken; - function lockedBalance(address account, address currency) external view returns (uint256 balance_) { - bytes32 first; - bytes32 second; - assembly { - mstore(0x00, account) - mstore(0x20, LOCK_SLOT) - first := keccak256(0x00, 0x40) + address internal operator = vm.addr(11); + address internal claimer = vm.addr(12); + address internal other = vm.addr(13); - mstore(0x00, currency) - mstore(0x20, first) - second := keccak256(0x00, 0x40) + function setUp() public initialize { + mockToken = new MockToken(); + token = address(mockToken); - balance_ := sload(second) - } - } -} + deployLedgerVault(); + vault = LedgerVault(ledger); -contract LedgerVaultTest is Test { - LedgerVaultHarness vault; - AccessManager manager; - MockToken token; - - address admin = vm.addr(1); - address operator = vm.addr(2); - address claimer = vm.addr(3); - address user = vm.addr(4); - address other = vm.addr(5); - - function setUp() public { - token = new MockToken(); - manager = new AccessManager(admin); - - LedgerVaultHarness implementation = new LedgerVaultHarness(); - ERC1967Proxy proxy = new ERC1967Proxy( - address(implementation), - abi.encodeWithSignature("initialize(address)", address(manager)) - ); - vault = LedgerVaultHarness(address(proxy)); + bytes4[] memory secSelectors = new bytes4[](2); + secSelectors[0] = AccessControlledUpgradeable.pause.selector; + secSelectors[1] = AccessControlledUpgradeable.unpause.selector; - vm.startPrank(admin); - bytes4[] memory adminSelectors = new bytes4[](2); - adminSelectors[0] = AccessControlledUpgradeable.pause.selector; - adminSelectors[1] = AccessControlledUpgradeable.unpause.selector; - manager.setTargetFunctionRole(address(vault), adminSelectors, C.ADMIN_ROLE); - - bytes4[] memory opsSelectors = new bytes4[](3); - opsSelectors[0] = LedgerVault.lock.selector; - opsSelectors[1] = LedgerVault.release.selector; - opsSelectors[2] = LedgerVault.claim.selector; - manager.setTargetFunctionRole(address(vault), opsSelectors, C.OPS_ROLE); - manager.setRoleAdmin(C.OPS_ROLE, C.ADMIN_ROLE); - manager.grantRole(C.OPS_ROLE, operator, 0); - manager.grantRole(C.OPS_ROLE, claimer, 0); - vm.stopPrank(); + _setSecPermissions(ledger, secSelectors); + _grantRole(C.OPS_ROLE, operator); + _grantRole(C.OPS_ROLE, claimer); - token.mint(admin, 1_000_000 ether); - token.mint(user, 1_000_000 ether); - token.mint(other, 1_000_000 ether); + mockToken.mint(admin, 1_000_000 ether); + mockToken.mint(user, 1_000_000 ether); + mockToken.mint(other, 1_000_000 ether); } function _deposit(address account, uint256 amount) internal returns (uint256) { vm.startPrank(account); - token.approve(address(vault), amount); - uint256 confirmed = vault.deposit(account, amount, address(token)); + mockToken.approve(address(vault), amount); + uint256 confirmed = vault.deposit(account, amount, address(mockToken)); vm.stopPrank(); return confirmed; } @@ -101,60 +63,71 @@ contract LedgerVaultTest is Test { assertEq(confirmed, 100 ether, "Deposit return mismatch"); assertEq( - ILedgerVerifiable(address(vault)).getLedgerBalance(admin, address(token)), + ILedgerVerifiable(address(vault)).getLedgerBalance(admin, address(mockToken)), 100 ether, "Ledger balance mismatch" ); - assertEq(token.balanceOf(address(vault)), 100 ether, "Vault token balance mismatch"); + assertEq(mockToken.balanceOf(address(vault)), 100 ether, "Vault token balance mismatch"); } function test_Deposit_RevertWhen_NoAllowance() public { vm.prank(admin); vm.expectRevert(abi.encodeWithSelector(FinancialOps.FailDuringDeposit.selector, "Amount exceeds allowance.")); - vault.deposit(admin, 10 ether, address(token)); + vault.deposit(admin, 10 ether, address(mockToken)); + } + + function test_Deposit_RevertWhen_CurrencyNotApproved() public { + MockToken unapproved = new MockToken(); + unapproved.mint(admin, 100 ether); + + vm.startPrank(admin); + unapproved.approve(address(vault), 10 ether); + vm.expectRevert(abi.encodeWithSelector(LedgerVault.CurrencyNotAllowed.selector, address(unapproved))); + vault.deposit(admin, 10 ether, address(unapproved)); + vm.stopPrank(); } function test_Withdraw_Succeeds() public { _deposit(admin, 200 ether); vm.prank(admin); - uint256 withdrawn = vault.withdraw(admin, 150 ether, address(token)); + uint256 withdrawn = vault.withdraw(admin, 150 ether, address(mockToken)); assertEq(withdrawn, 150 ether, "Withdrawn amount mismatch"); assertEq( - ILedgerVerifiable(address(vault)).getLedgerBalance(admin, address(token)), + ILedgerVerifiable(address(vault)).getLedgerBalance(admin, address(mockToken)), 50 ether, "Ledger balance after withdraw" ); - assertEq(token.balanceOf(admin), 1_000_000 ether - 50 ether, "Admin token balance mismatch"); + assertEq(mockToken.balanceOf(admin), 1_000_000 ether - 50 ether, "Admin token balance mismatch"); } function test_Withdraw_RevertWhen_NoFunds() public { vm.prank(admin); vm.expectRevert(bytes4(keccak256("NoFundsToWithdraw()"))); - vault.withdraw(admin, 1 ether, address(token)); + vault.withdraw(admin, 1 ether, address(mockToken)); } function test_Transfer_Succeeds() public { _deposit(admin, 100 ether); vm.prank(admin); - uint256 moved = vault.transfer(user, 40 ether, address(token)); + uint256 moved = vault.transfer(user, 40 ether, address(mockToken)); assertEq(moved, 40 ether, "Transfer amount mismatch"); assertEq( - ILedgerVerifiable(address(vault)).getLedgerBalance(admin, address(token)), + ILedgerVerifiable(address(vault)).getLedgerBalance(admin, address(mockToken)), 60 ether, "Admin ledger after transfer" ); assertEq( - ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(token)), + ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(mockToken)), 40 ether, "User ledger after transfer" ); assertEq( - ILedgerVerifiable(address(vault)).getLedgerBalance(admin, address(token)) + - ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(token)), + ILedgerVerifiable(address(vault)).getLedgerBalance(admin, address(mockToken)) + + ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(mockToken)), 100 ether, "Ledger totals must conserve balance" ); @@ -165,22 +138,22 @@ contract LedgerVaultTest is Test { vm.prank(admin); vm.expectRevert(bytes4(keccak256("InvalidOperationParameters()"))); - vault.transfer(admin, 10 ether, address(token)); + vault.transfer(admin, 10 ether, address(mockToken)); } function test_Lock_Succeeds() public { _deposit(user, 120 ether); vm.prank(operator); - uint256 locked = vault.lock(user, 70 ether, address(token)); + uint256 locked = vault.lock(user, 70 ether, address(mockToken)); assertEq(locked, 70 ether, "Locked amount mismatch"); assertEq( - ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(token)), + ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(mockToken)), 50 ether, "User ledger after lock" ); - assertEq(vault.lockedBalance(user, address(token)), 70 ether, "Locked balance mismatch"); + assertEq(vault.getLockedBalance(user, address(mockToken)), 70 ether, "Locked balance mismatch"); } function test_Lock_RevertWhen_Insufficient() public { @@ -188,21 +161,21 @@ contract LedgerVaultTest is Test { vm.prank(operator); vm.expectRevert(bytes4(keccak256("NoFundsToLock()"))); - vault.lock(user, 20 ether, address(token)); + vault.lock(user, 20 ether, address(mockToken)); } function test_Release_Succeeds() public { _deposit(user, 90 ether); vm.prank(operator); - vault.lock(user, 60 ether, address(token)); + vault.lock(user, 60 ether, address(mockToken)); vm.prank(operator); - uint256 released = vault.release(user, 30 ether, address(token)); + uint256 released = vault.release(user, 30 ether, address(mockToken)); assertEq(released, 30 ether, "Released amount mismatch"); - assertEq(vault.lockedBalance(user, address(token)), 30 ether, "Locked balance after release"); + assertEq(vault.getLockedBalance(user, address(mockToken)), 30 ether, "Locked balance after release"); assertEq( - ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(token)), + ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(mockToken)), 60 ether, "Ledger after release" ); @@ -211,15 +184,15 @@ contract LedgerVaultTest is Test { function test_Claim_Succeeds() public { _deposit(user, 100 ether); vm.prank(operator); - vault.lock(user, 40 ether, address(token)); + vault.lock(user, 40 ether, address(mockToken)); vm.prank(claimer); - uint256 claimed = vault.claim(user, 25 ether, address(token)); + uint256 claimed = vault.claim(user, 25 ether, address(mockToken)); assertEq(claimed, 25 ether, "Claim amount mismatch"); - assertEq(vault.lockedBalance(user, address(token)), 15 ether, "Locked balance after claim"); + assertEq(vault.getLockedBalance(user, address(mockToken)), 15 ether, "Locked balance after claim"); assertEq( - ILedgerVerifiable(address(vault)).getLedgerBalance(claimer, address(token)), + ILedgerVerifiable(address(vault)).getLedgerBalance(claimer, address(mockToken)), 25 ether, "Claimer ledger after claim" ); @@ -230,54 +203,54 @@ contract LedgerVaultTest is Test { vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, user)); vm.prank(user); - vault.lock(user, 10 ether, address(token)); + vault.lock(user, 10 ether, address(mockToken)); } function test_Claim_RevertWhen_Unauthorized() public { _deposit(user, 50 ether); vm.prank(operator); - vault.lock(user, 20 ether, address(token)); + vault.lock(user, 20 ether, address(mockToken)); vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, other)); vm.prank(other); - vault.claim(user, 5 ether, address(token)); + vault.claim(user, 5 ether, address(mockToken)); } function test_Pause_BlocksStateChanging() public { _deposit(admin, 10 ether); - vm.prank(admin); + vm.prank(sec); vault.pause(); vm.prank(admin); vm.expectRevert(PausableUpgradeable.EnforcedPause.selector); - vault.withdraw(admin, 1 ether, address(token)); + vault.withdraw(admin, 1 ether, address(mockToken)); - vm.prank(admin); + vm.prank(sec); vault.unpause(); vm.prank(admin); - vault.withdraw(admin, 1 ether, address(token)); + vault.withdraw(admin, 1 ether, address(mockToken)); } function test_Integration_FullFlow() public { _deposit(user, 200 ether); vm.prank(operator); - vault.lock(user, 120 ether, address(token)); + vault.lock(user, 120 ether, address(mockToken)); vm.prank(claimer); - vault.claim(user, 70 ether, address(token)); + vault.claim(user, 70 ether, address(mockToken)); vm.prank(operator); - vault.release(user, 30 ether, address(token)); + vault.release(user, 30 ether, address(mockToken)); vm.prank(user); - vault.transfer(other, 40 ether, address(token)); + vault.transfer(other, 40 ether, address(mockToken)); - assertEq(vault.lockedBalance(user, address(token)), 20 ether, "Remaining locked"); + assertEq(vault.getLockedBalance(user, address(mockToken)), 20 ether, "Remaining locked"); assertEq( - ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(token)), + ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(mockToken)), 70 ether, "User ledger after flow" ); assertEq( - ILedgerVerifiable(address(vault)).getLedgerBalance(claimer, address(token)), + ILedgerVerifiable(address(vault)).getLedgerBalance(claimer, address(mockToken)), 70 ether, "Claimer ledger after flow" ); @@ -288,29 +261,29 @@ contract LedgerVaultTest is Test { _deposit(user, amount); vm.prank(user); - uint256 withdrawn = vault.withdraw(user, amount, address(token)); + uint256 withdrawn = vault.withdraw(user, amount, address(mockToken)); assertEq(withdrawn, amount, "Withdrawn amount mismatch"); assertEq( - ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(token)), + ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(mockToken)), 0, "Ledger balance should return to zero" ); - assertEq(token.balanceOf(address(vault)), 0, "Vault should hold no tokens"); + assertEq(mockToken.balanceOf(address(vault)), 0, "Vault should hold no tokens"); } function test_LedgerAndLockedBalancesMatchVaultHoldings() public { _deposit(user, 300 ether); vm.prank(operator); - vault.lock(user, 120 ether, address(token)); + vault.lock(user, 120 ether, address(mockToken)); vm.prank(claimer); - vault.claim(user, 40 ether, address(token)); + vault.claim(user, 40 ether, address(mockToken)); vm.prank(operator); - vault.release(user, 50 ether, address(token)); + vault.release(user, 50 ether, address(mockToken)); - uint256 ledgerUser = ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(token)); - uint256 ledgerClaimer = ILedgerVerifiable(address(vault)).getLedgerBalance(claimer, address(token)); - uint256 lockedUser = vault.lockedBalance(user, address(token)); - uint256 vaultBalance = token.balanceOf(address(vault)); + uint256 ledgerUser = ILedgerVerifiable(address(vault)).getLedgerBalance(user, address(mockToken)); + uint256 ledgerClaimer = ILedgerVerifiable(address(vault)).getLedgerBalance(claimer, address(mockToken)); + uint256 lockedUser = vault.getLockedBalance(user, address(mockToken)); + uint256 vaultBalance = mockToken.balanceOf(address(vault)); assertEq(ledgerUser + ledgerClaimer + lockedUser, vaultBalance, "Vault balance must equal ledger + locked"); } diff --git a/test/primitives/AccessControlledUpgradeable.t.sol b/test/primitives/AccessControlledUpgradeable.t.sol deleted file mode 100644 index 7dc0d77..0000000 --- a/test/primitives/AccessControlledUpgradeable.t.sol +++ /dev/null @@ -1,145 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.26; - -import "forge-std/Test.sol"; - -import { AccessManager } from "@openzeppelin/contracts/access/manager/AccessManager.sol"; -import { AccessControlledUpgradeable } from "contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol"; -import { IAccessManaged } from "@openzeppelin/contracts/access/manager/IAccessManaged.sol"; -import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; -import { C } from "contracts/core/primitives/Constants.sol"; - -contract AccessControlledHarness is AccessControlledUpgradeable { - uint256 public counter; - - function initialize(address manager) external initializer { - __AccessControlled_init(manager); - } - - function adminAction() external onlyAdmin returns (uint256) { - counter += 1; - return counter; - } - - function opsAction() external restricted whenNotPaused returns (uint256) { - counter += 1; - return counter; - } - - function isPaused() external view returns (bool) { - return paused(); - } - - function hasRoleView(uint64 role, address account) external view returns (bool) { - return _hasRole(role, account); - } -} - -contract AccessControlledUpgradeableTest is Test { - AccessManager internal manager; - AccessControlledHarness internal harness; - - address internal admin = vm.addr(1); - address internal operator = vm.addr(2); - address internal stranger = vm.addr(3); - - function setUp() public { - manager = new AccessManager(admin); - harness = new AccessControlledHarness(); - - vm.prank(admin); - harness.initialize(address(manager)); - - vm.startPrank(admin); - bytes4[] memory adminSelectors = new bytes4[](3); - adminSelectors[0] = AccessControlledUpgradeable.pause.selector; - adminSelectors[1] = AccessControlledUpgradeable.unpause.selector; - adminSelectors[2] = AccessControlledHarness.adminAction.selector; - manager.setTargetFunctionRole(address(harness), adminSelectors, C.ADMIN_ROLE); - - bytes4[] memory opsSelectors = new bytes4[](1); - opsSelectors[0] = AccessControlledHarness.opsAction.selector; - manager.setTargetFunctionRole(address(harness), opsSelectors, C.OPS_ROLE); - manager.setRoleAdmin(C.OPS_ROLE, C.ADMIN_ROLE); - manager.grantRole(C.OPS_ROLE, operator, 0); - vm.stopPrank(); - } - - function test_Initialize_RevertWhen_InvalidManager() public { - AccessControlledHarness fresh = new AccessControlledHarness(); - vm.expectRevert( - abi.encodeWithSelector( - AccessControlledUpgradeable.InvalidUnauthorizedOperation.selector, - "Invalid authority address." - ) - ); - fresh.initialize(address(0)); - } - - function test_AdminAction_AllowsOnlyAdmin() public { - vm.prank(admin); - uint256 result = harness.adminAction(); - assertEq(result, 1, "Admin action should increment counter"); - - vm.expectRevert( - abi.encodeWithSelector( - AccessControlledUpgradeable.InvalidUnauthorizedOperation.selector, - "Only admin can perform this action." - ) - ); - vm.prank(operator); - harness.adminAction(); - } - - function test_OpsAction_AllowsOperator() public { - vm.prank(operator); - uint256 result = harness.opsAction(); - assertEq(result, 1, "Ops action should increment counter"); - - vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, stranger)); - vm.prank(stranger); - harness.opsAction(); - } - - function test_PauseAndUnpauseControlOps() public { - vm.prank(admin); - harness.pause(); - assertTrue(harness.isPaused(), "Harness should be paused"); - - vm.expectRevert(PausableUpgradeable.EnforcedPause.selector); - vm.prank(operator); - harness.opsAction(); - - vm.prank(admin); - harness.unpause(); - assertFalse(harness.isPaused(), "Harness should be unpaused"); - - vm.prank(operator); - uint256 result = harness.opsAction(); - assertEq(result, 1, "Ops action should work after unpause"); - } - - function test_RoleAssignmentsVisible() public { - assertTrue(harness.hasRoleView(C.ADMIN_ROLE, admin), "Admin should have admin role"); - assertTrue(harness.hasRoleView(C.OPS_ROLE, operator), "Operator should have ops role"); - - vm.prank(admin); - manager.revokeRole(C.OPS_ROLE, operator); - assertFalse(harness.hasRoleView(C.OPS_ROLE, operator), "Operator role should be revoked"); - } - - function test_RolesCannotBeStolen() public { - vm.expectRevert( - abi.encodeWithSelector( - AccessControlledUpgradeable.InvalidUnauthorizedOperation.selector, - "Only admin can perform this action." - ) - ); - vm.prank(stranger); - harness.adminAction(); - - vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, stranger)); - vm.prank(stranger); - harness.opsAction(); - } -} diff --git a/test/primitives/LockOperatorUpgradeable.t.sol b/test/primitives/LockOperatorUpgradeable.t.sol index 31f0973..272c9c7 100644 --- a/test/primitives/LockOperatorUpgradeable.t.sol +++ b/test/primitives/LockOperatorUpgradeable.t.sol @@ -10,9 +10,6 @@ import { ILockReleaser } from "contracts/core/interfaces/base/ILockReleaser.sol" import { ILockClaimer } from "contracts/core/interfaces/base/ILockClaimer.sol"; contract LockOperatorHarness is LockOperatorUpgradeable { - bytes32 private constant LOCK_SLOT = - 0xece3ff917f3a3127e521e0c3f2f90ff09a3c8199be32f9b40bff79e776960800; - function initialize() external initializer { __LockOperator_init(); } @@ -32,22 +29,6 @@ contract LockOperatorHarness is LockOperatorUpgradeable { function claim(address account, uint256 amount, address currency) external override returns (uint256) { return _claim(account, amount, currency); } - - function lockedBalance(address account, address currency) external view returns (uint256 balance_) { - bytes32 first; - bytes32 second; - assembly { - mstore(0x00, account) - mstore(0x20, LOCK_SLOT) - first := keccak256(0x00, 0x40) - - mstore(0x00, currency) - mstore(0x20, first) - second := keccak256(0x00, 0x40) - - balance_ := sload(second) - } - } } contract LockOperatorUpgradeableTest is Test { @@ -70,7 +51,7 @@ contract LockOperatorUpgradeableTest is Test { harness.lock(alice, 40 ether, TOKEN); assertEq(ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN), 80 ether, "Ledger deduction mismatch"); - assertEq(harness.lockedBalance(alice, TOKEN), 40 ether, "Locked balance mismatch"); + assertEq(harness.getLockedBalance(alice, TOKEN), 40 ether, "Locked balance mismatch"); } function test_Lock_RevertWhen_NoFunds() public { @@ -97,7 +78,7 @@ contract LockOperatorUpgradeableTest is Test { emit ILockReleaser.FundsReleased(address(this), alice, 25 ether, TOKEN); harness.release(alice, 25 ether, TOKEN); - assertEq(harness.lockedBalance(alice, TOKEN), 35 ether, "Locked after release mismatch"); + assertEq(harness.getLockedBalance(alice, TOKEN), 35 ether, "Locked after release mismatch"); assertEq(ILedgerVerifiable(address(harness)).getLedgerBalance(alice, TOKEN), 55 ether, "Ledger after release mismatch"); } @@ -118,7 +99,7 @@ contract LockOperatorUpgradeableTest is Test { harness.claim(alice, 18 ether, TOKEN); ILedgerVerifiable ledger = ILedgerVerifiable(address(harness)); - assertEq(harness.lockedBalance(alice, TOKEN), 12 ether, "Locked remainder mismatch"); + assertEq(harness.getLockedBalance(alice, TOKEN), 12 ether, "Locked remainder mismatch"); assertEq(ledger.getLedgerBalance(claimer, TOKEN), 18 ether, "Claimer ledger mismatch"); assertEq(ledger.getLedgerBalance(alice, TOKEN), 40 ether, "Alice ledger should reflect lock deduction"); } @@ -138,7 +119,7 @@ contract LockOperatorUpgradeableTest is Test { vm.prank(claimer); harness.claim(alice, 50 ether, TOKEN); - uint256 locked = harness.lockedBalance(alice, TOKEN); + uint256 locked = harness.getLockedBalance(alice, TOKEN); ILedgerVerifiable ledger = ILedgerVerifiable(address(harness)); uint256 aliceLedger = ledger.getLedgerBalance(alice, TOKEN); uint256 claimerLedger = ledger.getLedgerBalance(claimer, TOKEN); diff --git a/test/rights/RightsPolicyManager.t.sol b/test/rights/RightsPolicyManager.t.sol index fedea9f..6a8f24a 100644 --- a/test/rights/RightsPolicyManager.t.sol +++ b/test/rights/RightsPolicyManager.t.sol @@ -222,7 +222,7 @@ contract RightsPolicyManagerTest is BaseTest { } function _seedLedgerBalance(address account, uint256 amount) internal { - vm.startPrank(admin); + vm.startPrank(governor); currency.approve(address(ledgerVault), amount); ledgerVault.deposit(account, amount, address(currency)); vm.stopPrank();