diff --git a/contracts/core/accounts/facets/AccountsDepositWithdrawEndowments.sol b/contracts/core/accounts/facets/AccountsDepositWithdrawEndowments.sol index f9a161585..6e38f247b 100644 --- a/contracts/core/accounts/facets/AccountsDepositWithdrawEndowments.sol +++ b/contracts/core/accounts/facets/AccountsDepositWithdrawEndowments.sol @@ -234,6 +234,10 @@ contract AccountsDepositWithdrawEndowments is AccountStorage.Endowment storage tempEndowment = state.Endowments[id]; AccountStorage.EndowmentState storage tempEndowmentState = state.States[id]; + // Check if maturity has been reached for the endowment (0 == no maturity date) + bool mature = (tempEndowment.maturityTime != 0 && + block.timestamp >= tempEndowment.maturityTime); + // If an Endowment is closed and a withdraw is executed for it, check that the sender is the closing // beneficiary on record and procees the withdraw if so ensure funds are indeed moving to that beneficiary if (tempEndowmentState.closingEndowment) { @@ -255,9 +259,22 @@ contract AccountsDepositWithdrawEndowments is beneficiaryEndowId = tempEndowmentState.closingBeneficiary.data.endowId; } } - // If not closing, only owner can call + // If not closing, else { - require(msg.sender == tempEndowment.owner, "Unauthorized"); + // only owner can call if not mature + if (!mature) { + require(msg.sender == tempEndowment.owner, "Unauthorized"); + } + // otherwise the caller must be in the Allowlist + else { + require( + IterableMappingAddr.get( + state.Allowlists[id][LibAccounts.AllowlistType.MaturityAllowlist], + msg.sender + ), + "Unauthorized" + ); + } } // place an arbitrary cap on the qty of different tokens per withdraw to limit gas use @@ -277,10 +294,6 @@ contract AccountsDepositWithdrawEndowments is ); } - // Check if maturity has been reached for the endowment (0 == no maturity date) - bool mature = (tempEndowment.maturityTime != 0 && - block.timestamp >= tempEndowment.maturityTime); - if (tempEndowment.endowType == LibAccounts.EndowmentType.Daf) { require( beneficiaryAddress == address(0), diff --git a/test/core/accounts/AccountsDepositWithdrawEndowments.ts b/test/core/accounts/AccountsDepositWithdrawEndowments.ts index 0c957964c..316732c65 100644 --- a/test/core/accounts/AccountsDepositWithdrawEndowments.ts +++ b/test/core/accounts/AccountsDepositWithdrawEndowments.ts @@ -18,6 +18,7 @@ import { IAccountsDepositWithdrawEndowments, IERC20, IERC20__factory, + OwnershipFacet__factory, Registrar, Registrar__factory, TestFacetProxyContract, @@ -1099,7 +1100,9 @@ describe("AccountsDepositWithdrawEndowments", function () { let finalAmountLeftover = amountLeftAfterApFees.sub(expectedFeeEndow); await expect( - facet.withdraw(normalEndowId, acctType, beneficiaryAddress, beneficiaryId, tokens) + facet + .connect(endowOwner) + .withdraw(normalEndowId, acctType, beneficiaryAddress, beneficiaryId, tokens) ) .to.emit(facet, "EndowmentWithdraw") .withArgs( @@ -1145,7 +1148,9 @@ describe("AccountsDepositWithdrawEndowments", function () { await wait(state.setAllowlist(normalEndowId, 0, [beneficiaryAddress])); await expect( - facet.withdraw(normalEndowId, acctType, beneficiaryAddress, beneficiaryId, tokens) + facet + .connect(endowOwner) + .withdraw(normalEndowId, acctType, beneficiaryAddress, beneficiaryId, tokens) ) .to.emit(facet, "EndowmentWithdraw") .withArgs( @@ -1323,7 +1328,7 @@ describe("AccountsDepositWithdrawEndowments", function () { await expect( facet.withdraw(normalEndowId, acctType, beneficiaryAddress, beneficiaryId, tokens) - ).to.be.revertedWith("Beneficiary address is not listed in maturityAllowlist"); + ).to.be.revertedWith("Unauthorized"); }); describe("LOCKED withdrawals", () => { @@ -1337,7 +1342,13 @@ describe("AccountsDepositWithdrawEndowments", function () { maturityTime: currTime, }; await wait(state.setEndowmentDetails(normalEndowId, matureEndowment)); - await wait(state.setAllowlist(normalEndowId, 2, [beneficiaryAddress])); + const beneficiarySigner = new ethers.Wallet( + genWallet().privateKey, + hre.ethers.provider + ); + await accOwner.sendTransaction({value: ethers.utils.parseEther("1"), to: beneficiarySigner.address}) + + await wait(state.setAllowlist(normalEndowId, 2, [beneficiarySigner.address])); const acctType = VaultType.LOCKED; const beneficiaryId = 0; @@ -1349,7 +1360,7 @@ describe("AccountsDepositWithdrawEndowments", function () { const finalAmountLeftover = amount.sub(expectedFeeAp); await expect( - facet.withdraw(normalEndowId, acctType, beneficiaryAddress, beneficiaryId, tokens) + facet.connect(beneficiarySigner).withdraw(normalEndowId, acctType, beneficiarySigner.address, beneficiaryId, tokens) ) .to.emit(facet, "EndowmentWithdraw") .withArgs( @@ -1357,13 +1368,13 @@ describe("AccountsDepositWithdrawEndowments", function () { tokens[0].addr, tokens[0].amnt, acctType, - beneficiaryAddress, + beneficiarySigner.address, beneficiaryId ); expect(tokenFake.transfer).to.have.been.calledWith(treasury, expectedFeeAp); expect(tokenFake.transfer).to.have.been.calledWith( - beneficiaryAddress, + beneficiarySigner.address, finalAmountLeftover );