Kaynağa Gözat

Add getters for number of unclaimed tokens in PaymentSplitter (#3350)

alonbg 3 yıl önce
ebeveyn
işleme
6766b2de3b

+ 1 - 0
CHANGELOG.md

@@ -13,6 +13,7 @@
  * `MerkleProof`: add `multiProofVerify` to prove multiple values are part of a Merkle tree. ([#3276](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3276))
  * `ERC721`, `ERC1155`: simplified revert reasons. ([#3254](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3254))
  * `ERC721`: removed redundant require statement. ([#3434](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3434))
+ * `PaymentSplitter`: add `releasable` getters. ([#3350](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3350))
 
 ## 4.6.0 (2022-04-26)
 

+ 19 - 4
contracts/finance/PaymentSplitter.sol

@@ -120,6 +120,23 @@ contract PaymentSplitter is Context {
         return _payees[index];
     }
 
+    /**
+     * @dev Getter for the amount of payee's releasable Ether.
+     */
+    function releasable(address account) public view returns (uint256) {
+        uint256 totalReceived = address(this).balance + totalReleased();
+        return _pendingPayment(account, totalReceived, released(account));
+    }
+
+    /**
+     * @dev Getter for the amount of payee's releasable `token` tokens. `token` should be the address of an
+     * IERC20 contract.
+     */
+    function releasable(IERC20 token, address account) public view returns (uint256) {
+        uint256 totalReceived = token.balanceOf(address(this)) + totalReleased(token);
+        return _pendingPayment(account, totalReceived, released(token, account));
+    }
+
     /**
      * @dev Triggers a transfer to `account` of the amount of Ether they are owed, according to their percentage of the
      * total shares and their previous withdrawals.
@@ -127,8 +144,7 @@ contract PaymentSplitter is Context {
     function release(address payable account) public virtual {
         require(_shares[account] > 0, "PaymentSplitter: account has no shares");
 
-        uint256 totalReceived = address(this).balance + totalReleased();
-        uint256 payment = _pendingPayment(account, totalReceived, released(account));
+        uint256 payment = releasable(account);
 
         require(payment != 0, "PaymentSplitter: account is not due payment");
 
@@ -147,8 +163,7 @@ contract PaymentSplitter is Context {
     function release(IERC20 token, address account) public virtual {
         require(_shares[account] > 0, "PaymentSplitter: account has no shares");
 
-        uint256 totalReceived = token.balanceOf(address(this)) + totalReleased(token);
-        uint256 payment = _pendingPayment(account, totalReceived, released(token, account));
+        uint256 payment = releasable(token, account);
 
         require(payment != 0, "PaymentSplitter: account is not due payment");
 

+ 27 - 6
test/finance/PaymentSplitter.test.js

@@ -62,10 +62,11 @@ contract('PaymentSplitter', function (accounts) {
       await Promise.all(this.payees.map(async (payee, index) => {
         expect(await this.contract.payee(index)).to.equal(payee);
         expect(await this.contract.released(payee)).to.be.bignumber.equal('0');
+        expect(await this.contract.releasable(payee)).to.be.bignumber.equal('0');
       }));
     });
 
-    describe('accepts payments', async function () {
+    describe('accepts payments', function () {
       it('Ether', async function () {
         await send.ether(owner, this.contract.address, amount);
 
@@ -79,7 +80,7 @@ contract('PaymentSplitter', function (accounts) {
       });
     });
 
-    describe('shares', async function () {
+    describe('shares', function () {
       it('stores shares if address is payee', async function () {
         expect(await this.contract.shares(payee1)).to.be.bignumber.not.equal('0');
       });
@@ -89,8 +90,8 @@ contract('PaymentSplitter', function (accounts) {
       });
     });
 
-    describe('release', async function () {
-      describe('Ether', async function () {
+    describe('release', function () {
+      describe('Ether', function () {
         it('reverts if no funds to claim', async function () {
           await expectRevert(this.contract.release(payee1),
             'PaymentSplitter: account is not due payment',
@@ -104,7 +105,7 @@ contract('PaymentSplitter', function (accounts) {
         });
       });
 
-      describe('Token', async function () {
+      describe('Token', function () {
         it('reverts if no funds to claim', async function () {
           await expectRevert(this.contract.release(this.token.address, payee1),
             'PaymentSplitter: account is not due payment',
@@ -119,7 +120,27 @@ contract('PaymentSplitter', function (accounts) {
       });
     });
 
-    describe('distributes funds to payees', async function () {
+    describe('tracks releasable and released', function () {
+      it('Ether', async function () {
+        await send.ether(payer1, this.contract.address, amount);
+        const payment = amount.divn(10);
+        expect(await this.contract.releasable(payee2)).to.be.bignumber.equal(payment);
+        await this.contract.release(payee2);
+        expect(await this.contract.releasable(payee2)).to.be.bignumber.equal('0');
+        expect(await this.contract.released(payee2)).to.be.bignumber.equal(payment);
+      });
+
+      it('Token', async function () {
+        await this.token.transfer(this.contract.address, amount, { from: owner });
+        const payment = amount.divn(10);
+        expect(await this.contract.releasable(this.token.address, payee2, {})).to.be.bignumber.equal(payment);
+        await this.contract.release(this.token.address, payee2);
+        expect(await this.contract.releasable(this.token.address, payee2, {})).to.be.bignumber.equal('0');
+        expect(await this.contract.released(this.token.address, payee2)).to.be.bignumber.equal(payment);
+      });
+    });
+
+    describe('distributes funds to payees', function () {
       it('Ether', async function () {
         await send.ether(payer1, this.contract.address, amount);