Skip to content

Commit

Permalink
Merge pull request #111 from jakerumbles/payment-splitter-release-all
Browse files Browse the repository at this point in the history
Payment Splitter release_all()
  • Loading branch information
xgreenx authored May 20, 2022
2 parents da34c6c + 7ec2137 commit bb1e9d3
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 2 deletions.
14 changes: 14 additions & 0 deletions contracts/finance/payment_splitter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ pub trait PaymentSplitterInternal {
fn _init(&mut self, payees_and_shares: Vec<(AccountId, Balance)>) -> Result<(), PaymentSplitterError>;

fn _add_payee(&mut self, payee: AccountId, share: Balance) -> Result<(), PaymentSplitterError>;

/// Calls the `release` method for each `AccountId` in the `payees` vec.
fn _release_all(&mut self) -> Result<(), PaymentSplitterError>;
}

impl<T: PaymentSplitterStorage> PaymentSplitterInternal for T {
Expand Down Expand Up @@ -163,4 +166,15 @@ impl<T: PaymentSplitterStorage> PaymentSplitterInternal for T {
self._emit_payee_added_event(payee, share);
Ok(())
}

default fn _release_all(&mut self) -> Result<(), PaymentSplitterError> {
let len = self.get().payees.len();

for i in 0..len {
let account = self.get().payees[i];
self.release(account)?;
}

Ok(())
}
}
28 changes: 28 additions & 0 deletions contracts/tests/payment_splitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,34 @@ mod payment_splitter {
);
}

#[ink::test]
fn correct_release_all() {
let accounts = accounts();
let mut instance = MySplitter::new(vec![(accounts.charlie, 100), (accounts.bob, 200)]);
ink_env::test::set_account_balance::<ink_env::DefaultEnvironment>(accounts.charlie, 0);
ink_env::test::set_account_balance::<ink_env::DefaultEnvironment>(accounts.bob, 0);
let amount = 1000000;
add_funds(instance.env().account_id(), amount);

assert_eq!(100 + 200, instance.total_shares());
assert!(instance._release_all().is_ok());
assert_eq!(999999, instance.total_released());
assert_eq!(333333, instance.released(accounts.charlie));
assert_eq!(
333333,
ink_env::test::get_account_balance::<ink_env::DefaultEnvironment>(accounts.charlie).unwrap()
);
assert_eq!(2 * 333333, instance.released(accounts.bob));
assert_eq!(
2 * 333333,
ink_env::test::get_account_balance::<ink_env::DefaultEnvironment>(accounts.bob).unwrap()
);

let emitted_events = ink_env::test::recorded_events().collect::<Vec<_>>();
assert_payment_released_event(&emitted_events[2], accounts.charlie, 333333);
assert_payment_released_event(&emitted_events[3], accounts.bob, 2 * 333333);
}

fn add_funds(account: AccountId, amount: Balance) {
let balance = ink_env::balance::<ink_env::DefaultEnvironment>();
ink_env::test::set_account_balance::<ink_env::DefaultEnvironment>(account, balance + amount);
Expand Down
5 changes: 3 additions & 2 deletions examples/payment_splitter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ an amount proportional to the percentage of total shares they were assigned.

`PaymentSplitter` follows a _pull payment_ model. This means that payments are not automatically forwarded to the
accounts but kept in this contract, and the actual transfer is triggered as a separate step by calling the `release`
function.
function. `release` pays out to only the provided address. If you will have many people to pay out, especially if often, you will likely
want to use the `releaseAll` method instead to save you a lot of time.

** Note **: In the substrate balance of contract decreases each block. Because it pays rent for the storage.
So during `release`, each next user will get fewer native tokens.

This module is used through embedding of `PaymentSplitterData` and implementation of `PaymentSplitter` and
`PaymentSplitterStorage` traits.

[See example](https://supercolony-net.github.io/openbrush-contracts/smart-contracts/payment-splitter)
[See example](https://supercolony-net.github.io/openbrush-contracts/smart-contracts/payment-splitter)
8 changes: 8 additions & 0 deletions examples/payment_splitter/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ pub mod my_payment_splitter {
instance._init(payees_and_shares).expect("Should init");
})
}

/// Payout all payees at once.
/// Delete this method if you don't want this functionality in your version of the payment splitter.
#[ink(message)]
pub fn release_all(&mut self) -> Result<(), PaymentSplitterError> {
// `_release_all()` is an internal method defined by the `PaymentSplitterInternal` trait
self._release_all()
}
}

impl PaymentSplitter for SplitterStruct {}
Expand Down
22 changes: 22 additions & 0 deletions tests/payment-splitter.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,26 @@ describe('MY_PAYMENT_SPLITTER', () => {
expect(ianReleased).to.equal(totalReleased * IAN_SHARE / (KAYNE_SHARE + IAN_SHARE))
expect(ianReleased + kayneReleased).to.equal(totalReleased)
})

it('PAYMENT SPLITTER - release a native token using releaseAll function', async () => {
// Arrange - Create a contract
const { contract, kayne, ian } = await setup()

// Act - Send native token and release them
await expect(contract.contract.query.totalReleased()).to.have.output(0)
await expect(contract.contract.tx.receive({ value: 1000000000000 })).to.eventually.be.fulfilled
await expect(contract.contract.tx.releaseAll()).to.eventually.be.fulfilled

// Assert - Ian must hold more tokens than kayne
// @ts-ignore
let totalReleased = Number.parseInt((await contract.contract.query.totalReleased()).output)
// @ts-ignore
let kayneReleased = Number.parseInt((await contract.contract.query.released(kayne.address)).output)
// @ts-ignore
let ianReleased = Number.parseInt((await contract.contract.query.released(ian.address)).output)
expect(ianReleased > kayneReleased).to.true
expect(kayneReleased).to.equal(totalReleased * KAYNE_SHARE / (KAYNE_SHARE + IAN_SHARE))
expect(ianReleased).to.equal(totalReleased * IAN_SHARE / (KAYNE_SHARE + IAN_SHARE))
expect(ianReleased + kayneReleased).to.equal(totalReleased)
})
})

0 comments on commit bb1e9d3

Please sign in to comment.