Skip to content

Commit

Permalink
Merge pull request #5 from keep-network/approve-and-call
Browse files Browse the repository at this point in the history
Added `approveAndCall` to TBTC token
  • Loading branch information
dimpar authored Jul 5, 2021
2 parents ff22348 + d671d1a commit db23320
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 16 deletions.
33 changes: 33 additions & 0 deletions solidity/contracts/test/ReceiveApprovalStub.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT

pragma solidity <0.9.0;

import "../token/TBTCToken.sol";

contract ReceiveApprovalStub is IReceiveApproval {
bool public shouldRevert;

event ApprovalReceived(
address from,
uint256 value,
address token,
bytes extraData
);

function receiveApproval(
address from,
uint256 value,
address token,
bytes calldata extraData
) external override {
if (shouldRevert) {
revert("i am your father luke");
}

emit ApprovalReceived(from, value, token, extraData);
}

function setShouldRevert(bool _shouldRevert) external {
shouldRevert = _shouldRevert;
}
}
18 changes: 9 additions & 9 deletions solidity/contracts/token/ERC20WithPermit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,6 @@ contract ERC20WithPermit is IERC20WithPermit, Ownable {
return true;
}

function approve(address spender, uint256 amount)
external
override
returns (bool)
{
_approve(msg.sender, spender, amount);
return true;
}

function permit(
address owner,
address spender,
Expand Down Expand Up @@ -155,6 +146,15 @@ contract ERC20WithPermit is IERC20WithPermit, Ownable {
_burn(account, amount);
}

function approve(address spender, uint256 amount)
public
override
returns (bool)
{
_approve(msg.sender, spender, amount);
return true;
}

/* solhint-disable-next-line func-name-mixedcase */
function DOMAIN_SEPARATOR() public view override returns (bytes32) {
if (chainId() == cachedChainId) {
Expand Down
31 changes: 31 additions & 0 deletions solidity/contracts/token/TBTCToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,37 @@ pragma solidity <0.9.0;
import "./ERC20WithPermit.sol";
import "./MisfundRecovery.sol";

interface IReceiveApproval {
function receiveApproval(
address _from,
uint256 _value,
address _token,
bytes calldata _extraData
) external;
}

contract TBTCToken is ERC20WithPermit, MisfundRecovery {
constructor() ERC20WithPermit("TBTC v2 migration", "TBTC") {}

/// @notice Executes receiveApproval function on spender as specified in
/// IReceiveApproval interface. Approves spender to withdraw from
/// the caller multiple times, up to the value amount. If this
/// function is called again, it overwrites the current allowance
/// with value. Reverts if the approval reverted or if
/// receiveApproval call on the spender reverted.
function approveAndCall(
address spender,
uint256 value,
bytes memory extraData
) external returns (bool) {
if (approve(spender, value)) {
IReceiveApproval(spender).receiveApproval(
msg.sender,
value,
address(this),
extraData
);
return true;
}
}
}
7 changes: 0 additions & 7 deletions solidity/test/TBTCToken.test.js

This file was deleted.

69 changes: 69 additions & 0 deletions solidity/test/token/TBTCToken.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const { expect } = require("chai")
const { to1e18, ZERO_ADDRESS } = require("../helpers/contract-test-helpers")

describe("TBTCToken", () => {
let approver

let approvalReceiver
let tbtc

beforeEach(async () => {
approver = await ethers.getSigner(1)

const ReceiveApprovalStub = await ethers.getContractFactory(
"ReceiveApprovalStub"
)
approvalReceiver = await ReceiveApprovalStub.deploy()
await approvalReceiver.deployed()

const TBTCToken = await ethers.getContractFactory("TBTCToken")
tbtc = await TBTCToken.deploy()
await tbtc.deployed()

tbtc.mint(approver.address, to1e18(1000000))
})

describe("approveAndCall", () => {
const amount = to1e18(200)

context("when approval fails", () => {
it("should revert", async () => {
await expect(
tbtc.connect(approver).approveAndCall(ZERO_ADDRESS, amount, [])
).to.be.reverted
})
})

context("when receiveApproval fails", () => {
beforeEach(async () => {
await approvalReceiver.setShouldRevert(true)
})

it("should revert", async () => {
await expect(
tbtc
.connect(approver)
.approveAndCall(approvalReceiver.address, amount, [])
).to.be.revertedWith("i am your father luke")
})
})

it("approves the provided amount for transfer", async () => {
await tbtc
.connect(approver)
.approveAndCall(approvalReceiver.address, amount, [])
expect(
await tbtc.allowance(approver.address, approvalReceiver.address)
).to.equal(amount)
})

it("calls approveAndCall with the provided parameters", async () => {
const tx = await tbtc
.connect(approver)
.approveAndCall(approvalReceiver.address, amount, "0xbeef")
await expect(tx)
.to.emit(approvalReceiver, "ApprovalReceived")
.withArgs(approver.address, amount, tbtc.address, "0xbeef")
})
})
})

0 comments on commit db23320

Please sign in to comment.