Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add increase/decrease allowance functionality #20

Merged
merged 5 commits into from
Mar 9, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "modules/ds-test"]
path = modules/ds-test
url = https://github.com/dapphub/ds-test
[submodule "modules/contract-test-utils"]
path = modules/contract-test-utils
url = https://github.com/maple-labs/contract-test-utils
10 changes: 10 additions & 0 deletions contracts/ERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ contract ERC20 is IERC20 {
return true;
}

function decreaseAllowance(address spender_, uint256 subtractedAmount_) external override returns (bool success_) {
_approve(msg.sender, spender_, allowance[msg.sender][spender_] - subtractedAmount_);
return true;
}

function increaseAllowance(address spender_, uint256 addedAmount_) external override returns (bool success_) {
_approve(msg.sender, spender_, allowance[msg.sender][spender_] + addedAmount_);
return true;
}

function transfer(address recipient_, uint256 amount_) external override returns (bool success_) {
_transfer(msg.sender, recipient_, amount_);
return true;
Expand Down
10 changes: 10 additions & 0 deletions contracts/ERC20Permit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ contract ERC20Permit is IERC20Permit {
return true;
}

function decreaseAllowance(address spender_, uint256 subtractedAmount_) external override returns (bool success_) {
_approve(msg.sender, spender_, allowance[msg.sender][spender_] - subtractedAmount_);
return true;
}

function increaseAllowance(address spender_, uint256 addedAmount_) external override returns (bool success_) {
_approve(msg.sender, spender_, allowance[msg.sender][spender_] + addedAmount_);
return true;
}

function permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external override {
require(deadline >= block.timestamp, "ERC20Permit:EXPIRED");
bytes32 digest = keccak256(
Expand Down
18 changes: 18 additions & 0 deletions contracts/interfaces/IERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,24 @@ interface IERC20 {
*/
function approve(address spender_, uint256 amount_) external returns (bool success_);

/**
* @dev Function that allows one account to decrease the allowance of another account over their tokens.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spacing should be double for NatSpec.

* Emits an {Approval} event.
* @param spender_ Account that tokens are approved for.
* @param subtractedAmount_ Amount to decrease approval by.
* @return success_ Boolean indicating whether the operation succeeded.
*/
function decreaseAllowance(address spender_, uint256 subtractedAmount_) external returns (bool success_);

/**
* @dev Function that allows one account to increase the allowance of another account over their tokens.
* Emits an {Approval} event.
* @param spender_ Account that tokens are approved for.
* @param addedAmount_ Amount to increase approval by.
* @return success_ Boolean indicating whether the operation succeeded.
*/
function increaseAllowance(address spender_, uint256 addedAmount_) external returns (bool success_);

/**
* @dev Moves an amount of tokens from `msg.sender` to a specified account.
* Emits a {Transfer} event.
Expand Down
41 changes: 31 additions & 10 deletions contracts/test/ERC20.t.sol
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.7;

import { DSTest } from "../../modules/ds-test/src/test.sol";
import { InvariantTest, TestUtils } from "../../modules/contract-test-utils/contracts/test.sol";

import { ERC20User } from "./accounts/ERC20User.sol";
import { MockERC20 } from "./mocks/MockERC20.sol";
import { ERC20User } from "./accounts/ERC20User.sol";
import { MockERC20 } from "./mocks/MockERC20.sol";

import { InvariantTest } from "./utils/InvariantTest.sol";
import { Vm } from "./utils/Vm.sol";

contract ERC20Test is DSTest {

Vm vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
contract ERC20Test is TestUtils {

bytes constant ARITHMETIC_ERROR = abi.encodeWithSignature("Panic(uint256)", 0x11);

Expand Down Expand Up @@ -60,6 +55,32 @@ contract ERC20Test is DSTest {
assertEq(token.allowance(self, account), amount);
}

function test_increaseAllowance(address account, uint256 initialAmount, uint256 addedAmount) public {
initialAmount = constrictToRange(initialAmount, 0, type(uint256).max / 2);
addedAmount = constrictToRange(addedAmount, 0, type(uint256).max / 2);

token.approve(account, initialAmount);

assertEq(token.allowance(self, account), initialAmount);

assertTrue(token.increaseAllowance(account, addedAmount));

assertEq(token.allowance(self, account), initialAmount + addedAmount);
}

function test_decreaseAllowance(address account, uint256 initialAmount, uint256 subtractedAmount) public {
initialAmount = constrictToRange(initialAmount, 0, type(uint256).max);
subtractedAmount = constrictToRange(subtractedAmount, 0, initialAmount);

token.approve(account, initialAmount);

assertEq(token.allowance(self, account), initialAmount);

assertTrue(token.decreaseAllowance(account, subtractedAmount));

assertEq(token.allowance(self, account), initialAmount - subtractedAmount);
}

function test_transfer(address account, uint256 amount) public {
token.mint(self, amount);

Expand Down Expand Up @@ -152,7 +173,7 @@ contract ERC20Test is DSTest {

}

contract ERC20Invariants is DSTest, InvariantTest {
contract ERC20Invariants is TestUtils, InvariantTest {

BalanceSum balanceSum;

Expand Down
17 changes: 5 additions & 12 deletions contracts/test/ERC20Permit.t.sol
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.7;

import { DSTest } from "../../modules/ds-test/src/test.sol";
import { InvariantTest, TestUtils } from "../../modules/contract-test-utils/contracts/test.sol";

import { ERC20Permit } from "../ERC20Permit.sol";

import { ERC20PermitUser } from "./accounts/ERC20User.sol";

import { MockERC20Permit } from "./mocks/MockERC20.sol";

import { Vm } from "./utils/Vm.sol";
import { InvariantTest } from "./utils/InvariantTest.sol";

import { ERC20PermitUser } from "./accounts/ERC20User.sol";
import { MockERC20Permit } from "./mocks/MockERC20.sol";
import { ERC20Test, MockERC20 } from "./ERC20.t.sol";

contract ERC20PermitBaseTest is ERC20Test {
Expand All @@ -22,9 +17,7 @@ contract ERC20PermitBaseTest is ERC20Test {

}

contract ERC20PermitTest is DSTest {

Vm vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
contract ERC20PermitTest is TestUtils {

bytes constant ARITHMETIC_ERROR = abi.encodeWithSignature("Panic(uint256)", 0x11);

Expand Down Expand Up @@ -155,7 +148,7 @@ contract ERC20PermitTest is DSTest {

}

contract ERC20Invariants is DSTest, InvariantTest {
contract ERC20Invariants is TestUtils, InvariantTest {

BalanceSum balanceSum;

Expand Down
1 change: 1 addition & 0 deletions modules/contract-test-utils
Submodule contract-test-utils added at 3bda52
1 change: 0 additions & 1 deletion modules/ds-test
Submodule ds-test deleted from 0a5da5