Skip to content

Commit

Permalink
tasks: fix depositor for native tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
facuspagnuolo committed Nov 21, 2023
1 parent 09ba939 commit 109522f
Show file tree
Hide file tree
Showing 3 changed files with 339 additions and 91 deletions.
63 changes: 63 additions & 0 deletions packages/tasks/contracts/interfaces/primitives/IDepositor.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

pragma solidity >=0.8.0;

import '../ITask.sol';

/**
* @dev Depositor task interface
*/
interface IDepositor is ITask {
/**
* @dev The token is zero
*/
error TaskTokenZero();

/**
* @dev The amount is zero
*/
error TaskAmountZero();

/**
* @dev The msg value is zero
*/
error TaskValueZero();

/**
* @dev The previous balance connector is not zero
*/
error TaskPreviousConnectorNotZero(bytes32 id);

/**
* @dev The tokens source to be set is not the contract itself
*/
error TaskDepositorBadTokensSource(address tokensSource);

/**
* @dev Emitted every time the tokens source is set
*/
event TokensSourceSet(address indexed tokensSource);

/**
* @dev Sets the tokens source address
* @param tokensSource Address of the tokens source to be set
*/
function setTokensSource(address tokensSource) external;

/**
* @dev Executes the withdrawer task
*/
function call(address token, uint256 amount) external;
}
122 changes: 108 additions & 14 deletions packages/tasks/contracts/primitives/Depositor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,45 +14,139 @@

pragma solidity ^0.8.0;

import '@openzeppelin/contracts/utils/Address.sol';

import '@mimic-fi/v3-helpers/contracts/utils/ERC20Helpers.sol';
import '@mimic-fi/v3-helpers/contracts/utils/Denominations.sol';

import './Collector.sol';
import '../interfaces/primitives/ICollector.sol';
import '../Task.sol';
import '../interfaces/primitives/IDepositor.sol';

/**
* @title Depositor
* @dev Task that extends the Collector task to be the source from where funds can be pulled
* @dev Task that can be used as the origin to start any workflow
*/
contract Depositor is ICollector, Collector {
contract Depositor is IDepositor, Task {
// Execution type for relayers
bytes32 public constant override EXECUTION_TYPE = keccak256('DEPOSITOR');

// Address from where the tokens will be pulled
address internal _tokensSource;

/**
* @dev Deposit config. Only used in the initializer.
*/
struct DepositConfig {
address tokensSource;
TaskConfig taskConfig;
}

/**
* @dev Initializes the depositor
* @param config Deposit config
*/
function initialize(DepositConfig memory config) external virtual initializer {
__Depositor_init(config);
}

/**
* @dev The tokens source to be set is not the contract itself
* @dev Initializes the depositor. It does call upper contracts initializers.
* @param config Deposit config
*/
error TaskDepositorBadTokensSource(address tokensSource);
function __Depositor_init(DepositConfig memory config) internal onlyInitializing {
__Task_init(config.taskConfig);
__Depositor_init_unchained(config);
}

/**
* @dev Initializes the depositor. It does not call upper contracts initializers.
* @param config Deposit config
*/
function __Depositor_init_unchained(DepositConfig memory config) internal onlyInitializing {
_setTokensSource(config.tokensSource);
}

/**
* @dev Tells the address from where the token amounts to execute this task are fetched
*/
function getTokensSource() public view virtual override(IBaseTask, BaseTask) returns (address) {
return _tokensSource;
}

/**
* @dev Tells the balance of the depositor for a given token
* @param token Address of the token being queried
*/
function getTaskAmount(address token) public view virtual override(IBaseTask, BaseTask) returns (uint256) {
return ERC20Helpers.balanceOf(token, getTokensSource());
}

/**
* @dev Sets the tokens source address. Sender must be authorized.
* @param tokensSource Address of the tokens source to be set
*/
function setTokensSource(address tokensSource) external override authP(authParams(tokensSource)) {
_setTokensSource(tokensSource);
}

/**
* @dev It allows receiving native token transfers
*/
receive() external payable {
// solhint-disable-previous-line no-empty-blocks
if (msg.value == 0) revert TaskValueZero();
}

/**
* @dev Approves the requested amount of tokens to the smart vault in case it's not the native token
* @dev Execute Depositor
*/
function _beforeCollector(address token, uint256 amount) internal virtual override {
super._beforeCollector(token, amount);
if (!Denominations.isNativeToken(token)) {
function call(address token, uint256 amount) external override authP(authParams(token, amount)) {
if (amount == 0) amount = getTaskAmount(token);
_beforeDepositor(token, amount);

if (Denominations.isNativeToken(token)) {
Address.sendValue(payable(smartVault), amount);
} else {
ERC20Helpers.approve(token, smartVault, amount);
ISmartVault(smartVault).collect(token, _tokensSource, amount);
}

_afterDepositor(token, amount);
}

/**
* @dev Before depositor hook
*/
function _beforeDepositor(address token, uint256 amount) internal virtual {
_beforeTask(token, amount);
if (token == address(0)) revert TaskTokenZero();
if (amount == 0) revert TaskAmountZero();
}

/**
* @dev After depositor hook
*/
function _afterDepositor(address token, uint256 amount) internal virtual {
_increaseBalanceConnector(token, amount);
_afterTask(token, amount);
}

/**
* @dev Sets the balance connectors. Previous balance connector must be unset.
* @param previous Balance connector id of the previous task in the workflow
* @param next Balance connector id of the next task in the workflow
*/
function _setBalanceConnectors(bytes32 previous, bytes32 next) internal virtual override {
if (previous != bytes32(0)) revert TaskPreviousConnectorNotZero(previous);
super._setBalanceConnectors(previous, next);
}

/**
* @dev Sets the tokens source address
* @dev Sets the source address
* @param tokensSource Address of the tokens source to be set
*/
function _setTokensSource(address tokensSource) internal override {
function _setTokensSource(address tokensSource) internal virtual {
if (tokensSource != address(this)) revert TaskDepositorBadTokensSource(tokensSource);
super._setTokensSource(tokensSource);
_tokensSource = tokensSource;
emit TokensSourceSet(tokensSource);
}
}
Loading

0 comments on commit 109522f

Please sign in to comment.