Skip to content

Commit 7ef2730

Browse files
authored
Approval events on transferFrom and burnFrom (#1524)
* transferFrom now emits an Approval event, indicating the updated allowance. * Updated burnFrom to also emit Approval. * Added notices about the extra Approval events.
1 parent 6407d78 commit 7ef2730

File tree

2 files changed

+31
-4
lines changed

2 files changed

+31
-4
lines changed

contracts/token/ERC20/ERC20.sol

+12-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ import "../../math/SafeMath.sol";
99
* @dev Implementation of the basic standard token.
1010
* https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
1111
* Originally based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
12+
*
13+
* This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for
14+
* all accounts just by listening to said events. Note that this isn't required by the specification, and other
15+
* compliant implementations may not do it.
1216
*/
1317
contract ERC20 is IERC20 {
1418
using SafeMath for uint256;
@@ -73,14 +77,17 @@ contract ERC20 is IERC20 {
7377
}
7478

7579
/**
76-
* @dev Transfer tokens from one address to another
80+
* @dev Transfer tokens from one address to another.
81+
* Note that while this function emits an Approval event, this is not required as per the specification,
82+
* and other compliant implementations may not emit the event.
7783
* @param from address The address which you want to send tokens from
7884
* @param to address The address which you want to transfer to
7985
* @param value uint256 the amount of tokens to be transferred
8086
*/
8187
function transferFrom(address from, address to, uint256 value) public returns (bool) {
8288
_allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value);
8389
_transfer(from, to, value);
90+
emit Approval(from, msg.sender, _allowed[from][msg.sender]);
8491
return true;
8592
}
8693

@@ -90,6 +97,7 @@ contract ERC20 is IERC20 {
9097
* allowed value is better to use this function to avoid 2 calls (and wait until
9198
* the first transaction is mined)
9299
* From MonolithDAO Token.sol
100+
* Emits an Approval event.
93101
* @param spender The address which will spend the funds.
94102
* @param addedValue The amount of tokens to increase the allowance by.
95103
*/
@@ -107,6 +115,7 @@ contract ERC20 is IERC20 {
107115
* allowed value is better to use this function to avoid 2 calls (and wait until
108116
* the first transaction is mined)
109117
* From MonolithDAO Token.sol
118+
* Emits an Approval event.
110119
* @param spender The address which will spend the funds.
111120
* @param subtractedValue The amount of tokens to decrease the allowance by.
112121
*/
@@ -165,13 +174,13 @@ contract ERC20 is IERC20 {
165174
* @dev Internal function that burns an amount of the token of a given
166175
* account, deducting from the sender's allowance for said account. Uses the
167176
* internal burn function.
177+
* Emits an Approval event (reflecting the reduced allowance).
168178
* @param account The account whose tokens will be burnt.
169179
* @param value The amount that will be burnt.
170180
*/
171181
function _burnFrom(address account, uint256 value) internal {
172-
// Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted,
173-
// this function needs to emit an event with the updated approval.
174182
_allowed[account][msg.sender] = _allowed[account][msg.sender].sub(value);
175183
_burn(account, value);
184+
emit Approval(account, msg.sender, _allowed[account][msg.sender]);
176185
}
177186
}

test/token/ERC20/ERC20.test.js

+19-1
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,16 @@ contract('ERC20', function ([_, owner, recipient, anotherAccount]) {
199199
value: amount,
200200
});
201201
});
202+
203+
it('emits an approval event', async function () {
204+
const { logs } = await this.token.transferFrom(owner, to, amount, { from: spender });
205+
206+
expectEvent.inLogs(logs, 'Approval', {
207+
owner: owner,
208+
spender: spender,
209+
value: await this.token.allowance(owner, spender),
210+
});
211+
});
202212
});
203213

204214
describe('when the owner does not have enough balance', function () {
@@ -521,14 +531,22 @@ contract('ERC20', function ([_, owner, recipient, anotherAccount]) {
521531
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(expectedAllowance);
522532
});
523533

524-
it('emits Transfer event', async function () {
534+
it('emits a Transfer event', async function () {
525535
const event = expectEvent.inLogs(this.logs, 'Transfer', {
526536
from: owner,
527537
to: ZERO_ADDRESS,
528538
});
529539

530540
event.args.value.should.be.bignumber.equal(amount);
531541
});
542+
543+
it('emits an Approval event', async function () {
544+
expectEvent.inLogs(this.logs, 'Approval', {
545+
owner: owner,
546+
spender: spender,
547+
value: await this.token.allowance(owner, spender),
548+
});
549+
});
532550
});
533551
};
534552

0 commit comments

Comments
 (0)