Merge pull request #413 from frangio/add-safe-erc20
Add SafeERC20 helpers
This commit is contained in:
24
contracts/token/SafeERC20.sol
Normal file
24
contracts/token/SafeERC20.sol
Normal file
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
38
test/SafeERC20.js
Normal file
38
test/SafeERC20.js
Normal file
@ -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;
|
||||||
|
});
|
||||||
|
});
|
||||||
84
test/helpers/SafeERC20Helper.sol
Normal file
84
test/helpers/SafeERC20Helper.sol
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user