ETH Price: $2,015.74 (-1.38%)

Transaction Decoder

Block:
4821743 at Dec-30-2017 03:05:36 AM +UTC
Transaction Fee:
0.0003926075625 ETH $0.79
Gas Used:
41,057 Gas / 9.5625 Gwei

Emitted Events:

Account State Difference:

  Address   Before After State Difference Code
0x6CA06FC8...C650CddD8
0.001 Eth
Nonce: 0
0.0006073924375 Eth
Nonce: 1
0.0003926075625
(Ethermine)
700.65348918675681643 Eth700.65388179431931643 Eth0.0003926075625
0xEd1eba8B...50c85a010

Execution Trace

AGT.transfer( dst=0x0eCd86d531Cb01faa71fE8661affb26Ef837FFC4, wad=5000000000000000000 ) => ( True )
  • SwapController.onTransfer( _from=0x6CA06FC8A8f0098C00baBb18dF0efD3C650CddD8, _to=0x0eCd86d531Cb01faa71fE8661affb26Ef837FFC4, _amount=5000000000000000000 ) => ( True )
    • AGT2ATNSwap.onTokenTransfer( _from=0x6CA06FC8A8f0098C00baBb18dF0efD3C650CddD8, _to=0x0eCd86d531Cb01faa71fE8661affb26Ef837FFC4, _amount=5000000000000000000 ) => ( True )
    • ATNLongTermHolding.onTokenTransfer( _from=0x6CA06FC8A8f0098C00baBb18dF0efD3C650CddD8, _to=0x0eCd86d531Cb01faa71fE8661affb26Ef837FFC4, _amount=5000000000000000000 ) => ( True )
    • ATNLongTermHolding.onTokenTransfer( _from=0x6CA06FC8A8f0098C00baBb18dF0efD3C650CddD8, _to=0x0eCd86d531Cb01faa71fE8661affb26Ef837FFC4, _amount=5000000000000000000 ) => ( True )
    • ATNLongTermHolding.onTokenTransfer( _from=0x6CA06FC8A8f0098C00baBb18dF0efD3C650CddD8, _to=0x0eCd86d531Cb01faa71fE8661affb26Ef837FFC4, _amount=5000000000000000000 ) => ( True )
      transfer[AGT (ln:462)]
      File 1 of 6: AGT
      pragma solidity ^0.4.13;
      
      contract DSAuthority {
          function canCall(
              address src, address dst, bytes4 sig
          ) public view returns (bool);
      }
      
      contract DSAuthEvents {
          event LogSetAuthority (address indexed authority);
          event LogSetOwner     (address indexed owner);
      }
      
      contract DSAuth is DSAuthEvents {
          DSAuthority  public  authority;
          address      public  owner;
      
          function DSAuth() public {
              owner = msg.sender;
              LogSetOwner(msg.sender);
          }
      
          function setOwner(address owner_)
              public
              auth
          {
              owner = owner_;
              LogSetOwner(owner);
          }
      
          function setAuthority(DSAuthority authority_)
              public
              auth
          {
              authority = authority_;
              LogSetAuthority(authority);
          }
      
          modifier auth {
              require(isAuthorized(msg.sender, msg.sig));
              _;
          }
      
          function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
              if (src == address(this)) {
                  return true;
              } else if (src == owner) {
                  return true;
              } else if (authority == DSAuthority(0)) {
                  return false;
              } else {
                  return authority.canCall(src, this, sig);
              }
          }
      }
      
      contract DSNote {
          event LogNote(
              bytes4   indexed  sig,
              address  indexed  guy,
              bytes32  indexed  foo,
              bytes32  indexed  bar,
              uint              wad,
              bytes             fax
          ) anonymous;
      
          modifier note {
              bytes32 foo;
              bytes32 bar;
      
              assembly {
                  foo := calldataload(4)
                  bar := calldataload(36)
              }
      
              LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
      
              _;
          }
      }
      
      contract DSStop is DSNote, DSAuth {
      
          bool public stopped;
      
          modifier stoppable {
              require(!stopped);
              _;
          }
          function stop() public auth note {
              stopped = true;
          }
          function start() public auth note {
              stopped = false;
          }
      
      }
      
      contract ERC20 {
          function totalSupply() public view returns (uint supply);
          function balanceOf( address who ) public view returns (uint value);
          function allowance( address owner, address spender ) public view returns (uint _allowance);
      
          function transfer( address to, uint value) public returns (bool ok);
          function transferFrom( address from, address to, uint value) public returns (bool ok);
          function approve( address spender, uint value ) public returns (bool ok);
      
          event Transfer( address indexed from, address indexed to, uint value);
          event Approval( address indexed owner, address indexed spender, uint value);
      }
      
      contract DSMath {
          function add(uint x, uint y) internal pure returns (uint z) {
              require((z = x + y) >= x);
          }
          function sub(uint x, uint y) internal pure returns (uint z) {
              require((z = x - y) <= x);
          }
          function mul(uint x, uint y) internal pure returns (uint z) {
              require(y == 0 || (z = x * y) / y == x);
          }
      
          function min(uint x, uint y) internal pure returns (uint z) {
              return x <= y ? x : y;
          }
          function max(uint x, uint y) internal pure returns (uint z) {
              return x >= y ? x : y;
          }
          function imin(int x, int y) internal pure returns (int z) {
              return x <= y ? x : y;
          }
          function imax(int x, int y) internal pure returns (int z) {
              return x >= y ? x : y;
          }
      
          uint constant WAD = 10 ** 18;
          uint constant RAY = 10 ** 27;
      
          function wmul(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, y), WAD / 2) / WAD;
          }
          function rmul(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, y), RAY / 2) / RAY;
          }
          function wdiv(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, WAD), y / 2) / y;
          }
          function rdiv(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, RAY), y / 2) / y;
          }
      
          // This famous algorithm is called "exponentiation by squaring"
          // and calculates x^n with x as fixed-point and n as regular unsigned.
          //
          // It's O(log n), instead of O(n) for naive repeated multiplication.
          //
          // These facts are why it works:
          //
          //  If n is even, then x^n = (x^2)^(n/2).
          //  If n is odd,  then x^n = x * x^(n-1),
          //   and applying the equation for even x gives
          //    x^n = x * (x^2)^((n-1) / 2).
          //
          //  Also, EVM division is flooring and
          //    floor[(n-1) / 2] = floor[n / 2].
          //
          function rpow(uint x, uint n) internal pure returns (uint z) {
              z = n % 2 != 0 ? x : RAY;
      
              for (n /= 2; n != 0; n /= 2) {
                  x = rmul(x, x);
      
                  if (n % 2 != 0) {
                      z = rmul(z, x);
                  }
              }
          }
      }
      
      contract DSTokenBase is ERC20, DSMath {
          uint256                                            _supply;
          mapping (address => uint256)                       _balances;
          mapping (address => mapping (address => uint256))  _approvals;
      
          function DSTokenBase(uint supply) public {
              _balances[msg.sender] = supply;
              _supply = supply;
          }
      
          function totalSupply() public view returns (uint) {
              return _supply;
          }
          function balanceOf(address src) public view returns (uint) {
              return _balances[src];
          }
          function allowance(address src, address guy) public view returns (uint) {
              return _approvals[src][guy];
          }
      
          function transfer(address dst, uint wad) public returns (bool) {
              return transferFrom(msg.sender, dst, wad);
          }
      
          function transferFrom(address src, address dst, uint wad)
              public
              returns (bool)
          {
              if (src != msg.sender) {
                  _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
              }
      
              _balances[src] = sub(_balances[src], wad);
              _balances[dst] = add(_balances[dst], wad);
      
              Transfer(src, dst, wad);
      
              return true;
          }
      
          function approve(address guy, uint wad) public returns (bool) {
              _approvals[msg.sender][guy] = wad;
      
              Approval(msg.sender, guy, wad);
      
              return true;
          }
      }
      
      contract DSToken is DSTokenBase(0), DSStop {
      
          mapping (address => mapping (address => bool)) _trusted;
      
          bytes32  public  symbol;
          uint256  public  decimals = 18; // standard token precision. override to customize
      
          function DSToken(bytes32 symbol_) public {
              symbol = symbol_;
          }
      
          event Trust(address indexed src, address indexed guy, bool wat);
          event Mint(address indexed guy, uint wad);
          event Burn(address indexed guy, uint wad);
      
          function trusted(address src, address guy) public view returns (bool) {
              return _trusted[src][guy];
          }
          function trust(address guy, bool wat) public stoppable {
              _trusted[msg.sender][guy] = wat;
              Trust(msg.sender, guy, wat);
          }
      
          function approve(address guy, uint wad) public stoppable returns (bool) {
              return super.approve(guy, wad);
          }
          function transferFrom(address src, address dst, uint wad)
              public
              stoppable
              returns (bool)
          {
              if (src != msg.sender && !_trusted[src][msg.sender]) {
                  _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
              }
      
              _balances[src] = sub(_balances[src], wad);
              _balances[dst] = add(_balances[dst], wad);
      
              Transfer(src, dst, wad);
      
              return true;
          }
      
          function push(address dst, uint wad) public {
              transferFrom(msg.sender, dst, wad);
          }
          function pull(address src, uint wad) public {
              transferFrom(src, msg.sender, wad);
          }
          function move(address src, address dst, uint wad) public {
              transferFrom(src, dst, wad);
          }
      
          function mint(uint wad) public {
              mint(msg.sender, wad);
          }
          function burn(uint wad) public {
              burn(msg.sender, wad);
          }
          function mint(address guy, uint wad) public auth stoppable {
              _balances[guy] = add(_balances[guy], wad);
              _supply = add(_supply, wad);
              Mint(guy, wad);
          }
          function burn(address guy, uint wad) public auth stoppable {
              if (guy != msg.sender && !_trusted[guy][msg.sender]) {
                  _approvals[guy][msg.sender] = sub(_approvals[guy][msg.sender], wad);
              }
      
              _balances[guy] = sub(_balances[guy], wad);
              _supply = sub(_supply, wad);
              Burn(guy, wad);
          }
      
          // Optional token name
          bytes32   public  name = "";
      
          function setName(bytes32 name_) public auth {
              name = name_;
          }
      }
      
      /// @title ERC223ReceivingContract - Standard contract implementation for compatibility with ERC223 tokens.
      contract ERC223ReceivingContract {
      
          /// @dev Function that is called when a user or another contract wants to transfer funds.
          /// @param _from Transaction initiator, analogue of msg.sender
          /// @param _value Number of tokens to transfer.
          /// @param _data Data containig a function signature and/or parameters
          function tokenFallback(address _from, uint256 _value, bytes _data) public;
      
      
          /// @dev For ERC20 backward compatibility, same with above tokenFallback but without data.
          /// The function execution could fail, but do not influence the token transfer.
          /// @param _from Transaction initiator, analogue of msg.sender
          /// @param _value Number of tokens to transfer.
          //  function tokenFallback(address _from, uint256 _value) public;
      }
      
      /// @dev The token controller contract must implement these functions
      contract TokenController {
          /// @notice Called when `_owner` sends ether to the MiniMe Token contract
          /// @param _owner The address that sent the ether to create tokens
          /// @return True if the ether is accepted, false if it throws
          function proxyPayment(address _owner) payable public returns(bool);
      
          /// @notice Notifies the controller about a token transfer allowing the
          ///  controller to react if desired
          /// @param _from The origin of the transfer
          /// @param _to The destination of the transfer
          /// @param _amount The amount of the transfer
          /// @return False if the controller does not authorize the transfer
          function onTransfer(address _from, address _to, uint _amount) public returns(bool);
      
          /// @notice Notifies the controller about an approval allowing the
          ///  controller to react if desired
          /// @param _owner The address that calls `approve()`
          /// @param _spender The spender in the `approve()` call
          /// @param _amount The amount in the `approve()` call
          /// @return False if the controller does not authorize the approval
          function onApprove(address _owner, address _spender, uint _amount) public returns(bool);
      }
      
      contract Controlled {
          /// @notice The address of the controller is the only address that can call
          ///  a function with this modifier
          modifier onlyController { if (msg.sender != controller) throw; _; }
      
          address public controller;
      
          function Controlled() { controller = msg.sender;}
      
          /// @notice Changes the controller of the contract
          /// @param _newController The new controller of the contract
          function changeController(address _newController) onlyController {
              controller = _newController;
          }
      }
      
      contract ApproveAndCallFallBack {
          function receiveApproval(address from, uint256 _amount, address _token, bytes _data);
      }
      
      contract ERC223 {
          function transfer(address to, uint amount, bytes data) public returns (bool ok);
      
          function transferFrom(address from, address to, uint256 amount, bytes data) public returns (bool ok);
      
          function transfer(address to, uint amount, bytes data, string custom_fallback) public returns (bool ok);
      
          function transferFrom(address from, address to, uint256 amount, bytes data, string custom_fallback) public returns (bool ok);
      
          event ERC223Transfer(address indexed from, address indexed to, uint amount, bytes data);
      
          event ReceivingContractTokenFallbackFailed(address indexed from, address indexed to, uint amount);
      }
      
      contract AGT is DSToken("AGT"), ERC223, Controlled {
      
          function AGT() {
              setName("Genesis Token of ATNIO");
          }
      
          /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
          ///  is approved by `_from`
          /// @param _from The address holding the tokens being transferred
          /// @param _to The address of the recipient
          /// @param _amount The amount of tokens to be transferred
          /// @return True if the transfer was successful
          function transferFrom(address _from, address _to, uint256 _amount
          ) public returns (bool success) {
              // Alerts the token controller of the transfer
              if (isContract(controller)) {
                  if (!TokenController(controller).onTransfer(_from, _to, _amount))
                     throw;
              }
      
              success = super.transferFrom(_from, _to, _amount);
      
              if (success && isContract(_to))
              {
                  // ERC20 backward compatiability
                  if(!_to.call(bytes4(keccak256("tokenFallback(address,uint256)")), _from, _amount)) {
                      // do nothing when error in call in case that the _to contract is not inherited from ERC223ReceivingContract
                      // revert();
                      // bytes memory empty;
      
                      ReceivingContractTokenFallbackFailed(_from, _to, _amount);
      
                      // Even the fallback failed if there is such one, the transfer will not be revert since "revert()" is not called.
                  }
              }
          }
      
          /*
           * ERC 223
           * Added support for the ERC 223 "tokenFallback" method in a "transfer" function with a payload.
           */
          function transferFrom(address _from, address _to, uint256 _amount, bytes _data)
              public
              returns (bool success)
          {
              // Alerts the token controller of the transfer
              if (isContract(controller)) {
                  if (!TokenController(controller).onTransfer(_from, _to, _amount))
                     throw;
              }
      
              require(super.transferFrom(_from, _to, _amount));
      
              if (isContract(_to)) {
                  ERC223ReceivingContract receiver = ERC223ReceivingContract(_to);
                  receiver.tokenFallback(_from, _amount, _data);
              }
      
              ERC223Transfer(_from, _to, _amount, _data);
      
              return true;
          }
      
          /*
           * ERC 223
           * Added support for the ERC 223 "tokenFallback" method in a "transfer" function with a payload.
           * https://github.com/ethereum/EIPs/issues/223
           * function transfer(address _to, uint256 _value, bytes _data) public returns (bool success);
           */
          /// @notice Send `_value` tokens to `_to` from `msg.sender` and trigger
          /// tokenFallback if sender is a contract.
          /// @dev Function that is called when a user or another contract wants to transfer funds.
          /// @param _to Address of token receiver.
          /// @param _amount Number of tokens to transfer.
          /// @param _data Data to be sent to tokenFallback
          /// @return Returns success of function call.
          function transfer(
              address _to,
              uint256 _amount,
              bytes _data)
              public
              returns (bool success)
          {
              return transferFrom(msg.sender, _to, _amount, _data);
          }
      
          /*
           * ERC 223
           * Added support for the ERC 223 "tokenFallback" method in a "transfer" function with a payload.
           */
          function transferFrom(address _from, address _to, uint256 _amount, bytes _data, string _custom_fallback)
              public
              returns (bool success)
          {
              // Alerts the token controller of the transfer
              if (isContract(controller)) {
                  if (!TokenController(controller).onTransfer(_from, _to, _amount))
                     throw;
              }
      
              require(super.transferFrom(_from, _to, _amount));
      
              if (isContract(_to)) {
                  ERC223ReceivingContract receiver = ERC223ReceivingContract(_to);
                  receiver.call.value(0)(bytes4(keccak256(_custom_fallback)), _from, _amount, _data);
              }
      
              ERC223Transfer(_from, _to, _amount, _data);
      
              return true;
          }
      
          /*
           * ERC 223
           * Added support for the ERC 223 "tokenFallback" method in a "transfer" function with a payload.
           */
          function transfer(
              address _to, 
              uint _amount, 
              bytes _data, 
              string _custom_fallback)
              public 
              returns (bool success)
          {
              return transferFrom(msg.sender, _to, _amount, _data, _custom_fallback);
          }
      
          /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
          ///  its behalf. This is a modified version of the ERC20 approve function
          ///  to be a little bit safer
          /// @param _spender The address of the account able to transfer the tokens
          /// @param _amount The amount of tokens to be approved for transfer
          /// @return True if the approval was successful
          function approve(address _spender, uint256 _amount) returns (bool success) {
              // Alerts the token controller of the approve function call
              if (isContract(controller)) {
                  if (!TokenController(controller).onApprove(msg.sender, _spender, _amount))
                      throw;
              }
              
              return super.approve(_spender, _amount);
          }
      
          function mint(address _guy, uint _wad) auth stoppable {
              super.mint(_guy, _wad);
      
              Transfer(0, _guy, _wad);
          }
          function burn(address _guy, uint _wad) auth stoppable {
              super.burn(_guy, _wad);
      
              Transfer(_guy, 0, _wad);
          }
      
          /// @notice `msg.sender` approves `_spender` to send `_amount` tokens on
          ///  its behalf, and then a function is triggered in the contract that is
          ///  being approved, `_spender`. This allows users to use their tokens to
          ///  interact with contracts in one function call instead of two
          /// @param _spender The address of the contract able to transfer the tokens
          /// @param _amount The amount of tokens to be approved for transfer
          /// @return True if the function call was successful
          function approveAndCall(address _spender, uint256 _amount, bytes _extraData
          ) returns (bool success) {
              if (!approve(_spender, _amount)) throw;
      
              ApproveAndCallFallBack(_spender).receiveApproval(
                  msg.sender,
                  _amount,
                  this,
                  _extraData
              );
      
              return true;
          }
      
          /// @dev Internal function to determine if an address is a contract
          /// @param _addr The address being queried
          /// @return True if `_addr` is a contract
          function isContract(address _addr) constant internal returns(bool) {
              uint size;
              if (_addr == 0) return false;
              assembly {
                  size := extcodesize(_addr)
              }
              return size>0;
          }
      
          /// @notice The fallback function: If the contract's controller has not been
          ///  set to 0, then the `proxyPayment` method is called which relays the
          ///  ether and creates tokens as described in the token controller contract
          function ()  payable {
              if (isContract(controller)) {
                  if (! TokenController(controller).proxyPayment.value(msg.value)(msg.sender))
                      throw;
              } else {
                  throw;
              }
          }
      
      //////////
      // Safety Methods
      //////////
      
          /// @notice This method can be used by the controller to extract mistakenly
          ///  sent tokens to this contract.
          /// @param _token The address of the token contract that you want to recover
          ///  set to 0 in case you want to extract ether.
          function claimTokens(address _token) onlyController {
              if (_token == 0x0) {
                  controller.transfer(this.balance);
                  return;
              }
      
              ERC20 token = ERC20(_token);
              uint balance = token.balanceOf(this);
              token.transfer(controller, balance);
              ClaimedTokens(_token, controller, balance);
          }
      
      ////////////////
      // Events
      ////////////////
      
          event ClaimedTokens(address indexed _token, address indexed _controller, uint _amount);
      }

      File 2 of 6: SwapController
      // This program is free software: you can redistribute it and/or modify
      // it under the terms of the GNU General Public License as published by
      // the Free Software Foundation, either version 3 of the License, or
      // (at your option) any later version.
      
      // This program is distributed in the hope that it will be useful,
      // but WITHOUT ANY WARRANTY; without even the implied warranty of
      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      // GNU General Public License for more details.
      
      // You should have received a copy of the GNU General Public License
      // along with this program.  If not, see <http://www.gnu.org/licenses/>.
      
      pragma solidity ^0.4.13;
      
      contract DSAuthority {
          function canCall(
              address src, address dst, bytes4 sig
          ) public view returns (bool);
      }
      
      contract DSAuthEvents {
          event LogSetAuthority (address indexed authority);
          event LogSetOwner     (address indexed owner);
      }
      
      contract DSAuth is DSAuthEvents {
          DSAuthority  public  authority;
          address      public  owner;
      
          function DSAuth() public {
              owner = msg.sender;
              LogSetOwner(msg.sender);
          }
      
          function setOwner(address owner_)
              public
              auth
          {
              owner = owner_;
              LogSetOwner(owner);
          }
      
          function setAuthority(DSAuthority authority_)
              public
              auth
          {
              authority = authority_;
              LogSetAuthority(authority);
          }
      
          modifier auth {
              require(isAuthorized(msg.sender, msg.sig));
              _;
          }
      
          function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
              if (src == address(this)) {
                  return true;
              } else if (src == owner) {
                  return true;
              } else if (authority == DSAuthority(0)) {
                  return false;
              } else {
                  return authority.canCall(src, this, sig);
              }
          }
      }
      
      // Token standard API
      // https://github.com/ethereum/EIPs/issues/20
      
      contract ERC20 {
          function totalSupply() public view returns (uint supply);
          function balanceOf( address who ) public view returns (uint value);
          function allowance( address owner, address spender ) public view returns (uint _allowance);
      
          function transfer( address to, uint value) public returns (bool ok);
          function transferFrom( address from, address to, uint value) public returns (bool ok);
          function approve( address spender, uint value ) public returns (bool ok);
      
          event Transfer( address indexed from, address indexed to, uint value);
          event Approval( address indexed owner, address indexed spender, uint value);
      }
      
      /// @dev The token controller contract must implement these functions
      contract TokenController {
          /// @notice Called when `_owner` sends ether to the MiniMe Token contract
          /// @param _owner The address that sent the ether to create tokens
          /// @return True if the ether is accepted, false if it throws
          function proxyPayment(address _owner) payable public returns(bool);
      
          /// @notice Notifies the controller about a token transfer allowing the
          ///  controller to react if desired
          /// @param _from The origin of the transfer
          /// @param _to The destination of the transfer
          /// @param _amount The amount of the transfer
          /// @return False if the controller does not authorize the transfer
          function onTransfer(address _from, address _to, uint _amount) public returns(bool);
      
          /// @notice Notifies the controller about an approval allowing the
          ///  controller to react if desired
          /// @param _owner The address that calls `approve()`
          /// @param _spender The spender in the `approve()` call
          /// @param _amount The amount in the `approve()` call
          /// @return False if the controller does not authorize the approval
          function onApprove(address _owner, address _spender, uint _amount) public returns(bool);
      }
      
      contract Controlled {
          /// @notice The address of the controller is the only address that can call
          ///  a function with this modifier
          modifier onlyController { if (msg.sender != controller) throw; _; }
      
          address public controller;
      
          function Controlled() { controller = msg.sender;}
      
          /// @notice Changes the controller of the contract
          /// @param _newController The new controller of the contract
          function changeController(address _newController) onlyController {
              controller = _newController;
          }
      }
      
      contract TokenTransferGuard {
          function onTokenTransfer(address _from, address _to, uint _amount) public returns (bool);
      }
      
      contract SwapController is DSAuth, TokenController {
          TokenTransferGuard[] public guards;
      
          // Each Swap Controller has its own token, each token should set their own controller.
          function SwapController(address[] _guards)
          {
              for (uint i=0; i<_guards.length; i++) {
                  addGuard(_guards[i]);
              }
          }
      
          function changeController(address _token, address _newController) public auth {
              Controlled(_token).changeController(_newController);
          }
      
          function proxyPayment(address _owner) payable public returns (bool)
          {
              return false;
          }
      
          function onTransfer(address _from, address _to, uint _amount) public returns (bool)
          {
              for (uint i=0; i<guards.length; i++)
              {
                  if (!guards[i].onTokenTransfer(_from, _to, _amount))
                  {
                      return false;
                  }
              }
      
              return true;
          }
      
          function onApprove(address _owner, address _spender, uint _amount) public returns (bool)
          {
              return true;
          }
      
          function addGuard(address _guard) public auth
          {
              guards.push(TokenTransferGuard(_guard));
          }
      }

      File 3 of 6: AGT2ATNSwap
      pragma solidity ^0.4.13;
      
      contract DSAuthority {
          function canCall(
              address src, address dst, bytes4 sig
          ) public view returns (bool);
      }
      
      contract DSAuthEvents {
          event LogSetAuthority (address indexed authority);
          event LogSetOwner     (address indexed owner);
      }
      
      contract DSAuth is DSAuthEvents {
          DSAuthority  public  authority;
          address      public  owner;
      
          function DSAuth() public {
              owner = msg.sender;
              LogSetOwner(msg.sender);
          }
      
          function setOwner(address owner_)
              public
              auth
          {
              owner = owner_;
              LogSetOwner(owner);
          }
      
          function setAuthority(DSAuthority authority_)
              public
              auth
          {
              authority = authority_;
              LogSetAuthority(authority);
          }
      
          modifier auth {
              require(isAuthorized(msg.sender, msg.sig));
              _;
          }
      
          function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
              if (src == address(this)) {
                  return true;
              } else if (src == owner) {
                  return true;
              } else if (authority == DSAuthority(0)) {
                  return false;
              } else {
                  return authority.canCall(src, this, sig);
              }
          }
      }
      
      contract DSNote {
          event LogNote(
              bytes4   indexed  sig,
              address  indexed  guy,
              bytes32  indexed  foo,
              bytes32  indexed  bar,
              uint              wad,
              bytes             fax
          ) anonymous;
      
          modifier note {
              bytes32 foo;
              bytes32 bar;
      
              assembly {
                  foo := calldataload(4)
                  bar := calldataload(36)
              }
      
              LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
      
              _;
          }
      }
      
      contract DSStop is DSNote, DSAuth {
      
          bool public stopped;
      
          modifier stoppable {
              require(!stopped);
              _;
          }
          function stop() public auth note {
              stopped = true;
          }
          function start() public auth note {
              stopped = false;
          }
      
      }
      
      // Token standard API
      // https://github.com/ethereum/EIPs/issues/20
      
      contract ERC20 {
          function totalSupply() public view returns (uint supply);
          function balanceOf( address who ) public view returns (uint value);
          function allowance( address owner, address spender ) public view returns (uint _allowance);
      
          function transfer( address to, uint value) public returns (bool ok);
          function transferFrom( address from, address to, uint value) public returns (bool ok);
          function approve( address spender, uint value ) public returns (bool ok);
      
          event Transfer( address indexed from, address indexed to, uint value);
          event Approval( address indexed owner, address indexed spender, uint value);
      }
      
      contract TokenTransferGuard {
          function onTokenTransfer(address _from, address _to, uint _amount) public returns (bool);
      }
      
      contract AGT2ATNSwap is DSStop, TokenTransferGuard {
          ERC20 public AGT;
          ERC20 public ATN;
      
          uint public gasRequired;
      
          function AGT2ATNSwap(address _agt, address _atn)
          {
              AGT = ERC20(_agt);
              ATN = ERC20(_atn);
          }
      
          function tokenFallback(address _from, uint256 _value, bytes _data) public
          {
              tokenFallback(_from, _value);
          }
      
          function tokenFallback(address _from, uint256 _value) public
          {
              if(msg.sender == address(AGT))
              {
                  require(ATN.transfer(_from, _value));
      
                  TokenSwap(_from, _value);
              }
          }
      
          function onTokenTransfer(address _from, address _to, uint _amount) public returns (bool)
          {
              if (_to == address(this))
              {
                  if (msg.gas < gasRequired) return false;
      
                  if (stopped) return false;
      
                  if (ATN.balanceOf(this) < _amount) return false;
              }
      
              return true;
          }
      
          function changeGasRequired(uint _gasRequired) public auth {
              gasRequired = _gasRequired;
              ChangeGasReuired(_gasRequired);
          }
      
          /// @notice This method can be used by the controller to extract mistakenly
          ///  sent tokens to this contract.
          /// @param _token The address of the token contract that you want to recover
          ///  set to 0 in case you want to extract ether.
          function claimTokens(address _token) public auth {
              if (_token == 0x0) {
                  owner.transfer(this.balance);
                  return;
              }
              
              ERC20 token = ERC20(_token);
              
              uint256 balance = token.balanceOf(this);
              
              token.transfer(owner, balance);
              ClaimedTokens(_token, owner, balance);
          }
      
          event TokenSwap(address indexed _from, uint256 _value);
          event ClaimedTokens(address indexed _token, address indexed _controller, uint256 _amount);
      
          event ChangeGasReuired(uint _gasRequired);
      }

      File 4 of 6: ATNLongTermHolding
      pragma solidity ^0.4.13;
      
      contract DSAuthority {
          function canCall(
              address src, address dst, bytes4 sig
          ) public view returns (bool);
      }
      
      contract DSAuthEvents {
          event LogSetAuthority (address indexed authority);
          event LogSetOwner     (address indexed owner);
      }
      
      contract DSAuth is DSAuthEvents {
          DSAuthority  public  authority;
          address      public  owner;
      
          function DSAuth() public {
              owner = msg.sender;
              LogSetOwner(msg.sender);
          }
      
          function setOwner(address owner_)
              public
              auth
          {
              owner = owner_;
              LogSetOwner(owner);
          }
      
          function setAuthority(DSAuthority authority_)
              public
              auth
          {
              authority = authority_;
              LogSetAuthority(authority);
          }
      
          modifier auth {
              require(isAuthorized(msg.sender, msg.sig));
              _;
          }
      
          function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
              if (src == address(this)) {
                  return true;
              } else if (src == owner) {
                  return true;
              } else if (authority == DSAuthority(0)) {
                  return false;
              } else {
                  return authority.canCall(src, this, sig);
              }
          }
      }
      
      contract DSNote {
          event LogNote(
              bytes4   indexed  sig,
              address  indexed  guy,
              bytes32  indexed  foo,
              bytes32  indexed  bar,
              uint              wad,
              bytes             fax
          ) anonymous;
      
          modifier note {
              bytes32 foo;
              bytes32 bar;
      
              assembly {
                  foo := calldataload(4)
                  bar := calldataload(36)
              }
      
              LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
      
              _;
          }
      }
      
      // Token standard API
      // https://github.com/ethereum/EIPs/issues/20
      
      contract ERC20 {
          function totalSupply() public view returns (uint supply);
          function balanceOf( address who ) public view returns (uint value);
          function allowance( address owner, address spender ) public view returns (uint _allowance);
      
          function transfer( address to, uint value) public returns (bool ok);
          function transferFrom( address from, address to, uint value) public returns (bool ok);
          function approve( address spender, uint value ) public returns (bool ok);
      
          event Transfer( address indexed from, address indexed to, uint value);
          event Approval( address indexed owner, address indexed spender, uint value);
      }
      
      contract DSStop is DSNote, DSAuth {
      
          bool public stopped;
      
          modifier stoppable {
              require(!stopped);
              _;
          }
          function stop() public auth note {
              stopped = true;
          }
          function start() public auth note {
              stopped = false;
          }
      
      }
      
      /**
       * Math operations with safety checks
       */
      library SafeMath {
        function mul(uint a, uint b) internal returns (uint) {
          uint c = a * b;
          assert(a == 0 || c / a == b);
          return c;
        }
      
        function div(uint a, uint b) internal returns (uint) {
          // assert(b > 0); // Solidity automatically throws when dividing by 0
          uint c = a / b;
          // assert(a == b * c + a % b); // There is no case in which this doesn't hold
          return c;
        }
      
        function sub(uint a, uint b) internal returns (uint) {
          assert(b <= a);
          return a - b;
        }
      
        function add(uint a, uint b) internal returns (uint) {
          uint c = a + b;
          assert(c >= a);
          return c;
        }
      
        function max64(uint64 a, uint64 b) internal constant returns (uint64) {
          return a >= b ? a : b;
        }
      
        function min64(uint64 a, uint64 b) internal constant returns (uint64) {
          return a < b ? a : b;
        }
      
        function max256(uint256 a, uint256 b) internal constant returns (uint256) {
          return a >= b ? a : b;
        }
      
        function min256(uint256 a, uint256 b) internal constant returns (uint256) {
          return a < b ? a : b;
        }
      }
      
      contract TokenTransferGuard {
          function onTokenTransfer(address _from, address _to, uint _amount) public returns (bool);
      }
      
      contract RewardSharedPool is DSStop {
          using SafeMath for uint256;
      
          uint public maxReward      = 1000000 ether;
      
          uint public consumed   = 0;
      
          mapping(address => bool) public consumers;
      
          modifier onlyConsumer {
              require(msg.sender == owner || consumers[msg.sender]);
              _;
          }
      
          function RewardSharedPool()
          {
          }
      
          function consume(uint amount) onlyConsumer public returns (bool)
          {
              require(available(amount));
      
              consumed = consumed.add(amount);
      
              Consume(msg.sender, amount);
      
              return true;
          }
      
          function available(uint amount) constant public returns (bool)
          {
              return consumed.add(amount) <= maxReward;
          }
      
          function changeMaxReward(uint _maxReward) auth public
          {
              maxReward = _maxReward;
          }
      
          function addConsumer(address consumer) public auth
          {
              consumers[consumer] = true;
      
              ConsumerAddition(consumer);
          }
      
          function removeConsumer(address consumer) public auth
          {
              consumers[consumer] = false;
      
              ConsumerRemoval(consumer);
          }
      
          event Consume(address indexed _sender, uint _value);
          event ConsumerAddition(address indexed _consumer);
          event ConsumerRemoval(address indexed _consumer);
      }
      
      contract ATNLongTermHolding is DSStop, TokenTransferGuard {
          using SafeMath for uint256;
      
          uint public constant DEPOSIT_WINDOW                 = 60 days;
      
          // There are three kinds of options: 1. {105, 120 days}, 2. {110, 240 days}, 3. {115, 360 days}
          uint public rate = 105;
          uint public withdrawal_delay    = 120 days;
      
          uint public agtAtnReceived      = 0;
          uint public atnSent             = 0;
      
          uint public depositStartTime    = 0;
          uint public depositStopTime     = 0;
      
          RewardSharedPool public pool;
      
          struct Record {
              uint agtAtnAmount;
              uint timestamp;
          }
      
          mapping (address => Record) public records;
      
          ERC20 public AGT;
          ERC20 public ATN;
      
          uint public gasRequired;
      
          function ATNLongTermHolding(address _agt, address _atn, address _poolAddress, uint _rate, uint _delayDays)
          {
              AGT = ERC20(_agt);
              ATN = ERC20(_atn);
      
              pool = RewardSharedPool(_poolAddress);
      
              require(_rate > 100);
      
              rate = _rate;
              withdrawal_delay = _delayDays * 1 days;
          }
      
          function start() public auth {
              require(depositStartTime == 0);
      
              depositStartTime = now;
              depositStopTime  = now + DEPOSIT_WINDOW;
      
              Started(depositStartTime);
          }
      
          function changeDepositStopTimeFromNow(uint _daysFromNow) public auth {
              depositStopTime = now + _daysFromNow * 1 days;
          }
      
          function tokenFallback(address _from, uint256 _value, bytes _data) public
          {
              tokenFallback(_from, _value);
          }
      
          // TODO: To test the stoppable can work or not
          function tokenFallback(address _from, uint256 _value) public stoppable
          {
              if (msg.sender == address(AGT) || msg.sender == address(ATN))
              {
                  // the owner is not count in the statistics
                  // Only owner can use to deposit the ATN reward things.
                  if (_from == owner)
                  {
                      return;
                  }
      
                  require(now <= depositStopTime);
      
                  var record = records[_from];
      
                  record.agtAtnAmount += _value;
                  record.timestamp = now;
                  records[_from] = record;
      
                  agtAtnReceived += _value;
      
                  pool.consume( _value.mul(rate - 100 ).div(100) );
      
                  Deposit(depositId++, _from, _value);
              }
          }
      
          function onTokenTransfer(address _from, address _to, uint _amount) public returns (bool)
          {
              if (_to == address(this) && _from != owner)
              {
                  if (msg.gas < gasRequired) return false;
                  
                  if (stopped) return false;
                  if (now > depositStopTime) return false;
      
                  // each address can only deposit once.
                  if (records[_from].timestamp > 0 ) return false;
      
                  // can not over the limit of maximum reward amount
                  if ( !pool.available( _amount.mul(rate - 100 ).div(100) ) ) return false;
              }
      
              return true;
          }
      
          function withdrawATN() public stoppable {
              require(msg.sender != owner);
      
              Record record = records[msg.sender];
      
              require(record.timestamp > 0);
      
              require(now >= record.timestamp + withdrawal_delay);
      
              withdrawFor(msg.sender);
          }
      
          function withdrawATN(address _addr) public stoppable {
              require(_addr != owner);
      
              Record record = records[_addr];
      
              require(record.timestamp > 0);
      
              require(now >= record.timestamp + withdrawal_delay);
      
              withdrawFor(_addr);
          }
      
          function withdrawFor(address _addr) internal {
              Record record = records[_addr];
              
              uint atnAmount = record.agtAtnAmount.mul(rate).div(100);
      
              require(ATN.transfer(_addr, atnAmount));
      
              atnSent += atnAmount;
      
              delete records[_addr];
      
              Withdrawal(
                         withdrawId++,
                         _addr,
                         atnAmount
                         );
          }
      
          function batchWithdraw(address[] _addrList) public stoppable {
              for (uint i = 0; i < _addrList.length; i++) {
                  if (records[_addrList[i]].timestamp > 0 && now >= records[_addrList[i]].timestamp + withdrawal_delay)
                  {
                      withdrawFor(_addrList[i]);
                  }
              }
          }
      
          function changeGasRequired(uint _gasRequired) public auth {
              gasRequired = _gasRequired;
              ChangeGasRequired(_gasRequired);
          }
      
          /// @notice This method can be used by the controller to extract mistakenly
          ///  sent tokens to this contract.
          /// @param _token The address of the token contract that you want to recover
          ///  set to 0 in case you want to extract ether.
          function claimTokens(address _token) public auth {
              if (_token == 0x0) {
                  owner.transfer(this.balance);
                  return;
              }
              
              ERC20 token = ERC20(_token);
              
              uint256 balance = token.balanceOf(this);
              
              token.transfer(owner, balance);
              ClaimedTokens(_token, owner, balance);
          }
      
          event ClaimedTokens(address indexed _token, address indexed _controller, uint256 _amount);
      
          /*
           * EVENTS
           */
          /// Emitted when program starts.
          event Started(uint _time);
      
          /// Emitted for each sucuessful deposit.
          uint public depositId = 0;
          event Deposit(uint _depositId, address indexed _addr, uint agtAtnAmount);
      
          /// Emitted for each sucuessful withdrawal.
          uint public withdrawId = 0;
          event Withdrawal(uint _withdrawId, address indexed _addr, uint _atnAmount);
      
          event ChangeGasRequired(uint _gasRequired);
      }

      File 5 of 6: ATNLongTermHolding
      pragma solidity ^0.4.13;
      
      contract DSAuthority {
          function canCall(
              address src, address dst, bytes4 sig
          ) public view returns (bool);
      }
      
      contract DSAuthEvents {
          event LogSetAuthority (address indexed authority);
          event LogSetOwner     (address indexed owner);
      }
      
      contract DSAuth is DSAuthEvents {
          DSAuthority  public  authority;
          address      public  owner;
      
          function DSAuth() public {
              owner = msg.sender;
              LogSetOwner(msg.sender);
          }
      
          function setOwner(address owner_)
              public
              auth
          {
              owner = owner_;
              LogSetOwner(owner);
          }
      
          function setAuthority(DSAuthority authority_)
              public
              auth
          {
              authority = authority_;
              LogSetAuthority(authority);
          }
      
          modifier auth {
              require(isAuthorized(msg.sender, msg.sig));
              _;
          }
      
          function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
              if (src == address(this)) {
                  return true;
              } else if (src == owner) {
                  return true;
              } else if (authority == DSAuthority(0)) {
                  return false;
              } else {
                  return authority.canCall(src, this, sig);
              }
          }
      }
      
      contract DSNote {
          event LogNote(
              bytes4   indexed  sig,
              address  indexed  guy,
              bytes32  indexed  foo,
              bytes32  indexed  bar,
              uint              wad,
              bytes             fax
          ) anonymous;
      
          modifier note {
              bytes32 foo;
              bytes32 bar;
      
              assembly {
                  foo := calldataload(4)
                  bar := calldataload(36)
              }
      
              LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
      
              _;
          }
      }
      
      // Token standard API
      // https://github.com/ethereum/EIPs/issues/20
      
      contract ERC20 {
          function totalSupply() public view returns (uint supply);
          function balanceOf( address who ) public view returns (uint value);
          function allowance( address owner, address spender ) public view returns (uint _allowance);
      
          function transfer( address to, uint value) public returns (bool ok);
          function transferFrom( address from, address to, uint value) public returns (bool ok);
          function approve( address spender, uint value ) public returns (bool ok);
      
          event Transfer( address indexed from, address indexed to, uint value);
          event Approval( address indexed owner, address indexed spender, uint value);
      }
      
      contract DSStop is DSNote, DSAuth {
      
          bool public stopped;
      
          modifier stoppable {
              require(!stopped);
              _;
          }
          function stop() public auth note {
              stopped = true;
          }
          function start() public auth note {
              stopped = false;
          }
      
      }
      
      /**
       * Math operations with safety checks
       */
      library SafeMath {
        function mul(uint a, uint b) internal returns (uint) {
          uint c = a * b;
          assert(a == 0 || c / a == b);
          return c;
        }
      
        function div(uint a, uint b) internal returns (uint) {
          // assert(b > 0); // Solidity automatically throws when dividing by 0
          uint c = a / b;
          // assert(a == b * c + a % b); // There is no case in which this doesn't hold
          return c;
        }
      
        function sub(uint a, uint b) internal returns (uint) {
          assert(b <= a);
          return a - b;
        }
      
        function add(uint a, uint b) internal returns (uint) {
          uint c = a + b;
          assert(c >= a);
          return c;
        }
      
        function max64(uint64 a, uint64 b) internal constant returns (uint64) {
          return a >= b ? a : b;
        }
      
        function min64(uint64 a, uint64 b) internal constant returns (uint64) {
          return a < b ? a : b;
        }
      
        function max256(uint256 a, uint256 b) internal constant returns (uint256) {
          return a >= b ? a : b;
        }
      
        function min256(uint256 a, uint256 b) internal constant returns (uint256) {
          return a < b ? a : b;
        }
      }
      
      contract TokenTransferGuard {
          function onTokenTransfer(address _from, address _to, uint _amount) public returns (bool);
      }
      
      contract RewardSharedPool is DSStop {
          using SafeMath for uint256;
      
          uint public maxReward      = 1000000 ether;
      
          uint public consumed   = 0;
      
          mapping(address => bool) public consumers;
      
          modifier onlyConsumer {
              require(msg.sender == owner || consumers[msg.sender]);
              _;
          }
      
          function RewardSharedPool()
          {
          }
      
          function consume(uint amount) onlyConsumer public returns (bool)
          {
              require(available(amount));
      
              consumed = consumed.add(amount);
      
              Consume(msg.sender, amount);
      
              return true;
          }
      
          function available(uint amount) constant public returns (bool)
          {
              return consumed.add(amount) <= maxReward;
          }
      
          function changeMaxReward(uint _maxReward) auth public
          {
              maxReward = _maxReward;
          }
      
          function addConsumer(address consumer) public auth
          {
              consumers[consumer] = true;
      
              ConsumerAddition(consumer);
          }
      
          function removeConsumer(address consumer) public auth
          {
              consumers[consumer] = false;
      
              ConsumerRemoval(consumer);
          }
      
          event Consume(address indexed _sender, uint _value);
          event ConsumerAddition(address indexed _consumer);
          event ConsumerRemoval(address indexed _consumer);
      }
      
      contract ATNLongTermHolding is DSStop, TokenTransferGuard {
          using SafeMath for uint256;
      
          uint public constant DEPOSIT_WINDOW                 = 60 days;
      
          // There are three kinds of options: 1. {105, 120 days}, 2. {110, 240 days}, 3. {115, 360 days}
          uint public rate = 105;
          uint public withdrawal_delay    = 120 days;
      
          uint public agtAtnReceived      = 0;
          uint public atnSent             = 0;
      
          uint public depositStartTime    = 0;
          uint public depositStopTime     = 0;
      
          RewardSharedPool public pool;
      
          struct Record {
              uint agtAtnAmount;
              uint timestamp;
          }
      
          mapping (address => Record) public records;
      
          ERC20 public AGT;
          ERC20 public ATN;
      
          uint public gasRequired;
      
          function ATNLongTermHolding(address _agt, address _atn, address _poolAddress, uint _rate, uint _delayDays)
          {
              AGT = ERC20(_agt);
              ATN = ERC20(_atn);
      
              pool = RewardSharedPool(_poolAddress);
      
              require(_rate > 100);
      
              rate = _rate;
              withdrawal_delay = _delayDays * 1 days;
          }
      
          function start() public auth {
              require(depositStartTime == 0);
      
              depositStartTime = now;
              depositStopTime  = now + DEPOSIT_WINDOW;
      
              Started(depositStartTime);
          }
      
          function changeDepositStopTimeFromNow(uint _daysFromNow) public auth {
              depositStopTime = now + _daysFromNow * 1 days;
          }
      
          function tokenFallback(address _from, uint256 _value, bytes _data) public
          {
              tokenFallback(_from, _value);
          }
      
          // TODO: To test the stoppable can work or not
          function tokenFallback(address _from, uint256 _value) public stoppable
          {
              if (msg.sender == address(AGT) || msg.sender == address(ATN))
              {
                  // the owner is not count in the statistics
                  // Only owner can use to deposit the ATN reward things.
                  if (_from == owner)
                  {
                      return;
                  }
      
                  require(now <= depositStopTime);
      
                  var record = records[_from];
      
                  record.agtAtnAmount += _value;
                  record.timestamp = now;
                  records[_from] = record;
      
                  agtAtnReceived += _value;
      
                  pool.consume( _value.mul(rate - 100 ).div(100) );
      
                  Deposit(depositId++, _from, _value);
              }
          }
      
          function onTokenTransfer(address _from, address _to, uint _amount) public returns (bool)
          {
              if (_to == address(this) && _from != owner)
              {
                  if (msg.gas < gasRequired) return false;
                  
                  if (stopped) return false;
                  if (now > depositStopTime) return false;
      
                  // each address can only deposit once.
                  if (records[_from].timestamp > 0 ) return false;
      
                  // can not over the limit of maximum reward amount
                  if ( !pool.available( _amount.mul(rate - 100 ).div(100) ) ) return false;
              }
      
              return true;
          }
      
          function withdrawATN() public stoppable {
              require(msg.sender != owner);
      
              Record record = records[msg.sender];
      
              require(record.timestamp > 0);
      
              require(now >= record.timestamp + withdrawal_delay);
      
              withdrawFor(msg.sender);
          }
      
          function withdrawATN(address _addr) public stoppable {
              require(_addr != owner);
      
              Record record = records[_addr];
      
              require(record.timestamp > 0);
      
              require(now >= record.timestamp + withdrawal_delay);
      
              withdrawFor(_addr);
          }
      
          function withdrawFor(address _addr) internal {
              Record record = records[_addr];
              
              uint atnAmount = record.agtAtnAmount.mul(rate).div(100);
      
              require(ATN.transfer(_addr, atnAmount));
      
              atnSent += atnAmount;
      
              delete records[_addr];
      
              Withdrawal(
                         withdrawId++,
                         _addr,
                         atnAmount
                         );
          }
      
          function batchWithdraw(address[] _addrList) public stoppable {
              for (uint i = 0; i < _addrList.length; i++) {
                  if (records[_addrList[i]].timestamp > 0 && now >= records[_addrList[i]].timestamp + withdrawal_delay)
                  {
                      withdrawFor(_addrList[i]);
                  }
              }
          }
      
          function changeGasRequired(uint _gasRequired) public auth {
              gasRequired = _gasRequired;
              ChangeGasRequired(_gasRequired);
          }
      
          /// @notice This method can be used by the controller to extract mistakenly
          ///  sent tokens to this contract.
          /// @param _token The address of the token contract that you want to recover
          ///  set to 0 in case you want to extract ether.
          function claimTokens(address _token) public auth {
              if (_token == 0x0) {
                  owner.transfer(this.balance);
                  return;
              }
              
              ERC20 token = ERC20(_token);
              
              uint256 balance = token.balanceOf(this);
              
              token.transfer(owner, balance);
              ClaimedTokens(_token, owner, balance);
          }
      
          event ClaimedTokens(address indexed _token, address indexed _controller, uint256 _amount);
      
          /*
           * EVENTS
           */
          /// Emitted when program starts.
          event Started(uint _time);
      
          /// Emitted for each sucuessful deposit.
          uint public depositId = 0;
          event Deposit(uint _depositId, address indexed _addr, uint agtAtnAmount);
      
          /// Emitted for each sucuessful withdrawal.
          uint public withdrawId = 0;
          event Withdrawal(uint _withdrawId, address indexed _addr, uint _atnAmount);
      
          event ChangeGasRequired(uint _gasRequired);
      }

      File 6 of 6: ATNLongTermHolding
      pragma solidity ^0.4.13;
      
      contract DSAuthority {
          function canCall(
              address src, address dst, bytes4 sig
          ) public view returns (bool);
      }
      
      contract DSAuthEvents {
          event LogSetAuthority (address indexed authority);
          event LogSetOwner     (address indexed owner);
      }
      
      contract DSAuth is DSAuthEvents {
          DSAuthority  public  authority;
          address      public  owner;
      
          function DSAuth() public {
              owner = msg.sender;
              LogSetOwner(msg.sender);
          }
      
          function setOwner(address owner_)
              public
              auth
          {
              owner = owner_;
              LogSetOwner(owner);
          }
      
          function setAuthority(DSAuthority authority_)
              public
              auth
          {
              authority = authority_;
              LogSetAuthority(authority);
          }
      
          modifier auth {
              require(isAuthorized(msg.sender, msg.sig));
              _;
          }
      
          function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
              if (src == address(this)) {
                  return true;
              } else if (src == owner) {
                  return true;
              } else if (authority == DSAuthority(0)) {
                  return false;
              } else {
                  return authority.canCall(src, this, sig);
              }
          }
      }
      
      contract DSNote {
          event LogNote(
              bytes4   indexed  sig,
              address  indexed  guy,
              bytes32  indexed  foo,
              bytes32  indexed  bar,
              uint              wad,
              bytes             fax
          ) anonymous;
      
          modifier note {
              bytes32 foo;
              bytes32 bar;
      
              assembly {
                  foo := calldataload(4)
                  bar := calldataload(36)
              }
      
              LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
      
              _;
          }
      }
      
      // Token standard API
      // https://github.com/ethereum/EIPs/issues/20
      
      contract ERC20 {
          function totalSupply() public view returns (uint supply);
          function balanceOf( address who ) public view returns (uint value);
          function allowance( address owner, address spender ) public view returns (uint _allowance);
      
          function transfer( address to, uint value) public returns (bool ok);
          function transferFrom( address from, address to, uint value) public returns (bool ok);
          function approve( address spender, uint value ) public returns (bool ok);
      
          event Transfer( address indexed from, address indexed to, uint value);
          event Approval( address indexed owner, address indexed spender, uint value);
      }
      
      contract DSStop is DSNote, DSAuth {
      
          bool public stopped;
      
          modifier stoppable {
              require(!stopped);
              _;
          }
          function stop() public auth note {
              stopped = true;
          }
          function start() public auth note {
              stopped = false;
          }
      
      }
      
      /**
       * Math operations with safety checks
       */
      library SafeMath {
        function mul(uint a, uint b) internal returns (uint) {
          uint c = a * b;
          assert(a == 0 || c / a == b);
          return c;
        }
      
        function div(uint a, uint b) internal returns (uint) {
          // assert(b > 0); // Solidity automatically throws when dividing by 0
          uint c = a / b;
          // assert(a == b * c + a % b); // There is no case in which this doesn't hold
          return c;
        }
      
        function sub(uint a, uint b) internal returns (uint) {
          assert(b <= a);
          return a - b;
        }
      
        function add(uint a, uint b) internal returns (uint) {
          uint c = a + b;
          assert(c >= a);
          return c;
        }
      
        function max64(uint64 a, uint64 b) internal constant returns (uint64) {
          return a >= b ? a : b;
        }
      
        function min64(uint64 a, uint64 b) internal constant returns (uint64) {
          return a < b ? a : b;
        }
      
        function max256(uint256 a, uint256 b) internal constant returns (uint256) {
          return a >= b ? a : b;
        }
      
        function min256(uint256 a, uint256 b) internal constant returns (uint256) {
          return a < b ? a : b;
        }
      }
      
      contract TokenTransferGuard {
          function onTokenTransfer(address _from, address _to, uint _amount) public returns (bool);
      }
      
      contract RewardSharedPool is DSStop {
          using SafeMath for uint256;
      
          uint public maxReward      = 1000000 ether;
      
          uint public consumed   = 0;
      
          mapping(address => bool) public consumers;
      
          modifier onlyConsumer {
              require(msg.sender == owner || consumers[msg.sender]);
              _;
          }
      
          function RewardSharedPool()
          {
          }
      
          function consume(uint amount) onlyConsumer public returns (bool)
          {
              require(available(amount));
      
              consumed = consumed.add(amount);
      
              Consume(msg.sender, amount);
      
              return true;
          }
      
          function available(uint amount) constant public returns (bool)
          {
              return consumed.add(amount) <= maxReward;
          }
      
          function changeMaxReward(uint _maxReward) auth public
          {
              maxReward = _maxReward;
          }
      
          function addConsumer(address consumer) public auth
          {
              consumers[consumer] = true;
      
              ConsumerAddition(consumer);
          }
      
          function removeConsumer(address consumer) public auth
          {
              consumers[consumer] = false;
      
              ConsumerRemoval(consumer);
          }
      
          event Consume(address indexed _sender, uint _value);
          event ConsumerAddition(address indexed _consumer);
          event ConsumerRemoval(address indexed _consumer);
      }
      
      contract ATNLongTermHolding is DSStop, TokenTransferGuard {
          using SafeMath for uint256;
      
          uint public constant DEPOSIT_WINDOW                 = 60 days;
      
          // There are three kinds of options: 1. {105, 120 days}, 2. {110, 240 days}, 3. {115, 360 days}
          uint public rate = 105;
          uint public withdrawal_delay    = 120 days;
      
          uint public agtAtnReceived      = 0;
          uint public atnSent             = 0;
      
          uint public depositStartTime    = 0;
          uint public depositStopTime     = 0;
      
          RewardSharedPool public pool;
      
          struct Record {
              uint agtAtnAmount;
              uint timestamp;
          }
      
          mapping (address => Record) public records;
      
          ERC20 public AGT;
          ERC20 public ATN;
      
          uint public gasRequired;
      
          function ATNLongTermHolding(address _agt, address _atn, address _poolAddress, uint _rate, uint _delayDays)
          {
              AGT = ERC20(_agt);
              ATN = ERC20(_atn);
      
              pool = RewardSharedPool(_poolAddress);
      
              require(_rate > 100);
      
              rate = _rate;
              withdrawal_delay = _delayDays * 1 days;
          }
      
          function start() public auth {
              require(depositStartTime == 0);
      
              depositStartTime = now;
              depositStopTime  = now + DEPOSIT_WINDOW;
      
              Started(depositStartTime);
          }
      
          function changeDepositStopTimeFromNow(uint _daysFromNow) public auth {
              depositStopTime = now + _daysFromNow * 1 days;
          }
      
          function tokenFallback(address _from, uint256 _value, bytes _data) public
          {
              tokenFallback(_from, _value);
          }
      
          // TODO: To test the stoppable can work or not
          function tokenFallback(address _from, uint256 _value) public stoppable
          {
              if (msg.sender == address(AGT) || msg.sender == address(ATN))
              {
                  // the owner is not count in the statistics
                  // Only owner can use to deposit the ATN reward things.
                  if (_from == owner)
                  {
                      return;
                  }
      
                  require(now <= depositStopTime);
      
                  var record = records[_from];
      
                  record.agtAtnAmount += _value;
                  record.timestamp = now;
                  records[_from] = record;
      
                  agtAtnReceived += _value;
      
                  pool.consume( _value.mul(rate - 100 ).div(100) );
      
                  Deposit(depositId++, _from, _value);
              }
          }
      
          function onTokenTransfer(address _from, address _to, uint _amount) public returns (bool)
          {
              if (_to == address(this) && _from != owner)
              {
                  if (msg.gas < gasRequired) return false;
                  
                  if (stopped) return false;
                  if (now > depositStopTime) return false;
      
                  // each address can only deposit once.
                  if (records[_from].timestamp > 0 ) return false;
      
                  // can not over the limit of maximum reward amount
                  if ( !pool.available( _amount.mul(rate - 100 ).div(100) ) ) return false;
              }
      
              return true;
          }
      
          function withdrawATN() public stoppable {
              require(msg.sender != owner);
      
              Record record = records[msg.sender];
      
              require(record.timestamp > 0);
      
              require(now >= record.timestamp + withdrawal_delay);
      
              withdrawFor(msg.sender);
          }
      
          function withdrawATN(address _addr) public stoppable {
              require(_addr != owner);
      
              Record record = records[_addr];
      
              require(record.timestamp > 0);
      
              require(now >= record.timestamp + withdrawal_delay);
      
              withdrawFor(_addr);
          }
      
          function withdrawFor(address _addr) internal {
              Record record = records[_addr];
              
              uint atnAmount = record.agtAtnAmount.mul(rate).div(100);
      
              require(ATN.transfer(_addr, atnAmount));
      
              atnSent += atnAmount;
      
              delete records[_addr];
      
              Withdrawal(
                         withdrawId++,
                         _addr,
                         atnAmount
                         );
          }
      
          function batchWithdraw(address[] _addrList) public stoppable {
              for (uint i = 0; i < _addrList.length; i++) {
                  if (records[_addrList[i]].timestamp > 0 && now >= records[_addrList[i]].timestamp + withdrawal_delay)
                  {
                      withdrawFor(_addrList[i]);
                  }
              }
          }
      
          function changeGasRequired(uint _gasRequired) public auth {
              gasRequired = _gasRequired;
              ChangeGasRequired(_gasRequired);
          }
      
          /// @notice This method can be used by the controller to extract mistakenly
          ///  sent tokens to this contract.
          /// @param _token The address of the token contract that you want to recover
          ///  set to 0 in case you want to extract ether.
          function claimTokens(address _token) public auth {
              if (_token == 0x0) {
                  owner.transfer(this.balance);
                  return;
              }
              
              ERC20 token = ERC20(_token);
              
              uint256 balance = token.balanceOf(this);
              
              token.transfer(owner, balance);
              ClaimedTokens(_token, owner, balance);
          }
      
          event ClaimedTokens(address indexed _token, address indexed _controller, uint256 _amount);
      
          /*
           * EVENTS
           */
          /// Emitted when program starts.
          event Started(uint _time);
      
          /// Emitted for each sucuessful deposit.
          uint public depositId = 0;
          event Deposit(uint _depositId, address indexed _addr, uint agtAtnAmount);
      
          /// Emitted for each sucuessful withdrawal.
          uint public withdrawId = 0;
          event Withdrawal(uint _withdrawId, address indexed _addr, uint _atnAmount);
      
          event ChangeGasRequired(uint _gasRequired);
      }