diff --git a/.gas-snapshot b/.gas-snapshot index f129a939..816f4a5c 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -20,46 +20,46 @@ Certificate_supportsInterface:test() (gas: 5159) Certificate_transferFrom:test() (gas: 48618) Certificate_transferFrom:test_reverts_when_paused() (gas: 38088) Certificate_transferFrom_reverts_ForbiddenTransferAfterMinting:test() (gas: 18960) -Checkout_buyingFromOneRemoval:test() (gas: 470314) -Checkout_buyingFromOneRemoval_byApproval:test() (gas: 408705) -Checkout_buyingFromTenRemovals:test() (gas: 1549359) -Checkout_buyingFromTenRemovals_singleSupplier:test() (gas: 1309225) -Checkout_buyingFromTenRemovals_singleSupplier_withoutFee:test() (gas: 1304425) -Checkout_buyingFromTenRemovals_withoutFee:test() (gas: 1317176) -Checkout_buyingFromTenSuppliers:test() (gas: 1818158) -Checkout_buyingWithAlternateERC20:test() (gas: 540964) -Checkout_buyingWithAlternateERC20_floatingPointPriceMultiple:test() (gas: 506930) -Checkout_swapRevertsWhenBuyerIsMissingSANCTION_ALLOWLIST_ROLE:test() (gas: 168693) -Checkout_swapRevertsWithDifferentPermitSignerAndMsgSender:test() (gas: 168705) -Checkout_swapWithoutFeeSpecialOrder:test() (gas: 380597) -Checkout_swapWithoutFeeSpecialOrder_specificSupplier:test() (gas: 375252) +Checkout_buyingFromOneRemoval:test() (gas: 470402) +Checkout_buyingFromOneRemoval_byApproval:test() (gas: 408749) +Checkout_buyingFromTenRemovals:test() (gas: 1549843) +Checkout_buyingFromTenRemovals_singleSupplier:test() (gas: 1309445) +Checkout_buyingFromTenRemovals_singleSupplier_withoutFee:test() (gas: 1304645) +Checkout_buyingFromTenRemovals_withoutFee:test() (gas: 1317396) +Checkout_buyingFromTenSuppliers:test() (gas: 1818545) +Checkout_buyingWithAlternateERC20:test() (gas: 541052) +Checkout_buyingWithAlternateERC20_floatingPointPriceMultiple:test() (gas: 507018) +Checkout_swapRevertsWhenBuyerIsMissingSANCTION_ALLOWLIST_ROLE:test() (gas: 168737) +Checkout_swapRevertsWithDifferentPermitSignerAndMsgSender:test() (gas: 168749) +Checkout_swapWithoutFeeSpecialOrder:test() (gas: 380619) +Checkout_swapWithoutFeeSpecialOrder_specificSupplier:test() (gas: 375274) Checkout_swapWithoutFeeSpecialOrder_specificSupplier:test_revertsWhenSupplierDoesNotExistInMarket() (gas: 57753) -Checkout_swapWithoutFeeSpecialOrder_specificVintages:test_basicFulfillment() (gas: 642423) +Checkout_swapWithoutFeeSpecialOrder_specificVintages:test_basicFulfillment() (gas: 642489) Checkout_swapWithoutFeeSpecialOrder_specificVintages:test_revertsWhenNoRemovalsFromSpecifiedVintages() (gas: 91044) -Checkout_swapWithoutFeeSpecialOrder_specificVintagesSpecificSupplier:test_basicFulfillment() (gas: 491863) -GasBenchmark_buyingFromManyRemovals_singleSupplier:test() (gas: 29847653) -GasBenchmark_buyingFromOneRemoval_singleSupplier:test() (gas: 322867) +Checkout_swapWithoutFeeSpecialOrder_specificVintagesSpecificSupplier:test_basicFulfillment() (gas: 491903) +GasBenchmark_buyingFromManyRemovals_singleSupplier:test() (gas: 29853285) +GasBenchmark_buyingFromOneRemoval_singleSupplier:test() (gas: 322889) LockedNORILib_availableAmount:test() (gas: 12371) LockedNORITest:testBatchGrantCreation() (gas: 705179) LockedNORITest:testNormalWithdrawal() (gas: 1102743) LockedNORITest:testReentryTokensReceived() (gas: 1102887) LockedNORITest:testReentryTokensToSend() (gas: 1104432) LockedNORITest:testTokensReceivedReverts() (gas: 69026) -MarketInvariantTest:invariant_callSummary() (runs: 400, calls: 6000, reverts: 4285) -MarketInvariantTest:invariant_sumOfPurchaseAmounts() (runs: 400, calls: 6000, reverts: 4268) -MarketSupplierSelectionNotUsingUpSuppliersLastRemoval:test() (gas: 644612) +MarketInvariantTest:invariant_callSummary() (runs: 400, calls: 6000, reverts: 4265) +MarketInvariantTest:invariant_sumOfPurchaseAmounts() (runs: 400, calls: 6000, reverts: 4261) +MarketSupplierSelectionNotUsingUpSuppliersLastRemoval:test() (gas: 644744) Market_ALLOWLIST_ROLE:test() (gas: 12799) Market_SANCTION_ALLOWLIST_ROLE:test() (gas: 12897) -Market_USDC_swap_respects_decimal_mismatch:test() (gas: 786916) +Market_USDC_swap_respects_decimal_mismatch:test() (gas: 787070) Market__addActiveRemoval:test() (gas: 183344) Market__addActiveRemoval:test__lis2VintagesFor1SupplierFor2SubIdentifiers() (gas: 242879) Market__addActiveRemoval:test__list1VintageFor1Supplier() (gas: 188309) Market__addActiveRemoval:test__list1VintageFor2Suppliers() (gas: 360670) -Market__addActiveRemoval:test__list2VintagesFor1SupplierFor1SubIdentifier() (gas: 262754) -Market__isAuthorizedWithdrawal_false:test_returnsFalseWhenAllConditionsAreFalse() (gas: 7452) -Market__isAuthorizedWithdrawal_true:test_returnsTrueWhenMsgSenderEqualsOwner() (gas: 377) -Market__isAuthorizedWithdrawal_true:test_returnsTrueWhenMsgSenderHasDefaultAdminRole() (gas: 96578) -Market__isAuthorizedWithdrawal_true:test_returnsTrueWhenMsgSenderIsApprovedForAll() (gas: 8923) +Market__addActiveRemoval:test__list2VintagesFor1SupplierFor1SubIdentifier() (gas: 262709) +Market__isAuthorizedWithdrawal_false:test_returnsFalseWhenAllConditionsAreFalse() (gas: 25767) +Market__isAuthorizedWithdrawal_true:test_returnsTrueWhenMsgSenderEqualsOwner() (gas: 17086) +Market__isAuthorizedWithdrawal_true:test_returnsTrueWhenMsgSenderHasDefaultAdminRole() (gas: 113243) +Market__isAuthorizedWithdrawal_true:test_returnsTrueWhenMsgSenderIsApprovedForAll() (gas: 23245) Market__multicall_empty_bytes_reverts:test() (gas: 20935) Market__multicall_initialize_reverts:test() (gas: 33859) Market__setPriceMultiple:test() (gas: 29132) @@ -72,23 +72,23 @@ Market__validatePrioritySupply_buyerIsAllowlistedAndAmountExceedsPriorityRestric Market__validatePrioritySupply_reverts_LowSupplyAllowlistRequired:test() (gas: 7692) Market__validateSupply:test() (gas: 292) Market__validateSupply:test_reverts_OutOfSupply() (gas: 3172) -Market_calculates_prices_using_decimal:test() (gas: 66514) +Market_calculates_prices_using_decimal:test() (gas: 66624) Market_convertPurchasingTokenDecimalsToRemovalDecimals:test() (gas: 26029) -Market_convertRemovalDecimalsToPurchasingTokenDecimals:test() (gas: 29773) +Market_convertRemovalDecimalsToPurchasingTokenDecimals:test() (gas: 29817) Market_getActiveSuppliers:test_1_supplier() (gas: 447828) Market_getActiveSuppliers:test_3_suppliers() (gas: 1088942) Market_getActiveSuppliers:test_no_suppliers() (gas: 20859) Market_getPriceMultiple:test() (gas: 14851) -Market_getRemovalIdsForSupplier:test_1_removal() (gas: 448231) -Market_getRemovalIdsForSupplier:test_3_removals() (gas: 831646) -Market_getRemovalIdsForSupplier:test_3_removals_different_vintages() (gas: 877755) -Market_getRemovalIdsForSupplier:test_no_removals() (gas: 26044) +Market_getRemovalIdsForSupplier:test_1_removal() (gas: 448142) +Market_getRemovalIdsForSupplier:test_3_removals() (gas: 831557) +Market_getRemovalIdsForSupplier:test_3_removals_different_vintages() (gas: 877666) +Market_getRemovalIdsForSupplier:test_no_removals() (gas: 25955) Market_onERC1155BatchReceived:test() (gas: 208124) Market_onERC1155BatchReceived_reverts_SenderNotRemovalContract:test() (gas: 331570) Market_onERC1155Received:test() (gas: 206036) Market_onERC1155Received_reverts_SenderNotRemovalContract:test() (gas: 159044) -Market_purchasingTokenAddress:test() (gas: 17080) -Market_replace:test() (gas: 277991) +Market_purchasingTokenAddress:test() (gas: 17102) +Market_replace:test() (gas: 278013) Market_replace_reverts_CertificateNotYetMinted:test() (gas: 49559) Market_replace_reverts_ReplacementAmountExceedsNrtDeficit:test() (gas: 52590) Market_replace_reverts_ReplacementAmountMismatch:test() (gas: 86397) @@ -97,22 +97,23 @@ Market_setPriorityRestrictedThreshold:test() (gas: 157448) Market_setPriorityRestrictedThreshold:test_zeroAvailable() (gas: 152423) Market_setPurchasingTokenAndPriceMultiple:test() (gas: 1026641) Market_setPurchasingTokenAndPriceMultiple_revertsIfNotAdmin:test() (gas: 50813) -Market_supplierSelectionUsingUpSuppliersLastRemoval:test() (gas: 641321) -Market_swap_revertsWhenUnsafeERC20TransferFails:test() (gas: 189648) +Market_supplierSelectionUsingUpSuppliersLastRemoval:test() (gas: 641453) +Market_swap_revertsWhenUnsafeERC20TransferFails:test() (gas: 189736) Market_validates_certificate_amount:test() (gas: 596800) -Market_withdraw_1x3_center:test() (gas: 340814) -Market_withdraw_2x1_back:test() (gas: 345496) -Market_withdraw_2x1_front:test() (gas: 333831) +Market_withdraw_1x3_center:test() (gas: 346739) +Market_withdraw_2x1_back:test() (gas: 351412) +Market_withdraw_2x1_front:test() (gas: 339756) Market_withdraw_2x1_front_relist:test() (gas: 381788) -Market_withdraw_as_DEFAULT_ADMIN_ROLE:test() (gas: 276524) -Market_withdraw_as_operator:test() (gas: 285669) -Market_withdraw_as_supplier:test() (gas: 274665) -Market_withdraw_reverts:test() (gas: 138709) +Market_withdraw_as_DEFAULT_ADMIN_ROLE:test() (gas: 282449) +Market_withdraw_as_operator:test() (gas: 291594) +Market_withdraw_as_supplier:test() (gas: 280590) +Market_withdraw_reverts:test() (gas: 144618) +Market_withdraw_to_CONSIGNOR_ROLE:test() (gas: 284393) NORI_name:test() (gas: 17205) NORI_permit:test() (gas: 92382) NoriUSDC_permit:test() (gas: 122061) RemovalQueue_getTotalBalanceFromRemovalQueue:test() (gas: 23921) -RemovalQueue_getTotalBalanceFromRemovalQueue:test_100xRemovalsOfTheDifferentVintages() (gas: 895808) +RemovalQueue_getTotalBalanceFromRemovalQueue:test_100xRemovalsOfTheDifferentVintages() (gas: 895830) RemovalQueue_getTotalBalanceFromRemovalQueue:test_100xRemovalsOfTheSameVintage() (gas: 620321) RemovalQueue_insertRemovalByVintage:test_insertRemovalOnce() (gas: 119613) RemovalQueue_insertRemovalByVintage:test_insertRemovalTwice() (gas: 121103) @@ -123,7 +124,7 @@ Removal__createRemovalData:test_reverts_InvalidData() (gas: 25711) Removal__createRemovalDataBatch:test() (gas: 29594) Removal__createRemovalDataBatch:test_reverts_InvalidData2() (gas: 36802) Removal__isValidTransferAmount:testFuzz_ReturnFalse_NonMultiplesOf1e14(uint256) (runs: 256, μ: 13935, ~: 13891) -Removal__isValidTransferAmount:testFuzz_ReturnTrue_MultiplesOf1e14(uint256) (runs: 256, μ: 14315, ~: 14432) +Removal__isValidTransferAmount:testFuzz_ReturnTrue_MultiplesOf1e14(uint256) (runs: 256, μ: 14307, ~: 14432) Removal__isValidTransferAmount:testFuzz_ReturnTrue_SmallestGranularity() (gas: 6876) Removal__isValidTransferAmount:test_ReturnFalse_AmountIsTooGranular() (gas: 6854) Removal__isValidTransferAmount:test_ReturnFalse_AmountIsTooGranularAndToIsTheCertificate() (gas: 4789) @@ -135,11 +136,11 @@ Removal__validateRemoval:test() (gas: 2491) Removal__validateRemoval:test_reverts_InvalidData() (gas: 5373) Removal_addBalance:test() (gas: 60280) Removal_addBalance_reverts_RemovalNotYetMinted:test() (gas: 31115) -Removal_consign_revertsForSoldRemovals:test() (gas: 896622) +Removal_consign_revertsForSoldRemovals:test() (gas: 896728) Removal_consignorBatchTransfer:test() (gas: 297325) Removal_consignorBatchTransfer:test_reverts_whenReceiverIsNotConsignor() (gas: 128791) Removal_consignorBatchTransfer:test_reverts_whenSenderIsNotConsignor() (gas: 65646) -Removal_getMarketBalance:test() (gas: 907046) +Removal_getMarketBalance:test() (gas: 910292) Removal_getOwnedTokenIds:test_multiple_tokens_with_transfer() (gas: 916416) Removal_getOwnedTokenIds:test_no_tokens() (gas: 18683) Removal_getProjectId:test() (gas: 19307) @@ -157,7 +158,7 @@ Removal_mintBatch_zero_amount_removal:test() (gas: 139898) Removal_mintBatch_zero_amount_removal_to_market_reverts:test() (gas: 61595) Removal_multicall:test_balanceOfBatch() (gas: 320743) Removal_release_listed:test() (gas: 356643) -Removal_release_listed_isRemovedFromMarket:test() (gas: 356996) +Removal_release_listed_isRemovedFromMarket:test() (gas: 356854) Removal_release_partial_listed:test() (gas: 79593) Removal_release_retired:test() (gas: 92447) Removal_release_retired_2x:test() (gas: 98511) diff --git a/contracts/Market.sol b/contracts/Market.sol index 4b2a841a..e2459964 100644 --- a/contracts/Market.sol +++ b/contracts/Market.sol @@ -781,19 +781,22 @@ contract Market is } /** - * @notice Withdraws a removal to the supplier. - * @dev Withdraws a removal to the supplier address encoded in the removal ID. + * @notice Withdraws a removal from the Market. + * @dev Withdraws a removal to the specified address, which must be the supplier of the removal + * or have the `Removal.CONSIGNOR_ROLE`. * * ##### Requirements: * * - Can only be used when this contract is not paused. + * - Can only withdraw to the supplier of the removal or an address with the `Removal.CONSIGNOR_ROLE`. * @param removalId The ID of the removal to withdraw from the market. + * @param to The address to which the removal will be transferred. */ - function withdraw(uint256 removalId) external whenNotPaused { + function withdraw(uint256 removalId, address to) external whenNotPaused { address supplierAddress = RemovalIdLib.supplierAddress({ removalId: removalId }); - if (_isAuthorizedWithdrawal({owner: supplierAddress})) { + if (_isAuthorizedWithdrawal({supplier: supplierAddress, to: to})) { _removeActiveRemoval({ removalId: removalId, supplierAddress: supplierAddress @@ -1349,16 +1352,26 @@ contract Market is } /** - * @dev Authorizes withdrawal for the removal. Reverts if the caller is not the owner of the removal and - * does not have the role `MARKET_ADMIN_ROLE`. - * @param owner The owner of the removal. - * @return Returns true if the caller is the owner, an approved spender, or has the role `MARKET_ADMIN_ROLE`, - * false otherwise. + * @dev Authorizes withdrawal for the removal. Reverts if the caller is not the supplier of the removal and + * does not have the role `MARKET_ADMIN_ROLE`, or if the recipient of the removal is either not the supplier + * of the removal or does not have the `Removal.CONSIGNOR_ROLE`. + * @param supplier The supplier of the removal. + * @param to The recipient of the removal. + * @return Returns true if the caller is the supplier, an approved spender, or has the role `MARKET_ADMIN_ROLE`, + * and the recipient is the removal supplier or has the `Removal.CONSIGNOR_ROLE`, false otherwise. */ - function _isAuthorizedWithdrawal(address owner) internal view returns (bool) { - return (_msgSender() == owner || + function _isAuthorizedWithdrawal( + address supplier, + address to + ) internal view returns (bool) { + bool isApprovedCaller = _msgSender() == supplier || hasRole({role: MARKET_ADMIN_ROLE, account: _msgSender()}) || - _removal.isApprovedForAll({account: owner, operator: _msgSender()})); + _removal.isApprovedForAll({account: supplier, operator: _msgSender()}); + bool isApprovedRecipient = _removal.hasRole({ + role: _removal.CONSIGNOR_ROLE(), + account: to + }) || supplier == to; + return isApprovedCaller && isApprovedRecipient; } /** diff --git a/docs/Market.md b/docs/Market.md index 2e9fdcd7..8db1254b 100644 --- a/docs/Market.md +++ b/docs/Market.md @@ -671,20 +671,23 @@ contract to the specified recipient and the ERC20 is distributed to the supplier ### withdraw ```solidity -function withdraw(uint256 removalId) external +function withdraw(uint256 removalId, address to) external ``` -Withdraws a removal to the supplier. +Withdraws a removal from the Market. -Withdraws a removal to the supplier address encoded in the removal ID. +Withdraws a removal to the specified address, which must be the supplier of the removal +or have the `Removal.CONSIGNOR_ROLE`. ##### Requirements: -- Can only be used when this contract is not paused. +- Can only be used when this contract is not paused. +- Can only withdraw to the supplier of the removal or an address with the `Removal.CONSIGNOR_ROLE`. | Name | Type | Description | | ---- | ---- | ----------- | | removalId | uint256 | The ID of the removal to withdraw from the market. | +| to | address | The address to which the removal will be transferred. | ### getPriceMultiple @@ -1165,20 +1168,22 @@ Validates that the listed supply is enough to fulfill the purchase given the pri ### _isAuthorizedWithdrawal ```solidity -function _isAuthorizedWithdrawal(address owner) internal view returns (bool) +function _isAuthorizedWithdrawal(address supplier, address to) internal view returns (bool) ``` -Authorizes withdrawal for the removal. Reverts if the caller is not the owner of the removal and -does not have the role `MARKET_ADMIN_ROLE`. +Authorizes withdrawal for the removal. Reverts if the caller is not the supplier of the removal and +does not have the role `MARKET_ADMIN_ROLE`, or if the recipient of the removal is either not the supplier +of the removal or does not have the `Removal.CONSIGNOR_ROLE`. | Name | Type | Description | | ---- | ---- | ----------- | -| owner | address | The owner of the removal. | +| supplier | address | The supplier of the removal. | +| to | address | The recipient of the removal. | | Name | Type | Description | | ---- | ---- | ----------- | -| [0] | bool | Returns true if the caller is the owner, an approved spender, or has the role `MARKET_ADMIN_ROLE`, false otherwise. | +| [0] | bool | Returns true if the caller is the supplier, an approved spender, or has the role `MARKET_ADMIN_ROLE`, and the recipient is the removal supplier or has the `Removal.CONSIGNOR_ROLE`, false otherwise. | ### _validateReplacementAmounts diff --git a/test/Market.t.sol b/test/Market.t.sol index decf5b8a..b09acbdd 100644 --- a/test/Market.t.sol +++ b/test/Market.t.sol @@ -408,7 +408,7 @@ contract Market_withdraw_as_supplier is MarketBalanceTestHelper { function test() external { vm.prank(_namedAccounts.supplier); - _market.withdraw(_removalIds[0]); + _market.withdraw({removalId: _removalIds[0], to: _namedAccounts.supplier}); _expectedRemovalBalances = [_amountPerRemoval]; _expectedMarketSupply = 0; _expectedTokenCount.set(_namedAccounts.supplier, 1); @@ -441,7 +441,7 @@ contract Market_withdraw_as_operator is MarketBalanceTestHelper { function test() external { vm.prank(_namedAccounts.supplier2); - _market.withdraw(_removalIds[0]); + _market.withdraw({removalId: _removalIds[0], to: _namedAccounts.supplier}); _expectedRemovalBalances = [_amountPerRemoval]; _expectedMarketSupply = 0; _expectedTokenCount.set(_namedAccounts.supplier, 1); @@ -466,7 +466,7 @@ contract Market_withdraw_as_DEFAULT_ADMIN_ROLE is MarketBalanceTestHelper { } function test() external { - _market.withdraw(_removalIds[0]); + _market.withdraw({removalId: _removalIds[0], to: _namedAccounts.supplier}); _expectedRemovalBalances = [_amountPerRemoval]; _expectedMarketSupply = 0; _expectedTokenCount.set(_namedAccounts.supplier, 1); @@ -493,7 +493,7 @@ contract Market_withdraw_reverts is MarketBalanceTestHelper { function test() external { vm.prank(_namedAccounts.supplier2); vm.expectRevert(UnauthorizedWithdrawal.selector); - _market.withdraw(_removalIds[0]); + _market.withdraw({removalId: _removalIds[0], to: _namedAccounts.supplier2}); _assertCorrectStates(); } } @@ -515,7 +515,7 @@ contract Market_withdraw_1x3_center is MarketBalanceTestHelper { function test() external { vm.prank(_namedAccounts.supplier); - _market.withdraw(_removalIds[1]); + _market.withdraw({removalId: _removalIds[1], to: _namedAccounts.supplier}); _expectedRemovalBalances = [0, _amountPerRemoval, 0]; _expectedMarketSupply = _amountPerRemoval * (_removalIds.length - 1); _expectedTokenCount.set(_namedAccounts.supplier, 1); @@ -541,7 +541,7 @@ contract Market_withdraw_2x1_front is MarketBalanceTestHelper { function test() external { vm.prank(_namedAccounts.supplier); - _market.withdraw(_removalIds[0]); + _market.withdraw({removalId: _removalIds[0], to: _namedAccounts.supplier}); _expectedRemovalBalances = [_amountPerRemoval, 0]; _expectedMarketSupply = _amountPerRemoval * (_removalIds.length - 1); _expectedTokenCount.set(_namedAccounts.supplier, 1); @@ -568,7 +568,7 @@ contract Market_withdraw_2x1_front_relist is MarketBalanceTestHelper { ]; _assertListedState(); vm.prank(_namedAccounts.supplier); - _market.withdraw(_removalIds[0]); + _market.withdraw({removalId: _removalIds[0], to: _namedAccounts.supplier}); _expectedRemovalBalances = [_amountPerRemoval, 0]; _expectedMarketSupply = _amountPerRemoval * (_removalIds.length - 1); _expectedTokenCount.set(_namedAccounts.supplier, 1); @@ -604,7 +604,7 @@ contract Market_withdraw_2x1_back is MarketBalanceTestHelper { function test() external { vm.prank(_namedAccounts.supplier2); - _market.withdraw(_removalIds[1]); + _market.withdraw({removalId: _removalIds[1], to: _namedAccounts.supplier2}); _expectedRemovalBalances = [0, _amountPerRemoval]; _expectedMarketSupply = _amountPerRemoval * (_removalIds.length - 1); _expectedTokenCount.set(_namedAccounts.supplier, 0); @@ -614,6 +614,38 @@ contract Market_withdraw_2x1_back is MarketBalanceTestHelper { } } +contract Market_withdraw_to_CONSIGNOR_ROLE is MarketBalanceTestHelper { + function setUp() external { + _removalIds = _seedRemovals({ + to: _namedAccounts.supplier, + count: 1, + list: true + }); + _suppliers = new address[](1).fill(_namedAccounts.supplier); + _expectedRemovalBalances = [0]; + _expectedMarketSupply = _amountPerRemoval * _removalIds.length; + _expectedTokenCount.set(_namedAccounts.supplier, 0); + _expectedTokenCount.set(address(_market), 1); + _assertCorrectStates(); + _removal.grantRole({ + role: _removal.CONSIGNOR_ROLE(), + account: _namedAccounts.supplier3 + }); + assert( + _removal.hasRole(_removal.CONSIGNOR_ROLE(), _namedAccounts.supplier3) + ); + } + + function test() external { + _market.withdraw({removalId: _removalIds[0], to: _namedAccounts.supplier3}); + _expectedRemovalBalances = [_amountPerRemoval]; + _expectedMarketSupply = 0; + _expectedTokenCount.set(_namedAccounts.supplier, 1); + _expectedTokenCount.set(address(_market), 0); + _assertCorrectStates(); + } +} + contract Market_ALLOWLIST_ROLE is UpgradeableMarket { function test() external { assertEq( @@ -629,50 +661,83 @@ contract Market_SANCTION_ALLOWLIST_ROLE is UpgradeableMarket { } } -contract Market__isAuthorizedWithdrawal_true is NonUpgradeableMarket { +contract Market__isAuthorizedWithdrawal_true is + NonUpgradeableMarket, + UpgradeableRemoval +{ + Removal private _mockRemoval; + function setUp() external { + _mockRemoval = _deployRemoval(); + vm.store( address(this), - bytes32(uint256(301)), // sets the _removal storage slot to the market contract to enable mock calls - bytes32(uint256(uint160(address(this)))) + bytes32(uint256(301)), // sets the _removal storage slot in the market contract to enable mock calls + bytes32(uint256(uint160(address(_mockRemoval)))) ); } function test_returnsTrueWhenMsgSenderEqualsOwner() external { - assertEq(_isAuthorizedWithdrawal({owner: _msgSender()}), true); + assertEq( + _isAuthorizedWithdrawal({supplier: _msgSender(), to: _msgSender()}), + true + ); } function test_returnsTrueWhenMsgSenderHasDefaultAdminRole() external { _grantRole({role: MARKET_ADMIN_ROLE, account: _msgSender()}); - assertEq(_isAuthorizedWithdrawal({owner: _namedAccounts.supplier}), true); + assertEq( + _isAuthorizedWithdrawal({ + supplier: _namedAccounts.supplier, + to: _namedAccounts.supplier + }), + true + ); } function test_returnsTrueWhenMsgSenderIsApprovedForAll() external { vm.mockCall( - address(this), - abi.encodeWithSelector(IERC1155Upgradeable.isApprovedForAll.selector), + address(_mockRemoval), + abi.encodeWithSelector(_mockRemoval.isApprovedForAll.selector), abi.encode(true) ); - assertEq(_isAuthorizedWithdrawal({owner: address(0)}), true); + assertEq( + _isAuthorizedWithdrawal({supplier: address(1), to: address(1)}), + true + ); } } -contract Market__isAuthorizedWithdrawal_false is NonUpgradeableMarket { +contract Market__isAuthorizedWithdrawal_false is + NonUpgradeableMarket, + UpgradeableRemoval +{ + Removal private _mockRemoval; + function setUp() external { + _mockRemoval = _deployRemoval(); + vm.store( address(this), - bytes32(uint256(301)), // sets the _removal storage slot to the market contract to enable mock calls - bytes32(uint256(uint160(address(this)))) + bytes32(uint256(301)), // sets the _removal storage slot in the market contract to enable mock calls + bytes32(uint256(uint160(address(_mockRemoval)))) ); + vm.mockCall( address(this), - abi.encodeWithSelector(IERC1155Upgradeable.isApprovedForAll.selector), + abi.encodeWithSelector(_mockRemoval.isApprovedForAll.selector), abi.encode(false) ); } function test_returnsFalseWhenAllConditionsAreFalse() external { - assertEq(_isAuthorizedWithdrawal({owner: _namedAccounts.supplier}), false); + assertEq( + _isAuthorizedWithdrawal({ + supplier: _namedAccounts.supplier, + to: _namedAccounts.supplier + }), + false + ); } } diff --git a/test/Removal.t.sol b/test/Removal.t.sol index 0cf0ceb2..94fa1989 100644 --- a/test/Removal.t.sol +++ b/test/Removal.t.sol @@ -1135,7 +1135,7 @@ contract Removal_getMarketBalance is UpgradeableMarket { signedPermit.s ); assertEq(_removal.getMarketBalance(), amountToList - amountToSell); - _market.withdraw(_removalIds[0]); + _market.withdraw({removalId: _removalIds[0], to: _namedAccounts.supplier}); assertEq(_removal.getMarketBalance(), 0); } }