Skip to content

Commit

Permalink
Add getters for number of unclaimed tokens in PaymentSplitter (#3350)
Browse files Browse the repository at this point in the history
  • Loading branch information
alonbg committed May 31, 2022
1 parent 4942bd1 commit 6766b2d
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -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)

Expand Down
23 changes: 19 additions & 4 deletions contracts/finance/PaymentSplitter.sol
Expand Up @@ -120,15 +120,31 @@ 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.
*/
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");

Expand All @@ -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");

Expand Down
33 changes: 27 additions & 6 deletions test/finance/PaymentSplitter.test.js
Expand Up @@ -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);

Expand All @@ -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');
});
Expand All @@ -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',
Expand All @@ -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',
Expand All @@ -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);

Expand Down

0 comments on commit 6766b2d

Please sign in to comment.