Pārlūkot izejas kodu

Emit DelegateVotesChanged events after Transfer (#2733)

Hadrien Croubois 4 gadi atpakaļ
vecāks
revīzija
8a775cd8d4

+ 27 - 1
contracts/token/ERC20/ERC20.sol

@@ -234,6 +234,8 @@ contract ERC20 is Context, IERC20, IERC20Metadata {
         _balances[recipient] += amount;
 
         emit Transfer(sender, recipient, amount);
+
+        _afterTokenTransfer(sender, recipient, amount);
     }
 
     /** @dev Creates `amount` tokens and assigns them to `account`, increasing
@@ -253,6 +255,8 @@ contract ERC20 is Context, IERC20, IERC20Metadata {
         _totalSupply += amount;
         _balances[account] += amount;
         emit Transfer(address(0), account, amount);
+
+        _afterTokenTransfer(address(0), account, amount);
     }
 
     /**
@@ -279,6 +283,8 @@ contract ERC20 is Context, IERC20, IERC20Metadata {
         _totalSupply -= amount;
 
         emit Transfer(account, address(0), amount);
+
+        _afterTokenTransfer(account, address(0), amount);
     }
 
     /**
@@ -313,7 +319,7 @@ contract ERC20 is Context, IERC20, IERC20Metadata {
      * Calling conditions:
      *
      * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
-     * will be to transferred to `to`.
+     * will be transferred to `to`.
      * - when `from` is zero, `amount` tokens will be minted for `to`.
      * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
      * - `from` and `to` are never both zero.
@@ -325,4 +331,24 @@ contract ERC20 is Context, IERC20, IERC20Metadata {
         address to,
         uint256 amount
     ) internal virtual {}
+
+    /**
+     * @dev Hook that is called after any transfer of tokens. This includes
+     * minting and burning.
+     *
+     * Calling conditions:
+     *
+     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
+     * has been transferred to `to`.
+     * - when `from` is zero, `amount` tokens have been minted for `to`.
+     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
+     * - `from` and `to` are never both zero.
+     *
+     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
+     */
+    function _afterTokenTransfer(
+        address from,
+        address to,
+        uint256 amount
+    ) internal virtual {}
 }

+ 3 - 1
contracts/token/ERC20/extensions/ERC20Votes.sol

@@ -190,11 +190,13 @@ abstract contract ERC20Votes is ERC20Permit {
      *
      * Emits a {DelegateVotesChanged} event.
      */
-    function _beforeTokenTransfer(
+    function _afterTokenTransfer(
         address from,
         address to,
         uint256 amount
     ) internal virtual override {
+        super._afterTokenTransfer(from, to, amount);
+
         _moveVotingPower(delegates(from), delegates(to), amount);
     }
 

+ 9 - 0
test/token/ERC20/extensions/ERC20Votes.test.js

@@ -306,6 +306,9 @@ contract('ERC20Votes', function (accounts) {
       expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' });
       expectEvent(receipt, 'DelegateVotesChanged', { delegate: holder, previousBalance: supply, newBalance: supply.subn(1) });
 
+      const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
+      expect(receipt.logs.filter(({ event }) => event == 'DelegateVotesChanged').every(({ logIndex }) => transferLogIndex < logIndex)).to.be.equal(true);
+
       this.holderVotes = supply.subn(1);
       this.recipientVotes = '0';
     });
@@ -317,6 +320,9 @@ contract('ERC20Votes', function (accounts) {
       expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' });
       expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' });
 
+      const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
+      expect(receipt.logs.filter(({ event }) => event == 'DelegateVotesChanged').every(({ logIndex }) => transferLogIndex < logIndex)).to.be.equal(true);
+
       this.holderVotes = '0';
       this.recipientVotes = '1';
     });
@@ -330,6 +336,9 @@ contract('ERC20Votes', function (accounts) {
       expectEvent(receipt, 'DelegateVotesChanged', { delegate: holder, previousBalance: supply, newBalance: supply.subn(1) });
       expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' });
 
+      const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
+      expect(receipt.logs.filter(({ event }) => event == 'DelegateVotesChanged').every(({ logIndex }) => transferLogIndex < logIndex)).to.be.equal(true);
+
       this.holderVotes = supply.subn(1);
       this.recipientVotes = '1';
     });