ETH Price: $3,319.77 (-3.47%)
Gas: 9.21 Gwei

Contract

0x5094a8f54B12AEc540bF7cCd0Dd7B62f4FecF7f2
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Execute Pending ...151441812022-07-15 0:54:23865 days ago1657846463IN
0x5094a8f5...f4FecF7f2
0 ETH0.0019217516.78097149
Execute Pending ...123514872021-05-02 0:11:111304 days ago1619914271IN
0x5094a8f5...f4FecF7f2
0 ETH0.0025678534
Execute Pending ...123363602021-04-29 16:11:481307 days ago1619712708IN
0x5094a8f5...f4FecF7f2
0 ETH0.04332568133
Execute Pending ...119765512021-03-05 5:56:571362 days ago1614923817IN
0x5094a8f5...f4FecF7f2
0 ETH0.00606362106
Execute Pending ...119758332021-03-05 3:22:591362 days ago1614914579IN
0x5094a8f5...f4FecF7f2
0 ETH0.0062832102
Execute Pending ...119254362021-02-25 9:09:031370 days ago1614244143IN
0x5094a8f5...f4FecF7f2
0 ETH0.0071007121.75
Execute Pending ...119254332021-02-25 9:08:191370 days ago1614244099IN
0x5094a8f5...f4FecF7f2
0 ETH0.00698163121.75
Execute Pending ...118997802021-02-21 10:41:151374 days ago1613904075IN
0x5094a8f5...f4FecF7f2
0 ETH0.0062058106.75
Execute Pending ...118634072021-02-15 20:07:141380 days ago1613419634IN
0x5094a8f5...f4FecF7f2
0 ETH0.00807102171
Execute Pending ...115380512020-12-27 20:36:501430 days ago1609101410IN
0x5094a8f5...f4FecF7f2
0 ETH0.004528359
Execute Pending ...115340062020-12-27 5:47:441430 days ago1609048064IN
0x5094a8f5...f4FecF7f2
0 ETH0.0032356441.3
Execute Pending ...115238432020-12-25 16:23:551432 days ago1608913435IN
0x5094a8f5...f4FecF7f2
0 ETH0.002585645.844
Execute Pending ...114732602020-12-17 22:08:051439 days ago1608242885IN
0x5094a8f5...f4FecF7f2
0 ETH0.0031167166
Execute Pending ...114484572020-12-14 2:47:311443 days ago1607914051IN
0x5094a8f5...f4FecF7f2
0 ETH0.0038457453.5
Execute Pending ...114481902020-12-14 1:47:271443 days ago1607910447IN
0x5094a8f5...f4FecF7f2
0 ETH0.0029798153.25
Execute Pending ...114407552020-12-12 22:10:591444 days ago1607811059IN
0x5094a8f5...f4FecF7f2
0 ETH0.0074382728.225
Execute Pending ...114355332020-12-12 2:54:551445 days ago1607741695IN
0x5094a8f5...f4FecF7f2
0 ETH0.0014361231.05
Execute Pending ...114187002020-12-09 12:36:231448 days ago1607517383IN
0x5094a8f5...f4FecF7f2
0 ETH0.0016396828
Execute Pending ...113780202020-12-03 6:29:471454 days ago1606976987IN
0x5094a8f5...f4FecF7f2
0 ETH0.0009411915.071
Execute Pending ...113741422020-12-02 16:20:541455 days ago1606926054IN
0x5094a8f5...f4FecF7f2
0 ETH0.0011698724.128
Execute Pending ...113641102020-12-01 3:05:101456 days ago1606791910IN
0x5094a8f5...f4FecF7f2
0 ETH0.0031339157.75
Execute Pending ...113606712020-11-30 14:25:021457 days ago1606746302IN
0x5094a8f5...f4FecF7f2
0 ETH0.00593772125.77
Execute Pending ...113417532020-11-27 17:00:501460 days ago1606496450IN
0x5094a8f5...f4FecF7f2
0 ETH0.0010021234.75
Execute Pending ...113036652020-11-21 20:33:151466 days ago1605990795IN
0x5094a8f5...f4FecF7f2
0 ETH0.0028463648.41
Execute Pending ...112845902020-11-18 22:24:041468 days ago1605738244IN
0x5094a8f5...f4FecF7f2
0 ETH0.0010207335.366
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x6f592f1E...a78f636B5
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
TransferManager

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 999 runs

Other Settings:
default evmVersion
File 1 of 15 : TransferManager.sol
// Copyright (C) 2018  Argent Labs Ltd. <https://argent.xyz>

// 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/>.

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

import "./common/Utils.sol";
import "./common/BaseTransfer.sol";
import "./common/LimitUtils.sol";
import "../infrastructure/storage/ILimitStorage.sol";
import "../infrastructure/storage/ITransferStorage.sol";
import "../infrastructure/ITokenPriceRegistry.sol";
import "../../lib/other/ERC20.sol";

/**
 * @title TransferManager
 * @notice Feature to transfer and approve tokens (ETH or ERC20) or data (contract call) based on a security context (daily limit, whitelist, etc).
 * @author Julien Niset - <[email protected]>
 */
contract TransferManager is BaseTransfer {

    bytes32 constant NAME = "TransferManager";

    bytes4 private constant ERC1271_ISVALIDSIGNATURE_BYTES32 = bytes4(keccak256("isValidSignature(bytes32,bytes)"));

    enum ActionType { Transfer }

    using SafeMath for uint256;

    struct TokenManagerConfig {
        // Mapping between pending action hash and their timestamp
        mapping (bytes32 => uint256) pendingActions;
    }

    // wallet specific storage
    mapping (address => TokenManagerConfig) internal configs;

    // The security period
    uint256 public securityPeriod;
    // The execution window
    uint256 public securityWindow;
    // The default limit
    uint128 public defaultLimit;
    // The Token storage
    ITransferStorage public transferStorage;
    // The previous limit manager needed to migrate the limits
    TransferManager public oldTransferManager;
    // The limit storage
    ILimitStorage public limitStorage;
    // The token price storage
    ITokenPriceRegistry public tokenPriceRegistry;

    // *************** Events *************************** //

    event AddedToWhitelist(address indexed wallet, address indexed target, uint64 whitelistAfter);
    event RemovedFromWhitelist(address indexed wallet, address indexed target);
    event PendingTransferCreated(address indexed wallet, bytes32 indexed id, uint256 indexed executeAfter,
    address token, address to, uint256 amount, bytes data);
    event PendingTransferExecuted(address indexed wallet, bytes32 indexed id);
    event PendingTransferCanceled(address indexed wallet, bytes32 indexed id);
    event DailyLimitMigrated(address indexed wallet, uint256 currentDailyLimit, uint256 pendingDailyLimit, uint256 changeDailyLimitAfter);
    event DailyLimitDisabled(address indexed wallet, uint256 securityPeriod);

    // *************** Constructor ********************** //

    constructor(
        ILockStorage _lockStorage,
        ITransferStorage _transferStorage,
        ILimitStorage _limitStorage,
        ITokenPriceRegistry _tokenPriceRegistry,
        IVersionManager _versionManager,
        uint256 _securityPeriod,
        uint256 _securityWindow,
        uint256 _defaultLimit,
        address _wethToken,
        TransferManager _oldTransferManager
    )
        BaseFeature(_lockStorage, _versionManager, NAME)
        BaseTransfer(_wethToken)
        public
    {
        transferStorage = _transferStorage;
        limitStorage = _limitStorage;
        tokenPriceRegistry = _tokenPriceRegistry;
        securityPeriod = _securityPeriod;
        securityWindow = _securityWindow;
        defaultLimit = LimitUtils.safe128(_defaultLimit);
        oldTransferManager = _oldTransferManager;
    }

    /**
     * @inheritdoc IFeature
     */
    function getRequiredSignatures(address, bytes calldata) external view override returns (uint256, OwnerSignature) {
        return (1, OwnerSignature.Required);
    }

    /**
     * @inheritdoc IFeature
     */
    function getStaticCallSignatures() external virtual override view returns (bytes4[] memory _sigs) {
        _sigs = new bytes4[](1);
        _sigs[0] = ERC1271_ISVALIDSIGNATURE_BYTES32;
    }


    /**
     * @notice Inits the feature for a wallet by setting up the isValidSignature (EIP 1271)
     * static call redirection from the wallet to the feature and copying all the parameters
     * of the daily limit from the previous implementation of the LimitManager module.
     * @param _wallet The target wallet.
     */
    function init(address _wallet) external override(BaseFeature) onlyVersionManager {

        if (address(oldTransferManager) == address(0)) {
            setLimit(_wallet, ILimitStorage.Limit(defaultLimit, 0, 0));
        } else {
            uint256 current = oldTransferManager.getCurrentLimit(_wallet);
            (uint256 pending, uint64 changeAfter) = oldTransferManager.getPendingLimit(_wallet);
            if (current == 0 && changeAfter == 0) {
                // new wallet: we setup the default limit
                setLimit(_wallet, ILimitStorage.Limit(defaultLimit, 0, 0));
            } else {
                // migrate limit and daily spent (if we are in a rolling period)
                (uint256 unspent, uint64 periodEnd) = oldTransferManager.getDailyUnspent(_wallet);

                if (periodEnd < block.timestamp) {
                    setLimit(_wallet, ILimitStorage.Limit(LimitUtils.safe128(current), LimitUtils.safe128(pending), changeAfter));
                } else {
                    setLimitAndDailySpent(
                        _wallet,
                        ILimitStorage.Limit(LimitUtils.safe128(current), LimitUtils.safe128(pending), changeAfter),
                        ILimitStorage.DailySpent(LimitUtils.safe128(current.sub(unspent)), periodEnd)
                    );
                }

                emit DailyLimitMigrated(_wallet, current, pending, changeAfter);
            }
        }
    }

    // *************** External/Public Functions ********************* //

    /**
    * @notice Lets the owner transfer tokens (ETH or ERC20) from a wallet.
    * @param _wallet The target wallet.
    * @param _token The address of the token to transfer.
    * @param _to The destination address
    * @param _amount The amoutn of token to transfer
    * @param _data The data for the transaction
    */
    function transferToken(
        address _wallet,
        address _token,
        address _to,
        uint256 _amount,
        bytes calldata _data
    )
        external
        onlyWalletOwnerOrFeature(_wallet)
        onlyWhenUnlocked(_wallet)
    {
        if (isWhitelisted(_wallet, _to)) {
            // transfer to whitelist
            doTransfer(_wallet, _token, _to, _amount, _data);
        } else {
            uint256 etherAmount = (_token == ETH_TOKEN) ? _amount : LimitUtils.getEtherValue(tokenPriceRegistry, _amount, _token);
            if (LimitUtils.checkAndUpdateDailySpent(limitStorage, versionManager, _wallet, etherAmount)) {
                // transfer under the limit
                doTransfer(_wallet, _token, _to, _amount, _data);
            } else {
                // transfer above the limit
                (bytes32 id, uint256 executeAfter) = addPendingAction(ActionType.Transfer, _wallet, _token, _to, _amount, _data);
                emit PendingTransferCreated(_wallet, id, executeAfter, _token, _to, _amount, _data);
            }
        }
    }

    /**
    * @notice Lets the owner approve an allowance of ERC20 tokens for a spender (dApp).
    * @param _wallet The target wallet.
    * @param _token The address of the token to transfer.
    * @param _spender The address of the spender
    * @param _amount The amount of tokens to approve
    */
    function approveToken(
        address _wallet,
        address _token,
        address _spender,
        uint256 _amount
    )
        external
        onlyWalletOwnerOrFeature(_wallet)
        onlyWhenUnlocked(_wallet)
    {
        if (isWhitelisted(_wallet, _spender)) {
            // approve to whitelist
            doApproveToken(_wallet, _token, _spender, _amount);
        } else {
            // get current alowance
            uint256 currentAllowance = ERC20(_token).allowance(_wallet, _spender);
            if (_amount <= currentAllowance) {
                // approve if we reduce the allowance
                doApproveToken(_wallet, _token, _spender, _amount);
            } else {
                // check if delta is under the limit
                uint delta = _amount - currentAllowance;
                uint256 deltaInEth = LimitUtils.getEtherValue(tokenPriceRegistry, delta, _token);
                require(LimitUtils.checkAndUpdateDailySpent(limitStorage, versionManager, _wallet, deltaInEth), "TM: Approve above daily limit");
                // approve if under the limit
                doApproveToken(_wallet, _token, _spender, _amount);
            }
        }
    }

    /**
    * @notice Lets the owner call a contract.
    * @param _wallet The target wallet.
    * @param _contract The address of the contract.
    * @param _value The amount of ETH to transfer as part of call
    * @param _data The encoded method data
    */
    function callContract(
        address _wallet,
        address _contract,
        uint256 _value,
        bytes calldata _data
    )
        external
        onlyWalletOwnerOrFeature(_wallet)
        onlyWhenUnlocked(_wallet)
        onlyAuthorisedContractCall(_wallet, _contract)
    {
        checkAndUpdateDailySpentIfNeeded(_wallet, ETH_TOKEN, _value, _contract);
        doCallContract(_wallet, _contract, _value, _data);
    }

    /**
    * @notice Lets the owner do an ERC20 approve followed by a call to a contract.
    * We assume that the contract will pull the tokens and does not require ETH.
    * @param _wallet The target wallet.
    * @param _token The token to approve.
    * @param _proxy The address to approve, which may be different from the contract being called.
    * @param _amount The amount of ERC20 tokens to approve.
    * @param _contract The address of the contract.
    * @param _data The encoded method data
    */
    function approveTokenAndCallContract(
        address _wallet,
        address _token,
        address _proxy,
        uint256 _amount,
        address _contract,
        bytes calldata _data
    )
        external
        onlyWalletOwnerOrFeature(_wallet)
        onlyWhenUnlocked(_wallet)
        onlyAuthorisedContractCall(_wallet, _contract)
    {
        checkAndUpdateDailySpentIfNeeded(_wallet, _token, _amount, _contract);
        doApproveTokenAndCallContract(_wallet, _token, _proxy, _amount, _contract, _data);
    }

    /**
    * @notice Lets the owner wrap ETH into WETH, approve the WETH and call a contract.
    * We assume that the contract will pull the tokens and does not require ETH.
    * @param _wallet The target wallet.
    * @param _proxy The address to approve, which may be different from the contract being called.
    * @param _amount The amount of ETH to wrap and approve.
    * @param _contract The address of the contract.
    * @param _data The encoded method data
    */
    function approveWethAndCallContract(
        address _wallet,
        address _proxy,
        uint256 _amount,
        address _contract,
        bytes calldata _data
    )
        external
        onlyWalletOwnerOrFeature(_wallet)
        onlyWhenUnlocked(_wallet)
        onlyAuthorisedContractCall(_wallet, _contract)
    {
        checkAndUpdateDailySpentIfNeeded(_wallet, wethToken, _amount, _contract);
        doApproveWethAndCallContract(_wallet, _proxy, _amount, _contract, _data);
    }

    /**
     * @notice Adds an address to the whitelist of a wallet.
     * @param _wallet The target wallet.
     * @param _target The address to add.
     */
    function addToWhitelist(
        address _wallet,
        address _target
    )
        external
        onlyWalletOwnerOrFeature(_wallet)
        onlyWhenUnlocked(_wallet)
    {
        require(!isWhitelisted(_wallet, _target), "TT: target already whitelisted");

        uint256 whitelistAfter = block.timestamp.add(securityPeriod);
        setWhitelist(_wallet, _target, whitelistAfter);
        emit AddedToWhitelist(_wallet, _target, uint64(whitelistAfter));
    }

    /**
     * @notice Removes an address from the whitelist of a wallet.
     * @param _wallet The target wallet.
     * @param _target The address to remove.
     */
    function removeFromWhitelist(
        address _wallet,
        address _target
    )
        external
        onlyWalletOwnerOrFeature(_wallet)
        onlyWhenUnlocked(_wallet)
    {
        setWhitelist(_wallet, _target, 0);
        emit RemovedFromWhitelist(_wallet, _target);
    }

    /**
    * @notice Executes a pending transfer for a wallet.
    * The method can be called by anyone to enable orchestration.
    * @param _wallet The target wallet.
    * @param _token The token of the pending transfer.
    * @param _to The destination address of the pending transfer.
    * @param _amount The amount of token to transfer of the pending transfer.
    * @param _data The data associated to the pending transfer.
    * @param _block The block at which the pending transfer was created.
    */
    function executePendingTransfer(
        address _wallet,
        address _token,
        address _to,
        uint _amount,
        bytes calldata _data,
        uint _block
    )
        external
        onlyWhenUnlocked(_wallet)
    {
        bytes32 id = keccak256(abi.encodePacked(ActionType.Transfer, _token, _to, _amount, _data, _block));
        uint executeAfter = configs[_wallet].pendingActions[id];
        require(executeAfter > 0, "TT: unknown pending transfer");
        uint executeBefore = executeAfter.add(securityWindow);

        require(executeAfter <= block.timestamp && block.timestamp <= executeBefore, "TT: transfer outside of the execution window");
        delete configs[_wallet].pendingActions[id];
        doTransfer(_wallet, _token, _to, _amount, _data);
        emit PendingTransferExecuted(_wallet, id);
    }

    function cancelPendingTransfer(
        address _wallet,
        bytes32 _id
    )
        external
        onlyWalletOwnerOrFeature(_wallet)
        onlyWhenUnlocked(_wallet)
    {
        require(configs[_wallet].pendingActions[_id] > 0, "TT: unknown pending action");
        delete configs[_wallet].pendingActions[_id];
        emit PendingTransferCanceled(_wallet, _id);
    }

    /**
     * @notice Lets the owner of a wallet change its daily limit.
     * The limit is expressed in ETH. Changes to the limit take 24 hours.
     * @param _wallet The target wallet.
     * @param _newLimit The new limit.
     */
    function changeLimit(address _wallet, uint256 _newLimit) external onlyWalletOwnerOrFeature(_wallet) onlyWhenUnlocked(_wallet) {
        ILimitStorage.Limit memory limit = LimitUtils.changeLimit(limitStorage, versionManager, _wallet, _newLimit, securityPeriod);
        emit LimitChanged(_wallet, _newLimit, limit.changeAfter);
    }

    /**
     * @notice Convenience method to disable the limit
     * The limit is disabled by setting it to an arbitrary large value.
     * @param _wallet The target wallet.
     */
    function disableLimit(address _wallet) external onlyWalletOwnerOrFeature(_wallet) onlyWhenUnlocked(_wallet) {
        LimitUtils.disableLimit(limitStorage, versionManager, _wallet, securityPeriod);
        emit DailyLimitDisabled(_wallet, securityPeriod);
    }

    /**
    * @notice Gets the current daily limit for a wallet.
    * @param _wallet The target wallet.
    * @return _currentLimit The current limit expressed in ETH.
    */
    function getCurrentLimit(address _wallet) external view returns (uint256 _currentLimit) {
        ILimitStorage.Limit memory limit = limitStorage.getLimit(_wallet);
        return LimitUtils.currentLimit(limit);
    }

    /**
    * @notice Returns whether the daily limit is disabled for a wallet.
    * @param _wallet The target wallet.
    * @return _limitDisabled true if the daily limit is disabled, false otherwise.
    */
    function isLimitDisabled(address _wallet) public view returns (bool _limitDisabled) {
        return LimitUtils.isLimitDisabled(limitStorage, _wallet);
    }

    /**
    * @notice Gets a pending limit for a wallet if any.
    * @param _wallet The target wallet.
    * @return _pendingLimit The pending limit (in ETH).
    * @return _changeAfter The time at which the pending limit will become effective.
    */
    function getPendingLimit(address _wallet) external view returns (uint256 _pendingLimit, uint64 _changeAfter) {
        ILimitStorage.Limit memory limit = limitStorage.getLimit(_wallet);

        return ((block.timestamp < limit.changeAfter)? (limit.pending, uint64(limit.changeAfter)) : (0,0));
    }

    /**
    * @notice Gets the amount of tokens that has not yet been spent during the current period.
    * @param _wallet The target wallet.
    * @return _unspent The amount of tokens (in ETH) that has not been spent yet.
    * @return _periodEnd The end of the daily period.
    */
    function getDailyUnspent(address _wallet) external view returns (uint256 _unspent, uint64 _periodEnd) {
        (
            ILimitStorage.Limit memory limit,
            ILimitStorage.DailySpent memory dailySpent
        ) = limitStorage.getLimitAndDailySpent(_wallet);
        uint256 currentLimit = LimitUtils.currentLimit(limit);

        if (block.timestamp > dailySpent.periodEnd) {
            return (currentLimit, uint64(block.timestamp.add(24 hours)));
        } else if (dailySpent.alreadySpent < currentLimit) {
            return (currentLimit.sub(dailySpent.alreadySpent), dailySpent.periodEnd);
        } else {
            return (0, dailySpent.periodEnd);
        }
    }

    /**
    * @notice Checks if an address is whitelisted for a wallet.
    * @param _wallet The target wallet.
    * @param _target The address.
    * @return _isWhitelisted true if the address is whitelisted.
    */
    function isWhitelisted(address _wallet, address _target) public view returns (bool _isWhitelisted) {
        uint whitelistAfter = transferStorage.getWhitelist(_wallet, _target);
        
        return whitelistAfter > 0 && whitelistAfter < block.timestamp;
    }

    /**
    * @notice Gets the info of a pending transfer for a wallet.
    * @param _wallet The target wallet.
    * @param _id The pending transfer ID.
    * @return _executeAfter The epoch time at which the pending transfer can be executed.
    */
    function getPendingTransfer(address _wallet, bytes32 _id) external view returns (uint64 _executeAfter) {
        _executeAfter = uint64(configs[address(_wallet)].pendingActions[_id]);
    }

    /**
    * @notice Implementation of EIP 1271.
    * Should return whether the signature provided is valid for the provided data.
    * @param _msgHash Hash of a message signed on the behalf of address(this)
    * @param _signature Signature byte array associated with _msgHash
    */
    function isValidSignature(bytes32 _msgHash, bytes memory _signature) public view returns (bytes4) {
        require(_signature.length == 65, "TM: invalid signature length");
        address signer = Utils.recoverSigner(_msgHash, _signature, 0);
        require(isOwner(msg.sender, signer), "TM: Invalid signer");
        return ERC1271_ISVALIDSIGNATURE_BYTES32;
    }

    // *************** Internal Functions ********************* //

    /**
     * @notice Creates a new pending action for a wallet.
     * @param _action The target action.
     * @param _wallet The target wallet.
     * @param _token The target token for the action.
     * @param _to The recipient of the action.
     * @param _amount The amount of token associated to the action.
     * @param _data The data associated to the action.
     * @return id The identifier for the new pending action.
     * @return executeAfter The time when the action can be executed
     */
    function addPendingAction(
        ActionType _action,
        address _wallet,
        address _token,
        address _to,
        uint _amount,
        bytes memory _data
    )
        internal
        returns (bytes32 id, uint256 executeAfter)
    {
        id = keccak256(abi.encodePacked(_action, _token, _to, _amount, _data, block.number));
        require(configs[_wallet].pendingActions[id] == 0, "TM: duplicate pending action");

        executeAfter = block.timestamp.add(securityPeriod);
        configs[_wallet].pendingActions[id] = executeAfter;
    }

    /**
    * @notice Make sure a contract call is not trying to call a supported ERC20.
    * @param _wallet The target wallet.
    * @param _contract The address of the contract.
     */
    function coveredByDailyLimit(address _wallet, address _contract) internal view returns (bool) {
        return (tokenPriceRegistry.getTokenPrice(_contract) > 0 && !isLimitDisabled(_wallet));
    }

    /**
    * @notice Verify and update the daily spent if the spender is not whitelisted.
    * Reverts if the daily spent is insufficient or if the contract to call is
    * protected by the daily limit (i.e. is a token contract).
    * @param _wallet The target wallet.
    * @param _token The token that the spender will spend.
    * @param _amount The amount of ERC20 or ETH that the spender will spend.
    * @param _contract The address of the contract called by the wallet for the spend to occur.
    */

    function checkAndUpdateDailySpentIfNeeded(
        address _wallet,
        address _token,
        uint256 _amount,
        address _contract
    )
        internal
    {
        if (!isWhitelisted(_wallet, _contract)) {
            // Make sure we don't call a supported ERC20 that's not whitelisted
            require(!coveredByDailyLimit(_wallet, _contract), "TM: Forbidden contract");

            // Check if the amount is under the daily limit.
            // Check the entire amount because the currently approved amount will be restored and should still count towards the daily limit
            uint256 valueInEth;
            if (_token == ETH_TOKEN || _token == wethToken) {
                valueInEth = _amount;
            } else {
                valueInEth = LimitUtils.getEtherValue(tokenPriceRegistry, _amount, _token);
            }
            require(LimitUtils.checkAndUpdateDailySpent(limitStorage, versionManager, _wallet, valueInEth), "TM: Approve above daily limit");
        }
    }

    // *************** Internal Functions ********************* //

    function setWhitelist(address _wallet, address _target, uint256 _whitelistAfter) internal {
        versionManager.invokeStorage(
            _wallet,
            address(transferStorage),
            abi.encodeWithSelector(transferStorage.setWhitelist.selector, _wallet, _target, _whitelistAfter)
        );
    }

    function setLimit(address _wallet, ILimitStorage.Limit memory _limit) internal {
        versionManager.invokeStorage(
            _wallet,
            address(limitStorage),
            abi.encodeWithSelector(limitStorage.setLimit.selector, _wallet, _limit)
        );
    }

    function setLimitAndDailySpent(
        address _wallet,
        ILimitStorage.Limit memory _limit,
        ILimitStorage.DailySpent memory _dailySpent
    ) internal {
        versionManager.invokeStorage(
            _wallet,
            address(limitStorage),
            abi.encodeWithSelector(limitStorage.setLimitAndDailySpent.selector, _wallet, _limit, _dailySpent)
        );
    }
}

File 2 of 15 : IModuleRegistry.sol
// Copyright (C) 2020  Argent Labs Ltd. <https://argent.xyz>

// 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/>.

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.7.0;

/**
 * @title IModuleRegistry
 * @notice Interface for the registry of authorised modules.
 */
interface IModuleRegistry {
    function registerModule(address _module, bytes32 _name) external;

    function deregisterModule(address _module) external;

    function registerUpgrader(address _upgrader, bytes32 _name) external;

    function deregisterUpgrader(address _upgrader) external;

    function recoverToken(address _token) external;

    function moduleInfo(address _module) external view returns (bytes32);

    function upgraderInfo(address _upgrader) external view returns (bytes32);

    function isRegisteredModule(address _module) external view returns (bool);

    function isRegisteredModule(address[] calldata _modules) external view returns (bool);

    function isRegisteredUpgrader(address _upgrader) external view returns (bool);
}

File 3 of 15 : ITokenPriceRegistry.sol
// 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/>.

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.6.12;

/**
 * @title ITokenPriceRegistry
 * @notice TokenPriceRegistry interface
 */
interface ITokenPriceRegistry {
    function getTokenPrice(address _token) external view returns (uint184 _price);
    function isTokenTradable(address _token) external view returns (bool _isTradable);
}

File 4 of 15 : ILimitStorage.sol
// 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/>.

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

/**
 * @title ILimitStorage
 * @notice LimitStorage interface
 */
interface ILimitStorage {

    struct Limit {
        // the current limit
        uint128 current;
        // the pending limit if any
        uint128 pending;
        // when the pending limit becomes the current limit
        uint64 changeAfter;
    }

    struct DailySpent {
        // The amount already spent during the current period
        uint128 alreadySpent;
        // The end of the current period
        uint64 periodEnd;
    }

    function setLimit(address _wallet, Limit memory _limit) external;

    function getLimit(address _wallet) external view returns (Limit memory _limit);

    function setDailySpent(address _wallet, DailySpent memory _dailySpent) external;

    function getDailySpent(address _wallet) external view returns (DailySpent memory _dailySpent);

    function setLimitAndDailySpent(address _wallet, Limit memory _limit, DailySpent memory _dailySpent) external;

    function getLimitAndDailySpent(address _wallet) external view returns (Limit memory _limit, DailySpent memory _dailySpent);
}

File 5 of 15 : ILockStorage.sol
// Copyright (C) 2018  Argent Labs Ltd. <https://argent.xyz>

// 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/>.

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.7.0;

interface ILockStorage {
    function isLocked(address _wallet) external view returns (bool);

    function getLock(address _wallet) external view returns (uint256);

    function getLocker(address _wallet) external view returns (address);

    function setLock(address _wallet, address _locker, uint256 _releaseAfter) external;
}

File 6 of 15 : ITransferStorage.sol
// Copyright (C) 2020  Argent Labs Ltd. <https://argent.xyz>

// 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/>.

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.7.0;

/**
 * @title ITransferStorage
 * @notice TransferStorage interface
 */
interface ITransferStorage {
    function setWhitelist(address _wallet, address _target, uint256 _value) external;

    function getWhitelist(address _wallet, address _target) external view returns (uint256);
}

File 7 of 15 : BaseFeature.sol
// Copyright (C) 2018  Argent Labs Ltd. <https://argent.xyz>

// 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.s

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

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.6.12;

import "@openzeppelin/contracts/math/SafeMath.sol";
import "../../wallet/IWallet.sol";
import "../../infrastructure/IModuleRegistry.sol";
import "../../infrastructure/storage/ILockStorage.sol";
import "./IFeature.sol";
import "../../../lib/other/ERC20.sol";
import "./IVersionManager.sol";

/**
 * @title BaseFeature
 * @notice Base Feature contract that contains methods common to all Feature contracts.
 * @author Julien Niset - <[email protected]>, Olivier VDB - <[email protected]>
 */
contract BaseFeature is IFeature {

    // Empty calldata
    bytes constant internal EMPTY_BYTES = "";
    // Mock token address for ETH
    address constant internal ETH_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
    // The address of the Lock storage
    ILockStorage internal lockStorage;
    // The address of the Version Manager
    IVersionManager internal versionManager;

    event FeatureCreated(bytes32 name);

    /**
     * @notice Throws if the wallet is locked.
     */
    modifier onlyWhenUnlocked(address _wallet) {
        require(!lockStorage.isLocked(_wallet), "BF: wallet locked");
        _;
    }

    /**
     * @notice Throws if the sender is not the VersionManager.
     */
    modifier onlyVersionManager() {
        require(msg.sender == address(versionManager), "BF: caller must be VersionManager");
        _;
    }

    /**
     * @notice Throws if the sender is not the owner of the target wallet.
     */
    modifier onlyWalletOwner(address _wallet) {
        require(isOwner(_wallet, msg.sender), "BF: must be wallet owner");
        _;
    }

    /**
     * @notice Throws if the sender is not an authorised feature of the target wallet.
     */
    modifier onlyWalletFeature(address _wallet) {
        require(versionManager.isFeatureAuthorised(_wallet, msg.sender), "BF: must be a wallet feature");
        _;
    }

    /**
     * @notice Throws if the sender is not the owner of the target wallet or the feature itself.
     */
    modifier onlyWalletOwnerOrFeature(address _wallet) {
        // Wrapping in an internal method reduces deployment cost by avoiding duplication of inlined code
        verifyOwnerOrAuthorisedFeature(_wallet, msg.sender);
        _;
    }

    constructor(
        ILockStorage _lockStorage,
        IVersionManager _versionManager,
        bytes32 _name
    ) public {
        lockStorage = _lockStorage;
        versionManager = _versionManager;
        emit FeatureCreated(_name);
    }

    /**
    * @inheritdoc IFeature
    */
    function recoverToken(address _token) external virtual override {
        uint total = ERC20(_token).balanceOf(address(this));
        _token.call(abi.encodeWithSelector(ERC20(_token).transfer.selector, address(versionManager), total));
    }

    /**
     * @notice Inits the feature for a wallet by doing nothing.
     * @dev !! Overriding methods need make sure `init()` can only be called by the VersionManager !!
     * @param _wallet The wallet.
     */
    function init(address _wallet) external virtual override  {}

    /**
     * @inheritdoc IFeature
     */
    function getRequiredSignatures(address, bytes calldata) external virtual view override returns (uint256, OwnerSignature) {
        revert("BF: disabled method");
    }

    /**
     * @inheritdoc IFeature
     */
    function getStaticCallSignatures() external virtual override view returns (bytes4[] memory _sigs) {}

    /**
     * @inheritdoc IFeature
     */
    function isFeatureAuthorisedInVersionManager(address _wallet, address _feature) public override view returns (bool) {
        return versionManager.isFeatureAuthorised(_wallet, _feature);
    }

    /**
    * @notice Checks that the wallet address provided as the first parameter of _data matches _wallet
    * @return false if the addresses are different.
    */
    function verifyData(address _wallet, bytes calldata _data) internal pure returns (bool) {
        require(_data.length >= 36, "RM: Invalid dataWallet");
        address dataWallet = abi.decode(_data[4:], (address));
        return dataWallet == _wallet;
    }
    
     /**
     * @notice Helper method to check if an address is the owner of a target wallet.
     * @param _wallet The target wallet.
     * @param _addr The address.
     */
    function isOwner(address _wallet, address _addr) internal view returns (bool) {
        return IWallet(_wallet).owner() == _addr;
    }

    /**
     * @notice Verify that the caller is an authorised feature or the wallet owner.
     * @param _wallet The target wallet.
     * @param _sender The caller.
     */
    function verifyOwnerOrAuthorisedFeature(address _wallet, address _sender) internal view {
        require(isFeatureAuthorisedInVersionManager(_wallet, _sender) || isOwner(_wallet, _sender), "BF: must be owner or feature");
    }

    /**
     * @notice Helper method to invoke a wallet.
     * @param _wallet The target wallet.
     * @param _to The target address for the transaction.
     * @param _value The value of the transaction.
     * @param _data The data of the transaction.
     */
    function invokeWallet(address _wallet, address _to, uint256 _value, bytes memory _data)
        internal
        returns (bytes memory _res) 
    {
        _res = versionManager.checkAuthorisedFeatureAndInvokeWallet(_wallet, _to, _value, _data);
    }

}

File 8 of 15 : BaseTransfer.sol
// Copyright (C) 2018  Argent Labs Ltd. <https://argent.xyz>

// 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/>.

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.6.12;

import "./BaseFeature.sol";
import "./LimitUtils.sol";

/**
 * @title BaseTransfer
 * @notice Contains common methods to transfer tokens or call third-party contracts.
 * @author Olivier VDB - <[email protected]>
 */
abstract contract BaseTransfer is BaseFeature {

    // The address of the WETH token
    address public wethToken;

    // *************** Events *************************** //

    event Transfer(address indexed wallet, address indexed token, uint256 indexed amount, address to, bytes data);
    event Approved(address indexed wallet, address indexed token, uint256 amount, address spender);
    event CalledContract(address indexed wallet, address indexed to, uint256 amount, bytes data);
    event ApprovedAndCalledContract(
        address indexed wallet,
        address indexed to,
        address spender,
        address indexed token,
        uint256 amountApproved,
        uint256 amountSpent,
        bytes data
    );
    event LimitChanged(address indexed wallet, uint indexed newLimit, uint64 indexed startAfter);


    // *************** Constructor ********************** //

    constructor(address _wethToken) public {
        wethToken = _wethToken;
    }

            
    // *************** Internal Functions ********************* //
    /**
    * @notice Make sure a contract call is not trying to call a module, a feature, or the wallet itself.
    * @param _wallet The target wallet.
    * @param _contract The address of the contract.
     */
    modifier onlyAuthorisedContractCall(address _wallet, address _contract) {
        require(
            _contract != _wallet && // not calling the wallet
            !IWallet(_wallet).authorised(_contract) && // not calling an authorised module
            !versionManager.isFeatureAuthorised(_wallet, _contract), // not calling an authorised feature
            "BT: Forbidden contract"
        );
        _;
    }

    /**
    * @notice Helper method to transfer ETH or ERC20 for a wallet.
    * @param _wallet The target wallet.
    * @param _token The ERC20 address.
    * @param _to The recipient.
    * @param _value The amount of ETH to transfer
    * @param _data The data to *log* with the transfer.
    */
    function doTransfer(address _wallet, address _token, address _to, uint256 _value, bytes memory _data) internal {
        if (_token == ETH_TOKEN) {
            invokeWallet(_wallet, _to, _value, EMPTY_BYTES);
        } else {
            bytes memory methodData = abi.encodeWithSignature("transfer(address,uint256)", _to, _value);
            bytes memory transferSuccessBytes = invokeWallet(_wallet, _token, 0, methodData);
            // Check transfer is successful, when `transfer` returns a success bool result
            if (transferSuccessBytes.length > 0) {
                require(abi.decode(transferSuccessBytes, (bool)), "RM: Transfer failed");
            }
        }
        emit Transfer(_wallet, _token, _value, _to, _data);
    }

    /**
    * @notice Helper method to approve spending the ERC20 of a wallet.
    * @param _wallet The target wallet.
    * @param _token The ERC20 address.
    * @param _spender The spender address.
    * @param _value The amount of token to transfer.
    */
    function doApproveToken(address _wallet, address _token, address _spender, uint256 _value) internal {
        bytes memory methodData = abi.encodeWithSignature("approve(address,uint256)", _spender, _value);
        invokeWallet(_wallet, _token, 0, methodData);
        emit Approved(_wallet, _token, _value, _spender);
    }

    /**
    * @notice Helper method to call an external contract.
    * @param _wallet The target wallet.
    * @param _contract The contract address.
    * @param _value The ETH value to transfer.
    * @param _data The method data.
    */
    function doCallContract(address _wallet, address _contract, uint256 _value, bytes memory _data) internal {
        invokeWallet(_wallet, _contract, _value, _data);
        emit CalledContract(_wallet, _contract, _value, _data);
    }

    /**
    * @notice Helper method to approve a certain amount of token and call an external contract.
    * The address that spends the _token and the address that is called with _data can be different.
    * @param _wallet The target wallet.
    * @param _token The ERC20 address.
    * @param _proxy The address to approve.
    * @param _amount The amount of tokens to transfer.
    * @param _contract The contract address.
    * @param _data The method data.
    */
    function doApproveTokenAndCallContract(
        address _wallet,
        address _token,
        address _proxy,
        uint256 _amount,
        address _contract,
        bytes memory _data
    )
        internal
    {
        // Ensure there is sufficient balance of token before we approve
        uint256 balance = ERC20(_token).balanceOf(_wallet);
        require(balance >= _amount, "BT: insufficient balance");

        uint256 existingAllowance = ERC20(_token).allowance(_wallet, _proxy);
        uint256 totalAllowance = SafeMath.add(existingAllowance, _amount);
        // Approve the desired amount plus existing amount. This logic allows for potential gas saving later
        // when restoring the original approved amount, in cases where the _proxy uses the exact approved _amount.
        bytes memory methodData = abi.encodeWithSignature("approve(address,uint256)", _proxy, totalAllowance);

        invokeWallet(_wallet, _token, 0, methodData);
        invokeWallet(_wallet, _contract, 0, _data);

        // Calculate the approved amount that was spent after the call
        uint256 unusedAllowance = ERC20(_token).allowance(_wallet, _proxy);
        uint256 usedAllowance = SafeMath.sub(totalAllowance, unusedAllowance);
        // Ensure the amount spent does not exceed the amount approved for this call
        require(usedAllowance <= _amount, "BT: insufficient amount for call");

        if (unusedAllowance != existingAllowance) {
            // Restore the original allowance amount if the amount spent was different (can be lower).
            methodData = abi.encodeWithSignature("approve(address,uint256)", _proxy, existingAllowance);
            invokeWallet(_wallet, _token, 0, methodData);
        }

        emit ApprovedAndCalledContract(
            _wallet,
            _contract,
            _proxy,
            _token,
            _amount,
            usedAllowance,
            _data);
    }

    /**
    * @notice Helper method to wrap ETH into WETH, approve a certain amount of WETH and call an external contract.
    * The address that spends the WETH and the address that is called with _data can be different.
    * @param _wallet The target wallet.
    * @param _proxy The address to approves.
    * @param _amount The amount of tokens to transfer.
    * @param _contract The contract address.
    * @param _data The method data.
    */
    function doApproveWethAndCallContract(
        address _wallet,
        address _proxy,
        uint256 _amount,
        address _contract,
        bytes memory _data
    )
        internal
    {
        uint256 wethBalance = ERC20(wethToken).balanceOf(_wallet);
        if (wethBalance < _amount) {
            // Wrap ETH into WETH
            invokeWallet(_wallet, wethToken, _amount - wethBalance, abi.encodeWithSignature("deposit()"));
        }

        doApproveTokenAndCallContract(_wallet, wethToken, _proxy, _amount, _contract, _data);
    }
}

File 9 of 15 : IFeature.sol
// Copyright (C) 2018  Argent Labs Ltd. <https://argent.xyz>

// 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/>.

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.7.0;

/**
 * @title IFeature
 * @notice Interface for a Feature.
 * @author Julien Niset - <[email protected]>, Olivier VDB - <[email protected]>
 */
interface IFeature {

    enum OwnerSignature {
        Anyone,             // Anyone
        Required,           // Owner required
        Optional,           // Owner and/or guardians
        Disallowed          // guardians only
    }

    /**
    * @notice Utility method to recover any ERC20 token that was sent to the Feature by mistake.
    * @param _token The token to recover.
    */
    function recoverToken(address _token) external;

    /**
     * @notice Inits a Feature for a wallet by e.g. setting some wallet specific parameters in storage.
     * @param _wallet The wallet.
     */
    function init(address _wallet) external;

    /**
     * @notice Helper method to check if an address is an authorised feature of a target wallet.
     * @param _wallet The target wallet.
     * @param _feature The address.
     */
    function isFeatureAuthorisedInVersionManager(address _wallet, address _feature) external view returns (bool);

    /**
    * @notice Gets the number of valid signatures that must be provided to execute a
    * specific relayed transaction.
    * @param _wallet The target wallet.
    * @param _data The data of the relayed transaction.
    * @return The number of required signatures and the wallet owner signature requirement.
    */
    function getRequiredSignatures(address _wallet, bytes calldata _data) external view returns (uint256, OwnerSignature);

    /**
    * @notice Gets the list of static call signatures that this feature responds to on behalf of wallets
    */
    function getStaticCallSignatures() external view returns (bytes4[] memory);
}

File 10 of 15 : IVersionManager.sol
// Copyright (C) 2018  Argent Labs Ltd. <https://argent.xyz>

// 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/>.

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.7.0;
pragma experimental ABIEncoderV2;

import "../../infrastructure/storage/ILimitStorage.sol";

/**
 * @title IVersionManager
 * @notice Interface for the VersionManager module.
 * @author Olivier VDB - <[email protected]>
 */
interface IVersionManager {
    /**
     * @notice Returns true if the feature is authorised for the wallet
     * @param _wallet The target wallet.
     * @param _feature The feature.
     */
    function isFeatureAuthorised(address _wallet, address _feature) external view returns (bool);

    /**
     * @notice Lets a feature (caller) invoke a wallet.
     * @param _wallet The target wallet.
     * @param _to The target address for the transaction.
     * @param _value The value of the transaction.
     * @param _data The data of the transaction.
     */
    function checkAuthorisedFeatureAndInvokeWallet(
        address _wallet,
        address _to,
        uint256 _value,
        bytes calldata _data
    ) external returns (bytes memory _res);

    /* ******* Backward Compatibility with old Storages and BaseWallet *************** */

    /**
     * @notice Sets a new owner for the wallet.
     * @param _newOwner The new owner.
     */
    function setOwner(address _wallet, address _newOwner) external;

    /**
     * @notice Lets a feature write data to a storage contract.
     * @param _wallet The target wallet.
     * @param _storage The storage contract.
     * @param _data The data of the call
     */
    function invokeStorage(address _wallet, address _storage, bytes calldata _data) external;

    /**
     * @notice Upgrade a wallet to a new version.
     * @param _wallet the wallet to upgrade
     * @param _toVersion the new version
     */
    function upgradeWallet(address _wallet, uint256 _toVersion) external;
 
}

File 11 of 15 : LimitUtils.sol
// Copyright (C) 2018  Argent Labs Ltd. <https://argent.xyz>

// 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/>.

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/math/SafeMath.sol";
import "../../infrastructure/storage/ILimitStorage.sol";
import "../../infrastructure/ITokenPriceRegistry.sol";
import "./IVersionManager.sol";

/**
 * @title LimitUtils
 * @notice Helper library to manage the daily limit and interact with a contract implementing the ILimitStorage interface.
 * @author Julien Niset - <[email protected]>
 */
library LimitUtils {

    // large limit when the limit can be considered disabled
    uint128 constant internal LIMIT_DISABLED = uint128(-1);

    using SafeMath for uint256;

    // *************** Internal Functions ********************* //

    /**
     * @notice Changes the daily limit (expressed in ETH).
     * Decreasing the limit is immediate while increasing the limit is pending for the security period.
     * @param _lStorage The storage contract.
     * @param _versionManager The version manager.
     * @param _wallet The target wallet.
     * @param _targetLimit The target limit.
     * @param _securityPeriod The security period.
     */
    function changeLimit(
        ILimitStorage _lStorage,
        IVersionManager _versionManager,
        address _wallet,
        uint256 _targetLimit,
        uint256 _securityPeriod
    )
        internal
        returns (ILimitStorage.Limit memory)
    {
        ILimitStorage.Limit memory limit = _lStorage.getLimit(_wallet);
        uint256 currentLimit = currentLimit(limit);
        ILimitStorage.Limit memory newLimit;
        if (_targetLimit <= currentLimit) {
            uint128 targetLimit = safe128(_targetLimit);
            newLimit = ILimitStorage.Limit(targetLimit, targetLimit, safe64(block.timestamp));
        } else {
            newLimit = ILimitStorage.Limit(safe128(currentLimit), safe128(_targetLimit), safe64(block.timestamp.add(_securityPeriod)));
        }
        setLimit(_versionManager, _lStorage, _wallet, newLimit);
        return newLimit;
    }

     /**
     * @notice Disable the daily limit.
     * The change is pending for the security period.
     * @param _lStorage The storage contract.
     * @param _versionManager The version manager.
     * @param _wallet The target wallet.
     * @param _securityPeriod The security period.
     */
    function disableLimit(
        ILimitStorage _lStorage,
        IVersionManager _versionManager,
        address _wallet,
        uint256 _securityPeriod
    )
        internal
    {
        changeLimit(_lStorage, _versionManager, _wallet, LIMIT_DISABLED, _securityPeriod);
    }

    /**
    * @notice Returns whether the daily limit is disabled for a wallet.
    * @param _wallet The target wallet.
    * @return _limitDisabled true if the daily limit is disabled, false otherwise.
    */
    function isLimitDisabled(ILimitStorage _lStorage, address _wallet) internal view returns (bool) {
        ILimitStorage.Limit memory limit = _lStorage.getLimit(_wallet);
        uint256 currentLimit = currentLimit(limit);
        return (currentLimit == LIMIT_DISABLED);
    }

    /**
    * @notice Checks if a transfer is within the limit. If yes the daily spent is updated.
    * @param _lStorage The storage contract.
    * @param _versionManager The Version Manager.
    * @param _wallet The target wallet.
    * @param _amount The amount for the transfer
    * @return true if the transfer is withing the daily limit.
    */
    function checkAndUpdateDailySpent(
        ILimitStorage _lStorage,
        IVersionManager _versionManager,
        address _wallet,
        uint256 _amount
    )
        internal
        returns (bool)
    {
        (ILimitStorage.Limit memory limit, ILimitStorage.DailySpent memory dailySpent) = _lStorage.getLimitAndDailySpent(_wallet);
        uint256 currentLimit = currentLimit(limit);
        if (_amount == 0 || currentLimit == LIMIT_DISABLED) {
            return true;
        }
        ILimitStorage.DailySpent memory newDailySpent;
        if (dailySpent.periodEnd <= block.timestamp && _amount <= currentLimit) {
            newDailySpent = ILimitStorage.DailySpent(safe128(_amount), safe64(block.timestamp + 24 hours));
            setDailySpent(_versionManager, _lStorage, _wallet, newDailySpent);
            return true;
        } else if (dailySpent.periodEnd > block.timestamp && _amount.add(dailySpent.alreadySpent) <= currentLimit) {
            newDailySpent = ILimitStorage.DailySpent(safe128(_amount.add(dailySpent.alreadySpent)), safe64(dailySpent.periodEnd));
            setDailySpent(_versionManager, _lStorage, _wallet, newDailySpent);
            return true;
        }
        return false;
    }

    /**
    * @notice Helper method to Reset the daily consumption.
    * @param _versionManager The Version Manager.
    * @param _wallet The target wallet.
    */
    function resetDailySpent(IVersionManager _versionManager, ILimitStorage limitStorage, address _wallet) internal {
        setDailySpent(_versionManager, limitStorage, _wallet, ILimitStorage.DailySpent(uint128(0), uint64(0)));
    }

    /**
    * @notice Helper method to get the ether value equivalent of a token amount.
    * @notice For low value amounts of tokens we accept this to return zero as these are small enough to disregard.
    * Note that the price stored for tokens = price for 1 token (in ETH wei) * 10^(18-token decimals).
    * @param _amount The token amount.
    * @param _token The address of the token.
    * @return The ether value for _amount of _token.
    */
    function getEtherValue(ITokenPriceRegistry _priceRegistry, uint256 _amount, address _token) internal view returns (uint256) {
        uint256 price = _priceRegistry.getTokenPrice(_token);
        uint256 etherValue = price.mul(_amount).div(10**18);
        return etherValue;
    }

    /**
    * @notice Helper method to get the current limit from a Limit struct.
    * @param _limit The limit struct
    */
    function currentLimit(ILimitStorage.Limit memory _limit) internal view returns (uint256) {
        if (_limit.changeAfter > 0 && _limit.changeAfter < block.timestamp) {
            return _limit.pending;
        }
        return _limit.current;
    }

    function safe128(uint256 _num) internal pure returns (uint128) {
        require(_num < 2**128, "LU: more then 128 bits");
        return uint128(_num);
    }

    function safe64(uint256 _num) internal pure returns (uint64) {
        require(_num < 2**64, "LU: more then 64 bits");
        return uint64(_num);
    }

    // *************** Storage invocations in VersionManager ********************* //

    function setLimit(
        IVersionManager _versionManager,
        ILimitStorage _lStorage,
        address _wallet, 
        ILimitStorage.Limit memory _limit
    ) internal {
        _versionManager.invokeStorage(
            _wallet,
            address(_lStorage),
            abi.encodeWithSelector(_lStorage.setLimit.selector, _wallet, _limit)
        );
    }

    function setDailySpent(
        IVersionManager _versionManager,
        ILimitStorage _lStorage,
        address _wallet, 
        ILimitStorage.DailySpent memory _dailySpent
    ) private {
        _versionManager.invokeStorage(
            _wallet,
            address(_lStorage),
            abi.encodeWithSelector(_lStorage.setDailySpent.selector, _wallet, _dailySpent)
        );
    }

}

File 12 of 15 : Utils.sol
// Copyright (C) 2020  Argent Labs Ltd. <https://argent.xyz>

// 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/>.

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.6.12;

/**
 * @title Utils
 * @notice Common utility methods used by modules.
 */
library Utils {

    /**
    * @notice Helper method to recover the signer at a given position from a list of concatenated signatures.
    * @param _signedHash The signed hash
    * @param _signatures The concatenated signatures.
    * @param _index The index of the signature to recover.
    */
    function recoverSigner(bytes32 _signedHash, bytes memory _signatures, uint _index) internal pure returns (address) {
        uint8 v;
        bytes32 r;
        bytes32 s;
        // we jump 32 (0x20) as the first slot of bytes contains the length
        // we jump 65 (0x41) per signature
        // for v we load 32 bytes ending with v (the first 31 come from s) then apply a mask
        // solhint-disable-next-line no-inline-assembly
        assembly {
            r := mload(add(_signatures, add(0x20,mul(0x41,_index))))
            s := mload(add(_signatures, add(0x40,mul(0x41,_index))))
            v := and(mload(add(_signatures, add(0x41,mul(0x41,_index)))), 0xff)
        }
        require(v == 27 || v == 28);

        address recoveredAddress = ecrecover(_signedHash, v, r, s);
        require(recoveredAddress != address(0), "Utils: ecrecover returned 0");
        return recoveredAddress;
    }

    /**
    * @notice Helper method to parse data and extract the method signature.
    */
    function functionPrefix(bytes memory _data) internal pure returns (bytes4 prefix) {
        require(_data.length >= 4, "RM: Invalid functionPrefix");
        // solhint-disable-next-line no-inline-assembly
        assembly {
            prefix := mload(add(_data, 0x20))
        }
    }

    /**
    * @notice Returns ceil(a / b).
    */
    function ceil(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a / b;
        if (a % b == 0) {
            return c;
        } else {
            return c + 1;
        }
    }

    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a < b) {
            return a;
        }
        return b;
    }
}

File 13 of 15 : IWallet.sol
// Copyright (C) 2018  Argent Labs Ltd. <https://argent.xyz>

// 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/>.

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.7.0;

/**
 * @title IWallet
 * @notice Interface for the BaseWallet
 */
interface IWallet {
    /**
     * @notice Returns the wallet owner.
     * @return The wallet owner address.
     */
    function owner() external view returns (address);

    /**
     * @notice Returns the number of authorised modules.
     * @return The number of authorised modules.
     */
    function modules() external view returns (uint);

    /**
     * @notice Sets a new owner for the wallet.
     * @param _newOwner The new owner.
     */
    function setOwner(address _newOwner) external;

    /**
     * @notice Checks if a module is authorised on the wallet.
     * @param _module The module address to check.
     * @return `true` if the module is authorised, otherwise `false`.
     */
    function authorised(address _module) external view returns (bool);

    /**
     * @notice Returns the module responsible for a static call redirection.
     * @param _sig The signature of the static call.
     * @return the module doing the redirection
     */
    function enabled(bytes4 _sig) external view returns (address);

    /**
     * @notice Enables/Disables a module.
     * @param _module The target module.
     * @param _value Set to `true` to authorise the module.
     */
    function authoriseModule(address _module, bool _value) external;

    /**
    * @notice Enables a static method by specifying the target module to which the call must be delegated.
    * @param _module The target module.
    * @param _method The static method signature.
    */
    function enableStaticCall(address _module, bytes4 _method) external;
}

File 14 of 15 : ERC20.sol
pragma solidity >=0.5.4 <0.7.0;

/**
 * ERC20 contract interface.
 */
interface ERC20 {
    function totalSupply() external view returns (uint);
    function decimals() external view returns (uint);
    function balanceOf(address tokenOwner) external view returns (uint balance);
    function allowance(address tokenOwner, address spender) external view returns (uint remaining);
    function transfer(address to, uint tokens) external returns (bool success);
    function approve(address spender, uint tokens) external returns (bool success);
    function transferFrom(address from, address to, uint tokens) external returns (bool success);
}

File 15 of 15 : SafeMath.sol
pragma solidity ^0.6.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

Settings
{
  "remappings": [],
  "optimizer": {
    "enabled": true,
    "runs": 999
  },
  "evmVersion": "istanbul",
  "libraries": {
    "": {}
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract ILockStorage","name":"_lockStorage","type":"address"},{"internalType":"contract ITransferStorage","name":"_transferStorage","type":"address"},{"internalType":"contract ILimitStorage","name":"_limitStorage","type":"address"},{"internalType":"contract ITokenPriceRegistry","name":"_tokenPriceRegistry","type":"address"},{"internalType":"contract IVersionManager","name":"_versionManager","type":"address"},{"internalType":"uint256","name":"_securityPeriod","type":"uint256"},{"internalType":"uint256","name":"_securityWindow","type":"uint256"},{"internalType":"uint256","name":"_defaultLimit","type":"uint256"},{"internalType":"address","name":"_wethToken","type":"address"},{"internalType":"contract TransferManager","name":"_oldTransferManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"uint64","name":"whitelistAfter","type":"uint64"}],"name":"AddedToWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"spender","type":"address"}],"name":"Approved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountApproved","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountSpent","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"ApprovedAndCalledContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"CalledContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"securityPeriod","type":"uint256"}],"name":"DailyLimitDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"currentDailyLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pendingDailyLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"changeDailyLimitAfter","type":"uint256"}],"name":"DailyLimitMigrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"name","type":"bytes32"}],"name":"FeatureCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"uint256","name":"newLimit","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"startAfter","type":"uint64"}],"name":"LimitChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"PendingTransferCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"executeAfter","type":"uint256"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"PendingTransferCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"PendingTransferExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"}],"name":"RemovedFromWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_target","type":"address"}],"name":"addToWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"approveToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_proxy","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_contract","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"approveTokenAndCallContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_proxy","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_contract","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"approveWethAndCallContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_contract","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"callContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"bytes32","name":"_id","type":"bytes32"}],"name":"cancelPendingTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"uint256","name":"_newLimit","type":"uint256"}],"name":"changeLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultLimit","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"disableLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"uint256","name":"_block","type":"uint256"}],"name":"executePendingTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"getCurrentLimit","outputs":[{"internalType":"uint256","name":"_currentLimit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"getDailyUnspent","outputs":[{"internalType":"uint256","name":"_unspent","type":"uint256"},{"internalType":"uint64","name":"_periodEnd","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"getPendingLimit","outputs":[{"internalType":"uint256","name":"_pendingLimit","type":"uint256"},{"internalType":"uint64","name":"_changeAfter","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"bytes32","name":"_id","type":"bytes32"}],"name":"getPendingTransfer","outputs":[{"internalType":"uint64","name":"_executeAfter","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"getRequiredSignatures","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"enum IFeature.OwnerSignature","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStaticCallSignatures","outputs":[{"internalType":"bytes4[]","name":"_sigs","type":"bytes4[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_feature","type":"address"}],"name":"isFeatureAuthorisedInVersionManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"isLimitDisabled","outputs":[{"internalType":"bool","name":"_limitDisabled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_msgHash","type":"bytes32"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_target","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"bool","name":"_isWhitelisted","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"limitStorage","outputs":[{"internalType":"contract ILimitStorage","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oldTransferManager","outputs":[{"internalType":"contract TransferManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"recoverToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_target","type":"address"}],"name":"removeFromWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"securityPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"securityWindow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenPriceRegistry","outputs":[{"internalType":"contract ITokenPriceRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"transferStorage","outputs":[{"internalType":"contract ITransferStorage","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"transferToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wethToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101e45760003560e01c8063961bfeee1161010f578063d5e69ee9116100a2578063ea2347e611610071578063ea2347e614610407578063f8d3277d1461041c578063f9f6499e1461042f578063fd6ac30914610442576101e4565b8063d5e69ee9146103b7578063d60a0fbb146103ca578063e1ee38ec146103d2578063e26b013b146103f2576101e4565b8063a3411c0a116100de578063a3411c0a1461036b578063b20f3f371461037e578063b377a9d514610391578063b6b35272146103a4576101e4565b8063961bfeee1461031d5780639be65a6014610325578063a0aec10514610338578063a287fdbd1461034b576101e4565b80633b73d67f116101875780635ed4bf81116101565780635ed4bf81146102ce5780637cb8f8ba146102e15780637cc0d906146103025780638eac81d51461030a576101e4565b80633b73d67f1461027f57806343cd5c7e146102a05780634b57b0be146102b357806357518243146102bb576101e4565b80631626ba7e116101c35780631626ba7e1461023157806319ab453c1461025157806329b59552146102645780632df546f41461026c576101e4565b80626fda35146101e95780631094fa571461020757806312ef080d1461021c575b600080fd5b6101f1610455565b6040516101fe9190614551565b60405180910390f35b61020f61045b565b6040516101fe9190613ddd565b61022f61022a36600461371f565b61046a565b005b61024461023f366004613a88565b61064a565b6040516101fe9190614022565b61022f61025f3660046136af565b6106ce565b61020f610ab1565b61022f61027a366004613805565b610ac0565b61029261028d366004613a15565b610d16565b6040516101fe92919061458a565b6101f16102ae3660046136af565b610d21565b61020f610dbf565b61022f6102c93660046136e7565b610dce565b61022f6102dc366004613888565b610f13565b6102f46102ef3660046136af565b611117565b6040516101fe9291906145c8565b6101f161123b565b61022f610318366004613914565b611241565b61020f611495565b61022f6103333660046136af565b6114a4565b6102f46103463660046136af565b6115d8565b61035e6103593660046136e7565b6116a2565b6040516101fe9190613ff9565b61022f6103793660046136af565b61172c565b61022f61038c3660046139ea565b61183e565b61022f61039f3660046139ea565b611961565b61035e6103b23660046136e7565b611a9d565b61022f6103c536600461376f565b611b56565b61020f611d9f565b6103e56103e03660046139ea565b611dae565b6040516101fe91906145e0565b6103fa611dd5565b6040516101fe919061453d565b61040f611de4565b6040516101fe9190613fab565b61022f61042a3660046136e7565b611e50565b61035e61043d3660046136af565b611f4a565b61022f610450366004613979565b611f63565b60055481565b6009546001600160a01b031681565b8361047581336121e7565b600054604051631293efbb60e21b815286916001600160a01b031690634a4fbeec906104a5908490600401613ddd565b60206040518083038186803b1580156104bd57600080fd5b505afa1580156104d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f59190613a68565b1561051b5760405162461bcd60e51b815260040161051290614126565b60405180910390fd5b6105258685611a9d565b1561053b5761053686868686612221565b610642565b604051636eb1769f60e11b81526000906001600160a01b0387169063dd62ed3e9061056c908a908990600401613df1565b60206040518083038186803b15801561058457600080fd5b505afa158015610598573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105bc9190613c3b565b90508084116105d6576105d187878787612221565b610640565b600a54818503906000906105f4906001600160a01b0316838a6122b5565b600954600154919250610615916001600160a01b0391821691168b84612377565b6106315760405162461bcd60e51b8152600401610512906143be565b61063d89898989612221565b50505b505b505050505050565b6000815160411461066d5760405162461bcd60e51b815260040161051290614498565b600061067b84846000612556565b90506106873382612616565b6106a35760405162461bcd60e51b81526004016105129061415d565b7f1626ba7e356f5979dd355a3d2bfb43e80420a480c3b854edce286a82d74968699150505b92915050565b6001546001600160a01b031633146106f85760405162461bcd60e51b8152600401610512906142bc565b6008546001600160a01b031661074057604080516060810182526006546001600160801b031681526000602082018190529181019190915261073b9082906126a4565b610aae565b6008546040517f43cd5c7e0000000000000000000000000000000000000000000000000000000081526000916001600160a01b0316906343cd5c7e9061078a908590600401613ddd565b60206040518083038186803b1580156107a257600080fd5b505afa1580156107b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107da9190613c3b565b6008546040517fa0aec10500000000000000000000000000000000000000000000000000000000815291925060009182916001600160a01b03169063a0aec10590610829908790600401613ddd565b604080518083038186803b15801561084057600080fd5b505afa158015610854573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108789190613c53565b91509150826000148015610894575067ffffffffffffffff8116155b156108d157604080516060810182526006546001600160801b03168152600060208201819052918101919091526108cc9085906126a4565b610aaa565b6008546040517f7cb8f8ba00000000000000000000000000000000000000000000000000000000815260009182916001600160a01b0390911690637cb8f8ba9061091f908990600401613ddd565b604080518083038186803b15801561093657600080fd5b505afa15801561094a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096e9190613c53565b91509150428167ffffffffffffffff1610156109d9576109d486604051806060016040528061099c896121b1565b6001600160801b031681526020016109b3886121b1565b6001600160801b031681526020018667ffffffffffffffff168152506126a4565b610a62565b610a628660405180606001604052806109f1896121b1565b6001600160801b03168152602001610a08886121b1565b6001600160801b0316815267ffffffffffffffff87166020909101526040805180820190915280610a41610a3c8b8961276b565b6121b1565b6001600160801b031681526020018567ffffffffffffffff168152506127ad565b856001600160a01b03167f26d77533e727d724b23e95ad7031e1097932c4eaf2eb37b4370d29516847d5af868686604051610a9f939291906145a8565b60405180910390a250505b5050505b50565b6008546001600160a01b031681565b85610acb81336121e7565b600054604051631293efbb60e21b815288916001600160a01b031690634a4fbeec90610afb908490600401613ddd565b60206040518083038186803b158015610b1357600080fd5b505afa158015610b27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4b9190613a68565b15610b685760405162461bcd60e51b815260040161051290614126565b610b728887611a9d565b15610bbf57610bba8888888888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061287692505050565b610d0c565b60006001600160a01b03881673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610c0157600a54610bfc906001600160a01b0316878a6122b5565b610c03565b855b600954600154919250610c24916001600160a01b0391821691168b84612377565b15610c7157610c6c8989898989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061287692505050565b61063d565b600080610cb960008c8c8c8c8c8c8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061299e92505050565b9150915080828c6001600160a01b03167fc63146cfd39cd6097f6e314e8595c4554faf95175b45c6215517903c12e765d98d8d8d8d8d604051610d00959493929190613e5b565b60405180910390a45050505b5050505050505050565b600180935093915050565b6000610d2b6135c4565b600954604051630e71473960e11b81526001600160a01b0390911690631ce28e7290610d5b908690600401613ddd565b60606040518083038186803b158015610d7357600080fd5b505afa158015610d87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dab9190613b76565b9050610db681612a53565b9150505b919050565b6002546001600160a01b031681565b81610dd981336121e7565b600054604051631293efbb60e21b815284916001600160a01b031690634a4fbeec90610e09908490600401613ddd565b60206040518083038186803b158015610e2157600080fd5b505afa158015610e35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e599190613a68565b15610e765760405162461bcd60e51b815260040161051290614126565b610e808484611a9d565b15610e9d5760405162461bcd60e51b815260040161051290614194565b6000610eb460045442612aa690919063ffffffff16565b9050610ec1858583612acb565b836001600160a01b0316856001600160a01b03167f1f57f9641d3e8733ed672fef5ac85464bd7215ef2f21e83428e8408248b13dcd83604051610f0491906145e0565b60405180910390a35050505050565b600054604051631293efbb60e21b815288916001600160a01b031690634a4fbeec90610f43908490600401613ddd565b60206040518083038186803b158015610f5b57600080fd5b505afa158015610f6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f939190613a68565b15610fb05760405162461bcd60e51b815260040161051290614126565b600080888888888888604051602001610fcf9796959493929190613d1c565b60408051601f1981840301815291815281516020928301206001600160a01b038c16600090815260038452828120828252909352912054909150806110265760405162461bcd60e51b8152600401610512906141cb565b600061103d60055483612aa690919063ffffffff16565b905042821115801561104f5750804211155b61106b5760405162461bcd60e51b815260040161051290614202565b6001600160a01b038b1660009081526003602090815260408083208684528252808320929092558151601f89018290048202810182019092528782526110d4918d918d918d918d91908d908d908190840183828082843760009201919091525061287692505050565b60405183906001600160a01b038d16907f53d984c4cd3917405bdcc3baabad7c1269dd3baf7c2c53ca571d8d7de9629bc990600090a35050505050505050505050565b6000806111226135c4565b61112a6135e4565b6009546040516304d596cb60e21b81526001600160a01b03909116906313565b2c9061115a908890600401613ddd565b60a06040518083038186803b15801561117257600080fd5b505afa158015611186573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111aa9190613b91565b9150915060006111b983612a53565b9050816020015167ffffffffffffffff164211156111eb57806111df4262015180612aa6565b94509450505050611236565b81516001600160801b03168111156112245781516112139082906001600160801b031661276b565b826020015194509450505050611236565b50602001516000935091506112369050565b915091565b60045481565b8561124c81336121e7565b600054604051631293efbb60e21b815288916001600160a01b031690634a4fbeec9061127c908490600401613ddd565b60206040518083038186803b15801561129457600080fd5b505afa1580156112a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cc9190613a68565b156112e95760405162461bcd60e51b815260040161051290614126565b8785816001600160a01b0316816001600160a01b031614158015611386575060405163d6eb1bbf60e01b81526001600160a01b0383169063d6eb1bbf90611334908490600401613ddd565b60206040518083038186803b15801561134c57600080fd5b505afa158015611360573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113849190613a68565b155b80156114115750600154604051635a51fd4360e01b81526001600160a01b0390911690635a51fd43906113bf9085908590600401613df1565b60206040518083038186803b1580156113d757600080fd5b505afa1580156113eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061140f9190613a68565b155b61142d5760405162461bcd60e51b815260040161051290614506565b600254611446908b906001600160a01b03168a8a612b1f565b6114898a8a8a8a8a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612bee92505050565b50505050505050505050565b6007546001600160a01b031681565b6040516370a0823160e01b81526000906001600160a01b038316906370a08231906114d3903090600401613ddd565b60206040518083038186803b1580156114eb57600080fd5b505afa1580156114ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115239190613c3b565b6001546040519192506001600160a01b038085169263a9059cbb60e01b926115519216908590602401613f64565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161158f9190613d00565b6000604051808303816000865af19150503d80600081146115cc576040519150601f19603f3d011682016040523d82523d6000602084013e6115d1565b606091505b5050505050565b6000806115e36135c4565b600954604051630e71473960e11b81526001600160a01b0390911690631ce28e7290611613908790600401613ddd565b60606040518083038186803b15801561162b57600080fd5b505afa15801561163f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116639190613b76565b9050806040015167ffffffffffffffff1642106116825760008061168d565b806020015181604001515b6001600160801b039091169350915050915091565b600154604051635a51fd4360e01b81526000916001600160a01b031690635a51fd43906116d59086908690600401613df1565b60206040518083038186803b1580156116ed57600080fd5b505afa158015611701573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117259190613a68565b9392505050565b8061173781336121e7565b600054604051631293efbb60e21b815283916001600160a01b031690634a4fbeec90611767908490600401613ddd565b60206040518083038186803b15801561177f57600080fd5b505afa158015611793573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b79190613a68565b156117d45760405162461bcd60e51b815260040161051290614126565b6009546001546004546117f6926001600160a01b039081169216908690612cf6565b826001600160a01b03167f900b0dba45e6dacc3a60c4304ad1a8c5378d5f1704e16a6600477ee969137b906004546040516118319190614551565b60405180910390a2505050565b8161184981336121e7565b600054604051631293efbb60e21b815284916001600160a01b031690634a4fbeec90611879908490600401613ddd565b60206040518083038186803b15801561189157600080fd5b505afa1580156118a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c99190613a68565b156118e65760405162461bcd60e51b815260040161051290614126565b6118ee6135c4565b600954600154600454611912926001600160a01b0390811692169088908890612d06565b9050806040015167ffffffffffffffff1684866001600160a01b03167f8a747eae44b6307d1b112c127968367d02d9f52ffef8533b3e899983ff2b1d4a60405160405180910390a45050505050565b8161196c81336121e7565b600054604051631293efbb60e21b815284916001600160a01b031690634a4fbeec9061199c908490600401613ddd565b60206040518083038186803b1580156119b457600080fd5b505afa1580156119c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ec9190613a68565b15611a095760405162461bcd60e51b815260040161051290614126565b6001600160a01b0384166000908152600360209081526040808320868452909152902054611a495760405162461bcd60e51b815260040161051290614387565b6001600160a01b0384166000818152600360209081526040808320878452909152808220829055518592917f2914460f2e2359d06bcda666d815164a8e77d104644dfbe6360885abfa2da59c91a350505050565b6007546040517f13f4a0ea00000000000000000000000000000000000000000000000000000000815260009182916001600160a01b03909116906313f4a0ea90611aed9087908790600401613df1565b60206040518083038186803b158015611b0557600080fd5b505afa158015611b19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3d9190613c3b565b9050600081118015611b4e57504281105b949350505050565b86611b6181336121e7565b600054604051631293efbb60e21b815289916001600160a01b031690634a4fbeec90611b91908490600401613ddd565b60206040518083038186803b158015611ba957600080fd5b505afa158015611bbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611be19190613a68565b15611bfe5760405162461bcd60e51b815260040161051290614126565b8885816001600160a01b0316816001600160a01b031614158015611c9b575060405163d6eb1bbf60e01b81526001600160a01b0383169063d6eb1bbf90611c49908490600401613ddd565b60206040518083038186803b158015611c6157600080fd5b505afa158015611c75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c999190613a68565b155b8015611d265750600154604051635a51fd4360e01b81526001600160a01b0390911690635a51fd4390611cd49085908590600401613df1565b60206040518083038186803b158015611cec57600080fd5b505afa158015611d00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d249190613a68565b155b611d425760405162461bcd60e51b815260040161051290614506565b611d4e8b8b8a8a612b1f565b611d928b8b8b8b8b8b8b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612e6c92505050565b5050505050505050505050565b600a546001600160a01b031681565b6001600160a01b039091166000908152600360209081526040808320938352929052205490565b6006546001600160801b031681565b604080516001808252818301909252606091602080830190803683370190505090507f1626ba7e356f5979dd355a3d2bfb43e80420a480c3b854edce286a82d749686981600081518110611e3457fe5b6001600160e01b03199092166020928302919091019091015290565b81611e5b81336121e7565b600054604051631293efbb60e21b815284916001600160a01b031690634a4fbeec90611e8b908490600401613ddd565b60206040518083038186803b158015611ea357600080fd5b505afa158015611eb7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611edb9190613a68565b15611ef85760405162461bcd60e51b815260040161051290614126565b611f0484846000612acb565b826001600160a01b0316846001600160a01b03167fd288ab5da2e1f37cf384a1565a3f905ad289b092fbdd31950dbbfef148c04f8860405160405180910390a350505050565b6009546000906106c8906001600160a01b03168361316a565b84611f6e81336121e7565b600054604051631293efbb60e21b815287916001600160a01b031690634a4fbeec90611f9e908490600401613ddd565b60206040518083038186803b158015611fb657600080fd5b505afa158015611fca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fee9190613a68565b1561200b5760405162461bcd60e51b815260040161051290614126565b8686816001600160a01b0316816001600160a01b0316141580156120a8575060405163d6eb1bbf60e01b81526001600160a01b0383169063d6eb1bbf90612056908490600401613ddd565b60206040518083038186803b15801561206e57600080fd5b505afa158015612082573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120a69190613a68565b155b80156121335750600154604051635a51fd4360e01b81526001600160a01b0390911690635a51fd43906120e19085908590600401613df1565b60206040518083038186803b1580156120f957600080fd5b505afa15801561210d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121319190613a68565b155b61214f5760405162461bcd60e51b815260040161051290614506565b61216f8973eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee898b612b1f565b61063d89898989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061320f92505050565b600070010000000000000000000000000000000082106121e35760405162461bcd60e51b81526004016105129061404a565b5090565b6121f182826116a2565b8061220157506122018282612616565b61221d5760405162461bcd60e51b8152600401610512906143f5565b5050565b60608282604051602401612236929190613f64565b60408051601f198184030181529190526020810180516001600160e01b031663095ea7b360e01b179052905061226f858560008461326f565b50836001600160a01b0316856001600160a01b03167fdc47705473b4a899de6e16a740ecc86f2a65dc7dbb9eadd0a06ce5421a44e2308486604051610f0492919061455a565b600080846001600160a01b031663d02641a0846040518263ffffffff1660e01b81526004016122e49190613ddd565b60206040518083038186803b1580156122fc57600080fd5b505afa158015612310573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123349190613c04565b76ffffffffffffffffffffffffffffffffffffffffffffff169050600061236d670de0b6b3a7640000612367848861331e565b90613358565b9695505050505050565b60006123816135c4565b6123896135e4565b6040516304d596cb60e21b81526001600160a01b038816906313565b2c906123b5908890600401613ddd565b60a06040518083038186803b1580156123cd57600080fd5b505afa1580156123e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124059190613b91565b91509150600061241483612a53565b905084158061242957506001600160801b0381145b1561243a5760019350505050611b4e565b6124426135e4565b42836020015167ffffffffffffffff16111580156124605750818611155b156124bc576040518060400160405280612479886121b1565b6001600160801b0316815260200161249542620151800161339a565b67ffffffffffffffff16905290506124af888a89846133c4565b6001945050505050611b4e565b42836020015167ffffffffffffffff161180156124ef5750825182906124ec9088906001600160801b0316612aa6565b11155b15612547576040518060400160405280612522610a3c86600001516001600160801b03168a612aa690919063ffffffff16565b6001600160801b03168152602001612495856020015167ffffffffffffffff1661339a565b50600098975050505050505050565b6041808202830160208101516040820151919092015160009260ff9190911691601b83148061258857508260ff16601c145b61259157600080fd5b6000600188858585604051600081526020016040526040516125b69493929190614004565b6020604051602081039080840390855afa1580156125d8573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661260b5760405162461bcd60e51b815260040161051290614081565b979650505050505050565b6000816001600160a01b0316836001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561265b57600080fd5b505afa15801561266f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061269391906136cb565b6001600160a01b0316149392505050565b6001546009546040516001600160a01b039283169263e452b7909286929116907fb843fe5900000000000000000000000000000000000000000000000000000000906126f69084908890602401613f1d565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199485161790525160e086901b909216825261273d939291600401613e0b565b600060405180830381600087803b15801561275757600080fd5b505af1158015610642573d6000803e3d6000fd5b600061172583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613465565b6001546009546040516001600160a01b039283169263e452b7909287929116907f61c4121e000000000000000000000000000000000000000000000000000000009061280190849089908990602401613f3a565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199485161790525160e086901b9092168252612848939291600401613e0b565b600060405180830381600087803b15801561286257600080fd5b505af1158015610640573d6000803e3d6000fd5b6001600160a01b03841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14156128bc576128b68584846040518060200160405280600081525061326f565b50612949565b606083836040516024016128d1929190613f64565b60408051601f198184030181529190526020810180516001600160e01b031663a9059cbb60e01b1790529050606061290c878760008561326f565b805190915015612946578080602001905181019061292a9190613a68565b6129465760405162461bcd60e51b815260040161051290614350565b50505b81846001600160a01b0316866001600160a01b03167fd5c97f2e041b2046be3b4337472f05720760a198f4d7d84980b7155eec7cca6f868560405161298f929190613ede565b60405180910390a45050505050565b6000808786868686436040516020016129bc96959493929190613d75565b60408051601f1981840301815291815281516020928301206001600160a01b038a1660009081526003845282812082825290935291205490925015612a135760405162461bcd60e51b8152600401610512906144cf565b600454612a21904290612aa6565b6001600160a01b0390971660009081526003602090815260408083208584529091529020879055509694955050505050565b600080826040015167ffffffffffffffff16118015612a7f575042826040015167ffffffffffffffff16105b15612a98575060208101516001600160801b0316610dba565b50516001600160801b031690565b6000828201838110156117255760405162461bcd60e51b8152600401610512906140b8565b6001546007546040516001600160a01b039283169263e452b7909287929116907f80bfbe68000000000000000000000000000000000000000000000000000000009061280190849089908990602401613e37565b612b298482611a9d565b610aaa57612b378482613491565b15612b545760405162461bcd60e51b815260040161051290614319565b60006001600160a01b03841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480612b8e57506002546001600160a01b038581169116145b15612b9a575081612bb4565b600a54612bb1906001600160a01b031684866122b5565b90505b600954600154612bd2916001600160a01b0390811691168784612377565b6115d15760405162461bcd60e51b8152600401610512906143be565b6002546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612c1f908990600401613ddd565b60206040518083038186803b158015612c3757600080fd5b505afa158015612c4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c6f9190613c3b565b905083811015612cdb576002546040805160048152602481019091526020810180516001600160e01b03167fd0e30db000000000000000000000000000000000000000000000000000000000179052612cd99188916001600160a01b03909116908488039061326f565b505b6002546106429087906001600160a01b031687878787612e6c565b6115d18484846001600160801b03855b612d0e6135c4565b612d166135c4565b604051630e71473960e11b81526001600160a01b03881690631ce28e7290612d42908890600401613ddd565b60606040518083038186803b158015612d5a57600080fd5b505afa158015612d6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d929190613b76565b90506000612d9f82612a53565b9050612da96135c4565b818611612dfa576000612dbb876121b1565b604080516060810182526001600160801b03831680825260208201529192508101612de54261339a565b67ffffffffffffffff16815250915050612e54565b6040518060600160405280612e0e846121b1565b6001600160801b03168152602001612e25886121b1565b6001600160801b03168152602001612e45612e404289612aa6565b61339a565b67ffffffffffffffff16905290505b612e60888a8984613561565b98975050505050505050565b6040516370a0823160e01b81526000906001600160a01b038716906370a0823190612e9b908a90600401613ddd565b60206040518083038186803b158015612eb357600080fd5b505afa158015612ec7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612eeb9190613c3b565b905083811015612f0d5760405162461bcd60e51b81526004016105129061442c565b604051636eb1769f60e11b81526000906001600160a01b0388169063dd62ed3e90612f3e908b908a90600401613df1565b60206040518083038186803b158015612f5657600080fd5b505afa158015612f6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f8e9190613c3b565b90506000612f9c8287612aa6565b905060608782604051602401612fb3929190613f64565b60408051601f198184030181529190526020810180516001600160e01b031663095ea7b360e01b1790529050612fec8a8a60008461326f565b50612ffa8a8760008861326f565b50604051636eb1769f60e11b81526000906001600160a01b038b169063dd62ed3e9061302c908e908d90600401613df1565b60206040518083038186803b15801561304457600080fd5b505afa158015613058573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061307c9190613c3b565b9050600061308a848361276b565b9050888111156130ac5760405162461bcd60e51b815260040161051290614463565b8482146131015789856040516024016130c6929190613f64565b60408051601f198184030181529190526020810180516001600160e01b031663095ea7b360e01b17905292506130ff8c8c60008661326f565b505b8a6001600160a01b0316886001600160a01b03168d6001600160a01b03167fb99e2a91cdfde581196884f6b42392a5000200a43dd5726d92d9405616fdffb98d8d868d6040516131549493929190613f7d565b60405180910390a4505050505050505050505050565b60006131746135c4565b604051630e71473960e11b81526001600160a01b03851690631ce28e72906131a0908690600401613ddd565b60606040518083038186803b1580156131b857600080fd5b505afa1580156131cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131f09190613b76565b905060006131fd82612a53565b6001600160801b031495945050505050565b61321b8484848461326f565b50826001600160a01b0316846001600160a01b03167fbfbd7fb6c6d7dd1ef01d18a7e98333f084363d82d5ce600328e8b941a53d66548484604051613261929190614571565b60405180910390a350505050565b6001546040517f915c77b90000000000000000000000000000000000000000000000000000000081526060916001600160a01b03169063915c77b9906132bf908890889088908890600401613eac565b600060405180830381600087803b1580156132d957600080fd5b505af11580156132ed573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526133159190810190613b0c565b95945050505050565b60008261332d575060006106c8565b8282028284828161333a57fe5b04146117255760405162461bcd60e51b81526004016105129061425f565b600061172583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061358d565b60006801000000000000000082106121e35760405162461bcd60e51b8152600401610512906140ef565b836001600160a01b031663e452b7908385635ae5bc5260e01b86866040516024016133f0929190613f00565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199485161790525160e086901b9092168252613437939291600401613e0b565b600060405180830381600087803b15801561345157600080fd5b505af1158015610d0c573d6000803e3d6000fd5b600081848411156134895760405162461bcd60e51b81526004016105129190614037565b505050900390565b600a546040517fd02641a000000000000000000000000000000000000000000000000000000000815260009182916001600160a01b039091169063d02641a0906134df908690600401613ddd565b60206040518083038186803b1580156134f757600080fd5b505afa15801561350b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061352f9190613c04565b76ffffffffffffffffffffffffffffffffffffffffffffff16118015611725575061355983611f4a565b159392505050565b836001600160a01b031663e452b790838563b843fe5960e01b86866040516024016133f0929190613f1d565b600081836135ae5760405162461bcd60e51b81526004016105129190614037565b5060008385816135ba57fe5b0495945050505050565b604080516060810182526000808252602082018190529181019190915290565b604080518082019091526000808252602082015290565b60008083601f84011261360c578182fd5b50813567ffffffffffffffff811115613623578182fd5b60208301915083602082850101111561363b57600080fd5b9250929050565b600060608284031215613653578081fd5b61365d60606145f5565b9050815161366a81614681565b8152602082015161367a81614681565b602082015261368c8360408401613697565b604082015292915050565b805167ffffffffffffffff811681146106c857600080fd5b6000602082840312156136c0578081fd5b81356117258161466c565b6000602082840312156136dc578081fd5b81516117258161466c565b600080604083850312156136f9578081fd5b82356137048161466c565b915060208301356137148161466c565b809150509250929050565b60008060008060808587031215613734578182fd5b843561373f8161466c565b9350602085013561374f8161466c565b9250604085013561375f8161466c565b9396929550929360600135925050565b600080600080600080600060c0888a031215613789578283fd5b87356137948161466c565b965060208801356137a48161466c565b955060408801356137b48161466c565b94506060880135935060808801356137cb8161466c565b925060a088013567ffffffffffffffff8111156137e6578283fd5b6137f28a828b016135fb565b989b979a50959850939692959293505050565b60008060008060008060a0878903121561381d578182fd5b86356138288161466c565b955060208701356138388161466c565b945060408701356138488161466c565b935060608701359250608087013567ffffffffffffffff81111561386a578283fd5b61387689828a016135fb565b979a9699509497509295939492505050565b600080600080600080600060c0888a0312156138a2578283fd5b87356138ad8161466c565b965060208801356138bd8161466c565b955060408801356138cd8161466c565b945060608801359350608088013567ffffffffffffffff8111156138ef578384fd5b6138fb8a828b016135fb565b989b979a5095989497959660a090950135949350505050565b60008060008060008060a0878903121561392c578384fd5b86356139378161466c565b955060208701356139478161466c565b945060408701359350606087013561395e8161466c565b9250608087013567ffffffffffffffff81111561386a578283fd5b600080600080600060808688031215613990578283fd5b853561399b8161466c565b945060208601356139ab8161466c565b935060408601359250606086013567ffffffffffffffff8111156139cd578182fd5b6139d9888289016135fb565b969995985093965092949392505050565b600080604083850312156139fc578182fd5b8235613a078161466c565b946020939093013593505050565b600080600060408486031215613a29578081fd5b8335613a348161466c565b9250602084013567ffffffffffffffff811115613a4f578182fd5b613a5b868287016135fb565b9497909650939450505050565b600060208284031215613a79578081fd5b81518015158114611725578182fd5b60008060408385031215613a9a578182fd5b82359150602083013567ffffffffffffffff811115613ab7578182fd5b8301601f81018513613ac7578182fd5b8035613ada613ad58261461c565b6145f5565b818152866020838501011115613aee578384fd5b81602084016020830137908101602001929092525090939092509050565b600060208284031215613b1d578081fd5b815167ffffffffffffffff811115613b33578182fd5b8201601f81018413613b43578182fd5b8051613b51613ad58261461c565b818152856020838501011115613b65578384fd5b613315826020830160208601614640565b600060608284031215613b87578081fd5b6117258383613642565b60008082840360a0811215613ba4578283fd5b613bae8585613642565b92506040605f1982011215613bc1578182fd5b50613bcc60406145f5565b60608401516001600160801b0381168114613be5578283fd5b8152613bf48560808601613697565b6020820152809150509250929050565b600060208284031215613c15578081fd5b815176ffffffffffffffffffffffffffffffffffffffffffffff81168114611725578182fd5b600060208284031215613c4c578081fd5b5051919050565b60008060408385031215613c65578182fd5b82519150613c768460208501613697565b90509250929050565b60008151808452613c97816020860160208601614640565b601f01601f19169290920160200192915050565b80516001600160801b0316825260209081015167ffffffffffffffff16910152565b6001600160801b038082511683528060208301511660208401525067ffffffffffffffff60408201511660408301525050565b60008251613d12818460208701614640565b9190910192915050565b600060018910613d2857fe5b8860f81b82526bffffffffffffffffffffffff19808960601b166001840152808860601b166015840152508560298301528385604984013750604992019182015260690195945050505050565b600060018810613d8157fe5b8760f81b82526bffffffffffffffffffffffff19808860601b166001840152808760601b166015840152508460298301528351613dc5816049850160208801614640565b60499201918201929092526069019695505050505050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b60006001600160a01b038086168352808516602084015250606060408301526133156060830184613c7f565b6001600160a01b039384168152919092166020820152604081019190915260600190565b60006001600160a01b03808816835280871660208401525084604083015260806060830152826080830152828460a084013781830160a090810191909152601f909201601f19160101949350505050565b60006001600160a01b0380871683528086166020840152508360408301526080606083015261236d6080830184613c7f565b60006001600160a01b038416825260406020830152611b4e6040830184613c7f565b6001600160a01b0383168152606081016117256020830184613cab565b6001600160a01b0383168152608081016117256020830184613ccd565b6001600160a01b038416815260c08101613f576020830185613ccd565b611b4e6080830184613cab565b6001600160a01b03929092168252602082015260400190565b60006001600160a01b03861682528460208301528360408301526080606083015261236d6080830184613c7f565b6020808252825182820181905260009190848201906040850190845b81811015613fed5783516001600160e01b03191683529284019291840191600101613fc7565b50909695505050505050565b901515815260200190565b93845260ff9290921660208401526040830152606082015260800190565b6001600160e01b031991909116815260200190565b6000602082526117256020830184613c7f565b60208082526016908201527f4c553a206d6f7265207468656e20313238206269747300000000000000000000604082015260600190565b6020808252601b908201527f5574696c733a2065637265636f7665722072657475726e656420300000000000604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526015908201527f4c553a206d6f7265207468656e20363420626974730000000000000000000000604082015260600190565b60208082526011908201527f42463a2077616c6c6574206c6f636b6564000000000000000000000000000000604082015260600190565b60208082526012908201527f544d3a20496e76616c6964207369676e65720000000000000000000000000000604082015260600190565b6020808252601e908201527f54543a2074617267657420616c72656164792077686974656c69737465640000604082015260600190565b6020808252601c908201527f54543a20756e6b6e6f776e2070656e64696e67207472616e7366657200000000604082015260600190565b6020808252602c908201527f54543a207472616e73666572206f757473696465206f6620746865206578656360408201527f7574696f6e2077696e646f770000000000000000000000000000000000000000606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60408201527f7700000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526021908201527f42463a2063616c6c6572206d7573742062652056657273696f6e4d616e61676560408201527f7200000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526016908201527f544d3a20466f7262696464656e20636f6e747261637400000000000000000000604082015260600190565b60208082526013908201527f524d3a205472616e73666572206661696c656400000000000000000000000000604082015260600190565b6020808252601a908201527f54543a20756e6b6e6f776e2070656e64696e6720616374696f6e000000000000604082015260600190565b6020808252601d908201527f544d3a20417070726f76652061626f7665206461696c79206c696d6974000000604082015260600190565b6020808252601c908201527f42463a206d757374206265206f776e6572206f72206665617475726500000000604082015260600190565b60208082526018908201527f42543a20696e73756666696369656e742062616c616e63650000000000000000604082015260600190565b6020808252818101527f42543a20696e73756666696369656e7420616d6f756e7420666f722063616c6c604082015260600190565b6020808252601c908201527f544d3a20696e76616c6964207369676e6174757265206c656e67746800000000604082015260600190565b6020808252601c908201527f544d3a206475706c69636174652070656e64696e6720616374696f6e00000000604082015260600190565b60208082526016908201527f42543a20466f7262696464656e20636f6e747261637400000000000000000000604082015260600190565b6001600160801b0391909116815260200190565b90815260200190565b9182526001600160a01b0316602082015260400190565b600083825260406020830152611b4e6040830184613c7f565b828152604081016004831061459b57fe5b8260208301529392505050565b928352602083019190915267ffffffffffffffff16604082015260600190565b91825267ffffffffffffffff16602082015260400190565b67ffffffffffffffff91909116815260200190565b60405181810167ffffffffffffffff8111828210171561461457600080fd5b604052919050565b600067ffffffffffffffff821115614632578081fd5b50601f01601f191660200190565b60005b8381101561465b578181015183820152602001614643565b83811115610aaa5750506000910152565b6001600160a01b0381168114610aae57600080fd5b6001600160801b0381168114610aae57600080fdfea2646970667358221220f81384e48be173d3e9104508fc4646138fdba86f4ca72bda3c6309b07226e67664736f6c634300060c0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.