Skip to content
This repository has been archived by the owner on Jan 18, 2023. It is now read-only.

Commit

Permalink
Merge pull request #73 from SetProtocol/brian/require_successful_tran…
Browse files Browse the repository at this point in the history
…sfer

Brian/require successful transfer
  • Loading branch information
asoong authored Jun 26, 2018
2 parents f04712d + 21b551c commit 8c7ca7a
Show file tree
Hide file tree
Showing 11 changed files with 610 additions and 24 deletions.
1 change: 0 additions & 1 deletion contracts/core/SetToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ pragma solidity 0.4.24;


import { DetailedERC20 } from "zeppelin-solidity/contracts/token/ERC20/DetailedERC20.sol";
import { ERC20 } from "zeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import { StandardToken } from "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";
import { SafeMath } from "zeppelin-solidity/contracts/math/SafeMath.sol";
import { ISetFactory } from "./interfaces/ISetFactory.sol";
Expand Down
16 changes: 12 additions & 4 deletions contracts/core/TransferProxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ pragma solidity 0.4.24;


import { Authorizable } from "../lib/Authorizable.sol";
import { ERC20 } from "zeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import { SafeMath } from "zeppelin-solidity/contracts/math/SafeMath.sol";
import { ERC20Wrapper } from "./lib/ERC20Wrapper.sol";


/**
Expand Down Expand Up @@ -80,17 +80,25 @@ contract TransferProxy is
onlyAuthorized
{
// Retrieve current balance of token for the vault
uint existingVaultBalance = ERC20(_tokenAddress).balanceOf(vaultAddress);
uint existingVaultBalance = ERC20Wrapper.balanceOf(
_tokenAddress,
vaultAddress
);

// Call specified ERC20 contract to transfer tokens from user to Vault (via proxy).
ERC20(_tokenAddress).transferFrom(

ERC20Wrapper.transferFrom(
_tokenAddress,
_from,
vaultAddress,
_quantity
);

// Verify transfer quantity is reflected in balance
uint newVaultBalance = ERC20(_tokenAddress).balanceOf(vaultAddress);
uint newVaultBalance = ERC20Wrapper.balanceOf(
_tokenAddress,
vaultAddress
);
require(newVaultBalance == existingVaultBalance.add(_quantity));
}
}
17 changes: 12 additions & 5 deletions contracts/core/Vault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ pragma solidity 0.4.24;


import { Authorizable } from "../lib/Authorizable.sol";
import { ERC20 } from "zeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import { SafeMath } from "zeppelin-solidity/contracts/math/SafeMath.sol";
import { ERC20Wrapper } from "./lib/ERC20Wrapper.sol";


/**
Expand Down Expand Up @@ -92,16 +92,23 @@ contract Vault is
isValidDestination(_to)
{
// Retrieve current balance of token for the vault
uint existingVaultBalance = ERC20(_tokenAddress).balanceOf(this);
uint existingVaultBalance = ERC20Wrapper.balanceOf(
_tokenAddress,
this
);

// Call specified ERC20 token contract to transfer tokens from Vault to user
ERC20(_tokenAddress).transfer(
ERC20Wrapper.transfer(
_tokenAddress,
_to,
_quantity
);

// Verify transfer quantity is reflected in balance
uint newVaultBalance = ERC20(_tokenAddress).balanceOf(this);
uint newVaultBalance = ERC20Wrapper.balanceOf(
_tokenAddress,
this
);
require(newVaultBalance == existingVaultBalance.sub(_quantity));
}

Expand Down Expand Up @@ -154,7 +161,7 @@ contract Vault is
}

/* ============ Getter Functions ============ */

/*
* Get balance of particular contract for owner.
*
Expand Down
121 changes: 121 additions & 0 deletions contracts/core/lib/ERC20Wrapper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
Copyright 2018 Set Labs Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

pragma solidity 0.4.24;

import { IERC20 } from "../../lib/IERC20.sol";


/**
* @title TokenInteract
* @author Set Protocol
*
* This library contains functions for interacting wtih ERC20 tokens, even those not fully compliant.
* For all functions we will only accept tokens that return a null or true value, any other values will
* cause the operation to revert.
*/
library ERC20Wrapper {

// ============ Constants ============

string constant INVALID_RETURN_VALUE_TRANSFER = "Transferred token does not return null or true on successful trasnfer.";
string constant INVALID_RETURN_VALUE_TRANSFERFROM = "Transferred token does not return null or true on successful transferFrom.";

// ============ Internal Functions ============

function balanceOf(
address _tokenAddress,
address _ownerAddress
)
internal
view
returns (uint256)
{
return IERC20(_tokenAddress).balanceOf(_ownerAddress);
}

function transfer(
address _tokenAddress,
address _to,
uint256 _quantity
)
internal
{
IERC20(_tokenAddress).transfer(_to, _quantity);

require(
checkSuccess(),
INVALID_RETURN_VALUE_TRANSFER
);
}

function transferFrom(
address _tokenAddress,
address _from,
address _to,
uint256 _quantity
)
internal
{
IERC20(_tokenAddress).transferFrom(_from, _to, _quantity);

require(
checkSuccess(),
INVALID_RETURN_VALUE_TRANSFERFROM
);
}

// ============ Private Functions ============

/**
* Checks the return value of the previous function up to 32 bytes. Returns true if the previous
* function returned 0 bytes or 1.
*/
function checkSuccess(
)
private
pure
returns (bool)
{
// default to failure
uint256 returnValue = 0;

assembly {
// check number of bytes returned from last function call
switch returndatasize

// no bytes returned: assume success
case 0x0 {
returnValue := 1
}

// 32 bytes returned
case 0x20 {
// copy 32 bytes into scratch space
returndatacopy(0x0, 0x0, 0x20)

// load those bytes into returnValue
returnValue := mload(0x0)
}

// not sure what was returned: dont mark as success
default { }
}

// check if returned value is one or nothing
return returnValue == 1;
}
}
1 change: 0 additions & 1 deletion contracts/lib/Authorizable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import { Ownable } from "zeppelin-solidity/contracts/ownership/Ownable.sol";
* The Authorizable contract is an inherited contract that sets permissions on certain function calls
* through the onlyAuthorized modifier. Permissions can be managed only by the Owner of the contract.
*/

contract Authorizable is
Ownable
{
Expand Down
47 changes: 47 additions & 0 deletions contracts/lib/IERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
Copyright 2018 Set Labs Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

pragma solidity 0.4.24;


/**
* @title GeneralERC20
* @author Set Protocol
*
* Interface for using ERC20 Tokens. This interface is needed to interact with tokens that are not
* fully ERC20 compliant and return something other than true on successful transfers.
*/
interface IERC20 {
function balanceOf(
address _owner
)
external
view
returns (uint256);

function transfer(
address _to,
uint256 _quantity
)
external;

function transferFrom(
address _from,
address _to,
uint256 _quantity
)
external;
}
Loading

0 comments on commit 8c7ca7a

Please sign in to comment.