diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 8c2afdaa..285b6060 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -12,64 +12,66 @@ env: NODE_OPTIONS: --max_old_space_size=4096 jobs: - tests: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v3 - - name: Cache Compiler Installations - uses: actions/cache@v2 - with: - path: | - ~/.solcx - ~/.vvm - key: compiler-cache + - name: Cache Compiler Installations + uses: actions/cache@v2 + with: + path: | + ~/.solcx + ~/.vvm + key: compiler-cache - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: 16.x - cache: 'npm' - - run: npm install -g ganache + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 16.x + cache: "npm" + - run: npm install -g ganache - - name: Setup Python 3.8 - uses: actions/setup-python@v3 - with: - cache: 'pip' - python-version: '3.8' - - run: pip install -r requirements.txt + - name: Setup Python 3.8 + uses: actions/setup-python@v3 + with: + cache: "pip" + python-version: "3.8" + - run: pip install -r requirements.txt - - name: Run Tests - run: ape test + - name: Run Tests + run: ape test - - name: Deploy NuCypher Token - run: ape run scripts/deploy_nucypher_token.py --network ethereum:local + - name: Deploy NuCypher Token + run: ape run scripts/deploy_nucypher_token.py --network ethereum:local - - name: Deploy TACo Application - run: ape run scripts/deploy_taco_application.py --network ethereum:local + - name: Deploy TACo Application + run: ape run scripts/deploy_taco_application.py --network ethereum:local - - name: Deploy Staking Escrow - run: ape run scripts/deploy_staking_escrow.py --network ethereum:local + - name: Deploy Staking Escrow + run: ape run scripts/deploy_staking_escrow.py --network ethereum:local - - name: Deploy Subscription Manager - run: ape run scripts/deploy_subscription_manager.py --network ethereum:local + - name: Deploy Subscription Manager + run: ape run scripts/deploy_subscription_manager.py --network ethereum:local linting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v3 + + - name: Install Solhint and Prettier + run: npm install -g solhint solhint-plugin-prettier prettier - - name: Install Solhint - run: npm install -g solhint + - name: Install Solidity plugin for Prettier + run: npm install prettier-plugin-solidity - - name: Solidty Lint - run: solhint 'contracts/**/*.sol' + - name: Solidty Lint + run: solhint 'contracts/**/*.sol' - - name: Python lint - uses: cclauss/GitHub-Action-for-pylint@0.7.0 - continue-on-error: true - with: - args: "pylint **/*.py" + - name: Python lint + uses: cclauss/GitHub-Action-for-pylint@0.7.0 + continue-on-error: true + with: + args: "pylint **/*.py" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4547ab4c..5b143ebd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,15 +1,38 @@ repos: -- repo: https://github.com/psf/black + - repo: https://github.com/psf/black rev: 22.3.0 hooks: - - id: black + - id: black -- repo: https://github.com/pre-commit/pre-commit-hooks + - repo: https://github.com/pre-commit/pre-commit-hooks rev: v2.4.0 hooks: - - id: flake8 + - id: flake8 -- repo: https://github.com/pre-commit/mirrors-isort + - repo: https://github.com/pre-commit/mirrors-isort rev: v4.3.21 hooks: - - id: isort + - id: isort + + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v2.5.1 + hooks: + - id: prettier + + - repo: local + hooks: + - id: lint-sol + name: "lint solidity" + description: "Checks Solidity code according to the package's linter configuration" + language: node + entry: solhint + files: '\.sol$' + args: + - --config=./.solhint.json + - --ignore-path=./.solhintignore + - ./contracts/**/*.sol + additional_dependencies: + - solhint + - solhint-plugin-prettier + - prettier + - prettier-plugin-solidity diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..2ea008ee --- /dev/null +++ b/.prettierignore @@ -0,0 +1,6 @@ +**/contracts/contracts/proxy/ +**/contracts/contracts/StakingEscrow.sol +**/contracts/contracts/NuCypherToken.sol +**/contracts/test/proxy/ +**/contracts/test/StakingEscrowTestSet.sol +**/.cache \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 00000000..41cd22dc --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,4 @@ +{ + "plugins": ["prettier-plugin-solidity"], + "printWidth": 100 +} diff --git a/.solhint.json b/.solhint.json index b8b919f3..1f7b23cc 100644 --- a/.solhint.json +++ b/.solhint.json @@ -1,9 +1,46 @@ { "extends": "solhint:recommended", - "plugins": [], + "plugins": ["prettier"], "rules": { + "explicit-types": ["error", "explicit"], + "no-console": "error", + "no-empty-blocks": "error", + "compiler-version": ["error", "^0.8.0"], + "max-states-count": ["warn", 20], + "no-unused-vars": "error", + "reason-string": ["error", { "maxLength": 250 }], + "constructor-syntax": "error", + "quotes": ["error", "double"], + "const-name-snakecase": "error", + "contract-name-camelcase": "error", + "event-name-camelcase": "error", + "func-name-mixedcase": "error", + "immutable-vars-naming": ["error", { "immutablesAsConstants": false }], + "modifier-name-mixedcase": "error", + "var-name-mixedcase": "error", + "named-parameters-mapping": "warn", + "use-forbidden-name": "error", + "imports-on-top": "error", + "ordering": "warn", + "visibility-modifier-order": "error", + "avoid-call-value": "error", + "avoid-low-level-calls": "error", + "avoid-sha3": "error", "avoid-suicide": "error", - "avoid-sha3": "warn", - "compiler-version": ["error", "^0.8.0"] + "avoid-throw": "error", + "avoid-tx-origin": "error", + "check-send-result": "error", + "func-visibility": ["error", { "ignoreConstructors": true }], + "multiple-sends": "error", + "no-complex-fallback": "error", + "no-inline-assembly": "off", + "no-unused-import": "error", + "not-rely-on-block-hash": "error", + "not-rely-on-time": "off", + "reentrancy": "error", + "state-visibility": "error", + "no-global-import": "off", + "func-named-parameters": "off", + "prettier/prettier": "error" } } diff --git a/.solhintignore b/.solhintignore new file mode 100644 index 00000000..6986c444 --- /dev/null +++ b/.solhintignore @@ -0,0 +1,5 @@ +**/contracts/contracts/proxy/ +**/contracts/contracts/StakingEscrow.sol +**/contracts/contracts/NuCypherToken.sol +**/contracts/test/proxy/ +**/contracts/test/StakingEscrowTestSet.sol diff --git a/contracts/aragon/interfaces/IERC900History.sol b/contracts/aragon/interfaces/IERC900History.sol index e61e4249..a7c3ca9a 100644 --- a/contracts/aragon/interfaces/IERC900History.sol +++ b/contracts/aragon/interfaces/IERC900History.sol @@ -2,10 +2,11 @@ pragma solidity ^0.8.0; - // Minimum interface to interact with Aragon's Aggregator interface IERC900History { function totalStakedForAt(address addr, uint256 blockNumber) external view returns (uint256); + function totalStakedAt(uint256 blockNumber) external view returns (uint256); + function supportsHistory() external pure returns (bool); } diff --git a/contracts/contracts/Adjudicator.sol b/contracts/contracts/Adjudicator.sol index a2be80c9..0ecfeb44 100644 --- a/contracts/contracts/Adjudicator.sol +++ b/contracts/contracts/Adjudicator.sol @@ -8,14 +8,12 @@ import "@openzeppelin/contracts/utils/math/Math.sol"; import "@openzeppelin/contracts/utils/math/SafeCast.sol"; import "./TACoApplication.sol"; - /** -* @title Adjudicator -* @notice Supervises operators' behavior and punishes when something's wrong. -* @dev |v3.1.1| -*/ + * @title Adjudicator + * @notice Supervises operators' behavior and punishes when something's wrong. + * @dev |v3.1.1| + */ contract Adjudicator { - using UmbralDeserializer for bytes; using SafeCast for uint256; @@ -30,25 +28,21 @@ contract Adjudicator { address indexed stakingProvider ); - // used only for upgrading - bytes32 constant RESERVED_CAPSULE_AND_CFRAG_BYTES = bytes32(0); - address constant RESERVED_ADDRESS = address(0); - SignatureVerifier.HashAlgorithm public immutable hashAlgorithm; uint256 public immutable basePenalty; uint256 public immutable penaltyHistoryCoefficient; uint256 public immutable percentagePenaltyCoefficient; TACoApplication public immutable application; - mapping (address => uint256) public penaltyHistory; - mapping (bytes32 => bool) public evaluatedCFrags; + mapping(address => uint256) public penaltyHistory; + mapping(bytes32 => bool) public evaluatedCFrags; /** - * @param _hashAlgorithm Hashing algorithm - * @param _basePenalty Base for the penalty calculation - * @param _penaltyHistoryCoefficient Coefficient for calculating the penalty depending on the history - * @param _percentagePenaltyCoefficient Coefficient for calculating the percentage penalty - */ + * @param _hashAlgorithm Hashing algorithm + * @param _basePenalty Base for the penalty calculation + * @param _penaltyHistoryCoefficient Coefficient for calculating the penalty depending on the history + * @param _percentagePenaltyCoefficient Coefficient for calculating the percentage penalty + */ constructor( TACoApplication _application, SignatureVerifier.HashAlgorithm _hashAlgorithm, @@ -57,8 +51,7 @@ contract Adjudicator { uint256 _percentagePenaltyCoefficient ) { require( - _percentagePenaltyCoefficient != 0 && - address(_application.token()) != address(0), + _percentagePenaltyCoefficient != 0 && address(_application.token()) != address(0), "Wrong input parameters" ); hashAlgorithm = _hashAlgorithm; @@ -69,16 +62,16 @@ contract Adjudicator { } /** - * @notice Submit proof that a operator created wrong CFrag - * @param _capsuleBytes Serialized capsule - * @param _cFragBytes Serialized CFrag - * @param _cFragSignature Signature of CFrag by operator - * @param _taskSignature Signature of task specification by Bob - * @param _requesterPublicKey Bob's signing public key, also known as "stamp" - * @param _operatorPublicKey Operator's signing public key, also known as "stamp" - * @param _operatorIdentityEvidence Signature of operator's public key by operator's eth-key - * @param _preComputedData Additional pre-computed data for CFrag correctness verification - */ + * @notice Submit proof that a operator created wrong CFrag + * @param _capsuleBytes Serialized capsule + * @param _cFragBytes Serialized CFrag + * @param _cFragSignature Signature of CFrag by operator + * @param _taskSignature Signature of task specification by Bob + * @param _requesterPublicKey Bob's signing public key, also known as "stamp" + * @param _operatorPublicKey Operator's signing public key, also known as "stamp" + * @param _operatorIdentityEvidence Signature of operator's public key by operator's eth-key + * @param _preComputedData Additional pre-computed data for CFrag correctness verification + */ function evaluateCFrag( bytes memory _capsuleBytes, bytes memory _cFragBytes, @@ -88,44 +81,56 @@ contract Adjudicator { bytes memory _operatorPublicKey, bytes memory _operatorIdentityEvidence, bytes memory _preComputedData - ) - public - { + ) public { // 1. Check that CFrag is not evaluated yet bytes32 evaluationHash = SignatureVerifier.hash( - abi.encodePacked(_capsuleBytes, _cFragBytes), hashAlgorithm); + abi.encodePacked(_capsuleBytes, _cFragBytes), + hashAlgorithm + ); require(!evaluatedCFrags[evaluationHash], "This CFrag has already been evaluated."); evaluatedCFrags[evaluationHash] = true; // 2. Verify correctness of re-encryption - bool cFragIsCorrect = ReEncryptionValidator.validateCFrag(_capsuleBytes, _cFragBytes, _preComputedData); + bool cFragIsCorrect = ReEncryptionValidator.validateCFrag( + _capsuleBytes, + _cFragBytes, + _preComputedData + ); emit CFragEvaluated(evaluationHash, msg.sender, cFragIsCorrect); // 3. Verify associated public keys and signatures - require(ReEncryptionValidator.checkSerializedCoordinates(_operatorPublicKey), - "Staker's public key is invalid"); - require(ReEncryptionValidator.checkSerializedCoordinates(_requesterPublicKey), - "Requester's public key is invalid"); + require( + ReEncryptionValidator.checkSerializedCoordinates(_operatorPublicKey), + "Staker's public key is invalid" + ); + require( + ReEncryptionValidator.checkSerializedCoordinates(_requesterPublicKey), + "Requester's public key is invalid" + ); UmbralDeserializer.PreComputedData memory precomp = _preComputedData.toPreComputedData(); // Verify operator's signature of CFrag - require(SignatureVerifier.verify( + require( + SignatureVerifier.verify( _cFragBytes, abi.encodePacked(_cFragSignature, precomp.lostBytes[1]), _operatorPublicKey, - hashAlgorithm), - "CFrag signature is invalid" + hashAlgorithm + ), + "CFrag signature is invalid" ); // Verify operator's signature of taskSignature and that it corresponds to cfrag.proof.metadata UmbralDeserializer.CapsuleFrag memory cFrag = _cFragBytes.toCapsuleFrag(); - require(SignatureVerifier.verify( + require( + SignatureVerifier.verify( _taskSignature, abi.encodePacked(cFrag.proof.metadata, precomp.lostBytes[2]), _operatorPublicKey, - hashAlgorithm), - "Task signature is invalid" + hashAlgorithm + ), + "Task signature is invalid" ); // Verify that _taskSignature is bob's signature of the task specification. @@ -136,22 +141,27 @@ contract Adjudicator { } bytes memory stamp = abi.encodePacked(precomp.lostBytes[4], stampXCoord); - require(SignatureVerifier.verify( - abi.encodePacked(_capsuleBytes, - stamp, - _operatorIdentityEvidence, - precomp.alicesKeyAsAddress, - bytes32(0)), + require( + SignatureVerifier.verify( + abi.encodePacked( + _capsuleBytes, + stamp, + _operatorIdentityEvidence, + precomp.alicesKeyAsAddress, + bytes32(0) + ), abi.encodePacked(_taskSignature, precomp.lostBytes[3]), _requesterPublicKey, - hashAlgorithm), - "Specification signature is invalid" + hashAlgorithm + ), + "Specification signature is invalid" ); // 4. Extract operator address from stamp signature. address operator = SignatureVerifier.recover( SignatureVerifier.hashEIP191(stamp, bytes1(0x45)), // Currently, we use version E (0x45) of EIP191 signatures - _operatorIdentityEvidence); + _operatorIdentityEvidence + ); address stakingProvider = application.stakingProviderFromOperator(operator); require(stakingProvider != address(0), "Operator must be associated with a provider"); @@ -168,18 +178,20 @@ contract Adjudicator { } /** - * @notice Calculate penalty to the staking provider - * @param _stakingProvider Staking provider address - * @param _stakingProviderValue Amount of tokens that belong to the staking provider - */ - function calculatePenalty(address _stakingProvider, uint96 _stakingProviderValue) - internal returns (uint96) - { - uint256 penalty = basePenalty + penaltyHistoryCoefficient * penaltyHistory[_stakingProvider]; + * @notice Calculate penalty to the staking provider + * @param _stakingProvider Staking provider address + * @param _stakingProviderValue Amount of tokens that belong to the staking provider + */ + function calculatePenalty( + address _stakingProvider, + uint96 _stakingProviderValue + ) internal returns (uint96) { + uint256 penalty = basePenalty + + penaltyHistoryCoefficient * + penaltyHistory[_stakingProvider]; penalty = Math.min(penalty, _stakingProviderValue / percentagePenaltyCoefficient); // TODO add maximum condition or other overflow protection or other penalty condition (#305?) penaltyHistory[_stakingProvider] = penaltyHistory[_stakingProvider] + 1; return penalty.toUint96(); } - } diff --git a/contracts/contracts/IStakingEscrow.sol b/contracts/contracts/IStakingEscrow.sol index 86896fdb..ad83337a 100644 --- a/contracts/contracts/IStakingEscrow.sol +++ b/contracts/contracts/IStakingEscrow.sol @@ -5,22 +5,39 @@ pragma solidity ^0.8.0; import "./NuCypherToken.sol"; interface IStakingEscrow { + function depositFromWorkLock(address, uint256, uint16) external; + + function setWorkMeasurement(address, bool) external returns (uint256); + + function setSnapshots(bool _enableSnapshots) external; + + function withdraw(uint256 _value) external; + + function slashStaker(address, uint256, address, uint256) external; + function token() external view returns (NuCypherToken); + function secondsPerPeriod() external view returns (uint32); + function stakerFromWorker(address) external view returns (address); + function getAllTokens(address) external view returns (uint256); - function slashStaker(address, uint256, address, uint256) external; + function genesisSecondsPerPeriod() external view returns (uint32); + function getPastDowntimeLength(address) external view returns (uint256); + function findIndexOfPastDowntime(address, uint16) external view returns (uint256); + function getPastDowntime(address, uint256) external view returns (uint16, uint16); + function getLastCommittedPeriod(address) external view returns (uint16); + function minLockedPeriods() external view returns (uint16); + function maxAllowableLockedTokens() external view returns (uint256); + function minAllowableLockedTokens() external view returns (uint256); + function getCompletedWork(address) external view returns (uint256); - function depositFromWorkLock(address, uint256, uint16) external; - function setWorkMeasurement(address, bool) external returns (uint256); - function setSnapshots(bool _enableSnapshots) external; - function withdraw(uint256 _value) external; } diff --git a/contracts/contracts/TACoApplication.sol b/contracts/contracts/TACoApplication.sol index 952fde43..bc4525b7 100644 --- a/contracts/contracts/TACoApplication.sol +++ b/contracts/contracts/TACoApplication.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.0; - import "@openzeppelin/contracts/utils/math/Math.sol"; import "@openzeppelin/contracts/utils/math/SafeCast.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; @@ -12,92 +11,115 @@ import "@threshold/contracts/staking/IApplication.sol"; import "@threshold/contracts/staking/IStaking.sol"; import "./coordination/IUpdatableStakeInfo.sol"; - /** -* @title TACo Application -* @notice Contract distributes rewards for participating in app and slashes for violating rules -*/ + * @title TACo Application + * @notice Contract distributes rewards for participating in app and slashes for violating rules + */ contract TACoApplication is IApplication, OwnableUpgradeable { - using SafeERC20 for IERC20; using SafeCast for uint256; /** - * @notice Signals that distributor role was set - * @param distributor Address of reward distributor - */ + * @notice Signals that distributor role was set + * @param distributor Address of reward distributor + */ event RewardDistributorSet(address indexed distributor); /** - * @notice Signals that reward was added - * @param reward Amount of reward - */ + * @notice Signals that reward was added + * @param reward Amount of reward + */ event RewardAdded(uint256 reward); /** - * @notice Signals that the beneficiary related to the staking provider received reward - * @param stakingProvider Staking provider address - * @param beneficiary Beneficiary address - * @param reward Amount of reward - */ + * @notice Signals that the beneficiary related to the staking provider received reward + * @param stakingProvider Staking provider address + * @param beneficiary Beneficiary address + * @param reward Amount of reward + */ event RewardPaid(address indexed stakingProvider, address indexed beneficiary, uint256 reward); /** - * @notice Signals that authorization was increased for the staking provider - * @param stakingProvider Staking provider address - * @param fromAmount Previous amount of increased authorization - * @param toAmount New amount of increased authorization - */ - event AuthorizationIncreased(address indexed stakingProvider, uint96 fromAmount, uint96 toAmount); + * @notice Signals that authorization was increased for the staking provider + * @param stakingProvider Staking provider address + * @param fromAmount Previous amount of increased authorization + * @param toAmount New amount of increased authorization + */ + event AuthorizationIncreased( + address indexed stakingProvider, + uint96 fromAmount, + uint96 toAmount + ); /** - * @notice Signals that authorization was decreased involuntary - * @param stakingProvider Staking provider address - * @param fromAmount Previous amount of authorized tokens - * @param toAmount Amount of authorized tokens to decrease - */ - event AuthorizationInvoluntaryDecreased(address indexed stakingProvider, uint96 fromAmount, uint96 toAmount); + * @notice Signals that authorization was decreased involuntary + * @param stakingProvider Staking provider address + * @param fromAmount Previous amount of authorized tokens + * @param toAmount Amount of authorized tokens to decrease + */ + event AuthorizationInvoluntaryDecreased( + address indexed stakingProvider, + uint96 fromAmount, + uint96 toAmount + ); /** - * @notice Signals that authorization decrease was requested for the staking provider - * @param stakingProvider Staking provider address - * @param fromAmount Current amount of authorized tokens - * @param toAmount Amount of authorization to decrease - */ - event AuthorizationDecreaseRequested(address indexed stakingProvider, uint96 fromAmount, uint96 toAmount); + * @notice Signals that authorization decrease was requested for the staking provider + * @param stakingProvider Staking provider address + * @param fromAmount Current amount of authorized tokens + * @param toAmount Amount of authorization to decrease + */ + event AuthorizationDecreaseRequested( + address indexed stakingProvider, + uint96 fromAmount, + uint96 toAmount + ); /** - * @notice Signals that authorization decrease was approved for the staking provider - * @param stakingProvider Staking provider address - * @param fromAmount Previous amount of authorized tokens - * @param toAmount Decreased amount of authorized tokens - */ - event AuthorizationDecreaseApproved(address indexed stakingProvider, uint96 fromAmount, uint96 toAmount); + * @notice Signals that authorization decrease was approved for the staking provider + * @param stakingProvider Staking provider address + * @param fromAmount Previous amount of authorized tokens + * @param toAmount Decreased amount of authorized tokens + */ + event AuthorizationDecreaseApproved( + address indexed stakingProvider, + uint96 fromAmount, + uint96 toAmount + ); /** - * @notice Signals that authorization was resynchronized - * @param stakingProvider Staking provider address - * @param fromAmount Previous amount of authorized tokens - * @param toAmount Resynchronized amount of authorized tokens - */ - event AuthorizationReSynchronized(address indexed stakingProvider, uint96 fromAmount, uint96 toAmount); + * @notice Signals that authorization was resynchronized + * @param stakingProvider Staking provider address + * @param fromAmount Previous amount of authorized tokens + * @param toAmount Resynchronized amount of authorized tokens + */ + event AuthorizationReSynchronized( + address indexed stakingProvider, + uint96 fromAmount, + uint96 toAmount + ); /** - * @notice Signals that the staking provider was slashed - * @param stakingProvider Staking provider address - * @param penalty Slashing penalty - * @param investigator Investigator address - * @param reward Value of reward provided to investigator (in units of T) - */ - event Slashed(address indexed stakingProvider, uint256 penalty, address indexed investigator, uint256 reward); + * @notice Signals that the staking provider was slashed + * @param stakingProvider Staking provider address + * @param penalty Slashing penalty + * @param investigator Investigator address + * @param reward Value of reward provided to investigator (in units of T) + */ + event Slashed( + address indexed stakingProvider, + uint256 penalty, + address indexed investigator, + uint256 reward + ); /** - * @notice Signals that an operator was bonded to the staking provider - * @param stakingProvider Staking provider address - * @param operator Operator address - * @param previousOperator Previous operator address - * @param startTimestamp Timestamp bonding occurred - */ + * @notice Signals that an operator was bonded to the staking provider + * @param stakingProvider Staking provider address + * @param operator Operator address + * @param previousOperator Previous operator address + * @param startTimestamp Timestamp bonding occurred + */ event OperatorBonded( address indexed stakingProvider, address indexed operator, @@ -106,21 +128,19 @@ contract TACoApplication is IApplication, OwnableUpgradeable { ); /** - * @notice Signals that an operator address is confirmed - * @param stakingProvider Staking provider address - * @param operator Operator address - */ + * @notice Signals that an operator address is confirmed + * @param stakingProvider Staking provider address + * @param operator Operator address + */ event OperatorConfirmed(address indexed stakingProvider, address indexed operator); struct StakingProviderInfo { address operator; bool operatorConfirmed; uint64 operatorStartTimestamp; - uint96 authorized; uint96 deauthorizing; // TODO real usage only in getActiveStakingProviders, maybe remove? uint64 endDeauthorization; - uint96 tReward; uint96 rewardPerTokenPaid; } @@ -132,11 +152,11 @@ contract TACoApplication is IApplication, OwnableUpgradeable { IStaking public immutable tStaking; IERC20 public immutable token; - + IUpdatableStakeInfo public updatableStakeInfo; address public adjudicator; - mapping (address => StakingProviderInfo) public stakingProviderInfo; + mapping(address => StakingProviderInfo) public stakingProviderInfo; address[] public stakingProviders; mapping(address => address) internal _stakingProviderFromOperator; @@ -148,14 +168,14 @@ contract TACoApplication is IApplication, OwnableUpgradeable { uint96 public authorizedOverall; /** - * @notice Constructor sets address of token contract and parameters for staking - * @param _token T token contract - * @param _tStaking T token staking contract - * @param _minimumAuthorization Amount of minimum allowable authorization - * @param _minOperatorSeconds Min amount of seconds while an operator can't be changed - * @param _rewardDuration Duration of one reward cycle in seconds - * @param _deauthorizationDuration Duration of decreasing authorization in seconds - */ + * @notice Constructor sets address of token contract and parameters for staking + * @param _token T token contract + * @param _tStaking T token staking contract + * @param _minimumAuthorization Amount of minimum allowable authorization + * @param _minOperatorSeconds Min amount of seconds while an operator can't be changed + * @param _rewardDuration Duration of one reward cycle in seconds + * @param _deauthorizationDuration Duration of decreasing authorization in seconds + */ constructor( IERC20 _token, IStaking _tStaking, @@ -166,8 +186,8 @@ contract TACoApplication is IApplication, OwnableUpgradeable { ) { require( _rewardDuration != 0 && - _tStaking.authorizedStake(address(this), address(this)) == 0 && - _token.totalSupply() > 0, + _tStaking.authorizedStake(address(this), address(this)) == 0 && + _token.totalSupply() > 0, "Wrong input parameters" ); rewardDuration = _rewardDuration; @@ -180,30 +200,28 @@ contract TACoApplication is IApplication, OwnableUpgradeable { } /** - * @dev Update reward for the specified staking provider - */ + * @dev Update reward for the specified staking provider + */ modifier updateReward(address _stakingProvider) { updateRewardInternal(_stakingProvider); _; } /** - * @dev Checks caller is T staking contract - */ - modifier onlyStakingContract() - { + * @dev Checks caller is T staking contract + */ + modifier onlyStakingContract() { require(msg.sender == address(tStaking), "Caller must be the T staking contract"); _; } /** - * @dev Checks caller is a staking provider or stake owner - */ - modifier onlyOwnerOrStakingProvider(address _stakingProvider) - { + * @dev Checks caller is a staking provider or stake owner + */ + modifier onlyOwnerOrStakingProvider(address _stakingProvider) { require(isAuthorized(_stakingProvider), "Not owner or provider"); if (_stakingProvider != msg.sender) { - (address owner,,) = tStaking.rolesOf(_stakingProvider); + (address owner, , ) = tStaking.rolesOf(_stakingProvider); require(owner == msg.sender, "Not owner or provider"); } _; @@ -220,7 +238,10 @@ contract TACoApplication is IApplication, OwnableUpgradeable { * @notice Set contract for multi-chain interactions */ function setUpdatableStakeInfo(IUpdatableStakeInfo _updatableStakeInfo) external onlyOwner { - require(address(_updatableStakeInfo) != address(updatableStakeInfo), "New address must not be equal to the current one"); + require( + address(_updatableStakeInfo) != address(updatableStakeInfo), + "New address must not be equal to the current one" + ); if (address(_updatableStakeInfo) != address(0)) { // trying to call contract to be sure that is correct address _updatableStakeInfo.updateOperator(address(0), address(0)); @@ -232,27 +253,27 @@ contract TACoApplication is IApplication, OwnableUpgradeable { * @notice Set adjudicator contract. If zero then slashing is disabled */ function setAdjudicator(address _adjudicator) external onlyOwner { - require(address(_adjudicator) != address(adjudicator), "New address must not be equal to the current one"); + require( + address(_adjudicator) != address(adjudicator), + "New address must not be equal to the current one" + ); adjudicator = _adjudicator; } //------------------------Reward------------------------------ /** - * @notice Set reward distributor address - */ - function setRewardDistributor(address _rewardDistributor) - external - onlyOwner - { + * @notice Set reward distributor address + */ + function setRewardDistributor(address _rewardDistributor) external onlyOwner { rewardDistributor = _rewardDistributor; emit RewardDistributorSet(_rewardDistributor); } /** - * @notice Update reward for the specified staking provider - * @param _stakingProvider Staking provider address - */ + * @notice Update reward for the specified staking provider + * @param _stakingProvider Staking provider address + */ function updateRewardInternal(address _stakingProvider) internal { rewardPerTokenStored = rewardPerToken(); lastUpdateTime = lastTimeRewardApplicable(); @@ -264,51 +285,49 @@ contract TACoApplication is IApplication, OwnableUpgradeable { } /** - * @notice Returns last time when reward was applicable - */ + * @notice Returns last time when reward was applicable + */ function lastTimeRewardApplicable() public view returns (uint256) { return Math.min(block.timestamp, periodFinish); } /** - * @notice Returns current value of reward per token - */ + * @notice Returns current value of reward per token + */ function rewardPerToken() public view returns (uint96) { if (authorizedOverall == 0) { return rewardPerTokenStored; } uint256 result = rewardPerTokenStored + - (lastTimeRewardApplicable() - lastUpdateTime) - * rewardRateDecimals - / authorizedOverall; + ((lastTimeRewardApplicable() - lastUpdateTime) * rewardRateDecimals) / + authorizedOverall; return result.toUint96(); } /** - * @notice Returns amount of reward in T units for the staking provider - * @param _stakingProvider Staking provider address - */ + * @notice Returns amount of reward in T units for the staking provider + * @param _stakingProvider Staking provider address + */ function availableRewards(address _stakingProvider) public view returns (uint96) { StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider]; if (!info.operatorConfirmed) { return info.tReward; } - uint256 result = uint256(info.authorized) * - (rewardPerToken() - info.rewardPerTokenPaid) - / 1e18 - + info.tReward; + uint256 result = (uint256(info.authorized) * (rewardPerToken() - info.rewardPerTokenPaid)) / + 1e18 + + info.tReward; return result.toUint96(); } /** - * @notice Transfer reward for the next period. Can be called only by distributor - * @param _reward Amount of reward - */ + * @notice Transfer reward for the next period. Can be called only by distributor + * @param _reward Amount of reward + */ function pushReward(uint96 _reward) external updateReward(address(0)) { require(msg.sender == rewardDistributor, "Only distributor can push rewards"); require(_reward > 0, "Reward must be specified"); if (block.timestamp >= periodFinish) { - rewardRateDecimals = uint256(_reward) * 1e18 / rewardDuration; + rewardRateDecimals = (uint256(_reward) * 1e18) / rewardDuration; } else { uint256 remaining = periodFinish - block.timestamp; uint256 leftover = remaining * rewardRateDecimals; @@ -321,9 +340,9 @@ contract TACoApplication is IApplication, OwnableUpgradeable { } /** - * @notice Withdraw available amount of T reward to beneficiary. Can be called only by beneficiary - * @param _stakingProvider Staking provider address - */ + * @notice Withdraw available amount of T reward to beneficiary. Can be called only by beneficiary + * @param _stakingProvider Staking provider address + */ function withdrawRewards(address _stakingProvider) external updateReward(_stakingProvider) { address beneficiary = getBeneficiary(_stakingProvider); require(msg.sender == beneficiary, "Caller must be beneficiary"); @@ -338,34 +357,38 @@ contract TACoApplication is IApplication, OwnableUpgradeable { //------------------------Authorization------------------------------ /** - * @notice Recalculate `authorizedOverall` if desync happened - */ - function resynchronizeAuthorizedOverall(StakingProviderInfo storage _info, uint96 _properAmount) internal { + * @notice Recalculate `authorizedOverall` if desync happened + */ + function resynchronizeAuthorizedOverall( + StakingProviderInfo storage _info, + uint96 _properAmount + ) internal { if (_info.authorized != _properAmount) { authorizedOverall -= _info.authorized - _properAmount; } } /** - * @notice Recalculate reward and save increased authorization. Can be called only by staking contract - * @param _stakingProvider Address of staking provider - * @param _fromAmount Amount of previously authorized tokens to TACo application by staking provider - * @param _toAmount Amount of authorized tokens to TACo application by staking provider - */ + * @notice Recalculate reward and save increased authorization. Can be called only by staking contract + * @param _stakingProvider Address of staking provider + * @param _fromAmount Amount of previously authorized tokens to TACo application by staking provider + * @param _toAmount Amount of authorized tokens to TACo application by staking provider + */ function authorizationIncreased( address _stakingProvider, uint96 _fromAmount, uint96 _toAmount - ) - external override onlyStakingContract updateReward(_stakingProvider) - { - require(_stakingProvider != address(0) && _toAmount > 0, "Input parameters must be specified"); + ) external override onlyStakingContract updateReward(_stakingProvider) { + require( + _stakingProvider != address(0) && _toAmount > 0, + "Input parameters must be specified" + ); require(_toAmount >= minimumAuthorization, "Authorization must be greater than minimum"); StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider]; require( _stakingProviderFromOperator[_stakingProvider] == address(0) || - _stakingProviderFromOperator[_stakingProvider] == _stakingProvider, + _stakingProviderFromOperator[_stakingProvider] == _stakingProvider, "A provider can't be an operator for another provider" ); @@ -380,18 +403,16 @@ contract TACoApplication is IApplication, OwnableUpgradeable { } /** - * @notice Immediately decrease authorization. Can be called only by staking contract - * @param _stakingProvider Address of staking provider - * @param _fromAmount Previous amount of authorized tokens - * @param _toAmount Amount of authorized tokens to decrease - */ + * @notice Immediately decrease authorization. Can be called only by staking contract + * @param _stakingProvider Address of staking provider + * @param _fromAmount Previous amount of authorized tokens + * @param _toAmount Amount of authorized tokens to decrease + */ function involuntaryAuthorizationDecrease( address _stakingProvider, uint96 _fromAmount, uint96 _toAmount - ) - external override onlyStakingContract updateReward(_stakingProvider) - { + ) external override onlyStakingContract updateReward(_stakingProvider) { StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider]; if (info.operatorConfirmed) { resynchronizeAuthorizedOverall(info, _fromAmount); @@ -413,18 +434,16 @@ contract TACoApplication is IApplication, OwnableUpgradeable { } /** - * @notice Register request of decreasing authorization. Can be called only by staking contract - * @param _stakingProvider Address of staking provider - * @param _fromAmount Current amount of authorized tokens - * @param _toAmount Amount of authorized tokens to decrease - */ + * @notice Register request of decreasing authorization. Can be called only by staking contract + * @param _stakingProvider Address of staking provider + * @param _fromAmount Current amount of authorized tokens + * @param _toAmount Amount of authorized tokens to decrease + */ function authorizationDecreaseRequested( address _stakingProvider, uint96 _fromAmount, uint96 _toAmount - ) - external override onlyStakingContract updateReward(_stakingProvider) - { + ) external override onlyStakingContract updateReward(_stakingProvider) { StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider]; require(_toAmount <= info.authorized, "Amount to decrease greater than authorized"); require( @@ -443,13 +462,18 @@ contract TACoApplication is IApplication, OwnableUpgradeable { } /** - * @notice Approve request of decreasing authorization. Can be called by anyone - * @param _stakingProvider Address of staking provider - */ - function finishAuthorizationDecrease(address _stakingProvider) external updateReward(_stakingProvider) { + * @notice Approve request of decreasing authorization. Can be called by anyone + * @param _stakingProvider Address of staking provider + */ + function finishAuthorizationDecrease( + address _stakingProvider + ) external updateReward(_stakingProvider) { StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider]; require(info.deauthorizing > 0, "There is no deauthorizing in process"); - require(info.endDeauthorization <= block.timestamp, "Authorization decrease has not finished yet"); + require( + info.endDeauthorization <= block.timestamp, + "Authorization decrease has not finished yet" + ); uint96 toAmount = tStaking.approveAuthorizationDecrease(_stakingProvider); @@ -471,10 +495,12 @@ contract TACoApplication is IApplication, OwnableUpgradeable { } /** - * @notice Read authorization from staking contract and store it. Can be called by anyone - * @param _stakingProvider Address of staking provider - */ - function resynchronizeAuthorization(address _stakingProvider) external updateReward(_stakingProvider) { + * @notice Read authorization from staking contract and store it. Can be called by anyone + * @param _stakingProvider Address of staking provider + */ + function resynchronizeAuthorization( + address _stakingProvider + ) external updateReward(_stakingProvider) { StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider]; uint96 newAuthorized = tStaking.authorizedStake(_stakingProvider, address(this)); require(info.authorized > newAuthorized, "Nothing to synchronize"); @@ -499,45 +525,52 @@ contract TACoApplication is IApplication, OwnableUpgradeable { //-------------------------Main------------------------- /** - * @notice Returns staking provider for specified operator - */ + * @notice Returns staking provider for specified operator + */ function stakingProviderFromOperator(address _operator) public view returns (address) { return _stakingProviderFromOperator[_operator]; } /** - * @notice Returns operator for specified staking provider - */ - function getOperatorFromStakingProvider(address _stakingProvider) public view returns (address) { + * @notice Returns operator for specified staking provider + */ + function getOperatorFromStakingProvider( + address _stakingProvider + ) public view returns (address) { return stakingProviderInfo[_stakingProvider].operator; } /** - * @notice Get all tokens delegated to the staking provider - */ + * @notice Get all tokens delegated to the staking provider + */ function authorizedStake(address _stakingProvider) public view returns (uint96) { return stakingProviderInfo[_stakingProvider].authorized; } /** - * @notice Get all tokens delegated to the staking provider - */ + * @notice Get all tokens delegated to the staking provider + */ function getEligibleAmount(StakingProviderInfo storage _info) internal view returns (uint96) { return _info.authorized - _info.deauthorizing; } /** - * @notice Get the value of authorized tokens for active providers as well as providers and their authorized tokens - * @param _startIndex Start index for looking in providers array - * @param _maxStakingProviders Max providers for looking, if set 0 then all will be used - * @return allAuthorizedTokens Sum of authorized tokens for active providers - * @return activeStakingProviders Array of providers and their authorized tokens. - * Providers addresses stored as uint256 - * @dev Note that activeStakingProviders[0] is an array of uint256, but you want addresses. - * Careful when used directly! - */ - function getActiveStakingProviders(uint256 _startIndex, uint256 _maxStakingProviders) - external view returns (uint256 allAuthorizedTokens, uint256[2][] memory activeStakingProviders) + * @notice Get the value of authorized tokens for active providers as well as providers and their authorized tokens + * @param _startIndex Start index for looking in providers array + * @param _maxStakingProviders Max providers for looking, if set 0 then all will be used + * @return allAuthorizedTokens Sum of authorized tokens for active providers + * @return activeStakingProviders Array of providers and their authorized tokens. + * Providers addresses stored as uint256 + * @dev Note that activeStakingProviders[0] is an array of uint256, but you want addresses. + * Careful when used directly! + */ + function getActiveStakingProviders( + uint256 _startIndex, + uint256 _maxStakingProviders + ) + external + view + returns (uint256 allAuthorizedTokens, uint256[2][] memory activeStakingProviders) { uint256 endIndex = stakingProviders.length; require(_startIndex < endIndex, "Wrong start index"); @@ -565,22 +598,24 @@ contract TACoApplication is IApplication, OwnableUpgradeable { } /** - * @notice Returns beneficiary related to the staking provider - */ - function getBeneficiary(address _stakingProvider) public view returns (address payable beneficiary) { - (, beneficiary,) = tStaking.rolesOf(_stakingProvider); + * @notice Returns beneficiary related to the staking provider + */ + function getBeneficiary( + address _stakingProvider + ) public view returns (address payable beneficiary) { + (, beneficiary, ) = tStaking.rolesOf(_stakingProvider); } /** - * @notice Returns true if staking provider has authorized stake to this application - */ + * @notice Returns true if staking provider has authorized stake to this application + */ function isAuthorized(address _stakingProvider) public view returns (bool) { return stakingProviderInfo[_stakingProvider].authorized > 0; } /** - * @notice Returns true if operator has confirmed address - */ + * @notice Returns true if operator has confirmed address + */ // TODO maybe _stakingProvider instead of _operator as input? function isOperatorConfirmed(address _operator) public view returns (bool) { address stakingProvider = _stakingProviderFromOperator[_operator]; @@ -589,28 +624,32 @@ contract TACoApplication is IApplication, OwnableUpgradeable { } /** - * @notice Return the length of the array of staking providers - */ + * @notice Return the length of the array of staking providers + */ function getStakingProvidersLength() external view returns (uint256) { return stakingProviders.length; } /** - * @notice Bond operator - * @param _stakingProvider Staking provider address - * @param _operator Operator address. Must be an EOA, not a contract address - */ - function bondOperator(address _stakingProvider, address _operator) - external onlyOwnerOrStakingProvider(_stakingProvider) updateReward(_stakingProvider) - { + * @notice Bond operator + * @param _stakingProvider Staking provider address + * @param _operator Operator address. Must be an EOA, not a contract address + */ + function bondOperator( + address _stakingProvider, + address _operator + ) external onlyOwnerOrStakingProvider(_stakingProvider) updateReward(_stakingProvider) { StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider]; address previousOperator = info.operator; - require(_operator != previousOperator, "Specified operator is already bonded with this provider"); + require( + _operator != previousOperator, + "Specified operator is already bonded with this provider" + ); // If this staker had a operator ... if (previousOperator != address(0)) { require( !info.operatorConfirmed || - block.timestamp >= uint256(info.operatorStartTimestamp) + minOperatorSeconds, + block.timestamp >= uint256(info.operatorStartTimestamp) + minOperatorSeconds, "Not enough time passed to change operator" ); // Remove the old relation "operator->stakingProvider" @@ -618,7 +657,10 @@ contract TACoApplication is IApplication, OwnableUpgradeable { } if (_operator != address(0)) { - require(_stakingProviderFromOperator[_operator] == address(0), "Specified operator is already in use"); + require( + _stakingProviderFromOperator[_operator] == address(0), + "Specified operator is already in use" + ); require( _operator == _stakingProvider || getBeneficiary(_operator) == address(0), "Specified operator is a provider" @@ -643,13 +685,14 @@ contract TACoApplication is IApplication, OwnableUpgradeable { } /** - * @notice Make a confirmation by operator - */ + * @notice Make a confirmation by operator + */ function confirmOperatorAddress() external { address stakingProvider = _stakingProviderFromOperator[msg.sender]; require(isAuthorized(stakingProvider), "No stake associated with the operator"); StakingProviderInfo storage info = stakingProviderInfo[stakingProvider]; require(!info.operatorConfirmed, "Operator address is already confirmed"); + // solhint-disable-next-line avoid-tx-origin require(msg.sender == tx.origin, "Only operator with real address can make a confirmation"); updateRewardInternal(stakingProvider); @@ -661,12 +704,12 @@ contract TACoApplication is IApplication, OwnableUpgradeable { updatableStakeInfo.updateOperator(stakingProvider, msg.sender); } } - + //-------------------------XChain------------------------- /** - * @notice Resets operator confirmation - */ + * @notice Resets operator confirmation + */ function _releaseOperator(address _stakingProvider) internal { stakingProviderInfo[_stakingProvider].operatorConfirmed = false; if (address(updatableStakeInfo) != address(0)) { @@ -675,9 +718,12 @@ contract TACoApplication is IApplication, OwnableUpgradeable { } /** - * @notice Send updated authorized amount to xchain contract - */ - function _updateAuthorization(address _stakingProvider, StakingProviderInfo storage _info) internal { + * @notice Send updated authorized amount to xchain contract + */ + function _updateAuthorization( + address _stakingProvider, + StakingProviderInfo storage _info + ) internal { if (address(updatableStakeInfo) != address(0)) { // TODO send both authorized and eligible amounts in case of slashing from StakeInfo uint96 eligibleAmount = getEligibleAmount(_info); @@ -687,22 +733,15 @@ contract TACoApplication is IApplication, OwnableUpgradeable { //-------------------------Slashing------------------------- /** - * @notice Slash the provider's stake and reward the investigator - * @param _stakingProvider Staking provider address - * @param _penalty Penalty - * @param _investigator Investigator - */ - function slash( - address _stakingProvider, - uint96 _penalty, - address _investigator - ) - external - { + * @notice Slash the provider's stake and reward the investigator + * @param _stakingProvider Staking provider address + * @param _penalty Penalty + * @param _investigator Investigator + */ + function slash(address _stakingProvider, uint96 _penalty, address _investigator) external { require(msg.sender == adjudicator, "Only adjudicator allowed to slash"); address[] memory stakingProviderWrapper = new address[](1); stakingProviderWrapper[0] = _stakingProvider; tStaking.seize(_penalty, 100, _investigator, stakingProviderWrapper); } - } diff --git a/contracts/contracts/TestnetThresholdStaking.sol b/contracts/contracts/TestnetThresholdStaking.sol index 22ac6c5f..eef66099 100644 --- a/contracts/contracts/TestnetThresholdStaking.sol +++ b/contracts/contracts/TestnetThresholdStaking.sol @@ -2,13 +2,10 @@ pragma solidity ^0.8.0; - import "@threshold/contracts/staking/IApplication.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; - contract TestnetThresholdStaking is Ownable { - struct StakingProviderInfo { address owner; address payable beneficiary; @@ -20,7 +17,7 @@ contract TestnetThresholdStaking is Ownable { IApplication public application; - mapping (address => StakingProviderInfo) public stakingProviderInfo; + mapping(address => StakingProviderInfo) public stakingProviderInfo; function setApplication(IApplication _application) external onlyOwner { application = _application; @@ -35,9 +32,7 @@ contract TestnetThresholdStaking is Ownable { address _owner, address payable _beneficiary, address _authorizer - ) - external onlyOwner - { + ) external onlyOwner { StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider]; info.owner = _owner; info.beneficiary = _beneficiary; @@ -45,9 +40,9 @@ contract TestnetThresholdStaking is Ownable { } /** - * @dev If the function is called with only the _stakingProvider parameter, - * we presume that the caller wants that address set for the other roles as well. - */ + * @dev If the function is called with only the _stakingProvider parameter, + * we presume that the caller wants that address set for the other roles as well. + */ function setRoles(address _stakingProvider) external onlyOwner { StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider]; info.owner = _stakingProvider; @@ -60,35 +55,32 @@ contract TestnetThresholdStaking is Ownable { uint96 _tStake, uint96 _keepInTStake, uint96 _nuInTStake - ) - external onlyOwner - { + ) external onlyOwner { StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider]; info.tStake = _tStake; info.keepInTStake = _keepInTStake; info.nuInTStake = _nuInTStake; } - function authorizedStake(address _stakingProvider, address _application) external view returns (uint96) { + function authorizedStake( + address /* _stakingProvider */, + address /* _application */ + ) external view returns (uint96) { return 0; } - function stakes(address _stakingProvider) external view returns ( - uint96 tStake, - uint96 keepInTStake, - uint96 nuInTStake - ) { + function stakes( + address _stakingProvider + ) external view returns (uint96 tStake, uint96 keepInTStake, uint96 nuInTStake) { StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider]; tStake = info.tStake; keepInTStake = info.keepInTStake; nuInTStake = info.nuInTStake; } - function rolesOf(address _stakingProvider) external view returns ( - address owner, - address payable beneficiary, - address authorizer - ) { + function rolesOf( + address _stakingProvider + ) external view returns (address owner, address payable beneficiary, address authorizer) { StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider]; owner = info.owner; beneficiary = info.beneficiary; diff --git a/contracts/contracts/coordination/Coordinator.sol b/contracts/contracts/coordination/Coordinator.sol index b49a127b..69ec5906 100644 --- a/contracts/contracts/coordination/Coordinator.sol +++ b/contracts/contracts/coordination/Coordinator.sol @@ -12,11 +12,10 @@ import "../../threshold/IAccessControlApplication.sol"; import "./IEncryptionAuthorizer.sol"; /** -* @title Coordinator -* @notice Coordination layer for DKG-TDec -*/ + * @title Coordinator + * @notice Coordination layer for DKG-TDec + */ contract Coordinator is AccessControlDefaultAdminRules { - // Ritual event StartRitual(uint32 indexed ritualId, address indexed authority, address[] participants); event StartAggregationRound(uint32 indexed ritualId); @@ -25,13 +24,21 @@ contract Coordinator is AccessControlDefaultAdminRules { // Node event TranscriptPosted(uint32 indexed ritualId, address indexed node, bytes32 transcriptDigest); - event AggregationPosted(uint32 indexed ritualId, address indexed node, bytes32 aggregatedTranscriptDigest); + event AggregationPosted( + uint32 indexed ritualId, + address indexed node, + bytes32 aggregatedTranscriptDigest + ); // Admin event TimeoutChanged(uint32 oldTimeout, uint32 newTimeout); event MaxDkgSizeChanged(uint16 oldSize, uint16 newSize); - event ParticipantPublicKeySet(uint32 indexed ritualId, address indexed participant, BLS12381.G2Point publicKey); + event ParticipantPublicKeySet( + uint32 indexed ritualId, + address indexed participant, + BLS12381.G2Point publicKey + ); enum RitualState { NON_INITIATED, @@ -45,7 +52,7 @@ contract Coordinator is AccessControlDefaultAdminRules { struct Participant { address provider; bool aggregated; - bytes transcript; // TODO: Consider event processing complexity vs storage cost + bytes transcript; // TODO: Consider event processing complexity vs storage cost bytes decryptionRequestStaticKey; } @@ -74,7 +81,7 @@ contract Coordinator is AccessControlDefaultAdminRules { bytes32 public constant INITIATOR_ROLE = keccak256("INITIATOR_ROLE"); - mapping(address => ParticipantKey[]) keysHistory; + mapping(address => ParticipantKey[]) internal keysHistory; IAccessControlApplication public immutable application; @@ -82,8 +89,8 @@ contract Coordinator is AccessControlDefaultAdminRules { uint32 public timeout; uint16 public maxDkgSize; bool public isInitiationPublic; - IFeeModel feeModel; // TODO: Consider making feeModel specific to each ritual - IReimbursementPool reimbursementPool; + IFeeModel internal feeModel; // TODO: Consider making feeModel specific to each ritual + IReimbursementPool internal reimbursementPool; uint256 public totalPendingFees; mapping(uint256 => uint256) public pendingFees; @@ -93,8 +100,7 @@ contract Coordinator is AccessControlDefaultAdminRules { uint16 _maxDkgSize, address _admin, IFeeModel _feeModel - ) AccessControlDefaultAdminRules(0, _admin) - { + ) AccessControlDefaultAdminRules(0, _admin) { require(address(_feeModel.stakes()) == address(_stakes), "Invalid stakes for fee model"); application = _stakes; timeout = _timeout; @@ -102,16 +108,16 @@ contract Coordinator is AccessControlDefaultAdminRules { feeModel = IFeeModel(_feeModel); } - function getRitualState(uint32 ritualId) external view returns (RitualState){ + function getRitualState(uint32 ritualId) external view returns (RitualState) { // TODO: restrict to ritualId < rituals.length? return getRitualState(rituals[ritualId]); } - function isRitualFinalized(uint32 ritualId) external view returns (bool){ + function isRitualFinalized(uint32 ritualId) external view returns (bool) { return getRitualState(rituals[ritualId]) == RitualState.FINALIZED; } - function getRitualState(Ritual storage ritual) internal view returns (RitualState){ + function getRitualState(Ritual storage ritual) internal view returns (RitualState) { uint32 t0 = ritual.initTimestamp; uint32 deadline = t0 + timeout; if (t0 == 0) { @@ -126,6 +132,7 @@ contract Coordinator is AccessControlDefaultAdminRules { return RitualState.AWAITING_TRANSCRIPTS; } else if (ritual.totalAggregations < ritual.dkgSize) { return RitualState.AWAITING_AGGREGATIONS; + // solhint-disable-next-line no-empty-blocks } else { // TODO: Is it possible to reach this state? // - No public key @@ -150,10 +157,13 @@ contract Coordinator is AccessControlDefaultAdminRules { emit ParticipantPublicKeySet(lastRitualId, provider, _publicKey); } - function getProviderPublicKey(address _provider, uint _ritualId) external view returns (BLS12381.G2Point memory) { + function getProviderPublicKey( + address _provider, + uint256 _ritualId + ) external view returns (BLS12381.G2Point memory) { ParticipantKey[] storage participantHistory = keysHistory[_provider]; - for (uint i = participantHistory.length - 1; i >= 0; i--) { + for (uint256 i = participantHistory.length - 1; i >= 0; i--) { if (participantHistory[i].lastRitualId <= _ritualId) { return participantHistory[i].publicKey; } @@ -174,8 +184,7 @@ contract Coordinator is AccessControlDefaultAdminRules { function setReimbursementPool(IReimbursementPool pool) external onlyRole(DEFAULT_ADMIN_ROLE) { require( - address(pool) == address(0) || - pool.isAuthorized(address(this)), + address(pool) == address(0) || pool.isAuthorized(address(this)), "Invalid ReimbursementPool" ); reimbursementPool = pool; @@ -204,7 +213,6 @@ contract Coordinator is AccessControlDefaultAdminRules { uint32 duration, IEncryptionAuthorizer accessController ) external returns (uint32) { - require(authority != address(0), "Invalid authority"); require( @@ -214,7 +222,7 @@ contract Coordinator is AccessControlDefaultAdminRules { // TODO: Validate service fees, expiration dates, threshold uint256 length = providers.length; require(2 <= length && length <= maxDkgSize, "Invalid number of nodes"); - require(duration > 0, "Invalid ritual duration"); // TODO: We probably want to restrict it more + require(duration > 0, "Invalid ritual duration"); // TODO: We probably want to restrict it more uint32 id = uint32(rituals.length); Ritual storage ritual = rituals.push(); @@ -236,10 +244,7 @@ contract Coordinator is AccessControlDefaultAdminRules { require(previous < current, "Providers must be sorted"); // TODO: Improve check for eligible nodes (staking, etc) - nucypher#3109 // TODO: Change check to isAuthorized(), without amount - require( - application.authorizedStake(current) > 0, - "Not enough authorization" - ); + require(application.authorizedStake(current) > 0, "Not enough authorization"); newParticipant.provider = current; previous = current; } @@ -267,20 +272,14 @@ contract Coordinator is AccessControlDefaultAdminRules { address provider = application.stakingProviderFromOperator(msg.sender); Participant storage participant = getParticipantFromProvider(ritual, provider); - require( - application.authorizedStake(provider) > 0, - "Not enough authorization" - ); - require( - participant.transcript.length == 0, - "Node already posted transcript" - ); + require(application.authorizedStake(provider) > 0, "Not enough authorization"); + require(participant.transcript.length == 0, "Node already posted transcript"); // TODO: Validate transcript size based on dkg size // Nodes commit to their transcript bytes32 transcriptDigest = keccak256(transcript); - participant.transcript = transcript; // TODO: ??? + participant.transcript = transcript; // TODO: ??? emit TranscriptPosted(ritualId, provider, transcriptDigest); ritual.totalTranscripts++; @@ -311,15 +310,9 @@ contract Coordinator is AccessControlDefaultAdminRules { address provider = application.stakingProviderFromOperator(msg.sender); Participant storage participant = getParticipantFromProvider(ritual, provider); - require( - application.authorizedStake(provider) > 0, - "Not enough authorization" - ); + require(application.authorizedStake(provider) > 0, "Not enough authorization"); - require( - !participant.aggregated, - "Node already posted aggregation" - ); + require(!participant.aggregated, "Node already posted aggregation"); require( participant.decryptionRequestStaticKey.length == 0, @@ -342,23 +335,17 @@ contract Coordinator is AccessControlDefaultAdminRules { ritual.publicKey = dkgPublicKey; } else if ( !BLS12381.eqG1Point(ritual.publicKey, dkgPublicKey) || - keccak256(ritual.aggregatedTranscript) != aggregatedTranscriptDigest + keccak256(ritual.aggregatedTranscript) != aggregatedTranscriptDigest ) { ritual.aggregationMismatch = true; - emit EndRitual({ - ritualId: ritualId, - successful: false - }); + emit EndRitual({ritualId: ritualId, successful: false}); } if (!ritual.aggregationMismatch) { ritual.totalAggregations++; if (ritual.totalAggregations == ritual.dkgSize) { processPendingFee(ritualId); - emit EndRitual({ - ritualId: ritualId, - successful: true - }); + emit EndRitual({ritualId: ritualId, successful: true}); // TODO: Consider including public key in event } } @@ -370,9 +357,9 @@ contract Coordinator is AccessControlDefaultAdminRules { Ritual storage ritual, address provider ) internal view returns (Participant storage) { - uint length = ritual.participant.length; + uint256 length = ritual.participant.length; // TODO: Improve with binary search - for (uint i = 0; i < length; i++) { + for (uint256 i = 0; i < length; i++) { Participant storage participant = ritual.participant[i]; if (participant.provider == provider) { return participant; @@ -388,11 +375,15 @@ contract Coordinator is AccessControlDefaultAdminRules { return getParticipantFromProvider(rituals[ritualId], provider); } - function processRitualPayment(uint32 ritualId, address[] calldata providers, uint32 duration) internal { + function processRitualPayment( + uint32 ritualId, + address[] calldata providers, + uint32 duration + ) internal { uint256 ritualCost = feeModel.getRitualInitiationCost(providers, duration); if (ritualCost > 0) { totalPendingFees += ritualCost; - assert(pendingFees[ritualId] == 0); // TODO: This is an invariant, not sure if actually needed + assert(pendingFees[ritualId] == 0); // TODO: This is an invariant, not sure if actually needed pendingFees[ritualId] += ritualCost; IERC20 currency = IERC20(feeModel.currency()); currency.safeTransferFrom(msg.sender, address(this), ritualCost); @@ -405,8 +396,8 @@ contract Coordinator is AccessControlDefaultAdminRules { RitualState state = getRitualState(ritual); require( state == RitualState.TIMEOUT || - state == RitualState.INVALID || - state == RitualState.FINALIZED, + state == RitualState.INVALID || + state == RitualState.FINALIZED, "Ritual is not ended" ); uint256 pending = pendingFees[ritualId]; @@ -421,7 +412,7 @@ contract Coordinator is AccessControlDefaultAdminRules { // TODO: Validate if this is enough to remove griefing attacks uint256 executedTransactions = ritual.totalTranscripts + ritual.totalAggregations; uint256 expectedTransactions = 2 * ritual.dkgSize; - uint256 consumedFee = pending * executedTransactions / expectedTransactions; + uint256 consumedFee = (pending * executedTransactions) / expectedTransactions; uint256 refundableFee = pending - consumedFee; IERC20 currency = IERC20(feeModel.currency()); currency.transferFrom(address(this), ritual.initiator, refundableFee); @@ -429,7 +420,8 @@ contract Coordinator is AccessControlDefaultAdminRules { } function processReimbursement(uint256 initialGasLeft) internal { - if (address(reimbursementPool) != address(0)) { // TODO: Consider defining a method + if (address(reimbursementPool) != address(0)) { + // TODO: Consider defining a method uint256 gasUsed = initialGasLeft - gasleft(); try reimbursementPool.refund(gasUsed, msg.sender) { return; diff --git a/contracts/contracts/coordination/FlateRateFeeModel.sol b/contracts/contracts/coordination/FlateRateFeeModel.sol index 7f319d7a..5b49eee4 100644 --- a/contracts/contracts/coordination/FlateRateFeeModel.sol +++ b/contracts/contracts/coordination/FlateRateFeeModel.sol @@ -7,16 +7,15 @@ import "../../threshold/IAccessControlApplication.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** -* @title FlatRateFeeModel -* @notice FlateRateFeeModel -*/ + * @title FlatRateFeeModel + * @notice FlateRateFeeModel + */ contract FlatRateFeeModel is IFeeModel { - IERC20 public immutable currency; uint256 public immutable feeRatePerSecond; IAccessControlApplication public immutable stakes; - constructor(IERC20 _currency, uint256 _feeRatePerSecond, address _stakes){ + constructor(IERC20 _currency, uint256 _feeRatePerSecond, address _stakes) { currency = _currency; feeRatePerSecond = _feeRatePerSecond; stakes = IAccessControlApplication(_stakes); @@ -25,7 +24,7 @@ contract FlatRateFeeModel is IFeeModel { function getRitualInitiationCost( address[] calldata providers, uint32 duration - ) external view returns(uint256){ + ) external view returns (uint256) { uint256 size = providers.length; require(duration > 0, "Invalid ritual duration"); require(size > 0, "Invalid ritual size"); diff --git a/contracts/contracts/coordination/GlobalAllowList.sol b/contracts/contracts/coordination/GlobalAllowList.sol index 24da89fd..4813b7f7 100644 --- a/contracts/contracts/coordination/GlobalAllowList.sol +++ b/contracts/contracts/coordination/GlobalAllowList.sol @@ -4,7 +4,6 @@ import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "./IEncryptionAuthorizer.sol"; import "./Coordinator.sol"; - contract GlobalAllowList is AccessControlDefaultAdminRules, IEncryptionAuthorizer { using ECDSA for bytes32; @@ -21,8 +20,10 @@ contract GlobalAllowList is AccessControlDefaultAdminRules, IEncryptionAuthorize } modifier onlyAuthority(uint32 ritualId) { - require(coordinator.getAuthority(ritualId) == msg.sender, - "Only ritual authority is permitted"); + require( + coordinator.getAuthority(ritualId) == msg.sender, + "Only ritual authority is permitted" + ); _; } @@ -35,24 +36,34 @@ contract GlobalAllowList is AccessControlDefaultAdminRules, IEncryptionAuthorize uint32 ritualId, bytes memory evidence, bytes32 digest - ) public view override returns(bool) { - address recovered_address = digest.toEthSignedMessageHash().recover(evidence); - return authorizations[ritualId][recovered_address]; + ) public view override returns (bool) { + address recoveredAddress = digest.toEthSignedMessageHash().recover(evidence); + return authorizations[ritualId][recoveredAddress]; } - function authorize(uint32 ritualId, address[] calldata addresses) public onlyAuthority(ritualId) { - require(coordinator.isRitualFinalized(ritualId), - "Only active rituals can add authorizations"); - for (uint256 i=0; i < addresses.length; i++) { + function authorize( + uint32 ritualId, + address[] calldata addresses + ) public onlyAuthority(ritualId) { + require( + coordinator.isRitualFinalized(ritualId), + "Only active rituals can add authorizations" + ); + for (uint256 i = 0; i < addresses.length; i++) { authorizations[ritualId][addresses[i]] = true; } } - function deauthorize(uint32 ritualId, address[] calldata addresses) public onlyAuthority(ritualId) { - require(coordinator.isRitualFinalized(ritualId), - "Only active rituals can add authorizations"); - for (uint256 i=0; i < addresses.length; i++) { + function deauthorize( + uint32 ritualId, + address[] calldata addresses + ) public onlyAuthority(ritualId) { + require( + coordinator.isRitualFinalized(ritualId), + "Only active rituals can add authorizations" + ); + for (uint256 i = 0; i < addresses.length; i++) { authorizations[ritualId][addresses[i]] = false; } } -} \ No newline at end of file +} diff --git a/contracts/contracts/coordination/IEncryptionAuthorizer.sol b/contracts/contracts/coordination/IEncryptionAuthorizer.sol index dd1a036b..4ff32d40 100644 --- a/contracts/contracts/coordination/IEncryptionAuthorizer.sol +++ b/contracts/contracts/coordination/IEncryptionAuthorizer.sol @@ -4,6 +4,6 @@ interface IEncryptionAuthorizer { function isAuthorized( uint32 ritualID, bytes memory evidence, // signature - bytes32 digest // signed message hash - ) external view returns(bool); + bytes32 digest // signed message hash + ) external view returns (bool); } diff --git a/contracts/contracts/coordination/IFeeModel.sol b/contracts/contracts/coordination/IFeeModel.sol index a9eff90a..5bd319f2 100644 --- a/contracts/contracts/coordination/IFeeModel.sol +++ b/contracts/contracts/coordination/IFeeModel.sol @@ -6,11 +6,16 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../../threshold/IAccessControlApplication.sol"; /** -* @title IFeeModel -* @notice IFeeModel -*/ + * @title IFeeModel + * @notice IFeeModel + */ interface IFeeModel { - function currency() external view returns(IERC20); - function stakes() external view returns(IAccessControlApplication); - function getRitualInitiationCost(address[] calldata providers, uint32 duration) external view returns(uint256); + function currency() external view returns (IERC20); + + function stakes() external view returns (IAccessControlApplication); + + function getRitualInitiationCost( + address[] calldata providers, + uint32 duration + ) external view returns (uint256); } diff --git a/contracts/contracts/coordination/IReimbursementPool.sol b/contracts/contracts/coordination/IReimbursementPool.sol index cd696514..51ef6f07 100644 --- a/contracts/contracts/coordination/IReimbursementPool.sol +++ b/contracts/contracts/coordination/IReimbursementPool.sol @@ -3,10 +3,11 @@ pragma solidity ^0.8.0; /** -* @title IReimbursementPool -* @notice IReimbursementPool -*/ + * @title IReimbursementPool + * @notice IReimbursementPool + */ interface IReimbursementPool { - function isAuthorized(address caller) external view returns(bool); + function isAuthorized(address caller) external view returns (bool); + function refund(uint256 gasSpent, address receiver) external; } diff --git a/contracts/contracts/coordination/IUpdatableStakeInfo.sol b/contracts/contracts/coordination/IUpdatableStakeInfo.sol index 8410b08e..59debac2 100644 --- a/contracts/contracts/coordination/IUpdatableStakeInfo.sol +++ b/contracts/contracts/coordination/IUpdatableStakeInfo.sol @@ -3,11 +3,10 @@ pragma solidity ^0.8.0; /** -* @title IUpdatableStakeInfo -* @notice Interface for x-chain interactions between application and coordinator -*/ + * @title IUpdatableStakeInfo + * @notice Interface for x-chain interactions between application and coordinator + */ interface IUpdatableStakeInfo { - event UpdatedStakeOperator(address indexed stakingProvider, address indexed operator); event UpdatedStakeAmount(address indexed stakingProvider, uint96 amount); diff --git a/contracts/contracts/coordination/StakeInfo.sol b/contracts/contracts/coordination/StakeInfo.sol index 710e5b3c..250f3895 100644 --- a/contracts/contracts/coordination/StakeInfo.sol +++ b/contracts/contracts/coordination/StakeInfo.sol @@ -7,11 +7,10 @@ import "./IUpdatableStakeInfo.sol"; import "../../threshold/IAccessControlApplication.sol"; /** -* @title StakeInfo -* @notice StakeInfo -*/ + * @title StakeInfo + * @notice StakeInfo + */ contract StakeInfo is AccessControl, IUpdatableStakeInfo, IAccessControlApplication { - bytes32 public constant UPDATE_ROLE = keccak256("UPDATE_ROLE"); struct Stake { @@ -20,8 +19,8 @@ contract StakeInfo is AccessControl, IUpdatableStakeInfo, IAccessControlApplicat // TODO: what about undelegations etc? } - constructor(address[] memory updaters){ - for(uint i = 0; i < updaters.length; i++){ + constructor(address[] memory updaters) { + for (uint256 i = 0; i < updaters.length; i++) { _grantRole(UPDATE_ROLE, updaters[i]); } } @@ -29,19 +28,25 @@ contract StakeInfo is AccessControl, IUpdatableStakeInfo, IAccessControlApplicat mapping(address => Stake) public stakes; mapping(address => address) private operatorToProvider; - function stakingProviderFromOperator(address _operator) external view returns (address){ + function stakingProviderFromOperator(address _operator) external view returns (address) { return operatorToProvider[_operator]; } - function authorizedStake(address _stakingProvider) external view returns (uint96){ + function authorizedStake(address _stakingProvider) external view returns (uint96) { return stakes[_stakingProvider].amount; } - function updateOperator(address stakingProvider, address operator) external override onlyRole(UPDATE_ROLE) { + function updateOperator( + address stakingProvider, + address operator + ) external override onlyRole(UPDATE_ROLE) { _updateOperator(stakingProvider, operator); } - function updateAmount(address stakingProvider, uint96 amount) external override onlyRole(UPDATE_ROLE) { + function updateAmount( + address stakingProvider, + uint96 amount + ) external override onlyRole(UPDATE_ROLE) { _updateAmount(stakingProvider, amount); } @@ -49,7 +54,7 @@ contract StakeInfo is AccessControl, IUpdatableStakeInfo, IAccessControlApplicat Stake storage stake = stakes[stakingProvider]; address oldOperator = stake.operator; - if(operator != oldOperator){ + if (operator != oldOperator) { stake.operator = operator; // Update operator to provider mapping operatorToProvider[oldOperator] = address(0); @@ -62,8 +67,8 @@ contract StakeInfo is AccessControl, IUpdatableStakeInfo, IAccessControlApplicat function _updateAmount(address stakingProvider, uint96 amount) internal { Stake storage stake = stakes[stakingProvider]; uint256 oldAmount = stake.amount; - - if(amount != oldAmount){ + + if (amount != oldAmount) { stake.amount = amount; emit UpdatedStakeAmount(stakingProvider, amount); } @@ -71,16 +76,16 @@ contract StakeInfo is AccessControl, IUpdatableStakeInfo, IAccessControlApplicat function batchUpdate(bytes32[] calldata updateInfo) external override onlyRole(UPDATE_ROLE) { require(updateInfo.length % 2 == 0, "bad length"); - for(uint i = 0; i < updateInfo.length; i += 2){ + for (uint256 i = 0; i < updateInfo.length; i += 2) { bytes32 word0 = updateInfo[i]; bytes32 word1 = updateInfo[i + 1]; - + address provider = address(bytes20(word0)); uint96 amount = uint96(uint256(word0)); address operator = address(bytes20(word1)); _updateOperator(provider, operator); - _updateAmount(provider, amount); + _updateAmount(provider, amount); } } } diff --git a/contracts/contracts/lib/BLS12381.sol b/contracts/contracts/lib/BLS12381.sol index 12f29262..d9c092f2 100644 --- a/contracts/contracts/lib/BLS12381.sol +++ b/contracts/contracts/lib/BLS12381.sol @@ -3,10 +3,9 @@ pragma solidity ^0.8.0; /** -* @notice Library for dealing with BLS12-381 entities -*/ + * @notice Library for dealing with BLS12-381 entities + */ library BLS12381 { - uint256 public constant G1_POINT_SIZE = 48; uint256 public constant G2_POINT_SIZE = 96; @@ -24,32 +23,36 @@ library BLS12381 { bytes32 word2; } - function bytesToG1Point(bytes calldata pointBytes) internal pure returns(G1Point memory point){ + function bytesToG1Point( + bytes calldata pointBytes + ) internal pure returns (G1Point memory point) { require(pointBytes.length == G1_POINT_SIZE, "Wrong G1 point size"); point.word0 = bytes32(pointBytes[:32]); point.word1 = bytes16(pointBytes[32:]); } - function bytesToG2Point(bytes calldata pointBytes) internal pure returns(G2Point memory point){ + function bytesToG2Point( + bytes calldata pointBytes + ) internal pure returns (G2Point memory point) { require(pointBytes.length == G2_POINT_SIZE, "Wrong G2 point size"); point.word0 = bytes32(pointBytes[:32]); point.word1 = bytes32(pointBytes[32:64]); point.word2 = bytes32(pointBytes[64:]); } - function g1PointToBytes(G1Point memory point) internal pure returns(bytes memory){ + function g1PointToBytes(G1Point memory point) internal pure returns (bytes memory) { return bytes.concat(point.word0, point.word1); } - function g2PointToBytes(G2Point memory point) internal pure returns(bytes memory){ + function g2PointToBytes(G2Point memory point) internal pure returns (bytes memory) { return bytes.concat(point.word0, point.word1, point.word2); } - function eqG1Point(G1Point memory p0, G1Point memory p1) internal pure returns(bool){ + function eqG1Point(G1Point memory p0, G1Point memory p1) internal pure returns (bool) { return p0.word0 == p1.word0 && p0.word1 == p1.word1; } - function eqG2Point(G2Point memory p0, G2Point memory p1) internal pure returns(bool){ + function eqG2Point(G2Point memory p0, G2Point memory p1) internal pure returns (bool) { return p0.word0 == p1.word0 && p0.word1 == p1.word1 && p0.word2 == p1.word2; } -} \ No newline at end of file +} diff --git a/contracts/contracts/lib/Bits.sol b/contracts/contracts/lib/Bits.sol index 3780bbad..aca7595c 100644 --- a/contracts/contracts/lib/Bits.sol +++ b/contracts/contracts/lib/Bits.sol @@ -3,36 +3,34 @@ pragma solidity ^0.8.0; /** -* @dev Taken from https://github.com/ethereum/solidity-examples/blob/master/src/bits/Bits.sol -*/ + * @dev Taken from https://github.com/ethereum/solidity-examples/blob/master/src/bits/Bits.sol + */ library Bits { - uint256 internal constant ONE = uint256(1); /** - * @notice Sets the bit at the given 'index' in 'self' to: - * '1' - if the bit is '0' - * '0' - if the bit is '1' - * @return The modified value - */ + * @notice Sets the bit at the given 'index' in 'self' to: + * '1' - if the bit is '0' + * '0' - if the bit is '1' + * @return The modified value + */ function toggleBit(uint256 self, uint8 index) internal pure returns (uint256) { - return self ^ ONE << index; + return self ^ (ONE << index); } /** - * @notice Get the value of the bit at the given 'index' in 'self'. - */ + * @notice Get the value of the bit at the given 'index' in 'self'. + */ function bit(uint256 self, uint8 index) internal pure returns (uint8) { - return uint8(self >> index & 1); + return uint8((self >> index) & 1); } /** - * @notice Check if the bit at the given 'index' in 'self' is set. - * @return 'true' - if the value of the bit is '1', - * 'false' - if the value of the bit is '0' - */ + * @notice Check if the bit at the given 'index' in 'self' is set. + * @return 'true' - if the value of the bit is '1', + * 'false' - if the value of the bit is '0' + */ function bitSet(uint256 self, uint8 index) internal pure returns (bool) { - return self >> index & 1 == 1; + return (self >> index) & 1 == 1; } - } diff --git a/contracts/contracts/lib/ReEncryptionValidator.sol b/contracts/contracts/lib/ReEncryptionValidator.sol index 902f06ce..5a6e833c 100644 --- a/contracts/contracts/lib/ReEncryptionValidator.sol +++ b/contracts/contracts/lib/ReEncryptionValidator.sol @@ -6,13 +6,11 @@ import "./UmbralDeserializer.sol"; import "./SignatureVerifier.sol"; /** -* @notice Validates re-encryption correctness. -*/ + * @notice Validates re-encryption correctness. + */ library ReEncryptionValidator { - using UmbralDeserializer for bytes; - //------------------------------// // Umbral-specific constants // //------------------------------// @@ -20,42 +18,45 @@ library ReEncryptionValidator { // See parameter `u` of `UmbralParameters` class in pyUmbral // https://github.com/nucypher/pyUmbral/blob/master/umbral/params.py uint8 public constant UMBRAL_PARAMETER_U_SIGN = 0x02; - uint256 public constant UMBRAL_PARAMETER_U_XCOORD = 0x03c98795773ff1c241fc0b1cced85e80f8366581dda5c9452175ebd41385fa1f; - uint256 public constant UMBRAL_PARAMETER_U_YCOORD = 0x7880ed56962d7c0ae44d6f14bb53b5fe64b31ea44a41d0316f3a598778f0f936; - + uint256 public constant UMBRAL_PARAMETER_U_XCOORD = + 0x03c98795773ff1c241fc0b1cced85e80f8366581dda5c9452175ebd41385fa1f; + uint256 public constant UMBRAL_PARAMETER_U_YCOORD = + 0x7880ed56962d7c0ae44d6f14bb53b5fe64b31ea44a41d0316f3a598778f0f936; //------------------------------// // SECP256K1-specific constants // //------------------------------// // Base field order - uint256 constant FIELD_ORDER = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F; + uint256 internal constant FIELD_ORDER = + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F; // -2 mod FIELD_ORDER - uint256 constant MINUS_2 = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d; + uint256 internal constant MINUS_2 = + 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2d; // (-1/2) mod FIELD_ORDER - uint256 constant MINUS_ONE_HALF = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffe17; - + uint256 internal constant MINUS_ONE_HALF = + 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffe17; + /* solhint-disable var-name-mixedcase */ // /** - * @notice Check correctness of re-encryption - * @param _capsuleBytes Capsule - * @param _cFragBytes Capsule frag - * @param _precomputedBytes Additional precomputed data - */ + * @notice Check correctness of re-encryption + * @param _capsuleBytes Capsule + * @param _cFragBytes Capsule frag + * @param _precomputedBytes Additional precomputed data + */ function validateCFrag( bytes memory _capsuleBytes, bytes memory _cFragBytes, bytes memory _precomputedBytes - ) - internal pure returns (bool) - { + ) internal pure returns (bool) { UmbralDeserializer.Capsule memory _capsule = _capsuleBytes.toCapsule(); UmbralDeserializer.CapsuleFrag memory _cFrag = _cFragBytes.toCapsuleFrag(); - UmbralDeserializer.PreComputedData memory _precomputed = _precomputedBytes.toPreComputedData(); + UmbralDeserializer.PreComputedData memory _precomputed = _precomputedBytes + .toPreComputedData(); // Extract Alice's address and check that it corresponds to the one provided address alicesAddress = SignatureVerifier.recover( @@ -72,64 +73,76 @@ library ReEncryptionValidator { ////// // Input validation: E - require(checkCompressedPoint( - _capsule.pointE.sign, - _capsule.pointE.xCoord, - _precomputed.pointEyCoord), + require( + checkCompressedPoint( + _capsule.pointE.sign, + _capsule.pointE.xCoord, + _precomputed.pointEyCoord + ), "Precomputed Y coordinate of E doesn't correspond to compressed E point" ); // Input validation: z*E - require(isOnCurve(_precomputed.pointEZxCoord, _precomputed.pointEZyCoord), - "Point zE is not a valid EC point" + require( + isOnCurve(_precomputed.pointEZxCoord, _precomputed.pointEZyCoord), + "Point zE is not a valid EC point" ); - require(ecmulVerify( - _capsule.pointE.xCoord, // E_x - _precomputed.pointEyCoord, // E_y - _cFrag.proof.bnSig, // z - _precomputed.pointEZxCoord, // zE_x - _precomputed.pointEZyCoord), // zE_y + require( + ecmulVerify( + _capsule.pointE.xCoord, // E_x + _precomputed.pointEyCoord, // E_y + _cFrag.proof.bnSig, // z + _precomputed.pointEZxCoord, // zE_x + _precomputed.pointEZyCoord + ), // zE_y "Precomputed z*E value is incorrect" ); // Input validation: E1 - require(checkCompressedPoint( - _cFrag.pointE1.sign, // E1_sign - _cFrag.pointE1.xCoord, // E1_x - _precomputed.pointE1yCoord), // E1_y + require( + checkCompressedPoint( + _cFrag.pointE1.sign, // E1_sign + _cFrag.pointE1.xCoord, // E1_x + _precomputed.pointE1yCoord + ), // E1_y "Precomputed Y coordinate of E1 doesn't correspond to compressed E1 point" ); // Input validation: h*E1 - require(isOnCurve(_precomputed.pointE1HxCoord, _precomputed.pointE1HyCoord), - "Point h*E1 is not a valid EC point" + require( + isOnCurve(_precomputed.pointE1HxCoord, _precomputed.pointE1HyCoord), + "Point h*E1 is not a valid EC point" ); - require(ecmulVerify( - _cFrag.pointE1.xCoord, // E1_x - _precomputed.pointE1yCoord, // E1_y - h, - _precomputed.pointE1HxCoord, // hE1_x - _precomputed.pointE1HyCoord), // hE1_y + require( + ecmulVerify( + _cFrag.pointE1.xCoord, // E1_x + _precomputed.pointE1yCoord, // E1_y + h, + _precomputed.pointE1HxCoord, // hE1_x + _precomputed.pointE1HyCoord + ), // hE1_y "Precomputed h*E1 value is incorrect" ); // Input validation: E2 - require(checkCompressedPoint( - _cFrag.proof.pointE2.sign, // E2_sign - _cFrag.proof.pointE2.xCoord, // E2_x - _precomputed.pointE2yCoord), // E2_y + require( + checkCompressedPoint( + _cFrag.proof.pointE2.sign, // E2_sign + _cFrag.proof.pointE2.xCoord, // E2_x + _precomputed.pointE2yCoord + ), // E2_y "Precomputed Y coordinate of E2 doesn't correspond to compressed E2 point" ); bool equation_holds = eqAffineJacobian( - [_precomputed.pointEZxCoord, _precomputed.pointEZyCoord], + [_precomputed.pointEZxCoord, _precomputed.pointEZyCoord], addAffineJacobian( [_cFrag.proof.pointE2.xCoord, _precomputed.pointE2yCoord], [_precomputed.pointE1HxCoord, _precomputed.pointE1HyCoord] ) ); - if (!equation_holds){ + if (!equation_holds) { return false; } @@ -138,64 +151,76 @@ library ReEncryptionValidator { ////// // Input validation: V - require(checkCompressedPoint( - _capsule.pointV.sign, - _capsule.pointV.xCoord, - _precomputed.pointVyCoord), + require( + checkCompressedPoint( + _capsule.pointV.sign, + _capsule.pointV.xCoord, + _precomputed.pointVyCoord + ), "Precomputed Y coordinate of V doesn't correspond to compressed V point" ); // Input validation: z*V - require(isOnCurve(_precomputed.pointVZxCoord, _precomputed.pointVZyCoord), - "Point zV is not a valid EC point" + require( + isOnCurve(_precomputed.pointVZxCoord, _precomputed.pointVZyCoord), + "Point zV is not a valid EC point" ); - require(ecmulVerify( - _capsule.pointV.xCoord, // V_x - _precomputed.pointVyCoord, // V_y - _cFrag.proof.bnSig, // z - _precomputed.pointVZxCoord, // zV_x - _precomputed.pointVZyCoord), // zV_y + require( + ecmulVerify( + _capsule.pointV.xCoord, // V_x + _precomputed.pointVyCoord, // V_y + _cFrag.proof.bnSig, // z + _precomputed.pointVZxCoord, // zV_x + _precomputed.pointVZyCoord + ), // zV_y "Precomputed z*V value is incorrect" ); // Input validation: V1 - require(checkCompressedPoint( - _cFrag.pointV1.sign, // V1_sign - _cFrag.pointV1.xCoord, // V1_x - _precomputed.pointV1yCoord), // V1_y + require( + checkCompressedPoint( + _cFrag.pointV1.sign, // V1_sign + _cFrag.pointV1.xCoord, // V1_x + _precomputed.pointV1yCoord + ), // V1_y "Precomputed Y coordinate of V1 doesn't correspond to compressed V1 point" ); // Input validation: h*V1 - require(isOnCurve(_precomputed.pointV1HxCoord, _precomputed.pointV1HyCoord), + require( + isOnCurve(_precomputed.pointV1HxCoord, _precomputed.pointV1HyCoord), "Point h*V1 is not a valid EC point" ); - require(ecmulVerify( - _cFrag.pointV1.xCoord, // V1_x - _precomputed.pointV1yCoord, // V1_y - h, - _precomputed.pointV1HxCoord, // h*V1_x - _precomputed.pointV1HyCoord), // h*V1_y + require( + ecmulVerify( + _cFrag.pointV1.xCoord, // V1_x + _precomputed.pointV1yCoord, // V1_y + h, + _precomputed.pointV1HxCoord, // h*V1_x + _precomputed.pointV1HyCoord + ), // h*V1_y "Precomputed h*V1 value is incorrect" ); // Input validation: V2 - require(checkCompressedPoint( - _cFrag.proof.pointV2.sign, // V2_sign - _cFrag.proof.pointV2.xCoord, // V2_x - _precomputed.pointV2yCoord), // V2_y + require( + checkCompressedPoint( + _cFrag.proof.pointV2.sign, // V2_sign + _cFrag.proof.pointV2.xCoord, // V2_x + _precomputed.pointV2yCoord + ), // V2_y "Precomputed Y coordinate of V2 doesn't correspond to compressed V2 point" ); equation_holds = eqAffineJacobian( - [_precomputed.pointVZxCoord, _precomputed.pointVZyCoord], + [_precomputed.pointVZxCoord, _precomputed.pointVZyCoord], addAffineJacobian( [_cFrag.proof.pointV2.xCoord, _precomputed.pointV2yCoord], [_precomputed.pointV1HxCoord, _precomputed.pointV1HyCoord] ) ); - if (!equation_holds){ + if (!equation_holds) { return false; } @@ -206,49 +231,59 @@ library ReEncryptionValidator { // We don't have to validate U since it's fixed and hard-coded // Input validation: z*U - require(isOnCurve(_precomputed.pointUZxCoord, _precomputed.pointUZyCoord), - "Point z*U is not a valid EC point" + require( + isOnCurve(_precomputed.pointUZxCoord, _precomputed.pointUZyCoord), + "Point z*U is not a valid EC point" ); - require(ecmulVerify( - UMBRAL_PARAMETER_U_XCOORD, // U_x - UMBRAL_PARAMETER_U_YCOORD, // U_y - _cFrag.proof.bnSig, // z - _precomputed.pointUZxCoord, // zU_x - _precomputed.pointUZyCoord), // zU_y + require( + ecmulVerify( + UMBRAL_PARAMETER_U_XCOORD, // U_x + UMBRAL_PARAMETER_U_YCOORD, // U_y + _cFrag.proof.bnSig, // z + _precomputed.pointUZxCoord, // zU_x + _precomputed.pointUZyCoord + ), // zU_y "Precomputed z*U value is incorrect" ); // Input validation: U1 (a.k.a. KFragCommitment) - require(checkCompressedPoint( - _cFrag.proof.pointKFragCommitment.sign, // U1_sign - _cFrag.proof.pointKFragCommitment.xCoord, // U1_x - _precomputed.pointU1yCoord), // U1_y + require( + checkCompressedPoint( + _cFrag.proof.pointKFragCommitment.sign, // U1_sign + _cFrag.proof.pointKFragCommitment.xCoord, // U1_x + _precomputed.pointU1yCoord + ), // U1_y "Precomputed Y coordinate of U1 doesn't correspond to compressed U1 point" ); // Input validation: h*U1 - require(isOnCurve(_precomputed.pointU1HxCoord, _precomputed.pointU1HyCoord), - "Point h*U1 is not a valid EC point" + require( + isOnCurve(_precomputed.pointU1HxCoord, _precomputed.pointU1HyCoord), + "Point h*U1 is not a valid EC point" ); - require(ecmulVerify( - _cFrag.proof.pointKFragCommitment.xCoord, // U1_x - _precomputed.pointU1yCoord, // U1_y - h, - _precomputed.pointU1HxCoord, // h*V1_x - _precomputed.pointU1HyCoord), // h*V1_y + require( + ecmulVerify( + _cFrag.proof.pointKFragCommitment.xCoord, // U1_x + _precomputed.pointU1yCoord, // U1_y + h, + _precomputed.pointU1HxCoord, // h*V1_x + _precomputed.pointU1HyCoord + ), // h*V1_y "Precomputed h*V1 value is incorrect" ); // Input validation: U2 (a.k.a. KFragPok ("proof of knowledge")) - require(checkCompressedPoint( - _cFrag.proof.pointKFragPok.sign, // U2_sign - _cFrag.proof.pointKFragPok.xCoord, // U2_x - _precomputed.pointU2yCoord), // U2_y + require( + checkCompressedPoint( + _cFrag.proof.pointKFragPok.sign, // U2_sign + _cFrag.proof.pointKFragPok.xCoord, // U2_x + _precomputed.pointU2yCoord + ), // U2_y "Precomputed Y coordinate of U2 doesn't correspond to compressed U2 point" ); equation_holds = eqAffineJacobian( - [_precomputed.pointUZxCoord, _precomputed.pointUZyCoord], + [_precomputed.pointUZxCoord, _precomputed.pointUZyCoord], addAffineJacobian( [_cFrag.proof.pointKFragPok.xCoord, _precomputed.pointU2yCoord], [_precomputed.pointU1HxCoord, _precomputed.pointU1HyCoord] @@ -262,7 +297,6 @@ library ReEncryptionValidator { UmbralDeserializer.Capsule memory _capsule, UmbralDeserializer.CapsuleFrag memory _cFrag ) internal pure returns (uint256) { - // Compute h = hash_to_bignum(e, e1, e2, v, v1, v2, u, u1, u2, metadata) bytes memory hashInput = abi.encodePacked( // Point E @@ -306,11 +340,9 @@ library ReEncryptionValidator { uint256 h = extendedKeccakToBN(hashInput); return h; - } - function extendedKeccakToBN (bytes memory _data) internal pure returns (uint256) { - + function extendedKeccakToBN(bytes memory _data) internal pure returns (uint256) { bytes32 upper; bytes32 lower; @@ -318,8 +350,10 @@ library ReEncryptionValidator { // In the case of hash_to_curvebn is 'hash_to_curvebn', padded with zeroes. bytes memory input = abi.encodePacked(bytes32("hash_to_curvebn"), bytes32(0x00), _data); - (upper, lower) = (keccak256(abi.encodePacked(uint8(0x00), input)), - keccak256(abi.encodePacked(uint8(0x01), input))); + (upper, lower) = ( + keccak256(abi.encodePacked(uint8(0x00), input)), + keccak256(abi.encodePacked(uint8(0x01), input)) + ); // Let n be the order of secp256k1's group (n = 2^256 - 0x1000003D1) // n_minus_1 = n - 1 @@ -336,19 +370,19 @@ library ReEncryptionValidator { /// @param _pointX The X coordinate of an EC point in affine representation /// @param _pointY The Y coordinate of an EC point in affine representation /// @return true iff _pointSign and _pointX are the compressed representation of (_pointX, _pointY) - function checkCompressedPoint( - uint8 _pointSign, - uint256 _pointX, - uint256 _pointY - ) internal pure returns(bool) { - bool correct_sign = _pointY % 2 == _pointSign - 2; - return correct_sign && isOnCurve(_pointX, _pointY); - } + function checkCompressedPoint( + uint8 _pointSign, + uint256 _pointX, + uint256 _pointY + ) internal pure returns (bool) { + bool correct_sign = _pointY % 2 == _pointSign - 2; + return correct_sign && isOnCurve(_pointX, _pointY); + } /// @notice Tests if the given serialized coordinates represent a valid EC point /// @param _coords The concatenation of serialized X and Y coordinates /// @return true iff coordinates X and Y are a valid point - function checkSerializedCoordinates(bytes memory _coords) internal pure returns(bool) { + function checkSerializedCoordinates(bytes memory _coords) internal pure returns (bool) { require(_coords.length == 64, "Serialized coordinates should be 64 B"); uint256 coordX; uint256 coordY; @@ -356,8 +390,8 @@ library ReEncryptionValidator { coordX := mload(add(_coords, 32)) coordY := mload(add(_coords, 64)) } - return isOnCurve(coordX, coordY); - } + return isOnCurve(coordX, coordY); + } /// @notice Tests if a point is on the secp256k1 curve /// @param Px The X coordinate of an EC point in affine representation @@ -366,7 +400,7 @@ library ReEncryptionValidator { function isOnCurve(uint256 Px, uint256 Py) internal pure returns (bool) { uint256 p = FIELD_ORDER; - if (Px >= p || Py >= p){ + if (Px >= p || Py >= p) { return false; } @@ -377,35 +411,46 @@ library ReEncryptionValidator { // https://ethresear.ch/t/you-can-kinda-abuse-ecrecover-to-do-ecmul-in-secp256k1-today/2384/4 function ecmulVerify( - uint256 x1, - uint256 y1, - uint256 scalar, - uint256 qx, - uint256 qy - ) internal pure returns(bool) { - uint256 curve_order = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; - address signer = ecrecover(0, uint8(27 + (y1 % 2)), bytes32(x1), bytes32(mulmod(scalar, x1, curve_order))); - address xyAddress = address(uint160(uint256(keccak256(abi.encodePacked(qx, qy))) & 0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)); - return xyAddress == signer; - } + uint256 x1, + uint256 y1, + uint256 scalar, + uint256 qx, + uint256 qy + ) internal pure returns (bool) { + uint256 curve_order = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; + address signer = ecrecover( + 0, + uint8(27 + (y1 % 2)), + bytes32(x1), + bytes32(mulmod(scalar, x1, curve_order)) + ); + address xyAddress = address( + uint160( + uint256(keccak256(abi.encodePacked(qx, qy))) & + 0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + ) + ); + return xyAddress == signer; + } /// @notice Equality test of two points, in affine and Jacobian coordinates respectively /// @param P An EC point in affine coordinates /// @param Q An EC point in Jacobian coordinates /// @return true if P and Q represent the same point in affine coordinates; false otherwise function eqAffineJacobian( - uint256[2] memory P, - uint256[3] memory Q - ) internal pure returns(bool){ + uint256[2] memory P, + uint256[3] memory Q + ) internal pure returns (bool) { uint256 Qz = Q[2]; - if(Qz == 0){ - return false; // Q is zero but P isn't. + if (Qz == 0) { + return false; // Q is zero but P isn't. } uint256 p = FIELD_ORDER; uint256 Q_z_squared = mulmod(Qz, Qz, p); - return mulmod(P[0], Q_z_squared, p) == Q[0] && mulmod(P[1], mulmod(Q_z_squared, Qz, p), p) == Q[1]; - + return + mulmod(P[0], Q_z_squared, p) == Q[0] && + mulmod(P[1], mulmod(Q_z_squared, Qz, p), p) == Q[1]; } /// @notice Adds two points in affine coordinates, with the result in Jacobian @@ -414,45 +459,47 @@ library ReEncryptionValidator { /// @param Q An EC point in affine coordinates /// @return R An EC point in Jacobian coordinates with the sum, represented by an array of 3 uint256 function addAffineJacobian( - uint[2] memory P, - uint[2] memory Q - ) internal pure returns (uint[3] memory R) { - + uint256[2] memory P, + uint256[2] memory Q + ) internal pure returns (uint256[3] memory R) { uint256 p = FIELD_ORDER; - uint256 a = P[0]; - uint256 c = P[1]; - uint256 t0 = Q[0]; - uint256 t1 = Q[1]; + uint256 a = P[0]; + uint256 c = P[1]; + uint256 t0 = Q[0]; + uint256 t1 = Q[1]; - if ((a == t0) && (c == t1)){ + if ((a == t0) && (c == t1)) { return doubleJacobian([a, c, 1]); } - uint256 d = addmod(t1, p-c, p); // d = t1 - c - uint256 b = addmod(t0, p-a, p); // b = t0 - a + uint256 d = addmod(t1, p - c, p); // d = t1 - c + uint256 b = addmod(t0, p - a, p); // b = t0 - a uint256 e = mulmod(b, b, p); // e = b^2 - uint256 f = mulmod(e, b, p); // f = b^3 + uint256 f = mulmod(e, b, p); // f = b^3 uint256 g = mulmod(a, e, p); - R[0] = addmod(mulmod(d, d, p), p-addmod(mulmod(2, g, p), f, p), p); - R[1] = addmod(mulmod(d, addmod(g, p-R[0], p), p), p-mulmod(c, f, p), p); + R[0] = addmod(mulmod(d, d, p), p - addmod(mulmod(2, g, p), f, p), p); + R[1] = addmod(mulmod(d, addmod(g, p - R[0], p), p), p - mulmod(c, f, p), p); R[2] = b; } /// @notice Point doubling in Jacobian coordinates /// @param P An EC point in Jacobian coordinates. /// @return Q An EC point in Jacobian coordinates - function doubleJacobian(uint[3] memory P) internal pure returns (uint[3] memory Q) { + function doubleJacobian(uint256[3] memory P) internal pure returns (uint256[3] memory Q) { uint256 z = P[2]; - if (z == 0) - return Q; + if (z == 0) return Q; uint256 p = FIELD_ORDER; uint256 x = P[0]; uint256 _2y = mulmod(2, P[1], p); uint256 _4yy = mulmod(_2y, _2y, p); uint256 s = mulmod(_4yy, x, p); uint256 m = mulmod(3, mulmod(x, x, p), p); - uint256 t = addmod(mulmod(m, m, p), mulmod(MINUS_2, s, p),p); + uint256 t = addmod(mulmod(m, m, p), mulmod(MINUS_2, s, p), p); Q[0] = t; - Q[1] = addmod(mulmod(m, addmod(s, p - t, p), p), mulmod(MINUS_ONE_HALF, mulmod(_4yy, _4yy, p), p), p); + Q[1] = addmod( + mulmod(m, addmod(s, p - t, p), p), + mulmod(MINUS_ONE_HALF, mulmod(_4yy, _4yy, p), p), + p + ); Q[2] = mulmod(_2y, z, p); } } diff --git a/contracts/contracts/lib/SignatureVerifier.sol b/contracts/contracts/lib/SignatureVerifier.sol index 98a4d386..83fe1003 100644 --- a/contracts/contracts/lib/SignatureVerifier.sol +++ b/contracts/contracts/lib/SignatureVerifier.sol @@ -2,28 +2,27 @@ pragma solidity ^0.8.0; - /** -* @notice Library to recover address and verify signatures -* @dev Simple wrapper for `ecrecover` -*/ + * @notice Library to recover address and verify signatures + * @dev Simple wrapper for `ecrecover` + */ library SignatureVerifier { - - enum HashAlgorithm {KECCAK256, SHA256, RIPEMD160} + enum HashAlgorithm { + KECCAK256, + SHA256, + RIPEMD160 + } // Header for Version E as defined by EIP191. First byte ('E') is also the version - bytes25 constant EIP191_VERSION_E_HEADER = "Ethereum Signed Message:\n"; + bytes25 internal constant EIP191_VERSION_E_HEADER = "Ethereum Signed Message:\n"; /** - * @notice Recover signer address from hash and signature - * @param _hash 32 bytes message hash - * @param _signature Signature of hash - 32 bytes r + 32 bytes s + 1 byte v (could be 0, 1, 27, 28) - */ - function recover(bytes32 _hash, bytes memory _signature) - internal - pure - returns (address) - { + * @notice Recover signer address from hash and signature + * @param _hash 32 bytes message hash + * @param _signature Signature of hash - 32 bytes r + 32 bytes s + 1 byte v (could be 0, 1, 27, 28) + */ + function recover(bytes32 _hash, bytes memory _signature) internal pure returns (address) { + // solhint-disable-next-line reason-string require(_signature.length == 65); bytes32 r; @@ -39,28 +38,28 @@ library SignatureVerifier { if (v < 27) { v += 27; } + // solhint-disable-next-line reason-string require(v == 27 || v == 28); return ecrecover(_hash, v, r, s); } /** - * @notice Transform public key to address - * @param _publicKey secp256k1 public key - */ + * @notice Transform public key to address + * @param _publicKey secp256k1 public key + */ function toAddress(bytes memory _publicKey) internal pure returns (address) { return address(uint160(uint256(keccak256(_publicKey)))); } /** - * @notice Hash using one of pre built hashing algorithm - * @param _message Signed message - * @param _algorithm Hashing algorithm - */ - function hash(bytes memory _message, HashAlgorithm _algorithm) - internal - pure - returns (bytes32 result) - { + * @notice Hash using one of pre built hashing algorithm + * @param _message Signed message + * @param _algorithm Hashing algorithm + */ + function hash( + bytes memory _message, + HashAlgorithm _algorithm + ) internal pure returns (bytes32 result) { if (_algorithm == HashAlgorithm.KECCAK256) { result = keccak256(_message); } else if (_algorithm == HashAlgorithm.SHA256) { @@ -71,46 +70,41 @@ library SignatureVerifier { } /** - * @notice Verify ECDSA signature - * @dev Uses one of pre built hashing algorithm - * @param _message Signed message - * @param _signature Signature of message hash - * @param _publicKey secp256k1 public key in uncompressed format without prefix byte (64 bytes) - * @param _algorithm Hashing algorithm - */ + * @notice Verify ECDSA signature + * @dev Uses one of pre built hashing algorithm + * @param _message Signed message + * @param _signature Signature of message hash + * @param _publicKey secp256k1 public key in uncompressed format without prefix byte (64 bytes) + * @param _algorithm Hashing algorithm + */ function verify( bytes memory _message, bytes memory _signature, bytes memory _publicKey, HashAlgorithm _algorithm - ) - internal - pure - returns (bool) - { + ) internal pure returns (bool) { + // solhint-disable-next-line reason-string require(_publicKey.length == 64); return toAddress(_publicKey) == recover(hash(_message, _algorithm), _signature); } /** - * @notice Hash message according to EIP191 signature specification - * @dev It always assumes Keccak256 is used as hashing algorithm - * @dev Only supports version 0 and version E (0x45) - * @param _message Message to sign - * @param _version EIP191 version to use - */ + * @notice Hash message according to EIP191 signature specification + * @dev It always assumes Keccak256 is used as hashing algorithm + * @dev Only supports version 0 and version E (0x45) + * @param _message Message to sign + * @param _version EIP191 version to use + */ function hashEIP191( bytes memory _message, bytes1 _version - ) - internal - view - returns (bytes32 result) - { - if(_version == bytes1(0x00)){ // Version 0: Data with intended validator + ) internal view returns (bytes32 result) { + if (_version == bytes1(0x00)) { + // Version 0: Data with intended validator address validator = address(this); return keccak256(abi.encodePacked(bytes1(0x19), bytes1(0x00), validator, _message)); - } else if (_version == bytes1(0x45)){ // Version E: personal_sign messages + } else if (_version == bytes1(0x45)) { + // Version E: personal_sign messages uint256 length = _message.length; require(length > 0, "Empty message not allowed for version E"); @@ -124,37 +118,36 @@ library SignatureVerifier { length = _message.length; uint256 index = digits; while (length != 0) { - lengthAsText[--index] = bytes1(uint8(48 + length % 10)); + lengthAsText[--index] = bytes1(uint8(48 + (length % 10))); length /= 10; } - return keccak256(abi.encodePacked(bytes1(0x19), EIP191_VERSION_E_HEADER, lengthAsText, _message)); + return + keccak256( + abi.encodePacked(bytes1(0x19), EIP191_VERSION_E_HEADER, lengthAsText, _message) + ); } else { revert("Unsupported EIP191 version"); } } /** - * @notice Verify EIP191 signature - * @dev It always assumes Keccak256 is used as hashing algorithm - * @dev Only supports version 0 and version E (0x45) - * @param _message Signed message - * @param _signature Signature of message hash - * @param _publicKey secp256k1 public key in uncompressed format without prefix byte (64 bytes) - * @param _version EIP191 version to use - */ + * @notice Verify EIP191 signature + * @dev It always assumes Keccak256 is used as hashing algorithm + * @dev Only supports version 0 and version E (0x45) + * @param _message Signed message + * @param _signature Signature of message hash + * @param _publicKey secp256k1 public key in uncompressed format without prefix byte (64 bytes) + * @param _version EIP191 version to use + */ function verifyEIP191( bytes memory _message, bytes memory _signature, bytes memory _publicKey, bytes1 _version - ) - internal - view - returns (bool) - { + ) internal view returns (bool) { + // solhint-disable-next-line reason-string require(_publicKey.length == 64); return toAddress(_publicKey) == recover(hashEIP191(_message, _version), _signature); } - } diff --git a/contracts/contracts/lib/Snapshot.sol b/contracts/contracts/lib/Snapshot.sol index bd0e17f1..de38e742 100644 --- a/contracts/contracts/lib/Snapshot.sol +++ b/contracts/contracts/lib/Snapshot.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.0; - /** * @title Snapshot * @notice Manages snapshots of size 128 bits (32 bits for timestamp, 96 bits for value) @@ -12,12 +11,11 @@ pragma solidity ^0.8.0; * On average, adding snapshots spends ~6500 less gas than the 256-bit checkpoints of Aragon's Checkpointing */ library Snapshot { - - function encodeSnapshot(uint32 _time, uint96 _value) internal pure returns(uint128) { - return uint128(uint256(_time) << 96 | uint256(_value)); + function encodeSnapshot(uint32 _time, uint96 _value) internal pure returns (uint128) { + return uint128((uint256(_time) << 96) | uint256(_value)); } - function decodeSnapshot(uint128 _snapshot) internal pure returns(uint32 time, uint96 value){ + function decodeSnapshot(uint128 _snapshot) internal pure returns (uint32 time, uint96 value) { time = uint32(bytes4(bytes16(_snapshot))); value = uint96(_snapshot); } @@ -33,7 +31,8 @@ library Snapshot { if (uint32(_time) == currentTime) { _self[length - 1] = encodeSnapshot(uint32(_time), uint96(_value)); return; - } else if (uint32(_time) < currentTime){ + } else if (uint32(_time) < currentTime) { + // solhint-disable-next-line reason-string revert(); } } diff --git a/contracts/contracts/lib/UmbralDeserializer.sol b/contracts/contracts/lib/UmbralDeserializer.sol index 1891d72a..ef8a99b2 100644 --- a/contracts/contracts/lib/UmbralDeserializer.sol +++ b/contracts/contracts/lib/UmbralDeserializer.sol @@ -2,12 +2,10 @@ pragma solidity ^0.8.0; - /** -* @notice Deserialization library for Umbral objects -*/ + * @notice Deserialization library for Umbral objects + */ library UmbralDeserializer { - struct Point { uint8 sign; uint256 xCoord; @@ -60,24 +58,24 @@ library UmbralDeserializer { uint256 pointU2yCoord; bytes32 hashedKFragValidityMessage; address alicesKeyAsAddress; - bytes5 lostBytes; + bytes5 lostBytes; } - uint256 constant BIGNUM_SIZE = 32; - uint256 constant POINT_SIZE = 33; - uint256 constant SIGNATURE_SIZE = 64; - uint256 constant CAPSULE_SIZE = 2 * POINT_SIZE + BIGNUM_SIZE; - uint256 constant CORRECTNESS_PROOF_SIZE = 4 * POINT_SIZE + BIGNUM_SIZE + SIGNATURE_SIZE; - uint256 constant CAPSULE_FRAG_SIZE = 3 * POINT_SIZE + BIGNUM_SIZE; - uint256 constant FULL_CAPSULE_FRAG_SIZE = CAPSULE_FRAG_SIZE + CORRECTNESS_PROOF_SIZE; - uint256 constant PRECOMPUTED_DATA_SIZE = (20 * BIGNUM_SIZE) + 32 + 20 + 5; + uint256 internal constant BIGNUM_SIZE = 32; + uint256 internal constant POINT_SIZE = 33; + uint256 internal constant SIGNATURE_SIZE = 64; + uint256 internal constant CAPSULE_SIZE = 2 * POINT_SIZE + BIGNUM_SIZE; + uint256 internal constant CORRECTNESS_PROOF_SIZE = + 4 * POINT_SIZE + BIGNUM_SIZE + SIGNATURE_SIZE; + uint256 internal constant CAPSULE_FRAG_SIZE = 3 * POINT_SIZE + BIGNUM_SIZE; + uint256 internal constant FULL_CAPSULE_FRAG_SIZE = CAPSULE_FRAG_SIZE + CORRECTNESS_PROOF_SIZE; + uint256 internal constant PRECOMPUTED_DATA_SIZE = (20 * BIGNUM_SIZE) + 32 + 20 + 5; /** - * @notice Deserialize to capsule (not activated) - */ - function toCapsule(bytes memory _capsuleBytes) - internal pure returns (Capsule memory capsule) - { + * @notice Deserialize to capsule (not activated) + */ + function toCapsule(bytes memory _capsuleBytes) internal pure returns (Capsule memory capsule) { + // solhint-disable-next-line reason-string require(_capsuleBytes.length == CAPSULE_SIZE); uint256 pointer = getPointer(_capsuleBytes); pointer = copyPoint(pointer, capsule.pointE); @@ -86,13 +84,15 @@ library UmbralDeserializer { } /** - * @notice Deserialize to correctness proof - * @param _pointer Proof bytes memory pointer - * @param _proofBytesLength Proof bytes length - */ - function toCorrectnessProof(uint256 _pointer, uint256 _proofBytesLength) - internal pure returns (CorrectnessProof memory proof) - { + * @notice Deserialize to correctness proof + * @param _pointer Proof bytes memory pointer + * @param _proofBytesLength Proof bytes length + */ + function toCorrectnessProof( + uint256 _pointer, + uint256 _proofBytesLength + ) internal pure returns (CorrectnessProof memory proof) { + // solhint-disable-next-line reason-string require(_proofBytesLength >= CORRECTNESS_PROOF_SIZE); _pointer = copyPoint(_pointer, proof.pointE2); @@ -112,22 +112,23 @@ library UmbralDeserializer { } /** - * @notice Deserialize to correctness proof - */ - function toCorrectnessProof(bytes memory _proofBytes) - internal pure returns (CorrectnessProof memory proof) - { + * @notice Deserialize to correctness proof + */ + function toCorrectnessProof( + bytes memory _proofBytes + ) internal pure returns (CorrectnessProof memory proof) { uint256 pointer = getPointer(_proofBytes); return toCorrectnessProof(pointer, _proofBytes.length); } /** - * @notice Deserialize to CapsuleFrag - */ - function toCapsuleFrag(bytes memory _cFragBytes) - internal pure returns (CapsuleFrag memory cFrag) - { + * @notice Deserialize to CapsuleFrag + */ + function toCapsuleFrag( + bytes memory _cFragBytes + ) internal pure returns (CapsuleFrag memory cFrag) { uint256 cFragBytesLength = _cFragBytes.length; + // solhint-disable-next-line reason-string require(cFragBytesLength >= FULL_CAPSULE_FRAG_SIZE); uint256 pointer = getPointer(_cFragBytes); @@ -141,14 +142,15 @@ library UmbralDeserializer { } /** - * @notice Deserialize to precomputed data - */ - function toPreComputedData(bytes memory _preComputedData) - internal pure returns (PreComputedData memory data) - { + * @notice Deserialize to precomputed data + */ + function toPreComputedData( + bytes memory _preComputedData + ) internal pure returns (PreComputedData memory data) { + // solhint-disable-next-line reason-string require(_preComputedData.length == PRECOMPUTED_DATA_SIZE); - uint256 initial_pointer = getPointer(_preComputedData); - uint256 pointer = initial_pointer; + uint256 initialPointer = getPointer(_preComputedData); + uint256 pointer = initialPointer; data.pointEyCoord = uint256(getBytes32(pointer)); pointer += BIGNUM_SIZE; @@ -225,13 +227,14 @@ library UmbralDeserializer { data.lostBytes = bytes5(getBytes32(pointer)); pointer += 5; - require(pointer == initial_pointer + PRECOMPUTED_DATA_SIZE); + // solhint-disable-next-line reason-string + require(pointer == initialPointer + PRECOMPUTED_DATA_SIZE); } // TODO extract to external library if needed (#1500) /** - * @notice Get the memory pointer for start of array - */ + * @notice Get the memory pointer for start of array + */ function getPointer(bytes memory _bytes) internal pure returns (uint256 pointer) { assembly { pointer := add(_bytes, 32) // skip array length @@ -239,11 +242,12 @@ library UmbralDeserializer { } /** - * @notice Copy point data from memory in the pointer position - */ - function copyPoint(uint256 _pointer, Point memory _point) - internal pure returns (uint256 resultPointer) - { + * @notice Copy point data from memory in the pointer position + */ + function copyPoint( + uint256 _pointer, + Point memory _point + ) internal pure returns (uint256 resultPointer) { // TODO optimize, copy to point memory directly (#1500) uint8 temp; uint256 xCoord; @@ -257,8 +261,8 @@ library UmbralDeserializer { } /** - * @notice Read 1 byte from memory in the pointer position - */ + * @notice Read 1 byte from memory in the pointer position + */ function getByte(uint256 _pointer) internal pure returns (bytes1 result) { bytes32 word; assembly { @@ -269,8 +273,8 @@ library UmbralDeserializer { } /** - * @notice Read 32 bytes from memory in the pointer position - */ + * @notice Read 32 bytes from memory in the pointer position + */ function getBytes32(uint256 _pointer) internal pure returns (bytes32 result) { assembly { result := mload(_pointer) @@ -278,18 +282,18 @@ library UmbralDeserializer { } /** - * @notice Copy bytes from the source pointer to the target array - * @dev Assumes that enough memory has been allocated to store in target. - * Also assumes that '_target' was the last thing that was allocated - * @param _bytesPointer Source memory pointer - * @param _target Target array - * @param _bytesLength Number of bytes to copy - */ - function copyBytes(uint256 _bytesPointer, bytes memory _target, uint256 _bytesLength) - internal - pure - returns (uint256 resultPointer) - { + * @notice Copy bytes from the source pointer to the target array + * @dev Assumes that enough memory has been allocated to store in target. + * Also assumes that '_target' was the last thing that was allocated + * @param _bytesPointer Source memory pointer + * @param _target Target array + * @param _bytesLength Number of bytes to copy + */ + function copyBytes( + uint256 _bytesPointer, + bytes memory _target, + uint256 _bytesLength + ) internal pure returns (uint256 resultPointer) { // Exploiting the fact that '_target' was the last thing to be allocated, // we can write entire words, and just overwrite any excess. assembly { @@ -297,11 +301,12 @@ library UmbralDeserializer { let words := div(add(_bytesLength, 31), 32) let source := _bytesPointer let destination := add(_target, 32) - for - { let i := 0 } // start at arr + 32 -> first byte corresponds to length - lt(i, words) - { i := add(i, 1) } - { + for { + let i := 0 + } lt(i, words) { + // start at arr + 32 -> first byte corresponds to length + i := add(i, 1) + } { let offset := mul(i, 32) mstore(add(destination, offset), mload(add(source, offset))) } @@ -309,5 +314,4 @@ library UmbralDeserializer { } resultPointer = _bytesPointer + _bytesLength; } - } diff --git a/contracts/matic/SubscriptionManager.sol b/contracts/matic/SubscriptionManager.sol index b36938f7..e498e740 100644 --- a/contracts/matic/SubscriptionManager.sol +++ b/contracts/matic/SubscriptionManager.sol @@ -6,10 +6,8 @@ import "@openzeppelin-upgradeable/contracts/access/AccessControlUpgradeable.sol" import "@openzeppelin-upgradeable/contracts/proxy/utils/Initializable.sol"; contract SubscriptionManager is Initializable, AccessControlUpgradeable { - - bytes32 public constant SET_RATE_ROLE = - keccak256("Power to set the fee rate"); - bytes32 public constant WITHDRAW_ROLE = + bytes32 public constant SET_RATE_ROLE = keccak256("Power to set the fee rate"); + bytes32 public constant WITHDRAW_ROLE = keccak256("Power to withdraw funds from SubscriptionManager"); // The layout of policy struct is optimized, so sponsor, timestamps and size @@ -39,7 +37,7 @@ contract SubscriptionManager is Initializable, AccessControlUpgradeable { uint256 public feeRate; // Mapping that stores policy structs, keyed by policy ID - mapping (bytes16 => Policy) internal _policies; + mapping(bytes16 => Policy) internal _policies; function initialize(uint256 _feeRate) public initializer { _setFeeRate(_feeRate); @@ -52,7 +50,7 @@ contract SubscriptionManager is Initializable, AccessControlUpgradeable { uint16 _size, uint32 _startTimestamp, uint32 _endTimestamp - ) public view returns (uint256){ + ) public view returns (uint256) { uint32 duration = _endTimestamp - _startTimestamp; require(duration > 0, "Invalid timestamps"); require(_size > 0, "Invalid policy size"); @@ -65,9 +63,7 @@ contract SubscriptionManager is Initializable, AccessControlUpgradeable { uint16 _size, uint32 _startTimestamp, uint32 _endTimestamp - ) - external payable - { + ) external payable { require( _startTimestamp < _endTimestamp && block.timestamp < _endTimestamp, "Invalid timestamps" @@ -81,27 +77,22 @@ contract SubscriptionManager is Initializable, AccessControlUpgradeable { } /** - * @notice Create policy - * @param _policyId Policy id - * @param _policyOwner Policy owner. Zero address means sender is owner - * @param _size Number of nodes involved in the policy - * @param _startTimestamp Start timestamp of the policy in seconds - * @param _endTimestamp End timestamp of the policy in seconds - */ + * @notice Create policy + * @param _policyId Policy id + * @param _policyOwner Policy owner. Zero address means sender is owner + * @param _size Number of nodes involved in the policy + * @param _startTimestamp Start timestamp of the policy in seconds + * @param _endTimestamp End timestamp of the policy in seconds + */ function _createPolicy( bytes16 _policyId, address _policyOwner, uint16 _size, uint32 _startTimestamp, uint32 _endTimestamp - ) - internal returns (Policy storage policy) - { + ) internal returns (Policy storage policy) { policy = _policies[_policyId]; - require( - policy.endTimestamp < block.timestamp, - "Policy is currently active" - ); + require(policy.endTimestamp < block.timestamp, "Policy is currently active"); policy.sponsor = payable(msg.sender); policy.startTimestamp = _startTimestamp; @@ -123,11 +114,11 @@ contract SubscriptionManager is Initializable, AccessControlUpgradeable { ); } - function getPolicy(bytes16 _policyID) public view returns(Policy memory){ + function getPolicy(bytes16 _policyID) public view returns (Policy memory) { return _policies[_policyID]; } - function isPolicyActive(bytes16 _policyID) public view returns(bool){ + function isPolicyActive(bytes16 _policyID) public view returns (bool) { return _policies[_policyID].endTimestamp > block.timestamp; } @@ -137,14 +128,13 @@ contract SubscriptionManager is Initializable, AccessControlUpgradeable { emit FeeRateUpdated(oldFee, newFee); } - function setFeeRate(uint256 _ratePerSecond) onlyRole(SET_RATE_ROLE) external { + function setFeeRate(uint256 _ratePerSecond) external onlyRole(SET_RATE_ROLE) { _setFeeRate(_ratePerSecond); } - function sweep(address payable recipient) onlyRole(WITHDRAW_ROLE) external { + function sweep(address payable recipient) external onlyRole(WITHDRAW_ROLE) { uint256 balance = address(this).balance; (bool sent, ) = recipient.call{value: balance}(""); require(sent, "Failed transfer"); } - } diff --git a/contracts/test/AdjudicatorTestSet.sol b/contracts/test/AdjudicatorTestSet.sol index 5e825455..884f2dc6 100644 --- a/contracts/test/AdjudicatorTestSet.sol +++ b/contracts/test/AdjudicatorTestSet.sol @@ -2,27 +2,27 @@ pragma solidity ^0.8.0; - import "../contracts/Adjudicator.sol"; import "../contracts/lib/SignatureVerifier.sol"; -//import "../contracts/proxy/Upgradeable.sol"; - /** -* @notice Contract for testing the Adjudicator contract -*/ + * @notice Contract for testing the Adjudicator contract + */ contract TACoApplicationForAdjudicatorMock { - uint32 public immutable secondsPerPeriod = 1; - mapping (address => uint96) public stakingProviderInfo; - mapping (address => uint256) public rewardInfo; - mapping (address => address) _stakingProviderFromOperator; + mapping(address => uint96) public stakingProviderInfo; + mapping(address => uint256) public rewardInfo; + mapping(address => address) internal _stakingProviderFromOperator; function stakingProviderFromOperator(address _operator) public view returns (address) { return _stakingProviderFromOperator[_operator]; } - function setStakingProviderInfo(address _stakingProvider, uint96 _amount, address _operator) public { + function setStakingProviderInfo( + address _stakingProvider, + uint96 _amount, + address _operator + ) public { stakingProviderInfo[_stakingProvider] = _amount; if (_operator == address(0)) { _operator = _stakingProvider; @@ -34,20 +34,12 @@ contract TACoApplicationForAdjudicatorMock { return stakingProviderInfo[_stakingProvider]; } - function slash( - address _stakingProvider, - uint96 _penalty, - address _investigator - ) - external - { + function slash(address _stakingProvider, uint96 _penalty, address _investigator) external { stakingProviderInfo[_stakingProvider] -= _penalty; rewardInfo[_investigator] += 1; } - } - ///** //* @notice Upgrade to this contract must lead to fail //*/ diff --git a/contracts/test/LibTestSet.sol b/contracts/test/LibTestSet.sol index 488a43f2..cbff5be0 100644 --- a/contracts/test/LibTestSet.sol +++ b/contracts/test/LibTestSet.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.0; - import "../contracts/lib/SignatureVerifier.sol"; import "../contracts/lib/Snapshot.sol"; import "../contracts/lib/UmbralDeserializer.sol"; @@ -10,15 +9,10 @@ import "../contracts/lib/ReEncryptionValidator.sol"; import "../contracts/lib/BLS12381.sol"; /** -* @notice Contract for using SignatureVerifier library -*/ + * @notice Contract for using SignatureVerifier library + */ contract SignatureVerifierMock { - - function recover(bytes32 _hash, bytes memory _signature) - public - pure - returns (address) - { + function recover(bytes32 _hash, bytes memory _signature) public pure returns (address) { return SignatureVerifier.recover(_hash, _signature); } @@ -26,11 +20,10 @@ contract SignatureVerifierMock { return SignatureVerifier.toAddress(_publicKey); } - function hash(bytes memory _message, SignatureVerifier.HashAlgorithm _algorithm) - public - pure - returns (bytes32 result) - { + function hash( + bytes memory _message, + SignatureVerifier.HashAlgorithm _algorithm + ) public pure returns (bytes32 result) { return SignatureVerifier.hash(_message, _algorithm); } @@ -39,11 +32,7 @@ contract SignatureVerifierMock { bytes memory _signature, bytes memory _publicKey, SignatureVerifier.HashAlgorithm _algorithm - ) - public - pure - returns (bool) - { + ) public pure returns (bool) { return SignatureVerifier.verify(_message, _signature, _publicKey, _algorithm); } @@ -52,36 +41,27 @@ contract SignatureVerifierMock { bytes memory _signature, bytes memory _publicKey, bytes1 _version - ) - public - view - returns (bool) - { + ) public view returns (bool) { return SignatureVerifier.verifyEIP191(_message, _signature, _publicKey, _version); } - function hashEIP191( - bytes memory _message, - bytes1 _version - ) - public - view - returns (bytes32) - { + function hashEIP191(bytes memory _message, bytes1 _version) public view returns (bytes32) { return SignatureVerifier.hashEIP191(_message, _version); } - } - /** -* @dev Contract for testing UmbralDeserializer library -*/ + * @dev Contract for testing UmbralDeserializer library + */ contract UmbralDeserializerMock { using UmbralDeserializer for bytes; - function toCapsule(bytes memory _capsuleBytes) - public pure returns ( + function toCapsule( + bytes memory _capsuleBytes + ) + public + pure + returns ( bytes1 pointESign, bytes32 pointEXCoord, bytes1 pointVSign, @@ -97,8 +77,12 @@ contract UmbralDeserializerMock { bnSig = bytes32(capsule.bnSig); } - function toCorrectnessProof(bytes memory _proofBytes) - public pure returns ( + function toCorrectnessProof( + bytes memory _proofBytes + ) + public + pure + returns ( bytes1 pointE2Sign, bytes32 pointE2XCoord, bytes1 pointV2Sign, @@ -127,8 +111,12 @@ contract UmbralDeserializerMock { } // `toCapsuleFrag` is split into two methods because of EVM stack problems with many variables - function toCorrectnessProofFromCapsuleFrag(bytes memory _cFragBytes) - public pure returns ( + function toCorrectnessProofFromCapsuleFrag( + bytes memory _cFragBytes + ) + public + pure + returns ( bytes1 pointE2Sign, bytes32 pointE2XCoord, bytes1 pointV2Sign, @@ -157,8 +145,12 @@ contract UmbralDeserializerMock { metadata = proof.metadata; } - function toCapsuleFrag(bytes memory _cFragBytes) - public pure returns ( + function toCapsuleFrag( + bytes memory _cFragBytes + ) + public + pure + returns ( bytes1 pointE1Sign, bytes32 pointE1XCoord, bytes1 pointV1Sign, @@ -179,14 +171,13 @@ contract UmbralDeserializerMock { } } - /** -* @notice Contract for using ReEncryptionValidator library -*/ + * @notice Contract for using ReEncryptionValidator library + */ contract ReEncryptionValidatorMock { - using UmbralDeserializer for bytes; + /* solhint-disable func-name-mixedcase, var-name-mixedcase */ function UMBRAL_PARAMETER_U_SIGN() public pure returns (uint8) { return ReEncryptionValidator.UMBRAL_PARAMETER_U_SIGN; } @@ -215,81 +206,73 @@ contract ReEncryptionValidatorMock { bytes memory _capsuleBytes, bytes memory _cFragBytes, bytes memory _precomputedBytes - ) - public pure returns (bool) - { + ) public pure returns (bool) { return ReEncryptionValidator.validateCFrag(_capsuleBytes, _cFragBytes, _precomputedBytes); } function computeProofChallengeScalar( bytes memory _capsuleBytes, bytes memory _cFragBytes - ) - public pure returns (uint256) - { + ) public pure returns (uint256) { UmbralDeserializer.Capsule memory _capsule = _capsuleBytes.toCapsule(); UmbralDeserializer.CapsuleFrag memory _cFrag = _cFragBytes.toCapsuleFrag(); return ReEncryptionValidator.computeProofChallengeScalar(_capsule, _cFrag); } - function extendedKeccakToBN (bytes memory _data) public pure returns (uint256) { + function extendedKeccakToBN(bytes memory _data) public pure returns (uint256) { return ReEncryptionValidator.extendedKeccakToBN(_data); } - function checkCompressedPoint( - uint8 _pointSign, - uint256 _pointX, - uint256 _pointY - ) public pure returns(bool) { + function checkCompressedPoint( + uint8 _pointSign, + uint256 _pointX, + uint256 _pointY + ) public pure returns (bool) { return ReEncryptionValidator.checkCompressedPoint(_pointSign, _pointX, _pointY); - } + } - function checkSerializedCoordinates(bytes memory _coords) public pure returns(bool) { - return ReEncryptionValidator.checkSerializedCoordinates(_coords); - } + function checkSerializedCoordinates(bytes memory _coords) public pure returns (bool) { + return ReEncryptionValidator.checkSerializedCoordinates(_coords); + } function isOnCurve(uint256 Px, uint256 Py) public pure returns (bool) { return ReEncryptionValidator.isOnCurve(Px, Py); } function ecmulVerify( - uint256 x1, - uint256 y1, - uint256 scalar, - uint256 qx, - uint256 qy - ) public pure returns(bool) { + uint256 x1, + uint256 y1, + uint256 scalar, + uint256 qx, + uint256 qy + ) public pure returns (bool) { return ReEncryptionValidator.ecmulVerify(x1, y1, scalar, qx, qy); - } + } - function eqAffineJacobian( - uint256[2] memory P, - uint256[3] memory Q - ) public pure returns(bool){ + function eqAffineJacobian(uint256[2] memory P, uint256[3] memory Q) public pure returns (bool) { return ReEncryptionValidator.eqAffineJacobian(P, Q); } function addAffineJacobian( - uint[2] memory P, - uint[2] memory Q - ) public pure returns (uint[3] memory) { + uint256[2] memory P, + uint256[2] memory Q + ) public pure returns (uint256[3] memory) { return ReEncryptionValidator.addAffineJacobian(P, Q); } - function doubleJacobian(uint[3] memory P) public pure returns (uint[3] memory) { + function doubleJacobian(uint256[3] memory P) public pure returns (uint256[3] memory) { return ReEncryptionValidator.doubleJacobian(P); } } /** -* @notice Contract for using Snapshot library -*/ + * @notice Contract for using Snapshot library + */ contract SnapshotMock { - // Helpers uint128[] public history; - function length() public view returns(uint256){ + function length() public view returns (uint256) { return history.length; } @@ -298,11 +281,11 @@ contract SnapshotMock { } // Mock functions - function encodeSnapshot(uint32 _time, uint96 _value) public pure returns(uint128) { + function encodeSnapshot(uint32 _time, uint96 _value) public pure returns (uint128) { return Snapshot.encodeSnapshot(_time, _value); } - function decodeSnapshot(uint128 _snapshot) public pure returns(uint32, uint96){ + function decodeSnapshot(uint128 _snapshot) public pure returns (uint32, uint96) { return Snapshot.decodeSnapshot(_snapshot); } @@ -321,14 +304,12 @@ contract SnapshotMock { function lastValue() public view returns (uint96) { return Snapshot.lastValue(history); } - } /** -* @notice Contract for using BLS12381 library -*/ + * @notice Contract for using BLS12381 library + */ contract BLSLibraryMock { - // using BLS12381 for bytes; // BLS12381.G1Point internal g1; // BLS12381.G2Point internal g2; @@ -341,27 +322,37 @@ contract BLSLibraryMock { return BLS12381.G2_POINT_SIZE; } - function bytesToG1Point(bytes calldata pointBytes) public pure returns(BLS12381.G1Point memory){ + function bytesToG1Point( + bytes calldata pointBytes + ) public pure returns (BLS12381.G1Point memory) { return BLS12381.bytesToG1Point(pointBytes); } - function bytesToG2Point(bytes calldata pointBytes) public pure returns(BLS12381.G2Point memory){ + function bytesToG2Point( + bytes calldata pointBytes + ) public pure returns (BLS12381.G2Point memory) { return BLS12381.bytesToG2Point(pointBytes); } - function g1PointToBytes(BLS12381.G1Point calldata point) public pure returns(bytes memory){ + function g1PointToBytes(BLS12381.G1Point calldata point) public pure returns (bytes memory) { return BLS12381.g1PointToBytes(point); } - function g2PointToBytes(BLS12381.G2Point calldata point) public pure returns(bytes memory){ + function g2PointToBytes(BLS12381.G2Point calldata point) public pure returns (bytes memory) { return BLS12381.g2PointToBytes(point); } - function eqG1Point(BLS12381.G1Point calldata p0, BLS12381.G1Point calldata p1) public pure returns(bool){ + function eqG1Point( + BLS12381.G1Point calldata p0, + BLS12381.G1Point calldata p1 + ) public pure returns (bool) { return BLS12381.eqG1Point(p0, p1); } - function eqG2Point(BLS12381.G2Point calldata p0, BLS12381.G2Point calldata p1) public pure returns(bool){ + function eqG2Point( + BLS12381.G2Point calldata p0, + BLS12381.G2Point calldata p1 + ) public pure returns (bool) { return BLS12381.eqG2Point(p0, p1); } -} \ No newline at end of file +} diff --git a/contracts/test/ReceiveApprovalMethodMock.sol b/contracts/test/ReceiveApprovalMethodMock.sol index a4b8734e..1c011301 100644 --- a/contracts/test/ReceiveApprovalMethodMock.sol +++ b/contracts/test/ReceiveApprovalMethodMock.sol @@ -2,12 +2,10 @@ pragma solidity ^0.8.0; - /** -* @notice Contract for using in token tests -*/ + * @notice Contract for using in token tests + */ contract ReceiveApprovalMethodMock { - address public sender; uint256 public value; address public tokenContract; @@ -18,13 +16,10 @@ contract ReceiveApprovalMethodMock { uint256 _value, address _tokenContract, bytes calldata _extraData - ) - external - { + ) external { sender = _from; value = _value; tokenContract = _tokenContract; extraData = _extraData; } - } diff --git a/contracts/test/TACoApplicationTestSet.sol b/contracts/test/TACoApplicationTestSet.sol index 3fbc6ac0..96941f50 100644 --- a/contracts/test/TACoApplicationTestSet.sol +++ b/contracts/test/TACoApplicationTestSet.sol @@ -2,29 +2,23 @@ pragma solidity ^0.8.0; - import "../contracts/TACoApplication.sol"; import "@threshold/contracts/staking/IApplication.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - /** -* @notice Contract for testing the application contract -*/ + * @notice Contract for testing the application contract + */ contract TToken is ERC20("T", "T") { - - constructor (uint256 _totalSupplyOfTokens) { + constructor(uint256 _totalSupplyOfTokens) { _mint(msg.sender, _totalSupplyOfTokens); } - } - /** -* @notice Contract for testing TACo application contract -*/ + * @notice Contract for testing TACo application contract + */ contract ThresholdStakingForTACoApplicationMock { - struct StakingProviderInfo { address owner; address payable beneficiary; @@ -35,7 +29,7 @@ contract ThresholdStakingForTACoApplicationMock { IApplication public application; - mapping (address => StakingProviderInfo) public stakingProviderInfo; + mapping(address => StakingProviderInfo) public stakingProviderInfo; uint96 public amountToSeize; uint256 public rewardMultiplier; @@ -55,9 +49,7 @@ contract ThresholdStakingForTACoApplicationMock { address _owner, address payable _beneficiary, address _authorizer - ) - public - { + ) public { StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider]; info.owner = _owner; info.beneficiary = _beneficiary; @@ -65,9 +57,9 @@ contract ThresholdStakingForTACoApplicationMock { } /** - * @dev If the function is called with only the _stakingProvider parameter, - * we presume that the caller wants that address set for the other roles as well. - */ + * @dev If the function is called with only the _stakingProvider parameter, + * we presume that the caller wants that address set for the other roles as well. + */ function setRoles(address _stakingProvider) external { setRoles(_stakingProvider, _stakingProvider, payable(_stakingProvider), _stakingProvider); } @@ -80,16 +72,18 @@ contract ThresholdStakingForTACoApplicationMock { stakingProviderInfo[_stakingProvider].decreaseRequestTo = _decreaseRequestTo; } - function authorizedStake(address _stakingProvider, address _application) external view returns (uint96) { + function authorizedStake( + address _stakingProvider, + address _application + ) external view returns (uint96) { + // solhint-disable-next-line reason-string require(_stakingProvider == _application || _application == address(application)); return stakingProviderInfo[_stakingProvider].authorized; } - function rolesOf(address _stakingProvider) external view returns ( - address owner, - address payable beneficiary, - address authorizer - ) { + function rolesOf( + address _stakingProvider + ) external view returns (address owner, address payable beneficiary, address authorizer) { StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider]; owner = info.owner; beneficiary = info.beneficiary; @@ -118,7 +112,11 @@ contract ThresholdStakingForTACoApplicationMock { return stakingProvidersToSeize.length; } - function authorizationIncreased(address _stakingProvider, uint96 _fromAmount, uint96 _toAmount) external { + function authorizationIncreased( + address _stakingProvider, + uint96 _fromAmount, + uint96 _toAmount + ) external { application.authorizationIncreased(_stakingProvider, _fromAmount, _toAmount); stakingProviderInfo[_stakingProvider].authorized = _toAmount; } @@ -127,9 +125,7 @@ contract ThresholdStakingForTACoApplicationMock { address _stakingProvider, uint96 _fromAmount, uint96 _toAmount - ) - external - { + ) external { application.involuntaryAuthorizationDecrease(_stakingProvider, _fromAmount, _toAmount); stakingProviderInfo[_stakingProvider].authorized = _toAmount; } @@ -138,22 +134,17 @@ contract ThresholdStakingForTACoApplicationMock { address _stakingProvider, uint96 _fromAmount, uint96 _toAmount - ) - external - { + ) external { application.authorizationDecreaseRequested(_stakingProvider, _fromAmount, _toAmount); stakingProviderInfo[_stakingProvider].decreaseRequestTo = _toAmount; } - } - /** -* @notice Intermediary contract for testing operator -*/ + * @notice Intermediary contract for testing operator + */ contract Intermediary { - - TACoApplication immutable public application; + TACoApplication public immutable application; constructor(TACoApplication _application) { application = _application; @@ -166,5 +157,4 @@ contract Intermediary { function confirmOperatorAddress() external { application.confirmOperatorAddress(); } - } diff --git a/contracts/threshold/IAccessControlApplication.sol b/contracts/threshold/IAccessControlApplication.sol index 5d2788d2..0320f147 100644 --- a/contracts/threshold/IAccessControlApplication.sol +++ b/contracts/threshold/IAccessControlApplication.sol @@ -8,4 +8,4 @@ interface IAccessControlApplication { function authorizedStake(address _stakingProvider) external view returns (uint96); //TODO: Function to get locked stake duration? -} \ No newline at end of file +} diff --git a/contracts/xchain/PolygonChild.sol b/contracts/xchain/PolygonChild.sol index 166db1e0..53415186 100644 --- a/contracts/xchain/PolygonChild.sol +++ b/contracts/xchain/PolygonChild.sol @@ -5,14 +5,10 @@ import "@fx-portal/contracts/tunnel/FxBaseChildTunnel.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract PolygonChild is FxBaseChildTunnel, Ownable { - - event MessageReceived( - address indexed sender, - bytes data - ); + event MessageReceived(address indexed sender, bytes data); address public stakeInfoAddress; - + constructor(address _fxChild) FxBaseChildTunnel(_fxChild) {} function _processMessageFromRoot( @@ -21,7 +17,8 @@ contract PolygonChild is FxBaseChildTunnel, Ownable { bytes memory data ) internal override validateSender(sender) { emit MessageReceived(sender, data); - (bool success, /* returnId */ ) = stakeInfoAddress.call(data); + // solhint-disable-next-line avoid-low-level-calls + stakeInfoAddress.call(data); } function sendMessageToRoot(bytes memory message) public { @@ -31,4 +28,4 @@ contract PolygonChild is FxBaseChildTunnel, Ownable { function setStakeInfoAddress(address _stakeInfoAddress) public onlyOwner { stakeInfoAddress = _stakeInfoAddress; } -} \ No newline at end of file +} diff --git a/contracts/xchain/PolygonRoot.sol b/contracts/xchain/PolygonRoot.sol index 0bd6f1a6..71def5e6 100644 --- a/contracts/xchain/PolygonRoot.sol +++ b/contracts/xchain/PolygonRoot.sol @@ -4,28 +4,23 @@ pragma solidity ^0.8.0; import "@fx-portal/contracts/tunnel/FxBaseRootTunnel.sol"; import "../contracts/coordination/IUpdatableStakeInfo.sol"; - contract PolygonRoot is FxBaseRootTunnel, IUpdatableStakeInfo { - - address immutable public source; + address public immutable source; bytes public latestData; constructor( - address _checkpointManager, + address _checkpointManager, address _fxRoot, address _source - ) - FxBaseRootTunnel(_checkpointManager, _fxRoot) - { + ) FxBaseRootTunnel(_checkpointManager, _fxRoot) { require(_source != address(0), "Wrong input parameters"); source = _source; } /** - * @dev Checks caller is source of data - */ - modifier onlySource() - { + * @dev Checks caller is source of data + */ + modifier onlySource() { require(msg.sender == source, "Caller must be the source"); _; } @@ -34,18 +29,32 @@ contract PolygonRoot is FxBaseRootTunnel, IUpdatableStakeInfo { latestData = data; } - function updateOperator(address stakingProvider, address operator) external override onlySource { - bytes memory message = abi.encodeWithSelector(IUpdatableStakeInfo.updateOperator.selector, stakingProvider, operator); + function updateOperator( + address stakingProvider, + address operator + ) external override onlySource { + bytes memory message = abi.encodeWithSelector( + IUpdatableStakeInfo.updateOperator.selector, + stakingProvider, + operator + ); _sendMessageToChild(message); } function updateAmount(address stakingProvider, uint96 amount) external override onlySource { - bytes memory message = abi.encodeWithSelector(IUpdatableStakeInfo.updateAmount.selector, stakingProvider, amount); + bytes memory message = abi.encodeWithSelector( + IUpdatableStakeInfo.updateAmount.selector, + stakingProvider, + amount + ); _sendMessageToChild(message); } function batchUpdate(bytes32[] calldata updateInfo) external override onlySource { - bytes memory message = abi.encodeWithSelector(IUpdatableStakeInfo.batchUpdate.selector, updateInfo); + bytes memory message = abi.encodeWithSelector( + IUpdatableStakeInfo.batchUpdate.selector, + updateInfo + ); _sendMessageToChild(message); } -} \ No newline at end of file +} diff --git a/requirements.txt b/requirements.txt index b1efbc10..eec4de04 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ -i https://pypi.org/simple aiohttp==3.8.4 ; python_version >= '3.6' aiosignal==1.3.1 ; python_version >= '3.7' -ape-solidity==0.6.5 +ape-solidity==0.6.7 appnope==0.1.3 ; sys_platform == 'darwin' asn1crypto==1.5.1 asttokens==2.2.1 @@ -31,7 +31,7 @@ distlib==0.3.6 eip712==0.2.1 ; python_version >= '3.8' and python_version < '4' eth-abi==4.0.0 ; python_version >= '3.7' and python_version < '4' eth-account==0.8.0 ; python_version >= '3.6' and python_version < '4' -eth-ape==0.6.9 +eth-ape==0.6.13 eth-bloom==2.0.0 ; python_version >= '3.7' and python_version < '4' eth-hash[pycryptodome]==0.5.1 ; python_version >= '3.7' and python_version < '4' eth-keyfile==0.6.1 @@ -40,8 +40,8 @@ eth-rlp==0.3.0 ; python_version >= '3.7' and python_version < '4' eth-tester[py-evm]==0.9.0b1 eth-typing==3.3.0 ; python_full_version >= '3.7.2' and python_version < '4' eth-utils==2.1.0 ; python_version >= '3.7' and python_version < '4' -ethpm-types==0.5.1 ; python_version >= '3.8' and python_version < '4' -evm-trace==0.1.0a20 ; python_version >= '3.8' and python_version < '4' +ethpm-types==0.5.3 ; python_version >= '3.8' and python_version < '4' +evm-trace==0.1.0a21 ; python_version >= '3.8' and python_version < '4' exceptiongroup==1.1.1 ; python_version < '3.11' executing==1.2.0 filelock==3.12.0 ; python_version >= '3.7' @@ -88,7 +88,7 @@ pure-eval==0.2.2 py-cid==0.3.0 py-ecc==6.0.0 ; python_version >= '3.6' and python_version < '4' py-evm==0.7.0a2 -py-geth==3.12.0 ; python_version >= '3' +py-geth==3.13.0 ; python_version >= '3' py-multibase==1.0.3 py-multicodec==0.2.1 py-multihash==0.2.3 @@ -128,13 +128,13 @@ tox==4.5.1 tqdm==4.65.0 ; python_version >= '3.7' traitlets==5.9.0 ; python_version >= '3.7' trie==2.1.0 ; python_version >= '3.7' and python_version < '4' -typing-extensions==4.6.0 ; python_version < '3.10' +typing-extensions==4.5.0 ; python_version < '3.10' urllib3==2.0.2 ; python_version >= '3.7' varint==1.0.2 virtualenv==20.23.0 ; python_version >= '3.7' watchdog==2.3.1 ; python_version >= '3.6' wcwidth==0.2.6 -web3[tester]==6.4.0 ; python_full_version >= '3.7.2' +web3[tester]==6.5.0 ; python_full_version >= '3.7.2' websockets==11.0.3 ; python_version >= '3.7' wrapt==1.15.0 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' yarl==1.9.2 ; python_version >= '3.7' diff --git a/tests/application/test_authorization.py b/tests/application/test_authorization.py index 52422696..33dae231 100644 --- a/tests/application/test_authorization.py +++ b/tests/application/test_authorization.py @@ -63,11 +63,11 @@ def test_authorization_increase(accounts, threshold_staking, taco_application, s # Check that all events are emitted events = taco_application.AuthorizationIncreased.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == 0 - assert event["toAmount"] == value + assert events == [ + taco_application.AuthorizationIncreased( + stakingProvider=staking_provider, fromAmount=0, toAmount=value + ) + ] # Decrease and try to increase again threshold_staking.involuntaryAuthorizationDecrease( @@ -90,11 +90,11 @@ def test_authorization_increase(accounts, threshold_staking, taco_application, s assert taco_application.isAuthorized(staking_provider) events = taco_application.AuthorizationIncreased.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == value // 2 - assert event["toAmount"] == value + assert events == [ + taco_application.AuthorizationIncreased( + stakingProvider=staking_provider, fromAmount=value // 2, toAmount=value + ) + ] # Confirm operator address and try to increase authorization again taco_application.bondOperator(staking_provider, staking_provider, sender=staking_provider) @@ -113,11 +113,11 @@ def test_authorization_increase(accounts, threshold_staking, taco_application, s assert taco_application.isAuthorized(staking_provider) events = taco_application.AuthorizationIncreased.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == value - assert event["toAmount"] == authorization + assert events == [ + taco_application.AuthorizationIncreased( + stakingProvider=staking_provider, fromAmount=value, toAmount=authorization + ) + ] # Emulate slash and desync by sending smaller fromAmount tx = threshold_staking.authorizationIncreased( @@ -130,11 +130,11 @@ def test_authorization_increase(accounts, threshold_staking, taco_application, s assert taco_application.isAuthorized(staking_provider) events = taco_application.AuthorizationIncreased.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == value // 2 - assert event["toAmount"] == value + assert events == [ + taco_application.AuthorizationIncreased( + stakingProvider=staking_provider, fromAmount=value // 2, toAmount=value + ) + ] # Increase again without syncing with StakeInfo taco_application.setUpdatableStakeInfo(ZERO_ADDRESS, sender=creator) @@ -181,11 +181,11 @@ def test_involuntary_authorization_decrease( assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == ZERO_ADDRESS events = taco_application.AuthorizationInvoluntaryDecreased.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == value - assert event["toAmount"] == authorization + assert events == [ + taco_application.AuthorizationInvoluntaryDecreased( + stakingProvider=staking_provider, fromAmount=value, toAmount=authorization + ) + ] # Prepare request to decrease before involuntary decrease threshold_staking.authorizationDecreaseRequested( @@ -210,11 +210,11 @@ def test_involuntary_authorization_decrease( assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == ZERO_ADDRESS events = taco_application.AuthorizationInvoluntaryDecreased.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == value // 2 - assert event["toAmount"] == authorization + assert events == [ + taco_application.AuthorizationInvoluntaryDecreased( + stakingProvider=staking_provider, fromAmount=value // 2, toAmount=authorization + ) + ] # Confirm operator address and decrease again taco_application.bondOperator(staking_provider, staking_provider, sender=staking_provider) @@ -240,11 +240,11 @@ def test_involuntary_authorization_decrease( assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == staking_provider events = taco_application.AuthorizationInvoluntaryDecreased.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == value // 4 - assert event["toAmount"] == authorization + assert events == [ + taco_application.AuthorizationInvoluntaryDecreased( + stakingProvider=staking_provider, fromAmount=value // 4, toAmount=authorization + ) + ] # Decrease everything tx = threshold_staking.involuntaryAuthorizationDecrease( @@ -263,11 +263,11 @@ def test_involuntary_authorization_decrease( assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == ZERO_ADDRESS events = taco_application.AuthorizationInvoluntaryDecreased.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == authorization - assert event["toAmount"] == 0 + assert events == [ + taco_application.AuthorizationInvoluntaryDecreased( + stakingProvider=staking_provider, fromAmount=authorization, toAmount=0 + ) + ] # Emulate slash and desync by sending smaller fromAmount threshold_staking.authorizationIncreased(staking_provider, 0, 2 * value, sender=creator) @@ -286,11 +286,11 @@ def test_involuntary_authorization_decrease( assert stake_info.authorizedStake(staking_provider) == authorization events = taco_application.AuthorizationInvoluntaryDecreased.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == value - assert event["toAmount"] == authorization + assert events == [ + taco_application.AuthorizationInvoluntaryDecreased( + stakingProvider=staking_provider, fromAmount=value, toAmount=authorization + ) + ] # Decrease everything again without syncing with StakeInfo taco_application.setUpdatableStakeInfo(ZERO_ADDRESS, sender=creator) @@ -352,11 +352,11 @@ def test_authorization_decrease_request( assert taco_application.isAuthorized(staking_provider) events = taco_application.AuthorizationDecreaseRequested.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == value - assert event["toAmount"] == minimum_authorization + assert events == [ + taco_application.AuthorizationDecreaseRequested( + stakingProvider=staking_provider, fromAmount=value, toAmount=minimum_authorization + ) + ] # Confirm operator address and request full decrease taco_application.bondOperator(staking_provider, staking_provider, sender=staking_provider) @@ -379,11 +379,11 @@ def test_authorization_decrease_request( assert taco_application.isAuthorized(staking_provider) events = taco_application.AuthorizationDecreaseRequested.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == value - assert event["toAmount"] == 0 + assert events == [ + taco_application.AuthorizationDecreaseRequested( + stakingProvider=staking_provider, fromAmount=value, toAmount=0 + ) + ] # Emulate slash and desync by sending smaller fromAmount tx = threshold_staking.authorizationDecreaseRequested( @@ -396,11 +396,11 @@ def test_authorization_decrease_request( assert stake_info.authorizedStake(staking_provider) == 0 events = taco_application.AuthorizationDecreaseRequested.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == value // 2 - assert event["toAmount"] == 0 + assert events == [ + taco_application.AuthorizationDecreaseRequested( + stakingProvider=staking_provider, fromAmount=value // 2, toAmount=0 + ) + ] # Request decrease without syncing with StakeInfo taco_application.setUpdatableStakeInfo(ZERO_ADDRESS, sender=creator) @@ -453,11 +453,11 @@ def test_finish_authorization_decrease( ) events = taco_application.AuthorizationDecreaseApproved.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == value - assert event["toAmount"] == new_value + assert events == [ + taco_application.AuthorizationDecreaseApproved( + stakingProvider=staking_provider, fromAmount=value, toAmount=new_value + ) + ] # Confirm operator, request again then desync values and finish decrease value = new_value @@ -488,11 +488,11 @@ def test_finish_authorization_decrease( assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == staking_provider events = taco_application.AuthorizationDecreaseApproved.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == value - assert event["toAmount"] == new_value + assert events == [ + taco_application.AuthorizationDecreaseApproved( + stakingProvider=staking_provider, fromAmount=value, toAmount=new_value + ) + ] # Decrease everything value = new_value @@ -515,11 +515,11 @@ def test_finish_authorization_decrease( assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == ZERO_ADDRESS events = taco_application.AuthorizationDecreaseApproved.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == value - assert event["toAmount"] == 0 + assert events == [ + taco_application.AuthorizationDecreaseApproved( + stakingProvider=staking_provider, fromAmount=value, toAmount=0 + ) + ] # Decrease everything again without syncing with StakeInfo value = minimum_authorization @@ -570,11 +570,11 @@ def test_resync(accounts, threshold_staking, taco_application, stake_info): assert taco_application.isAuthorized(staking_provider) events = taco_application.AuthorizationReSynchronized.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == value - assert event["toAmount"] == new_value + assert events == [ + taco_application.AuthorizationReSynchronized( + stakingProvider=staking_provider, fromAmount=value, toAmount=new_value + ) + ] # Confirm operator and change authorized amount again value = new_value @@ -597,11 +597,11 @@ def test_resync(accounts, threshold_staking, taco_application, stake_info): assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == staking_provider events = taco_application.AuthorizationReSynchronized.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == value - assert event["toAmount"] == new_value + assert events == [ + taco_application.AuthorizationReSynchronized( + stakingProvider=staking_provider, fromAmount=value, toAmount=new_value + ) + ] # Request decrease and change authorized amount again value = new_value @@ -623,11 +623,11 @@ def test_resync(accounts, threshold_staking, taco_application, stake_info): assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == staking_provider events = taco_application.AuthorizationReSynchronized.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == value - assert event["toAmount"] == new_value + assert events == [ + taco_application.AuthorizationReSynchronized( + stakingProvider=staking_provider, fromAmount=value, toAmount=new_value + ) + ] # Set authorized amount to zero and resync again value = new_value @@ -647,11 +647,11 @@ def test_resync(accounts, threshold_staking, taco_application, stake_info): assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == ZERO_ADDRESS events = taco_application.AuthorizationReSynchronized.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["fromAmount"] == value - assert event["toAmount"] == 0 + assert events == [ + taco_application.AuthorizationReSynchronized( + stakingProvider=staking_provider, fromAmount=value, toAmount=0 + ) + ] # Resync again without syncing with StakeInfo value = minimum_authorization diff --git a/tests/application/test_operator.py b/tests/application/test_operator.py index 7e3affa4..45d0c0bd 100644 --- a/tests/application/test_operator.py +++ b/tests/application/test_operator.py @@ -111,12 +111,14 @@ def test_bond_operator(accounts, threshold_staking, taco_application, stake_info assert stake_info.stakingProviderFromOperator(operator1) == staking_provider_3 events = taco_application.OperatorBonded.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider_3 - assert event["operator"] == operator1 - assert event["previousOperator"] == ZERO_ADDRESS - assert event["startTimestamp"] == timestamp + assert events == [ + taco_application.OperatorBonded( + stakingProvider=staking_provider_3, + operator=operator1, + previousOperator=ZERO_ADDRESS, + startTimestamp=timestamp, + ) + ] # After confirmation operator is becoming active all_locked, staking_providers = taco_application.getActiveStakingProviders(0, 0) @@ -163,14 +165,14 @@ def test_bond_operator(accounts, threshold_staking, taco_application, stake_info assert len(staking_providers) == 0 events = taco_application.OperatorBonded.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider_3 - # Now the operator has been unbonded ... - assert event["operator"] == ZERO_ADDRESS - assert event["previousOperator"] == operator1 - # ... with a new starting period. - assert event["startTimestamp"] == timestamp + assert events == [ + taco_application.OperatorBonded( + stakingProvider=staking_provider_3, + operator=ZERO_ADDRESS, + previousOperator=operator1, + startTimestamp=timestamp, + ) + ] # The staking provider can bond now a new operator, without waiting additional time. tx = taco_application.bondOperator(staking_provider_3, operator2, sender=staking_provider_3) @@ -185,12 +187,14 @@ def test_bond_operator(accounts, threshold_staking, taco_application, stake_info assert stake_info.stakingProviderFromOperator(operator2) == ZERO_ADDRESS events = taco_application.OperatorBonded.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider_3 - assert event["operator"] == operator2 - assert event["previousOperator"] == ZERO_ADDRESS - assert event["startTimestamp"] == timestamp + assert events == [ + taco_application.OperatorBonded( + stakingProvider=staking_provider_3, + operator=operator2, + previousOperator=ZERO_ADDRESS, + startTimestamp=timestamp, + ) + ] # Now the previous operator can no longer make a confirmation with ape.reverts(): @@ -218,12 +222,14 @@ def test_bond_operator(accounts, threshold_staking, taco_application, stake_info assert stake_info.stakingProviderFromOperator(operator1) == ZERO_ADDRESS events = taco_application.OperatorBonded.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider_4 - assert event["operator"] == operator1 - assert event["previousOperator"] == ZERO_ADDRESS - assert event["startTimestamp"] == timestamp + assert events == [ + taco_application.OperatorBonded( + stakingProvider=staking_provider_4, + operator=operator1, + previousOperator=ZERO_ADDRESS, + startTimestamp=timestamp, + ) + ] # The first operator still can't be a staking provider threshold_staking.setRoles(operator1, sender=creator) @@ -260,12 +266,14 @@ def test_bond_operator(accounts, threshold_staking, taco_application, stake_info assert len(staking_providers) == 0 events = taco_application.OperatorBonded.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider_4 - assert event["operator"] == operator3 - assert event["previousOperator"] == operator1 - assert event["startTimestamp"] == timestamp + assert events == [ + taco_application.OperatorBonded( + stakingProvider=staking_provider_4, + operator=operator3, + previousOperator=operator1, + startTimestamp=timestamp, + ) + ] # The first operator is free and can deposit tokens and become a staking provider threshold_staking.setRoles(operator1, sender=creator) @@ -291,12 +299,14 @@ def test_bond_operator(accounts, threshold_staking, taco_application, stake_info assert taco_application.stakingProviders(2) == staking_provider_1 events = taco_application.OperatorBonded.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider_1 - assert event["operator"] == staking_provider_1 - assert event["previousOperator"] == ZERO_ADDRESS - assert event["startTimestamp"] == timestamp + assert events == [ + taco_application.OperatorBonded( + stakingProvider=staking_provider_1, + operator=staking_provider_1, + previousOperator=ZERO_ADDRESS, + startTimestamp=timestamp, + ) + ] # If stake will be less than minimum then confirmation is still possible threshold_staking.involuntaryAuthorizationDecrease( @@ -374,6 +384,9 @@ def test_confirm_address(accounts, threshold_staking, taco_application, chain, p event = events[0] assert event["stakingProvider"] == staking_provider assert event["operator"] == operator + assert events == [ + taco_application.OperatorConfirmed(stakingProvider=staking_provider, operator=operator) + ] # Can't confirm twice with ape.reverts(): diff --git a/tests/application/test_reward.py b/tests/application/test_reward.py index df2ad775..ab0f067f 100644 --- a/tests/application/test_reward.py +++ b/tests/application/test_reward.py @@ -46,11 +46,7 @@ def test_push_reward(accounts, token, threshold_staking, taco_application, chain tx = taco_application.setRewardDistributor(distributor, sender=creator) assert taco_application.rewardDistributor() == distributor - - events = taco_application.RewardDistributorSet.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["distributor"] == distributor + assert tx.events == [taco_application.RewardDistributorSet(distributor=distributor)] # Can't distribute zero rewards with ape.reverts(): @@ -72,9 +68,7 @@ def test_push_reward(accounts, token, threshold_staking, taco_application, chain assert taco_application.availableRewards(staking_provider_1) == 0 events = taco_application.RewardAdded.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["reward"] == reward_portion + assert events == [taco_application.RewardAdded(reward=reward_portion)] # Wait some time and push reward again (without staking providers) chain.pending_timestamp += reward_duration // 2 - 1 @@ -93,9 +87,7 @@ def test_push_reward(accounts, token, threshold_staking, taco_application, chain assert taco_application.availableRewards(staking_provider_1) == 0 events = taco_application.RewardAdded.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["reward"] == reward_portion + assert events == [taco_application.RewardAdded(reward=reward_portion)] # Wait, add one staking provider and push reward again chain.pending_timestamp += reward_duration @@ -116,9 +108,7 @@ def test_push_reward(accounts, token, threshold_staking, taco_application, chain assert taco_application.availableRewards(staking_provider_1) == 0 events = taco_application.RewardAdded.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["reward"] == reward_portion + assert events == [taco_application.RewardAdded(reward=reward_portion)] # Wait some time and check reward for staking provider chain.pending_timestamp += reward_duration // 2 @@ -153,9 +143,7 @@ def test_push_reward(accounts, token, threshold_staking, taco_application, chain assert taco_application.availableRewards(staking_provider_2) == 0 events = taco_application.RewardAdded.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["reward"] == reward_portion + assert events == [taco_application.RewardAdded(reward=reward_portion)] chain.pending_timestamp += reward_duration assert ( @@ -404,11 +392,11 @@ def test_withdraw(accounts, token, threshold_staking, taco_application, chain): assert token.balanceOf(taco_application.address) == reward_portion - earned events = taco_application.RewardPaid.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["beneficiary"] == beneficiary - assert event["reward"] == earned + assert events == [ + taco_application.RewardPaid( + stakingProvider=staking_provider, beneficiary=beneficiary, reward=earned + ) + ] # Add one more staking provider, push reward again and drop operator chain.pending_timestamp += min_operator_seconds @@ -438,8 +426,8 @@ def test_withdraw(accounts, token, threshold_staking, taco_application, chain): assert token.balanceOf(taco_application.address) == 2 * reward_portion - earned - new_earned events = taco_application.RewardPaid.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["stakingProvider"] == staking_provider - assert event["beneficiary"] == beneficiary - assert event["reward"] == new_earned + assert events == [ + taco_application.RewardPaid( + stakingProvider=staking_provider, beneficiary=beneficiary, reward=new_earned + ) + ] diff --git a/tests/staking_escrow/test_staking_escrow.py b/tests/staking_escrow/test_staking_escrow.py index 2937d20a..3395e91b 100644 --- a/tests/staking_escrow/test_staking_escrow.py +++ b/tests/staking_escrow/test_staking_escrow.py @@ -53,10 +53,7 @@ def test_staking_from_worklock(project, accounts, token, worklock, escrow): # Check that all events are emitted events = escrow.Deposited.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["staker"] == staker1 - assert event["value"] == value + assert events == [escrow.Deposited(staker=staker1, value=value)] # Deposit directly and then through WorkLock escrow.setStaker(staker2, value, 0, sender=staker2) @@ -68,10 +65,7 @@ def test_staking_from_worklock(project, accounts, token, worklock, escrow): # Check that all events are emitted events = escrow.Deposited.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["staker"] == staker2 - assert event["value"] == value + assert events == [escrow.Deposited(staker=staker2, value=value)] # Emulate case when staker withdraws everything and then deposits from WorkLock escrow.setStaker(staker3, 0, 1, sender=staker3) @@ -83,10 +77,7 @@ def test_staking_from_worklock(project, accounts, token, worklock, escrow): # Check that all events are emitted events = escrow.Deposited.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["staker"] == staker3 - assert event["value"] == value + assert events == [escrow.Deposited(staker=staker3, value=value)] def test_slashing(accounts, token, worklock, threshold_staking, escrow): @@ -116,12 +107,9 @@ def test_slashing(accounts, token, worklock, threshold_staking, escrow): assert token.balanceOf(investigator) == reward events = escrow.Slashed.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["staker"] == staker - assert event["penalty"] == stake - assert event["investigator"] == investigator - assert event["reward"] == reward + assert events == [ + escrow.Slashed(staker=staker, penalty=stake, investigator=investigator, reward=reward) + ] # Slash small part worklock.depositFromWorkLock(staker, stake, 0, sender=creator) @@ -134,12 +122,14 @@ def test_slashing(accounts, token, worklock, threshold_staking, escrow): assert token.balanceOf(investigator) == reward + amount_to_slash events = escrow.Slashed.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["staker"] == staker - assert event["penalty"] == amount_to_slash - assert event["investigator"] == investigator - assert event["reward"] == amount_to_slash + assert events == [ + escrow.Slashed( + staker=staker, + penalty=amount_to_slash, + investigator=investigator, + reward=amount_to_slash, + ) + ] # Slash without reward tx = threshold_staking.slashStaker(staker, amount_to_slash, investigator, 0, sender=creator) @@ -148,12 +138,9 @@ def test_slashing(accounts, token, worklock, threshold_staking, escrow): assert token.balanceOf(investigator) == reward + amount_to_slash events = escrow.Slashed.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["staker"] == staker - assert event["penalty"] == amount_to_slash - assert event["investigator"] == investigator - assert event["reward"] == 0 + assert events == [ + escrow.Slashed(staker=staker, penalty=amount_to_slash, investigator=investigator, reward=0) + ] def test_request_merge(accounts, threshold_staking, escrow): @@ -169,18 +156,14 @@ def test_request_merge(accounts, threshold_staking, escrow): assert escrow.stakerInfo(staker1)[STAKING_PROVIDER_SLOT] == staking_provider_1 assert threshold_staking.stakingProviders(staking_provider_1)[0] == 0 - events = escrow.MergeRequested.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["staker"] == staker1 - assert event["stakingProvider"] == staking_provider_1 + assert tx.events == [escrow.MergeRequested(staker=staker1, stakingProvider=staking_provider_1)] # Request can be made several times tx = threshold_staking.requestMerge(staker1, staking_provider_1, sender=creator) assert escrow.getAllTokens(staker1) == 0 assert escrow.stakerInfo(staker1)[STAKING_PROVIDER_SLOT] == staking_provider_1 assert threshold_staking.stakingProviders(staking_provider_1)[0] == 0 - assert "MergeRequested" not in tx.events + assert tx.events == [] # Can change provider if old provider has no delegated stake tx = threshold_staking.requestMerge(staker1, staker1, sender=creator) @@ -188,11 +171,7 @@ def test_request_merge(accounts, threshold_staking, escrow): assert escrow.stakerInfo(staker1)[STAKING_PROVIDER_SLOT] == staker1 assert threshold_staking.stakingProviders(staking_provider_1)[0] == 0 - events = escrow.MergeRequested.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["staker"] == staker1 - assert event["stakingProvider"] == staker1 + assert tx.events == [escrow.MergeRequested(staker=staker1, stakingProvider=staker1)] # Requesting merge for existent staker will return stake value = 1000 @@ -202,11 +181,7 @@ def test_request_merge(accounts, threshold_staking, escrow): assert escrow.stakerInfo(staker2)[STAKING_PROVIDER_SLOT] == staking_provider_2 assert threshold_staking.stakingProviders(staking_provider_2)[0] == value - events = escrow.MergeRequested.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["staker"] == staker2 - assert event["stakingProvider"] == staking_provider_2 + assert tx.events == [escrow.MergeRequested(staker=staker2, stakingProvider=staking_provider_2)] # Request can be made several times threshold_staking.requestMerge(staker2, staking_provider_2, sender=creator) @@ -219,8 +194,7 @@ def test_request_merge(accounts, threshold_staking, escrow): assert escrow.getAllTokens(staker2) == 2 * value assert escrow.stakerInfo(staker2)[STAKING_PROVIDER_SLOT] == staking_provider_2 assert threshold_staking.stakingProviders(staking_provider_2)[0] == 2 * value - events = escrow.MergeRequested.from_receipt(tx) - assert len(events) == 0 + assert tx.events == [] # Request can be done only with the same provider when NU is staked with ape.reverts(): @@ -233,18 +207,16 @@ def test_request_merge(accounts, threshold_staking, escrow): assert escrow.stakerInfo(staker2)[STAKING_PROVIDER_SLOT] == staking_provider_1 assert threshold_staking.stakingProviders(staking_provider_1)[0] == 2 * value - events = escrow.MergeRequested.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["staker"] == staker2 - assert event["stakingProvider"] == staking_provider_1 + assert tx.events == [escrow.MergeRequested(staker=staker2, stakingProvider=staking_provider_1)] def test_withdraw(accounts, token, worklock, threshold_staking, escrow, chain): creator, staker, staking_provider = accounts[0:3] # Deposit some tokens - value = Web3.to_wei(ONE_HOUR, "ether") # Exclude rounding error # TODO NU(ONE_HOUR, 'NU').to_units() + value = Web3.to_wei( + ONE_HOUR, "ether" + ) # Exclude rounding error # TODO NU(ONE_HOUR, 'NU').to_units() token.transfer(worklock.address, 10 * value, sender=creator) worklock.depositFromWorkLock(staker, value + 1, 0, sender=creator) @@ -255,10 +227,7 @@ def test_withdraw(accounts, token, worklock, threshold_staking, escrow, chain): assert token.balanceOf(escrow.address) == value events = escrow.Withdrawn.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["staker"] == staker - assert event["value"] == 1 + assert events == [escrow.Withdrawn(staker=staker, value=1)] threshold_staking.requestMerge(staker, staking_provider, sender=creator) @@ -292,10 +261,7 @@ def test_withdraw(accounts, token, worklock, threshold_staking, escrow, chain): assert token.balanceOf(escrow.address) == value - to_withdraw events = escrow.Withdrawn.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["staker"] == staker - assert event["value"] == to_withdraw + assert events == [escrow.Withdrawn(staker=staker, value=to_withdraw)] # Can't withdraw more than unstaked chain.pending_timestamp += 30 * 60 @@ -317,10 +283,7 @@ def test_withdraw(accounts, token, worklock, threshold_staking, escrow, chain): assert token.balanceOf(escrow.address) == value // 2 events = escrow.Withdrawn.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["staker"] == staker - assert event["value"] == unstaked + assert events == [escrow.Withdrawn(staker=staker, value=unstaked)] # Now unstake and withdraw everything threshold_staking.setStakedNu(staking_provider, 0, sender=creator) @@ -330,10 +293,7 @@ def test_withdraw(accounts, token, worklock, threshold_staking, escrow, chain): assert token.balanceOf(escrow.address) == 0 events = escrow.Withdrawn.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["staker"] == staker - assert event["value"] == value // 2 + assert events == [escrow.Withdrawn(staker=staker, value=value // 2)] def test_vesting(accounts, token, worklock, escrow, chain): @@ -357,9 +317,7 @@ def test_vesting(accounts, token, worklock, escrow, chain): [staker1, staker2], [release_timestamp, release_timestamp], [rate], sender=creator ) with ape.reverts(): - escrow.setupVesting( - [staker1, staker2], [release_timestamp], [rate, rate], sender=creator - ) + escrow.setupVesting([staker1, staker2], [release_timestamp], [rate, rate], sender=creator) with ape.reverts(): escrow.setupVesting( [staker1], [release_timestamp, release_timestamp], [rate, rate], sender=creator @@ -381,12 +339,9 @@ def test_vesting(accounts, token, worklock, escrow, chain): assert escrow.stakerInfo(staker1)[VESTING_RELEASE_TIMESTAMP_SLOT] == release_timestamp assert escrow.stakerInfo(staker1)[VESTING_RELEASE_RATE_SLOT] == rate - events = escrow.VestingSet.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["staker"] == staker1 - assert event["releaseTimestamp"] == release_timestamp - assert event["releaseRate"] == rate + assert tx.events == [ + escrow.VestingSet(staker=staker1, releaseTimestamp=release_timestamp, releaseRate=rate) + ] chain.pending_timestamp += 40 * 60 now = chain.pending_timestamp - 1 @@ -401,7 +356,9 @@ def test_vesting(accounts, token, worklock, escrow, chain): escrow.setupVesting([staker1], [release_timestamp], [rate], sender=creator) # Try again with three other stakers - value = Web3.to_wei(ONE_HOUR, "ether") # Exclude rounding error # TODO NU(ONE_HOUR, 'NU').to_units() + value = Web3.to_wei( + ONE_HOUR, "ether" + ) # Exclude rounding error # TODO NU(ONE_HOUR, 'NU').to_units() worklock.depositFromWorkLock(staker2, value, 0, sender=creator) worklock.depositFromWorkLock(staker3, value, 0, sender=creator) worklock.depositFromWorkLock(staker4, value, 0, sender=creator) @@ -430,20 +387,11 @@ def test_vesting(accounts, token, worklock, escrow, chain): assert escrow.stakerInfo(staker4)[VESTING_RELEASE_TIMESTAMP_SLOT] == release_timestamp_4 assert escrow.stakerInfo(staker4)[VESTING_RELEASE_RATE_SLOT] == rate_4 - events = escrow.VestingSet.from_receipt(tx) - assert len(events) == 3 - event = events[0] - assert event["staker"] == staker2 - assert event["releaseTimestamp"] == release_timestamp_2 - assert event["releaseRate"] == rate_2 - event = events[1] - assert event["staker"] == staker3 - assert event["releaseTimestamp"] == release_timestamp_3 - assert event["releaseRate"] == rate_3 - event = events[2] - assert event["staker"] == staker4 - assert event["releaseTimestamp"] == release_timestamp_4 - assert event["releaseRate"] == rate_4 + assert tx.events == [ + escrow.VestingSet(staker=staker2, releaseTimestamp=release_timestamp_2, releaseRate=rate_2), + escrow.VestingSet(staker=staker3, releaseTimestamp=release_timestamp_3, releaseRate=rate_3), + escrow.VestingSet(staker=staker4, releaseTimestamp=release_timestamp_4, releaseRate=rate_4), + ] chain.pending_timestamp += ONE_HOUR assert escrow.getUnvestedTokens(staker2) == 0 @@ -459,7 +407,7 @@ def test_vesting(accounts, token, worklock, escrow, chain): def test_combined_vesting(accounts, token, worklock, escrow, chain): staker = "0xcd087a44ED8EE2aCe79F497c803005Ff79A64A94" value = Web3.to_wei(1_500_000, "ether") # TODO - + creator = accounts[0] token.transfer(worklock.address, 10 * value, sender=creator) @@ -474,12 +422,9 @@ def test_combined_vesting(accounts, token, worklock, escrow, chain): assert escrow.stakerInfo(staker)[VESTING_RELEASE_TIMESTAMP_SLOT] == release_timestamp assert escrow.stakerInfo(staker)[VESTING_RELEASE_RATE_SLOT] == rate - events = escrow.VestingSet.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert event["staker"] == staker - assert event["releaseTimestamp"] == release_timestamp - assert event["releaseRate"] == rate + assert tx.events == [ + escrow.VestingSet(staker=staker, releaseTimestamp=release_timestamp, releaseRate=rate) + ] chain.pending_timestamp += 40 * 60 now = chain.pending_timestamp - 1 diff --git a/tests/staking_escrow/test_staking_escrow_additional.py b/tests/staking_escrow/test_staking_escrow_additional.py index a934dd72..a853dcf6 100644 --- a/tests/staking_escrow/test_staking_escrow_additional.py +++ b/tests/staking_escrow/test_staking_escrow_additional.py @@ -16,6 +16,7 @@ """ import ape +from ape.utils import ZERO_ADDRESS from web3 import Web3 @@ -34,16 +35,11 @@ def test_upgrading(accounts, token, project): dispatcher = creator.deploy(project.Dispatcher, contract_library_v1.address) tx = creator.history[-1] - events = dispatcher.StateVerified.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert contract_library_v1.address == event["testTarget"] - assert event["sender"] == creator - events = dispatcher.UpgradeFinished.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert contract_library_v1.address == event["target"] - assert event["sender"] == creator + assert tx.events == [ + dispatcher.OwnershipTransferred(previousOwner=ZERO_ADDRESS, newOwner=creator), + dispatcher.StateVerified(testTarget=contract_library_v1.address, sender=creator), + dispatcher.UpgradeFinished(target=contract_library_v1.address, sender=creator), + ] # Deploy second version of the contract contract_library_v2 = creator.deploy( @@ -74,16 +70,11 @@ def test_upgrading(accounts, token, project): contract.setValueToCheck(3, sender=creator) assert contract.valueToCheck() == 3 - events = dispatcher.StateVerified.from_receipt(tx) - assert len(events) == 2 - event = events[0] - assert contract_library_v2.address == event["testTarget"] - assert event["sender"] == creator - events = dispatcher.UpgradeFinished.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert contract_library_v2.address == event["target"] - assert event["sender"] == creator + assert tx.events == [ + dispatcher.StateVerified(testTarget=contract_library_v2.address, sender=creator), + dispatcher.StateVerified(testTarget=contract_library_v2.address, sender=creator), + dispatcher.UpgradeFinished(target=contract_library_v2.address, sender=creator), + ] # Can't upgrade to the previous version or to the bad version contract_library_bad = creator.deploy( @@ -116,6 +107,11 @@ def test_upgrading(accounts, token, project): assert contract_library_v1.address == event["target"] assert event["sender"] == creator + assert tx.events == [ + dispatcher.StateVerified(testTarget=contract_library_v2.address, sender=creator), + dispatcher.UpgradeFinished(target=contract_library_v1.address, sender=creator), + ] + def test_measure_work(accounts, token, worklock, escrow): creator, staker, *everyone_else = accounts[0:] diff --git a/tests/test_coordinator.py b/tests/test_coordinator.py index 6dd9be84..2e40bdc8 100644 --- a/tests/test_coordinator.py +++ b/tests/test_coordinator.py @@ -97,9 +97,7 @@ def coordinator(project, deployer, stake_info, flat_rate_fee_model, initiator): @pytest.fixture() def global_allow_list(project, deployer, coordinator): contract = project.GlobalAllowList.deploy( - coordinator.address, - deployer, # admin - sender=deployer + coordinator.address, deployer, sender=deployer # admin ) return contract @@ -119,18 +117,16 @@ def test_invalid_initiate_ritual(coordinator, nodes, accounts, initiator, global with ape.reverts("Invalid number of nodes"): coordinator.initiateRitual( - nodes[:5] * 20, - initiator, - DURATION, - global_allow_list.address, - sender=initiator + nodes[:5] * 20, initiator, DURATION, global_allow_list.address, sender=initiator ) with ape.reverts("Invalid ritual duration"): coordinator.initiateRitual(nodes, initiator, 0, global_allow_list.address, sender=initiator) with ape.reverts("Provider has not set their public key"): - coordinator.initiateRitual(nodes, initiator, DURATION, global_allow_list.address, sender=initiator) + coordinator.initiateRitual( + nodes, initiator, DURATION, global_allow_list.address, sender=initiator + ) for node in nodes: public_key = gen_public_key() @@ -138,21 +134,13 @@ def test_invalid_initiate_ritual(coordinator, nodes, accounts, initiator, global with ape.reverts("Providers must be sorted"): coordinator.initiateRitual( - nodes[1:] + [nodes[0]], - initiator, - DURATION, - global_allow_list.address, - sender=initiator + nodes[1:] + [nodes[0]], initiator, DURATION, global_allow_list.address, sender=initiator ) with ape.reverts("ERC20: insufficient allowance"): # Sender didn't approve enough tokens coordinator.initiateRitual( - nodes, - initiator, - DURATION, - global_allow_list.address, - sender=initiator + nodes, initiator, DURATION, global_allow_list.address, sender=initiator ) @@ -163,26 +151,24 @@ def initiate_ritual(coordinator, erc20, fee_model, allow_logic, authority, nodes cost = fee_model.getRitualInitiationCost(nodes, DURATION) erc20.approve(coordinator.address, cost, sender=authority) tx = coordinator.initiateRitual( - nodes, - authority, - DURATION, - allow_logic.address, - sender=authority + nodes, authority, DURATION, allow_logic.address, sender=authority ) return authority, tx -def test_initiate_ritual(coordinator, nodes, initiator, erc20, global_allow_list, flat_rate_fee_model): +def test_initiate_ritual( + coordinator, nodes, initiator, erc20, global_allow_list, flat_rate_fee_model +): authority, tx = initiate_ritual( coordinator=coordinator, erc20=erc20, fee_model=flat_rate_fee_model, authority=initiator, nodes=nodes, - allow_logic=global_allow_list + allow_logic=global_allow_list, ) - events = list(coordinator.StartRitual.from_receipt(tx)) + events = coordinator.StartRitual.from_receipt(tx) assert len(events) == 1 event = events[0] assert event["ritualId"] == 0 @@ -198,7 +184,7 @@ def test_provider_public_key(coordinator, nodes): tx = coordinator.setProviderPublicKey(public_key, sender=selected_provider) ritual_id = coordinator.numberOfRituals() - events = list(coordinator.ParticipantPublicKeySet.from_receipt(tx)) + events = coordinator.ParticipantPublicKeySet.from_receipt(tx) assert len(events) == 1 event = events[0] assert event["participant"] == selected_provider @@ -206,14 +192,16 @@ def test_provider_public_key(coordinator, nodes): assert coordinator.getProviderPublicKey(selected_provider, ritual_id) == public_key -def test_post_transcript(coordinator, nodes, initiator, erc20, flat_rate_fee_model, global_allow_list): +def test_post_transcript( + coordinator, nodes, initiator, erc20, flat_rate_fee_model, global_allow_list +): initiate_ritual( coordinator=coordinator, erc20=erc20, fee_model=flat_rate_fee_model, authority=initiator, nodes=nodes, - allow_logic=global_allow_list + allow_logic=global_allow_list, ) transcript = os.urandom(transcript_size(len(nodes), len(nodes))) @@ -223,11 +211,11 @@ def test_post_transcript(coordinator, nodes, initiator, erc20, flat_rate_fee_mod tx = coordinator.postTranscript(0, transcript, sender=node) events = list(coordinator.TranscriptPosted.from_receipt(tx)) - assert len(events) == 1 - event = events[0] - assert event["ritualId"] == 0 - assert event["node"] == node - assert event["transcriptDigest"] == Web3.keccak(transcript) + assert events == [ + coordinator.TranscriptPosted( + ritualId=0, node=node, transcriptDigest=Web3.keccak(transcript) + ) + ] participants = coordinator.getParticipants(0) for participant in participants: @@ -246,7 +234,7 @@ def test_post_transcript_but_not_part_of_ritual( fee_model=flat_rate_fee_model, authority=initiator, nodes=nodes, - allow_logic=global_allow_list + allow_logic=global_allow_list, ) transcript = os.urandom(transcript_size(len(nodes), len(nodes))) @@ -263,7 +251,7 @@ def test_post_transcript_but_already_posted_transcript( fee_model=flat_rate_fee_model, authority=initiator, nodes=nodes, - allow_logic=global_allow_list + allow_logic=global_allow_list, ) transcript = os.urandom(transcript_size(len(nodes), len(nodes))) coordinator.postTranscript(0, transcript, sender=nodes[0]) @@ -280,7 +268,7 @@ def test_post_transcript_but_not_waiting_for_transcripts( fee_model=flat_rate_fee_model, authority=initiator, nodes=nodes, - allow_logic=global_allow_list + allow_logic=global_allow_list, ) transcript = os.urandom(transcript_size(len(nodes), len(nodes))) for node in nodes: @@ -290,14 +278,16 @@ def test_post_transcript_but_not_waiting_for_transcripts( coordinator.postTranscript(0, transcript, sender=nodes[1]) -def test_post_aggregation(coordinator, nodes, initiator, erc20, flat_rate_fee_model, global_allow_list): +def test_post_aggregation( + coordinator, nodes, initiator, erc20, flat_rate_fee_model, global_allow_list +): initiate_ritual( coordinator=coordinator, erc20=erc20, fee_model=flat_rate_fee_model, authority=initiator, nodes=nodes, - allow_logic=global_allow_list + allow_logic=global_allow_list, ) transcript = os.urandom(transcript_size(len(nodes), len(nodes))) for node in nodes: @@ -312,12 +302,12 @@ def test_post_aggregation(coordinator, nodes, initiator, erc20, flat_rate_fee_mo 0, aggregated, dkg_public_key, decryption_request_static_keys[i], sender=node ) - events = list(coordinator.AggregationPosted.from_receipt(tx)) - assert len(events) == 1 - event = events[0] - assert event["ritualId"] == 0 - assert event["node"] == node.address - assert event["aggregatedTranscriptDigest"] == Web3.keccak(aggregated) + events = coordinator.AggregationPosted.from_receipt(tx) + assert events == [ + coordinator.AggregationPosted( + ritualId=0, node=node, aggregatedTranscriptDigest=Web3.keccak(aggregated) + ) + ] participants = coordinator.getParticipants(0) for i, participant in enumerate(participants): @@ -325,21 +315,12 @@ def test_post_aggregation(coordinator, nodes, initiator, erc20, flat_rate_fee_mo assert participant.decryptionRequestStaticKey == decryption_request_static_keys[i] assert coordinator.getRitualState(0) == RitualState.FINALIZED - events = list(coordinator.EndRitual.from_receipt(tx)) - assert len(events) == 1 - event = events[0] - assert event["ritualId"] == 0 - assert event["successful"] + events = coordinator.EndRitual.from_receipt(tx) + assert events == [coordinator.EndRitual(ritualId=0, successful=True)] def test_authorize_using_global_allow_list( - coordinator, - nodes, - deployer, - initiator, - erc20, - flat_rate_fee_model, - global_allow_list + coordinator, nodes, deployer, initiator, erc20, flat_rate_fee_model, global_allow_list ): initiate_ritual( @@ -348,7 +329,7 @@ def test_authorize_using_global_allow_list( fee_model=flat_rate_fee_model, authority=initiator, nodes=nodes, - allow_logic=global_allow_list + allow_logic=global_allow_list, ) global_allow_list.setCoordinator(coordinator.address, sender=deployer) @@ -380,7 +361,9 @@ def test_authorize_using_global_allow_list( decryption_request_static_keys = [os.urandom(42) for _ in nodes] dkg_public_key = (os.urandom(32), os.urandom(16)) for i, node in enumerate(nodes): - coordinator.postAggregation(0, aggregated, dkg_public_key, decryption_request_static_keys[i], sender=node) + coordinator.postAggregation( + 0, aggregated, dkg_public_key, decryption_request_static_keys[i], sender=node + ) # Actually authorize global_allow_list.authorize(0, [deployer.address], sender=initiator) diff --git a/tests/test_dispatcher.py b/tests/test_dispatcher.py index 8541a95b..71db5020 100644 --- a/tests/test_dispatcher.py +++ b/tests/test_dispatcher.py @@ -52,16 +52,10 @@ def test_dispatcher(project, accounts): assert creator == event["owner"] events = dispatcher.StateVerified.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert contract1_lib.address == event["testTarget"] - assert creator == event["sender"] + assert events == [dispatcher.StateVerified(testTarget=contract1_lib.address, sender=creator)] events = dispatcher.UpgradeFinished.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert contract1_lib.address == event["target"] - assert creator == event["sender"] + assert events == [dispatcher.UpgradeFinished(target=contract1_lib.address, sender=creator)] # Assign dispatcher address as contract. # In addition to the interface can be used ContractV1, ContractV2 or ContractV3 ABI @@ -125,16 +119,13 @@ def test_dispatcher(project, accounts): assert creator == event["owner"] events = dispatcher.StateVerified.from_receipt(tx) - assert len(events) == 2 - for event in events: - assert contract2_lib.address == event["testTarget"] - assert creator == event["sender"] + assert events == [ + dispatcher.StateVerified(testTarget=contract2_lib.address, sender=creator), + dispatcher.StateVerified(testTarget=contract2_lib.address, sender=creator), + ] events = dispatcher.UpgradeFinished.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert contract2_lib.address == event["target"] - assert creator == event["sender"] + assert events == [dispatcher.UpgradeFinished(target=contract2_lib.address, sender=creator)] # Check values and methods after upgrade assert 20 == contract_instance.returnValue() @@ -205,16 +196,10 @@ def test_dispatcher(project, accounts): assert creator == event["owner"] events = dispatcher.StateVerified.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert contract2_lib.address == event["testTarget"] - assert creator == event["sender"] + assert events == [dispatcher.StateVerified(testTarget=contract2_lib.address, sender=creator)] events = dispatcher.UpgradeFinished.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert contract1_lib.address == event["target"] - assert creator == event["sender"] + assert events == [dispatcher.UpgradeFinished(target=contract1_lib.address, sender=creator)] # Can't upgrade to the bad version with ape.reverts(): @@ -226,10 +211,7 @@ def test_dispatcher(project, accounts): # Create Event contract_instance = project.ContractV1.at(dispatcher.address) tx = contract_instance.createEvent(33, sender=creator) - events = contract_instance.EventV1.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert 33 == event["value"] + assert tx.events == [contract_instance.EventV1(value=33)] # Upgrade to the version 3 tx1 = dispatcher.upgrade(contract2_lib.address, sender=creator) @@ -250,28 +232,22 @@ def test_dispatcher(project, accounts): assert creator == event["owner"] events = dispatcher.StateVerified.from_receipt(tx1) - assert len(events) == 2 - for event in events: - assert contract2_lib.address == event["testTarget"] - assert creator == event["sender"] + assert events == [ + dispatcher.StateVerified(testTarget=contract2_lib.address, sender=creator), + dispatcher.StateVerified(testTarget=contract2_lib.address, sender=creator), + ] events = dispatcher.StateVerified.from_receipt(tx2) - assert len(events) == 2 - for event in events: - assert contract3_lib.address == event["testTarget"] - assert creator == event["sender"] + assert events == [ + dispatcher.StateVerified(testTarget=contract3_lib.address, sender=creator), + dispatcher.StateVerified(testTarget=contract3_lib.address, sender=creator), + ] events = dispatcher.UpgradeFinished.from_receipt(tx1) - assert len(events) == 1 - event = events[0] - assert contract2_lib.address == event["target"] - assert creator == event["sender"] + assert events == [dispatcher.UpgradeFinished(target=contract2_lib.address, sender=creator)] events = dispatcher.UpgradeFinished.from_receipt(tx2) - assert len(events) == 1 - event = events[0] - assert contract3_lib.address == event["target"] - assert creator == event["sender"] + assert events == [dispatcher.UpgradeFinished(target=contract3_lib.address, sender=creator)] contract_instance = project.ContractV3.at(dispatcher.address) assert contract3_lib.address == dispatcher.target() @@ -298,10 +274,7 @@ def test_dispatcher(project, accounts): # Create and check events tx = contract_instance.createEvent(22, sender=creator) - events = contract_instance.EventV2.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert 22 == event["value"] + assert tx.events == [contract_instance.EventV2(value=22)] # Check upgrading to the contract with explicit storage slots tx = dispatcher.upgrade(contract4_lib.address, sender=creator) @@ -328,16 +301,13 @@ def test_dispatcher(project, accounts): assert 77 == contract_instance.anotherStorageValue() events = dispatcher.StateVerified.from_receipt(tx) - assert len(events) == 2 - for event in events: - assert contract4_lib.address == event["testTarget"] - assert creator == event["sender"] + assert events == [ + dispatcher.StateVerified(testTarget=contract4_lib.address, sender=creator), + dispatcher.StateVerified(testTarget=contract4_lib.address, sender=creator), + ] events = dispatcher.UpgradeFinished.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert contract4_lib.address == event["target"] - assert creator == event["sender"] + assert events == [dispatcher.UpgradeFinished(target=contract4_lib.address, sender=creator)] # Upgrade to the previous version - check that new `verifyState` can handle old contract tx = dispatcher.upgrade(contract3_lib.address, sender=creator) @@ -363,10 +333,10 @@ def test_dispatcher(project, accounts): assert 77 == contract_instance.anotherStorageValue() events = dispatcher.StateVerified.from_receipt(tx) - assert len(events) == 2 - for event in events: - assert contract3_lib.address == event["testTarget"] - assert creator == event["sender"] + assert events == [ + dispatcher.StateVerified(testTarget=contract3_lib.address, sender=creator), + dispatcher.StateVerified(testTarget=contract3_lib.address, sender=creator), + ] def test_selfdestruct(project, accounts): diff --git a/tests/test_subscription_manager.py b/tests/test_subscription_manager.py index 0c317493..f0769355 100644 --- a/tests/test_subscription_manager.py +++ b/tests/test_subscription_manager.py @@ -67,16 +67,17 @@ def test_create_policy(subscription_manager, accounts, chain): assert policy[3] == size assert policy[4] == "0x0000000000000000000000000000000000000000" - events = subscription_manager.PolicyCreated.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert bytes(event["policyId"]) == policy_id - assert event["sponsor"] == alice - assert event["owner"] == alice - assert event["size"] == size - assert event["startTimestamp"] == start - assert event["endTimestamp"] == end - assert event["cost"] == fee + assert tx.events == [ + subscription_manager.PolicyCreated( + policyId=policy_id, + sponsor=alice, + owner=alice, + size=size, + startTimestamp=start, + endTimestamp=end, + cost=fee, + ) + ] def test_create_policy_with_sponsor(subscription_manager, accounts, chain): @@ -103,16 +104,17 @@ def test_create_policy_with_sponsor(subscription_manager, accounts, chain): assert policy[3] == size assert policy[4] == alice - events = subscription_manager.PolicyCreated.from_receipt(tx) - assert len(events) == 1 - event = events[0] - assert bytes(event["policyId"]) == policy_id - assert event["sponsor"] == sponsor - assert event["owner"] == alice - assert event["size"] == size - assert event["startTimestamp"] == start - assert event["endTimestamp"] == end - assert event["cost"] == fee + assert tx.events == [ + subscription_manager.PolicyCreated( + policyId=policy_id, + sponsor=sponsor, + owner=alice, + size=size, + startTimestamp=start, + endTimestamp=end, + cost=fee, + ) + ] def test_create_policy_with_same_id(subscription_manager, accounts, chain):