diff --git a/contracts/Bounty/Implementations/BountyCore.sol b/contracts/Bounty/Implementations/BountyCore.sol index 52431572..6e004913 100755 --- a/contracts/Bounty/Implementations/BountyCore.sol +++ b/contracts/Bounty/Implementations/BountyCore.sol @@ -119,11 +119,10 @@ abstract contract BountyCore is BountyStorageCore { /// @notice Sets the funding goal /// @param _fundingToken Token address for funding goal /// @param _fundingGoal Token volume for funding goal - function setFundingGoal(address _fundingToken, uint256 _fundingGoal) - external - virtual - onlyOpenQ - { + function setFundingGoal( + address _fundingToken, + uint256 _fundingGoal + ) external virtual onlyOpenQ { fundingGoal = _fundingGoal; fundingToken = _fundingToken; hasFundingGoal = true; @@ -137,21 +136,25 @@ abstract contract BountyCore is BountyStorageCore { /// @notice Whether or not the Bounty is invoiceRequired /// @param _invoiceRequired Whether or not the Bounty is invoiceRequired - function setInvoiceRequired(bool _invoiceRequired) - external - virtual - onlyOpenQ - { + function setInvoiceRequired( + bool _invoiceRequired + ) external virtual onlyOpenQ { invoiceRequired = _invoiceRequired; } + /// @notice Whether or not the Bounty is polygonIdRequired + /// @param _polygonIdRequired Whether or not the Bounty is polygonIdRequired + function setPolygonIdRequired( + bool _polygonIdRequired + ) external virtual onlyOpenQ { + polygonIdRequired = _polygonIdRequired; + } + /// @notice Whether or not KYC is required to fund and claim the bounty /// @param _supportingDocumentsRequired Whether or not KYC is required to fund and claim the bounty - function setSupportingDocumentsRequired(bool _supportingDocumentsRequired) - external - virtual - onlyOpenQ - { + function setSupportingDocumentsRequired( + bool _supportingDocumentsRequired + ) external virtual onlyOpenQ { supportingDocumentsRequired = _supportingDocumentsRequired; } @@ -211,10 +214,10 @@ abstract contract BountyCore is BountyStorageCore { /// @notice Transfers _volume of protocol token from bounty address to _payoutAddress /// @param _payoutAddress The destination address of the funds /// @param _volume The volume of token to transfer - function _transferProtocolToken(address _payoutAddress, uint256 _volume) - internal - virtual - { + function _transferProtocolToken( + address _payoutAddress, + uint256 _volume + ) internal virtual { payable(_payoutAddress).sendValue(_volume); } @@ -227,12 +230,9 @@ abstract contract BountyCore is BountyStorageCore { /// @notice Returns token balance for both ERC20 or protocol token /// @param _tokenAddress Address of an ERC20 or Zero Address for protocol token - function getTokenBalance(address _tokenAddress) - public - view - virtual - returns (uint256) - { + function getTokenBalance( + address _tokenAddress + ) public view virtual returns (uint256) { if (_tokenAddress == address(0)) { return address(this).balance; } else { @@ -243,12 +243,9 @@ abstract contract BountyCore is BountyStorageCore { /// @notice Returns the ERC20 balance for this bounty address /// @param _tokenAddress The ERC20 token address /// @return balance The ERC20 balance for this bounty address - function getERC20Balance(address _tokenAddress) - public - view - virtual - returns (uint256 balance) - { + function getERC20Balance( + address _tokenAddress + ) public view virtual returns (uint256 balance) { IERC20Upgradeable token = IERC20Upgradeable(_tokenAddress); return token.balanceOf(address(this)); } diff --git a/contracts/Bounty/Interfaces/IBountyCore.sol b/contracts/Bounty/Interfaces/IBountyCore.sol index 90721317..a0418d50 100755 --- a/contracts/Bounty/Interfaces/IBountyCore.sol +++ b/contracts/Bounty/Interfaces/IBountyCore.sol @@ -74,8 +74,10 @@ interface IBountyCore { /// @notice Sets the funding goal /// @param _fundingToken Token address for funding goal /// @param _fundingGoal Token volume for funding goal - function setFundingGoal(address _fundingToken, uint256 _fundingGoal) - external; + function setFundingGoal( + address _fundingToken, + uint256 _fundingGoal + ) external; /// @notice Whether or not KYC is required to fund and claim the bounty /// @param _kycRequired Whether or not KYC is required to fund and claim the bounty @@ -85,10 +87,15 @@ interface IBountyCore { /// @param _invoiceRequired Whether or not the Bounty is invoiceRequired function setInvoiceRequired(bool _invoiceRequired) external; + /// @notice Whether or not the Bounty is polygonIdRequired + /// @param _polygonIdRequired Whether or not the Bounty is _polygonIdRequired + function setPolygonIdRequired(bool _polygonIdRequired) external; + /// @notice Whether or not KYC is required to fund and claim the bounty /// @param _supportingDocumentsRequired Whether or not KYC is required to fund and claim the bounty - function setSupportingDocumentsRequired(bool _supportingDocumentsRequired) - external; + function setSupportingDocumentsRequired( + bool _supportingDocumentsRequired + ) external; /// @notice Whether or not invoice has been completed /// @param _data ABI encoded data @@ -117,10 +124,9 @@ interface IBountyCore { /// @notice Returns token balance for both ERC20 or protocol token /// @param _tokenAddress Address of an ERC20 or Zero Address for protocol token - function getTokenBalance(address _tokenAddress) - external - view - returns (uint256); + function getTokenBalance( + address _tokenAddress + ) external view returns (uint256); /// @notice Returns an array of all ERC20 token addresses which have funded this bounty /// @return tokenAddresses An array of all ERC20 token addresses which have funded this bounty @@ -175,6 +181,8 @@ interface IBountyCore { function invoiceRequired() external view returns (bool); + function polygonIdRequired() external view returns (bool); + function kycRequired() external view returns (bool); function supportingDocumentsRequired() external view returns (bool); diff --git a/contracts/Bounty/Storage/BountyStorageCore.sol b/contracts/Bounty/Storage/BountyStorageCore.sol index c2f15a2c..e4e476c8 100755 --- a/contracts/Bounty/Storage/BountyStorageCore.sol +++ b/contracts/Bounty/Storage/BountyStorageCore.sol @@ -66,5 +66,7 @@ abstract contract BountyStorageCore is bool public supportingDocumentsRequired; string public issuerExternalUserId; - uint256[50] private __gap; + bool public polygonIdRequired; + + uint256[49] private __gap; } diff --git a/contracts/ClaimManager/Implementations/ClaimManagerV1.sol b/contracts/ClaimManager/Implementations/ClaimManagerV1.sol index ef74cc75..aa9ffb4e 100755 --- a/contracts/ClaimManager/Implementations/ClaimManagerV1.sol +++ b/contracts/ClaimManager/Implementations/ClaimManagerV1.sol @@ -228,6 +228,13 @@ contract ClaimManagerV1 is ClaimManagerStorageV1 { return IKycValidity(kyc).hasValidToken(_address); } + /// @notice Checks if the address has a valid Polygon ID + /// @return True if address has a valid Polygon ID + function hasValidPolygonId(address _address) public view returns (bool) { + // TODO - Implement Polygon ID check + return true; + } + /// @notice Runs all require statements to determine if the claimant can claim the specified tier on the tiered bounty function _eligibleToClaimTier( ITieredBounty _bounty, @@ -253,6 +260,10 @@ contract ClaimManagerV1 is ClaimManagerStorageV1 { if (_bounty.kycRequired()) { require(hasKYC(_closer), Errors.ADDRESS_LACKS_KYC); } + + if (_bounty.polygonIdRequired()) { + require(hasValidPolygonId(_closer), Errors.ADDRESS_LACKS_KYC); + } } /// @notice Runs all require statements to determine if the claimant can claim the atomic bounty diff --git a/contracts/OpenQ/Implementations/OpenQV1.sol b/contracts/OpenQ/Implementations/OpenQV1.sol index 97e3640c..5aa2deaa 100755 --- a/contracts/OpenQ/Implementations/OpenQV1.sol +++ b/contracts/OpenQ/Implementations/OpenQV1.sol @@ -81,7 +81,7 @@ contract OpenQV1 is OpenQStorageV1 { block.timestamp, bountyType(_bountyId), _initOperation.data, - VERSION_1 + VERSION_2 ); return bountyAddress; @@ -139,7 +139,7 @@ contract OpenQV1 is OpenQStorageV1 { address(bounty), bounty.getTierWinners(), abi.encode(_bountyId, _winner, _tier), - VERSION_1 + VERSION_2 ); } @@ -164,7 +164,7 @@ contract OpenQV1 is OpenQStorageV1 { _fundingGoalVolume, bounty.bountyType(), new bytes(0), - VERSION_1 + VERSION_2 ); } @@ -186,7 +186,7 @@ contract OpenQV1 is OpenQStorageV1 { _kycRequired, bounty.bountyType(), new bytes(0), - VERSION_1 + VERSION_2 ); } @@ -208,7 +208,29 @@ contract OpenQV1 is OpenQStorageV1 { _invoiceRequired, bounty.bountyType(), new bytes(0), - VERSION_1 + VERSION_2 + ); + } + + /// @notice Sets invoiceRequired on bounty with id _bountyId + /// @param _bountyId The id to update + /// @param _polygonIdRequired Whether or not the bounty should be set as invoiceRequired + function setPolygonIdRequired( + string calldata _bountyId, + bool _polygonIdRequired + ) external onlyProxy { + IBounty bounty = getBounty(_bountyId); + + require(msg.sender == bounty.issuer(), Errors.CALLER_NOT_ISSUER); + + bounty.setPolygonIdRequired(_polygonIdRequired); + + emit PolygonIdRequired( + address(bounty), + _polygonIdRequired, + bounty.bountyType(), + new bytes(0), + VERSION_2 ); } @@ -230,7 +252,7 @@ contract OpenQV1 is OpenQStorageV1 { _supportingDocumentsRequired, bounty.bountyType(), new bytes(0), - VERSION_1 + VERSION_2 ); } @@ -270,7 +292,7 @@ contract OpenQV1 is OpenQStorageV1 { address(bounty), bounty.bountyType(), abi.encode(_bountyId, _winner, _tier, _invoiceComplete), - VERSION_1 + VERSION_2 ); } @@ -310,7 +332,7 @@ contract OpenQV1 is OpenQStorageV1 { address(bounty), bounty.bountyType(), abi.encode(_bountyId, _winner, _tier, _supportingDocumentsComplete), - VERSION_1 + VERSION_2 ); } @@ -335,7 +357,7 @@ contract OpenQV1 is OpenQStorageV1 { _payoutSchedule, bounty.bountyType(), new bytes(0), - VERSION_1 + VERSION_2 ); } @@ -437,7 +459,7 @@ contract OpenQV1 is OpenQStorageV1 { formerExternalUserId, formerAddress, new bytes(0), - VERSION_1 + VERSION_2 ); } } diff --git a/contracts/OpenQ/Interfaces/IOpenQ.sol b/contracts/OpenQ/Interfaces/IOpenQ.sol index e290b865..0be78ce7 100755 --- a/contracts/OpenQ/Interfaces/IOpenQ.sol +++ b/contracts/OpenQ/Interfaces/IOpenQ.sol @@ -5,9 +5,9 @@ pragma solidity 0.8.17; /// @author FlacoJones /// @notice Interface declaring OpenQ events and methods used by other contracts interface IOpenQ { - function externalUserIdToAddress(string calldata) - external - returns (address); + function externalUserIdToAddress( + string calldata + ) external returns (address); function addressToExternalUserId(address) external returns (string memory); @@ -66,6 +66,14 @@ interface IOpenQ { uint256 version ); + event PolygonIdRequired( + address bountyAddress, + bool polygonIdRequired, + uint256 bountyType, + bytes data, + uint256 version + ); + event InvoiceRequiredSet( address bountyAddress, bool invoiceRequired, diff --git a/contracts/OpenQ/Storage/OpenQStorage.sol b/contracts/OpenQ/Storage/OpenQStorage.sol index f4ee61d9..a349f11b 100755 --- a/contracts/OpenQ/Storage/OpenQStorage.sol +++ b/contracts/OpenQ/Storage/OpenQStorage.sol @@ -33,5 +33,7 @@ abstract contract OpenQStorageV1 is mapping(string => address) public externalUserIdToAddress; mapping(address => string) public addressToExternalUserId; - uint256[50] private __gap; + uint256 public constant VERSION_2 = 2; + + uint256[49] private __gap; }