Skip to content

Commit

Permalink
feat: add _changeEnabledTokens to AbstractAdapter
Browse files Browse the repository at this point in the history
  • Loading branch information
lekhovitsky committed Mar 1, 2023
1 parent ec40fcb commit 45fa38e
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 6 deletions.
16 changes: 13 additions & 3 deletions contracts/adapters/AbstractAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,25 +58,35 @@ abstract contract AbstractAdapter is IAdapter {
return creditManager.executeOrder(targetContract, callData); // F: [AA-6,9]
}

/// @dev Approves a token from the Credit Account to the target contract
/// @dev Approves the target contract to spend given token from the Credit Account
/// @param token Token to be approved
/// @param amount Amount to be approved
function _approveToken(address token, uint256 amount) internal {
creditManager.approveCreditAccount(targetContract, token, amount); // F: [AA-6,10]
}

/// @dev Enable a token in the Credit Account
/// @dev Enables a token in the Credit Account
/// @param token Address of the token to enable
function _enableToken(address token) internal {
creditManager.checkAndEnableToken(token); // F: [AA-6,11]
}

/// @dev Disable a token in the Credit Account
/// @dev Disables a token in the Credit Account
/// @param token Address of the token to disable
function _disableToken(address token) internal {
creditManager.disableToken(token); // F: [AA-6,12]
}

/// @dev Changes enabled tokens in the Credit Account
/// @param tokensToEnable Bitmask of tokens that should be enabled
/// @param tokensToDisable Bitmask of tokens that should be disabled
/// @dev This function might be useful for adapters that work with limited set of tokens, whose masks can be
/// determined in the adapter constructor, thus saving gas by avoiding querying them during execution
/// and combining multiple enable/disable operations into a single one
function _changeEnabledTokens(uint256 tokensToEnable, uint256 tokensToDisable) internal {
creditManager.changeEnabledTokens(tokensToEnable, tokensToDisable); // F: [AA-6,13]
}

/// @dev Executes a swap operation on the target contract from the Credit Account
/// without explicit approval to spend `tokenIn`
/// @param tokenIn The token that the call is expected to spend
Expand Down
6 changes: 3 additions & 3 deletions contracts/credit/CreditManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ contract CreditManager is ICreditManagerV2, ACLNonReentrantTrait {
}

/// @dev IMPLEMENTATION: checkAndEnableToken
function _checkAndEnableToken(address creditAccount, address token) internal {
function _checkAndEnableToken(address creditAccount, address token) internal virtual {
uint256 tokenMask = tokenMasksMap(token);
if (tokenMask == 0) {
revert TokenNotAllowedException(); // F:[CM-30]
Expand Down Expand Up @@ -965,7 +965,7 @@ contract CreditManager is ICreditManagerV2, ACLNonReentrantTrait {
}

/// @dev IMPLEMENTATION: disableToken
function _disableToken(address creditAccount, address token) internal returns (bool wasChanged) {
function _disableToken(address creditAccount, address token) internal virtual returns (bool wasChanged) {
uint256 tokenMask = tokenMasksMap(token);
(, wasChanged) = _changeEnabledTokens(creditAccount, 0, tokenMask);
}
Expand Down Expand Up @@ -999,7 +999,7 @@ contract CreditManager is ICreditManagerV2, ACLNonReentrantTrait {
tokensToEnable &= ~limitedTokens; // F:[CMQ-7]
tokensToDisable &= ~limitedTokens; // F:[CMQ-7]

// remove tokens on the intersection as they will cancel each other
// remove tokens on the intersection (otherwise return variables might be incorrect)
uint256 intersection = tokensToEnable & tokensToDisable;
tokensToEnable &= ~intersection; // F:[CM-33]
tokensToDisable &= ~intersection; // F:[CM-33]
Expand Down
28 changes: 28 additions & 0 deletions contracts/test/adapters/AbstractAdapter.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,17 @@ contract AbstractAdapterTest is
)
);

evm.prank(USER);
evm.expectRevert(HasNoOpenedAccountException.selector);
creditFacade.multicall(
multicallBuilder(
MultiCall({
target: address(adapterMock),
callData: abi.encodeCall(AdapterMock.changeEnabledTokens, (0, 0))
})
)
);

for (uint256 dt; dt < 2; ++dt) {
evm.prank(USER);
evm.expectRevert(HasNoOpenedAccountException.selector);
Expand Down Expand Up @@ -329,4 +340,21 @@ contract AbstractAdapterTest is
)
);
}

/// @dev [AA-13]: _changeEnabledTokens correctly passes parameters to CreditManager
function test_AA_13_changeEnabledTokens_correctly_passes_to_credit_manager() public {
_openTestCreditAccount();

evm.expectCall(address(creditManager), abi.encodeCall(ICreditManagerV2.changeEnabledTokens, (1, 2)));

evm.prank(USER);
creditFacade.multicall(
multicallBuilder(
MultiCall({
target: address(adapterMock),
callData: abi.encodeCall(adapterMock.changeEnabledTokens, (1, 2))
})
)
);
}
}
4 changes: 4 additions & 0 deletions contracts/test/mocks/adapters/AdapterMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ contract AdapterMock is AbstractAdapter {
_disableToken(token);
}

function changeEnabledTokens(uint256 tokensToEnable, uint256 tokensToDisable) external creditFacadeOnly {
_changeEnabledTokens(tokensToEnable, tokensToDisable);
}

fallback() external creditFacadeOnly {
_execute(msg.data);
}
Expand Down

0 comments on commit 45fa38e

Please sign in to comment.