diff --git a/contracts/core/accounts/facets/AccountsStrategy.sol b/contracts/core/accounts/facets/AccountsStrategy.sol index c2f472abc..669d035e9 100644 --- a/contracts/core/accounts/facets/AccountsStrategy.sol +++ b/contracts/core/accounts/facets/AccountsStrategy.sol @@ -45,6 +45,11 @@ contract AccountsStrategy is AccountStorage.State storage state = LibAccounts.diamondStorage(); AccountStorage.Endowment storage tempEndowment = state.ENDOWMENTS[id]; + require( + investRequest.lockAmt > 0 || investRequest.liquidAmt > 0, + "Must invest at least one of Locked/Liquid" + ); + // check if the msg sender is either the owner or their delegate address and // that they have the power to manage the investments for an account balance if (investRequest.lockAmt > 0) { @@ -98,6 +103,8 @@ contract AccountsStrategy is "Token not approved" ); + uint256 investAmt = investRequest.lockAmt + investRequest.liquidAmt; + uint32[] memory accts = new uint32[](1); accts[0] = id; @@ -115,16 +122,13 @@ contract AccountsStrategy is }); bytes memory packedPayload = RouterLib.packCallData(payload); - IERC20(tokenAddress).safeTransfer( - thisNetwork.router, - (investRequest.lockAmt + investRequest.liquidAmt) - ); + IERC20(tokenAddress).safeTransfer(thisNetwork.router, investAmt); IVault.VaultActionData memory response = IRouter(thisNetwork.router).executeWithTokenLocal( state.config.networkName, AddressToString.toString(address(this)), packedPayload, investRequest.token, - (investRequest.lockAmt + investRequest.liquidAmt) + investAmt ); if (response.status == IVault.VaultActionStatus.SUCCESS) { @@ -161,6 +165,7 @@ contract AccountsStrategy is tokenAddress, investRequest.lockAmt, investRequest.liquidAmt, + (investRequest.liquidAmt * LibAccounts.PERCENT_BASIS) / investAmt, (investRequest.gasFee - gasFwdGas) ); } @@ -171,21 +176,18 @@ contract AccountsStrategy is AddressToString.toString(network.router), packedPayload, investRequest.token, - (investRequest.lockAmt + investRequest.liquidAmt), + investAmt, tokenAddress, investRequest.gasFee, state.ENDOWMENTS[id].gasFwd ); - IERC20(tokenAddress).safeApprove( - thisNetwork.axelarGateway, - (investRequest.lockAmt + investRequest.liquidAmt) - ); + IERC20(tokenAddress).safeApprove(thisNetwork.axelarGateway, investAmt); IAxelarGateway(thisNetwork.axelarGateway).callContractWithToken( stratParams.network, AddressToString.toString(network.router), packedPayload, investRequest.token, - (investRequest.lockAmt + investRequest.liquidAmt) + investAmt ); state.STATES[id].balances.locked[tokenAddress] -= investRequest.lockAmt; state.STATES[id].balances.liquid[tokenAddress] -= investRequest.liquidAmt; @@ -204,6 +206,11 @@ contract AccountsStrategy is AccountStorage.State storage state = LibAccounts.diamondStorage(); AccountStorage.Endowment storage tempEndowment = state.ENDOWMENTS[id]; + require( + redeemRequest.lockAmt > 0 || redeemRequest.liquidAmt > 0, + "Must redeem at least one of Locked/Liquid" + ); + // check if the msg sender is either the owner or their delegate address and // that they have the power to manage the investments for an account balance if (redeemRequest.lockAmt > 0) { @@ -292,11 +299,14 @@ contract AccountsStrategy is redeemRequest.gasFee ); if (gasFwdGas < redeemRequest.gasFee) { + uint256 gasPercentFromLiq = (redeemRequest.liquidAmt * LibAccounts.PERCENT_BASIS) / + (redeemRequest.liquidAmt + redeemRequest.lockAmt); _payForGasWithAccountBalance( - id, - tokenAddress, - redeemRequest.lockAmt, - redeemRequest.liquidAmt, + id, + tokenAddress, + 0, // redeeming, no tokens will be sent + 0, + gasPercentFromLiq, (redeemRequest.gasFee - gasFwdGas) ); } @@ -420,11 +430,13 @@ contract AccountsStrategy is redeemAllRequest.gasFee ); if (gasFwdGas < redeemAllRequest.gasFee) { + uint256 gasPercentFromLiq = 50; _payForGasWithAccountBalance( - id, - tokenAddress, - 1, // Split evenly - 1, + id, + tokenAddress, + 0, // redeeming, no tokens will be sent + 0, + gasPercentFromLiq, (redeemAllRequest.gasFee - gasFwdGas) ); } @@ -563,26 +575,30 @@ contract AccountsStrategy is * We split the gas payment proprotionally between locked and liquid if possible and * use liquid funds for locked gas needs, but not the other way around in the case of a shortage. * Revert if the combined balances of the account cannot cover both the investment request and the gas payment. + * @param id Endowment ID + * @param token Token address + * @param lockAmt Amount needed from locked balance + * @param liqAmt Amount needed from liquid balance + * @param gasPercentFromLiq Percentage of gas to pay from liquid portion + * @param gasRemaining Amount of gas to be payed from locked & liquid balances */ function _payForGasWithAccountBalance( uint32 id, address token, uint256 lockAmt, uint256 liqAmt, + uint256 gasPercentFromLiq, uint256 gasRemaining ) internal { AccountStorage.State storage state = LibAccounts.diamondStorage(); uint256 lockBal = state.STATES[id].balances.locked[token]; uint256 liqBal = state.STATES[id].balances.liquid[token]; - uint256 sendAmt = lockAmt + liqAmt; - // Split gas proportionally between liquid and lock amts - uint256 liqGas = (gasRemaining * ((liqAmt * LibAccounts.BIG_NUMBA_BASIS) / sendAmt)) / - LibAccounts.BIG_NUMBA_BASIS; + uint256 liqGas = (gasRemaining * gasPercentFromLiq) / LibAccounts.PERCENT_BASIS; uint256 lockGas = gasRemaining - liqGas; - uint256 lockNeed = lockGas + lockAmt; uint256 liqNeed = liqGas + liqAmt; + uint256 lockNeed = lockGas + lockAmt; // Cases: // 1) lockBal and liqBal each cover the respective needs