parent
2a8af2f1a9
commit
e0a866977c
|
@ -1,6 +1,8 @@
|
|||
pragma solidity ^0.4.18;
|
||||
|
||||
import "./LiquidPledging.sol";
|
||||
import "./common/SafeToken.sol";
|
||||
import "./common/Ownable.sol";
|
||||
|
||||
|
||||
// On mainnet extract the values from here: https://developer.kyber.network/docs/Environments-Mainnet/
|
||||
|
@ -13,23 +15,12 @@ contract KyberNetworkProxy {
|
|||
function swapEtherToToken(address token, uint minConversionRate) public payable returns(uint);
|
||||
}
|
||||
|
||||
interface ERC20Token {
|
||||
function transfer(address _to, uint256 _value) external returns (bool success);
|
||||
function approve(address _spender, uint256 _value) external returns (bool success);
|
||||
function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);
|
||||
function balanceOf(address _owner) external view returns (uint256 balance);
|
||||
function allowance(address _owner, address _spender) external view returns (uint256 remaining);
|
||||
function totalSupply() external view returns (uint256 supply);
|
||||
event Transfer(address indexed _from, address indexed _to, uint256 _value);
|
||||
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
|
||||
}
|
||||
|
||||
contract SwapProxy {
|
||||
contract SwapProxy is Ownable, SafeToken {
|
||||
address public ETH;
|
||||
KyberNetworkProxy public kyberProxy;
|
||||
LiquidPledging public liquidPledging;
|
||||
address public vault;
|
||||
uint public maxSlippage;
|
||||
KyberNetworkProxy public kyberProxy;
|
||||
LiquidPledging public liquidPledging;
|
||||
|
||||
/**
|
||||
* @param _liquidPledging LiquidPledging contract address
|
||||
|
@ -88,7 +79,7 @@ contract SwapProxy {
|
|||
uint amount = kyberProxy.trade.value(msg.value)(ETH, msg.value, token, address(this), maxDestinationAmount, slippageRate, vault);
|
||||
require(amount > 0);
|
||||
|
||||
ERC20Token(token).approve(address(liquidPledging), amount);
|
||||
require(EIP20Interface(token).approve(address(liquidPledging), amount));
|
||||
liquidPledging.addGiverAndDonate(idReceiver, token, amount);
|
||||
}
|
||||
|
||||
|
@ -100,7 +91,8 @@ contract SwapProxy {
|
|||
* @param receiverToken token being converted to
|
||||
*/
|
||||
function fundWithToken(uint64 idReceiver, address token, uint amount, address receiverToken) public {
|
||||
require(ERC20Token(token).transferFrom(msg.sender, address(this), amount));
|
||||
Error err = doTransferIn(token, msg.sender, amount);
|
||||
require(err == Error.NO_ERROR);
|
||||
|
||||
uint expectedRate;
|
||||
uint slippageRate;
|
||||
|
@ -108,15 +100,20 @@ contract SwapProxy {
|
|||
require(expectedRate > 0);
|
||||
uint slippagePercent = (slippageRate * 100) / expectedRate;
|
||||
require(slippagePercent <= maxSlippage);
|
||||
require(ERC20Token(token).approve(address(kyberProxy), 0));
|
||||
require(ERC20Token(token).approve(address(kyberProxy), amount));
|
||||
require(EIP20Interface(token).approve(address(kyberProxy), 0));
|
||||
require(EIP20Interface(token).approve(address(kyberProxy), amount));
|
||||
|
||||
uint maxDestinationAmount = (slippageRate / (10**18)) * amount;
|
||||
uint receiverAmount = kyberProxy.trade(token, amount, receiverToken, address(this), maxDestinationAmount, slippageRate, vault);
|
||||
require(receiverAmount > 0);
|
||||
|
||||
ERC20Token(token).approve(address(liquidPledging), receiverAmount);
|
||||
require(EIP20Interface(token).approve(address(liquidPledging), receiverAmount));
|
||||
liquidPledging.addGiverAndDonate(idReceiver, receiverToken, receiverAmount);
|
||||
}
|
||||
|
||||
function transferOut(address asset, address to, uint amount) public onlyOwner {
|
||||
Error err = doTransferOut(asset, to, amount);
|
||||
require(err == Error.NO_ERROR);
|
||||
}
|
||||
|
||||
function() payable external {}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
// Abstract contract for the full ERC 20 Token standard
|
||||
// https://github.com/ethereum/EIPs/issues/20
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
contract EIP20Interface {
|
||||
/* This is a slight change to the ERC20 base standard.
|
||||
function totalSupply() constant returns (uint256 supply);
|
||||
is replaced with:
|
||||
uint256 public totalSupply;
|
||||
This automatically creates a getter function for the totalSupply.
|
||||
This is moved to the base contract since public getter functions are not
|
||||
currently recognised as an implementation of the matching abstract
|
||||
function by the compiler.
|
||||
*/
|
||||
/// total amount of tokens
|
||||
uint256 public totalSupply;
|
||||
|
||||
/// @param _owner The address from which the balance will be retrieved
|
||||
/// @return The balance
|
||||
function balanceOf(address _owner) public view returns (uint256 balance);
|
||||
|
||||
/// @notice send `_value` token to `_to` from `msg.sender`
|
||||
/// @param _to The address of the recipient
|
||||
/// @param _value The amount of token to be transferred
|
||||
/// @return Whether the transfer was successful or not
|
||||
function transfer(address _to, uint256 _value) public returns (bool success);
|
||||
|
||||
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
|
||||
/// @param _from The address of the sender
|
||||
/// @param _to The address of the recipient
|
||||
/// @param _value The amount of token to be transferred
|
||||
/// @return Whether the transfer was successful or not
|
||||
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
|
||||
|
||||
/// @notice `msg.sender` approves `_spender` to spend `_value` tokens
|
||||
/// @param _spender The address of the account able to transfer the tokens
|
||||
/// @param _value The amount of tokens to be approved for transfer
|
||||
/// @return Whether the approval was successful or not
|
||||
function approve(address _spender, uint256 _value) public returns (bool success);
|
||||
|
||||
/// @param _owner The address of the account owning tokens
|
||||
/// @param _spender The address of the account able to transfer the tokens
|
||||
/// @return Amount of remaining tokens allowed to spent
|
||||
function allowance(address _owner, address _spender) public view returns (uint256 remaining);
|
||||
|
||||
// solhint-disable-next-line no-simple-event-func-name
|
||||
event Transfer(address indexed _from, address indexed _to, uint256 _value);
|
||||
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
// Abstract contract for the full ERC 20 Token standard
|
||||
// https://github.com/ethereum/EIPs/issues/20
|
||||
pragma solidity ^0.4.18;
|
||||
|
||||
/**
|
||||
* @title EIP20NonStandardInterface
|
||||
* @dev Version of ERC20 with no return values for `transfer` and `transferFrom`
|
||||
* See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
|
||||
*/
|
||||
contract EIP20NonStandardInterface {
|
||||
/* This is a slight change to the ERC20 base standard.
|
||||
function totalSupply() constant returns (uint256 supply);
|
||||
is replaced with:
|
||||
uint256 public totalSupply;
|
||||
This automatically creates a getter function for the totalSupply.
|
||||
This is moved to the base contract since public getter functions are not
|
||||
currently recognised as an implementation of the matching abstract
|
||||
function by the compiler.
|
||||
*/
|
||||
/// total amount of tokens
|
||||
uint256 public totalSupply;
|
||||
|
||||
/// @param _owner The address from which the balance will be retrieved
|
||||
/// @return The balance
|
||||
function balanceOf(address _owner) public view returns (uint256 balance);
|
||||
|
||||
///
|
||||
/// !!!!!!!!!!!!!!
|
||||
/// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification
|
||||
/// !!!!!!!!!!!!!!
|
||||
///
|
||||
|
||||
/// @notice send `_value` token to `_to` from `msg.sender`
|
||||
/// @param _to The address of the recipient
|
||||
/// @param _value The amount of token to be transferred
|
||||
/// @return Whether the transfer was successful or not
|
||||
function transfer(address _to, uint256 _value) public;
|
||||
|
||||
///
|
||||
/// !!!!!!!!!!!!!!
|
||||
/// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification
|
||||
/// !!!!!!!!!!!!!!
|
||||
///
|
||||
|
||||
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
|
||||
/// @param _from The address of the sender
|
||||
/// @param _to The address of the recipient
|
||||
/// @param _value The amount of token to be transferred
|
||||
/// @return Whether the transfer was successful or not
|
||||
function transferFrom(address _from, address _to, uint256 _value) public;
|
||||
|
||||
/// @notice `msg.sender` approves `_spender` to spend `_value` tokens
|
||||
/// @param _spender The address of the account able to transfer the tokens
|
||||
/// @param _value The amount of tokens to be approved for transfer
|
||||
/// @return Whether the approval was successful or not
|
||||
function approve(address _spender, uint256 _value) public returns (bool success);
|
||||
|
||||
/// @param _owner The address of the account owning tokens
|
||||
/// @param _spender The address of the account able to transfer the tokens
|
||||
/// @return Amount of remaining tokens allowed to spent
|
||||
function allowance(address _owner, address _spender) public view returns (uint256 remaining);
|
||||
|
||||
// solhint-disable-next-line no-simple-event-func-name
|
||||
event Transfer(address indexed _from, address indexed _to, uint256 _value);
|
||||
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
pragma solidity ^0.4.18;
|
||||
|
||||
contract ErrorReporter {
|
||||
|
||||
/**
|
||||
* @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary
|
||||
* contract-specific code that enables us to report opaque error codes from upgradeable contracts.
|
||||
**/
|
||||
event Failure(uint error, uint info, uint detail);
|
||||
|
||||
enum Error {
|
||||
NO_ERROR,
|
||||
OPAQUE_ERROR, // To be used when reporting errors from upgradeable contracts; the opaque code should be given as `detail` in the `Failure` event
|
||||
UNAUTHORIZED,
|
||||
INTEGER_OVERFLOW,
|
||||
INTEGER_UNDERFLOW,
|
||||
DIVISION_BY_ZERO,
|
||||
BAD_INPUT,
|
||||
TOKEN_INSUFFICIENT_ALLOWANCE,
|
||||
TOKEN_INSUFFICIENT_BALANCE,
|
||||
TOKEN_TRANSFER_FAILED,
|
||||
MARKET_NOT_SUPPORTED,
|
||||
SUPPLY_RATE_CALCULATION_FAILED,
|
||||
BORROW_RATE_CALCULATION_FAILED,
|
||||
TOKEN_INSUFFICIENT_CASH,
|
||||
TOKEN_TRANSFER_OUT_FAILED,
|
||||
INSUFFICIENT_LIQUIDITY,
|
||||
INSUFFICIENT_BALANCE,
|
||||
INVALID_COLLATERAL_RATIO,
|
||||
MISSING_ASSET_PRICE,
|
||||
EQUITY_INSUFFICIENT_BALANCE,
|
||||
INVALID_CLOSE_AMOUNT_REQUESTED,
|
||||
ASSET_NOT_PRICED,
|
||||
INVALID_LIQUIDATION_DISCOUNT,
|
||||
INVALID_COMBINED_RISK_PARAMETERS,
|
||||
ZERO_ORACLE_ADDRESS,
|
||||
CONTRACT_PAUSED
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: FailureInfo (but not Error) is kept in alphabetical order
|
||||
* This is because FailureInfo grows significantly faster, and
|
||||
* the order of Error has some meaning, while the order of FailureInfo
|
||||
* is entirely arbitrary.
|
||||
*/
|
||||
enum FailureInfo {
|
||||
ACCEPT_ADMIN_PENDING_ADMIN_CHECK,
|
||||
BORROW_ACCOUNT_LIQUIDITY_CALCULATION_FAILED,
|
||||
BORROW_ACCOUNT_SHORTFALL_PRESENT,
|
||||
BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,
|
||||
BORROW_AMOUNT_LIQUIDITY_SHORTFALL,
|
||||
BORROW_AMOUNT_VALUE_CALCULATION_FAILED,
|
||||
BORROW_CONTRACT_PAUSED,
|
||||
BORROW_MARKET_NOT_SUPPORTED,
|
||||
BORROW_NEW_BORROW_INDEX_CALCULATION_FAILED,
|
||||
BORROW_NEW_BORROW_RATE_CALCULATION_FAILED,
|
||||
BORROW_NEW_SUPPLY_INDEX_CALCULATION_FAILED,
|
||||
BORROW_NEW_SUPPLY_RATE_CALCULATION_FAILED,
|
||||
BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
|
||||
BORROW_NEW_TOTAL_BORROW_CALCULATION_FAILED,
|
||||
BORROW_NEW_TOTAL_CASH_CALCULATION_FAILED,
|
||||
BORROW_ORIGINATION_FEE_CALCULATION_FAILED,
|
||||
BORROW_TRANSFER_OUT_FAILED,
|
||||
EQUITY_WITHDRAWAL_AMOUNT_VALIDATION,
|
||||
EQUITY_WITHDRAWAL_CALCULATE_EQUITY,
|
||||
EQUITY_WITHDRAWAL_MODEL_OWNER_CHECK,
|
||||
EQUITY_WITHDRAWAL_TRANSFER_OUT_FAILED,
|
||||
LIQUIDATE_ACCUMULATED_BORROW_BALANCE_CALCULATION_FAILED,
|
||||
LIQUIDATE_ACCUMULATED_SUPPLY_BALANCE_CALCULATION_FAILED_BORROWER_COLLATERAL_ASSET,
|
||||
LIQUIDATE_ACCUMULATED_SUPPLY_BALANCE_CALCULATION_FAILED_LIQUIDATOR_COLLATERAL_ASSET,
|
||||
LIQUIDATE_AMOUNT_SEIZE_CALCULATION_FAILED,
|
||||
LIQUIDATE_BORROW_DENOMINATED_COLLATERAL_CALCULATION_FAILED,
|
||||
LIQUIDATE_CLOSE_AMOUNT_TOO_HIGH,
|
||||
LIQUIDATE_CONTRACT_PAUSED,
|
||||
LIQUIDATE_DISCOUNTED_REPAY_TO_EVEN_AMOUNT_CALCULATION_FAILED,
|
||||
LIQUIDATE_NEW_BORROW_INDEX_CALCULATION_FAILED_BORROWED_ASSET,
|
||||
LIQUIDATE_NEW_BORROW_INDEX_CALCULATION_FAILED_COLLATERAL_ASSET,
|
||||
LIQUIDATE_NEW_BORROW_RATE_CALCULATION_FAILED_BORROWED_ASSET,
|
||||
LIQUIDATE_NEW_SUPPLY_INDEX_CALCULATION_FAILED_BORROWED_ASSET,
|
||||
LIQUIDATE_NEW_SUPPLY_INDEX_CALCULATION_FAILED_COLLATERAL_ASSET,
|
||||
LIQUIDATE_NEW_SUPPLY_RATE_CALCULATION_FAILED_BORROWED_ASSET,
|
||||
LIQUIDATE_NEW_TOTAL_BORROW_CALCULATION_FAILED_BORROWED_ASSET,
|
||||
LIQUIDATE_NEW_TOTAL_CASH_CALCULATION_FAILED_BORROWED_ASSET,
|
||||
LIQUIDATE_NEW_TOTAL_SUPPLY_BALANCE_CALCULATION_FAILED_BORROWER_COLLATERAL_ASSET,
|
||||
LIQUIDATE_NEW_TOTAL_SUPPLY_BALANCE_CALCULATION_FAILED_LIQUIDATOR_COLLATERAL_ASSET,
|
||||
LIQUIDATE_FETCH_ASSET_PRICE_FAILED,
|
||||
LIQUIDATE_TRANSFER_IN_FAILED,
|
||||
LIQUIDATE_TRANSFER_IN_NOT_POSSIBLE,
|
||||
REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,
|
||||
REPAY_BORROW_CONTRACT_PAUSED,
|
||||
REPAY_BORROW_NEW_BORROW_INDEX_CALCULATION_FAILED,
|
||||
REPAY_BORROW_NEW_BORROW_RATE_CALCULATION_FAILED,
|
||||
REPAY_BORROW_NEW_SUPPLY_INDEX_CALCULATION_FAILED,
|
||||
REPAY_BORROW_NEW_SUPPLY_RATE_CALCULATION_FAILED,
|
||||
REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
|
||||
REPAY_BORROW_NEW_TOTAL_BORROW_CALCULATION_FAILED,
|
||||
REPAY_BORROW_NEW_TOTAL_CASH_CALCULATION_FAILED,
|
||||
REPAY_BORROW_TRANSFER_IN_FAILED,
|
||||
REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE,
|
||||
SET_ASSET_PRICE_CHECK_ORACLE,
|
||||
SET_MARKET_INTEREST_RATE_MODEL_OWNER_CHECK,
|
||||
SET_ORACLE_OWNER_CHECK,
|
||||
SET_ORIGINATION_FEE_OWNER_CHECK,
|
||||
SET_PAUSED_OWNER_CHECK,
|
||||
SET_PENDING_ADMIN_OWNER_CHECK,
|
||||
SET_RISK_PARAMETERS_OWNER_CHECK,
|
||||
SET_RISK_PARAMETERS_VALIDATION,
|
||||
SUPPLY_ACCUMULATED_BALANCE_CALCULATION_FAILED,
|
||||
SUPPLY_CONTRACT_PAUSED,
|
||||
SUPPLY_MARKET_NOT_SUPPORTED,
|
||||
SUPPLY_NEW_BORROW_INDEX_CALCULATION_FAILED,
|
||||
SUPPLY_NEW_BORROW_RATE_CALCULATION_FAILED,
|
||||
SUPPLY_NEW_SUPPLY_INDEX_CALCULATION_FAILED,
|
||||
SUPPLY_NEW_SUPPLY_RATE_CALCULATION_FAILED,
|
||||
SUPPLY_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
|
||||
SUPPLY_NEW_TOTAL_CASH_CALCULATION_FAILED,
|
||||
SUPPLY_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,
|
||||
SUPPLY_TRANSFER_IN_FAILED,
|
||||
SUPPLY_TRANSFER_IN_NOT_POSSIBLE,
|
||||
SUPPORT_MARKET_FETCH_PRICE_FAILED,
|
||||
SUPPORT_MARKET_OWNER_CHECK,
|
||||
SUPPORT_MARKET_PRICE_CHECK,
|
||||
SUSPEND_MARKET_OWNER_CHECK,
|
||||
WITHDRAW_ACCOUNT_LIQUIDITY_CALCULATION_FAILED,
|
||||
WITHDRAW_ACCOUNT_SHORTFALL_PRESENT,
|
||||
WITHDRAW_ACCUMULATED_BALANCE_CALCULATION_FAILED,
|
||||
WITHDRAW_AMOUNT_LIQUIDITY_SHORTFALL,
|
||||
WITHDRAW_AMOUNT_VALUE_CALCULATION_FAILED,
|
||||
WITHDRAW_CAPACITY_CALCULATION_FAILED,
|
||||
WITHDRAW_CONTRACT_PAUSED,
|
||||
WITHDRAW_NEW_BORROW_INDEX_CALCULATION_FAILED,
|
||||
WITHDRAW_NEW_BORROW_RATE_CALCULATION_FAILED,
|
||||
WITHDRAW_NEW_SUPPLY_INDEX_CALCULATION_FAILED,
|
||||
WITHDRAW_NEW_SUPPLY_RATE_CALCULATION_FAILED,
|
||||
WITHDRAW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
|
||||
WITHDRAW_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,
|
||||
WITHDRAW_TRANSFER_OUT_FAILED,
|
||||
WITHDRAW_TRANSFER_OUT_NOT_POSSIBLE
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dev use this when reporting a known error
|
||||
*/
|
||||
function fail(Error err, FailureInfo info) internal returns (uint) {
|
||||
Failure(uint(err), uint(info), 0);
|
||||
|
||||
return uint(err);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dev use this when reporting an opaque error from an upgradeable collaborator contract
|
||||
*/
|
||||
function failOpaque(FailureInfo info, uint opaqueError) internal returns (uint) {
|
||||
Failure(uint(Error.OPAQUE_ERROR), uint(info), opaqueError);
|
||||
|
||||
return uint(Error.OPAQUE_ERROR);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
pragma solidity ^0.4.18;
|
||||
|
||||
|
||||
/*
|
||||
* Ownable
|
||||
*
|
||||
* Base contract with an owner.
|
||||
* Provides onlyOwner modifier, which prevents function from running if it is called by anyone other than the owner.
|
||||
*/
|
||||
contract Ownable {
|
||||
address public owner;
|
||||
|
||||
function Ownable() {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
modifier onlyOwner() {
|
||||
if (msg.sender == owner)
|
||||
_;
|
||||
}
|
||||
|
||||
function transferOwnership(address newOwner) onlyOwner {
|
||||
if (newOwner != address(0)) owner = newOwner;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
pragma solidity ^0.4.18;
|
||||
|
||||
import "./EIP20Interface.sol";
|
||||
import "./EIP20NonStandardInterface.sol";
|
||||
import "./ErrorReporter.sol";
|
||||
|
||||
/**
|
||||
* @title Safe Token
|
||||
* @author Compound
|
||||
* @notice This is a work in progress.
|
||||
*/
|
||||
contract SafeToken is ErrorReporter {
|
||||
|
||||
/**
|
||||
* @dev Checks whether or not there is sufficient allowance for this contract to move amount from `from` and
|
||||
* whether or not `from` has a balance of at least `amount`. Does NOT do a transfer.
|
||||
*/
|
||||
function checkTransferIn(address asset, address from, uint amount) internal view returns (Error) {
|
||||
|
||||
EIP20Interface token = EIP20Interface(asset);
|
||||
|
||||
if (token.allowance(from, address(this)) < amount) {
|
||||
return Error.TOKEN_INSUFFICIENT_ALLOWANCE;
|
||||
}
|
||||
|
||||
if (token.balanceOf(from) < amount) {
|
||||
return Error.TOKEN_INSUFFICIENT_BALANCE;
|
||||
}
|
||||
|
||||
return Error.NO_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and returns an explanatory
|
||||
* error code rather than reverting. If caller has not called `checkTransferIn`, this may revert due to
|
||||
* insufficient balance or insufficient allowance. If caller has called `checkTransferIn` prior to this call,
|
||||
* and it returned Error.NO_ERROR, this should not revert in normal conditions.
|
||||
*
|
||||
* Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.
|
||||
* See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
|
||||
*/
|
||||
function doTransferIn(address asset, address from, uint amount) internal returns (Error) {
|
||||
EIP20NonStandardInterface token = EIP20NonStandardInterface(asset);
|
||||
|
||||
bool result;
|
||||
|
||||
token.transferFrom(from, address(this), amount);
|
||||
|
||||
assembly {
|
||||
switch returndatasize()
|
||||
case 0 { // This is a non-standard ERC-20
|
||||
result := not(0) // set result to true
|
||||
}
|
||||
case 32 { // This is a complaint ERC-20
|
||||
returndatacopy(0, 0, 32)
|
||||
result := mload(0) // Set `result = returndata` of external call
|
||||
}
|
||||
default { // This is an excessively non-compliant ERC-20, revert.
|
||||
revert(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
return Error.TOKEN_TRANSFER_FAILED;
|
||||
}
|
||||
|
||||
return Error.NO_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Checks balance of this contract in asset
|
||||
*/
|
||||
function getCash(address asset) internal view returns (uint) {
|
||||
EIP20Interface token = EIP20Interface(asset);
|
||||
|
||||
return token.balanceOf(address(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Checks balance of `from` in `asset`
|
||||
*/
|
||||
function getBalanceOf(address asset, address from) internal view returns (uint) {
|
||||
EIP20Interface token = EIP20Interface(asset);
|
||||
|
||||
return token.balanceOf(from);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Similar to EIP20 transfer, except it handles a False result from `transfer` and returns an explanatory
|
||||
* error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to
|
||||
* insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified
|
||||
* it is >= amount, this should not revert in normal conditions.
|
||||
*
|
||||
* Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.
|
||||
* See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
|
||||
*/
|
||||
function doTransferOut(address asset, address to, uint amount) internal returns (Error) {
|
||||
EIP20NonStandardInterface token = EIP20NonStandardInterface(asset);
|
||||
|
||||
bool result;
|
||||
|
||||
token.transfer(to, amount);
|
||||
|
||||
assembly {
|
||||
switch returndatasize()
|
||||
case 0 { // This is a non-standard ERC-20
|
||||
result := not(0) // set result to true
|
||||
}
|
||||
case 32 { // This is a complaint ERC-20
|
||||
returndatacopy(0, 0, 32)
|
||||
result := mload(0) // Set `result = returndata` of external call
|
||||
}
|
||||
default { // This is an excessively non-compliant ERC-20, revert.
|
||||
revert(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
return Error.TOKEN_TRANSFER_OUT_FAILED;
|
||||
}
|
||||
|
||||
return Error.NO_ERROR;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue