Contract Name:
SmartWallet
Contract Source Code:
File 1 of 1 : SmartWallet
pragma solidity ^0.4.24;
contract IERC20Token {
// these functions aren't abstract since the compiler emits automatically generated getter functions as external
function name() public constant returns (string) {}
function symbol() public constant returns (string) {}
function decimals() public constant returns (uint8) {}
function totalSupply() public constant returns (uint256) {}
function balanceOf(address _owner) public constant returns (uint256) { _owner; }
function allowance(address _owner, address _spender) public constant returns (uint256) { _owner; _spender; }
function transfer(address _to, uint256 _value) public returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
function approve(address _spender, uint256 _value) public returns (bool success);
}
contract Ownable {
address public owner;
address public newOwner;
event OwnerUpdate(address _prevOwner, address _newOwner);
/*
@dev constructor
*/
constructor (address _owner) public {
owner = _owner;
}
/*
@dev allows execution by the owner only
*/
modifier ownerOnly {
require(msg.sender == owner);
_;
}
/*
@dev allows transferring the contract ownership
the new owner still needs to accept the transfer
can only be called by the contract owner
@param _newOwner new contract owner
*/
function transferOwnership(address _newOwner) public ownerOnly {
require(_newOwner != owner);
newOwner = _newOwner;
}
/*
@dev used by a new owner to accept an ownership transfer
*/
function acceptOwnership() public {
require(msg.sender == newOwner);
emit OwnerUpdate(owner, newOwner);
owner = newOwner;
newOwner = address(0);
}
}
contract Utils {
/*
@dev constructor
*/
constructor() public {
}
/*
@dev verifies that an amount is greater than zero
*/
modifier greaterThanZero(uint256 _amount) {
require(_amount > 0);
_;
}
/*
@dev validates an address - currently only checks that it isn't null
*/
modifier validAddress(address _address) {
require(_address != 0x0);
_;
}
/*
@dev verifies that the address is different than this contract address
*/
modifier notThis(address _address) {
require(_address != address(this));
_;
}
/*
@dev verifies that the string is not empty
*/
modifier notEmpty(string _str) {
require(bytes(_str).length > 0);
_;
}
// Overflow protected math functions
/*
@dev returns the sum of _x and _y, asserts if the calculation overflows
@param _x value 1
@param _y value 2
@return sum
*/
function safeAdd(uint256 _x, uint256 _y) internal pure returns (uint256) {
uint256 z = _x + _y;
assert(z >= _x);
return z;
}
/*
@dev returns the difference of _x minus _y, asserts if the subtraction results in a negative number
@param _x minuend
@param _y subtrahend
@return difference
*/
function safeSub(uint256 _x, uint256 _y) internal pure returns (uint256) {
require(_x >= _y);
return _x - _y;
}
/*
@dev returns the product of multiplying _x by _y, asserts if the calculation overflows
@param _x factor 1
@param _y factor 2
@return product
*/
function safeMul(uint256 _x, uint256 _y) internal pure returns (uint256) {
uint256 z = _x * _y;
assert(_x == 0 || z / _x == _y);
return z;
}
}
contract WithdrawalConfigurations is Ownable, Utils {
/*
* Members
*/
uint public minWithdrawalCoolingPeriod;
uint constant maxWithdrawalCoolingPeriod = 12 * 1 weeks; // = 14515200 seconds
uint public withdrawalCoolingPeriod;
/*
* Events
*/
event WithdrawalRequested(address _sender, address _smartWallet);
event SetWithdrawalCoolingPeriod(uint _withdrawalCoolingPeriod);
/*
@dev constructor
@param _withdrawalCoolingPeriod The cooling period
@param _minWithdrawalCoolingPeriod The minimum time from withdraw request to allow performing it
*/
constructor (uint _withdrawalCoolingPeriod, uint _minWithdrawalCoolingPeriod)
Ownable(msg.sender)
public
{
require(_withdrawalCoolingPeriod <= maxWithdrawalCoolingPeriod &&
_withdrawalCoolingPeriod >= _minWithdrawalCoolingPeriod);
require(_minWithdrawalCoolingPeriod >= 0);
minWithdrawalCoolingPeriod = _minWithdrawalCoolingPeriod;
withdrawalCoolingPeriod = _withdrawalCoolingPeriod;
}
/*
@dev Get the withdrawalCoolingPeriod parameter value.
*/
function getWithdrawalCoolingPeriod() external view returns(uint) {
return withdrawalCoolingPeriod;
}
/*
@dev Set the withdrawalCoolingPeriod parameter value.
@param _withdrawalCoolingPeriod Cooling period in seconds
*/
function setWithdrawalCoolingPeriod(uint _withdrawalCoolingPeriod)
ownerOnly()
public
{
require (_withdrawalCoolingPeriod <= maxWithdrawalCoolingPeriod &&
_withdrawalCoolingPeriod >= minWithdrawalCoolingPeriod);
withdrawalCoolingPeriod = _withdrawalCoolingPeriod;
emit SetWithdrawalCoolingPeriod(_withdrawalCoolingPeriod);
}
/*
@dev Fire the WithdrawalRequested event.
@param _sender The user account, activating this request
@param _smartWallet The smart wallet that the request was called upon
*/
function emitWithrawalRequestEvent(address _sender, address _smartWallet)
public
{
emit WithdrawalRequested(_sender, _smartWallet);
}
}
library SmartWalletLib {
/*
* Structs
*/
struct Wallet {
address operatorAccount;
address userWithdrawalAccount;
address feesAccount;
uint withdrawAllowedAt; // In seconds
}
/*
* Members
*/
string constant VERSION = "1.1";
address constant withdrawalConfigurationsContract = 0xDdD336eAad17F1D40cc81997Fb956608f00639FF;
/*
* Modifiers
*/
modifier validAddress(address _address) {
require(_address != 0x0);
_;
}
modifier addressNotSet(address _address) {
require(_address == 0);
_;
}
modifier operatorOnly(address _operatorAccount) {
require(msg.sender == _operatorAccount);
_;
}
modifier userWithdrawalAccountOnly(Wallet storage _self) {
require(msg.sender == _self.userWithdrawalAccount);
_;
}
/*
* Events
*/
event TransferToUserWithdrawalAccount(address _token, address _userWithdrawalAccount, uint _amount, address _feesToken, address _feesAccount, uint _fee);
event SetUserWithdrawalAccount(address _userWithdrawalAccount);
event PerformUserWithdraw(address _token, address _userWithdrawalAccount, uint _amount);
/*
@dev Initialize the wallet with the operator and backupAccount address
@param _self Wallet storage
@param _operator The operator account
@param _feesAccount The account to transfer fees to
*/
function initWallet(Wallet storage _self, address _operator, address _feesAccount)
public
validAddress(_operator)
validAddress(_feesAccount)
{
_self.operatorAccount = _operator;
_self.feesAccount = _feesAccount;
}
/*
@dev Setting the account of the user to send funds to.
@param _self Wallet storage
@param _userWithdrawalAccount The user account to withdraw funds to
*/
function setUserWithdrawalAccount(Wallet storage _self, address _userWithdrawalAccount)
public
operatorOnly(_self.operatorAccount)
validAddress(_userWithdrawalAccount)
addressNotSet(_self.userWithdrawalAccount)
{
_self.userWithdrawalAccount = _userWithdrawalAccount;
emit SetUserWithdrawalAccount(_userWithdrawalAccount);
}
/*
@dev Withdraw funds to the user account.
@param _self Wallet storage
@param _token The ERC20 token the owner withdraws from
@param _amount Amount to transfer
@param _fee Fee to transfer
*/
function transferToUserWithdrawalAccount(Wallet storage _self, IERC20Token _token, uint _amount, IERC20Token _feesToken, uint _fee)
public
operatorOnly(_self.operatorAccount)
validAddress(_self.userWithdrawalAccount)
{
if (_fee > 0) {
_feesToken.transfer(_self.feesAccount, _fee);
}
_token.transfer(_self.userWithdrawalAccount, _amount);
emit TransferToUserWithdrawalAccount(_token, _self.userWithdrawalAccount, _amount, _feesToken, _self.feesAccount, _fee);
}
/*
@dev returns the sum of _x and _y, asserts if the calculation overflows
@param _x value 1
@param _y value 2
@return sum
*/
function safeAdd(uint256 _x, uint256 _y) internal pure returns (uint256) {
uint256 z = _x + _y;
assert(z >= _x);
return z;
}
/*
@dev user request withdraw.
@param _self Wallet storage
@param _token The ERC20 token the owner withdraws from
*/
function requestWithdraw(Wallet storage _self)
public
userWithdrawalAccountOnly(_self)
{
WithdrawalConfigurations withdrawalConfigurations = WithdrawalConfigurations(withdrawalConfigurationsContract);
_self.withdrawAllowedAt = safeAdd(now, withdrawalConfigurations.getWithdrawalCoolingPeriod());
withdrawalConfigurations.emitWithrawalRequestEvent(msg.sender, address(this));
}
/*
@dev user perform withdraw.
@param _self Wallet storage
@param _token The ERC20 token the owner withdraws from
*/
function performUserWithdraw(Wallet storage _self, IERC20Token _token)
public
userWithdrawalAccountOnly(_self)
{
require(_self.withdrawAllowedAt != 0 &&
_self.withdrawAllowedAt <= now );
uint userBalance = _token.balanceOf(this);
_token.transfer(_self.userWithdrawalAccount, userBalance);
emit PerformUserWithdraw(_token, _self.userWithdrawalAccount, userBalance);
}
}
contract SmartWallet {
/*
* Members
*/
using SmartWalletLib for SmartWalletLib.Wallet;
SmartWalletLib.Wallet public wallet;
// Wallet public wallet;
/*
* Events
*/
event TransferToUserWithdrawalAccount(address _token, address _userWithdrawalAccount, uint _amount, address _feesToken, address _feesAccount, uint _fee);
event SetUserWithdrawalAccount(address _userWithdrawalAccount);
event PerformUserWithdraw(address _token, address _userWithdrawalAccount, uint _amount);
/*
@dev constructor
@param _backupAccount A default operator's account to send funds to, in cases where the user account is
unavailable or lost
@param _operator The contract operator address
@param _feesAccount The account to transfer fees to
*/
constructor (address _operator, address _feesAccount) public {
wallet.initWallet(_operator, _feesAccount);
}
/*
@dev Setting the account of the user to send funds to.
@param _userWithdrawalAccount The user account to withdraw funds to
*/
function setUserWithdrawalAccount(address _userWithdrawalAccount) public {
wallet.setUserWithdrawalAccount(_userWithdrawalAccount);
}
/*
@dev Withdraw funds to the user account.
@param _token The ERC20 token the owner withdraws from
@param _amount Amount to transfer
*/
function transferToUserWithdrawalAccount(IERC20Token _token, uint _amount, IERC20Token _feesToken, uint _fee) public {
wallet.transferToUserWithdrawalAccount(_token, _amount, _feesToken, _fee);
}
/*
@dev Allows the user to request a withdraw of his/her placements
@param _token The ERC20 token the user wishes to withdraw from
*/
function requestWithdraw() public {
wallet.requestWithdraw();
}
/*
@dev Allows the user to perform the requestWithdraw operation
@param _token The ERC20 token the user withdraws from
*/
function performUserWithdraw(IERC20Token _token) public {
wallet.performUserWithdraw(_token);
}
}