Merge pull request #413 from frangio/add-safe-erc20

Add SafeERC20 helpers
pull/416/head
Francisco Giordano 8 years ago committed by GitHub
commit dcdc453a55
  1. 24
      contracts/token/SafeERC20.sol
  2. 38
      test/SafeERC20.js
  3. 84
      test/helpers/SafeERC20Helper.sol

@ -0,0 +1,24 @@
pragma solidity ^0.4.11;
import './ERC20Basic.sol';
import './ERC20.sol';
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
function safeTransfer(ERC20Basic token, address to, uint256 value) internal {
assert(token.transfer(to, value));
}
function safeTransferFrom(ERC20 token, address from, address to, uint256 value) internal {
assert(token.transferFrom(from, to, value));
}
function safeApprove(ERC20 token, address spender, uint256 value) internal {
assert(token.approve(spender, value));
}
}

@ -0,0 +1,38 @@
import EVMThrow from './helpers/EVMThrow';
require('chai')
.use(require('chai-as-promised'))
.should();
const SafeERC20Helper = artifacts.require('./helpers/SafeERC20Helper.sol');
contract('SafeERC20', function () {
beforeEach(async function () {
this.helper = await SafeERC20Helper.new();
});
it('should throw on failed transfer', async function () {
await this.helper.doFailingTransfer().should.be.rejectedWith(EVMThrow);
});
it('should throw on failed transferFrom', async function () {
await this.helper.doFailingTransferFrom().should.be.rejectedWith(EVMThrow);
});
it('should throw on failed approve', async function () {
await this.helper.doFailingApprove().should.be.rejectedWith(EVMThrow);
});
it('should not throw on succeeding transfer', async function () {
await this.helper.doSucceedingTransfer().should.be.fulfilled;
});
it('should not throw on succeeding transferFrom', async function () {
await this.helper.doSucceedingTransferFrom().should.be.fulfilled;
});
it('should not throw on succeeding approve', async function () {
await this.helper.doSucceedingApprove().should.be.fulfilled;
});
});

@ -0,0 +1,84 @@
pragma solidity ^0.4.11;
import '../../contracts/token/ERC20.sol';
import '../../contracts/token/SafeERC20.sol';
contract ERC20FailingMock is ERC20 {
function transfer(address, uint256) returns (bool) {
return false;
}
function transferFrom(address, address, uint256) returns (bool) {
return false;
}
function approve(address, uint256) returns (bool) {
return false;
}
function balanceOf(address) constant returns (uint256) {
return 0;
}
function allowance(address, address) constant returns (uint256) {
return 0;
}
}
contract ERC20SucceedingMock is ERC20 {
function transfer(address, uint256) returns (bool) {
return true;
}
function transferFrom(address, address, uint256) returns (bool) {
return true;
}
function approve(address, uint256) returns (bool) {
return true;
}
function balanceOf(address) constant returns (uint256) {
return 0;
}
function allowance(address, address) constant returns (uint256) {
return 0;
}
}
contract SafeERC20Helper {
using SafeERC20 for ERC20;
ERC20 failing;
ERC20 succeeding;
function SafeERC20Helper() {
failing = new ERC20FailingMock();
succeeding = new ERC20SucceedingMock();
}
function doFailingTransfer() {
failing.safeTransfer(0, 0);
}
function doFailingTransferFrom() {
failing.safeTransferFrom(0, 0, 0);
}
function doFailingApprove() {
failing.safeApprove(0, 0);
}
function doSucceedingTransfer() {
succeeding.safeTransfer(0, 0);
}
function doSucceedingTransferFrom() {
succeeding.safeTransferFrom(0, 0, 0);
}
function doSucceedingApprove() {
succeeding.safeApprove(0, 0);
}
}
Loading…
Cancel
Save