Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Conditional Splitter ADO #441

Merged
merged 29 commits into from
May 20, 2024
Merged

Conversation

joemonem
Copy link
Contributor

@joemonem joemonem commented Apr 29, 2024

Motivation

Resolves: #336

Implementation

The splitter's AddressPercent struct is used to couple each recipient to a respective percentage.

Each threshold has a min value and a vector of AddressPercent

When the Send execute msg is called, we find the appropriate threshold for the funds sent with the message, and use its values to calculate for the funds' distribution.

The contract owner also has the option to update the thresholds if there's no lock, or if the lock's expired.

Testing

Unit tests and an integration test were created.

Test on G4:
First threshold:
min: 0
one recipient getting 20%

Second threshold:
min: 3
two recipients getting 30% and 60% respectively

Third threshold
min: 10
three recipients getting 40%, 50% and 10% respectively. The last recipient has no funds on testnet, doesn’t exist yet

Instantiation
https://explorer.testnet.andromedaprotocol.io/galileo-4/tx/3C12D67545573EBA2268700B2712E6D7AA74041629C11BA3F236D0BB05E3B3A0

Tx hash for sending 2000000uandr which is 2ANDR (1st threshold)
https://explorer.testnet.andromedaprotocol.io/galileo-4/tx/EA4F02523BC00AD3C85DCB5FB73E239D61B0EF80B0D0170C0F5930207509642D

Tx hash for sending 5000000uandr which is 5ANDR (2nd threshold)
https://explorer.testnet.andromedaprotocol.io/galileo-4/tx/F44F31C17A25F8F0DA5A28E2F5CE4741AAA0F0523E3B7005ECD13223EA011093

Tx hash for sending 10000000uandr which is 10ANDR (exactly at 3rd threshold)
https://explorer.testnet.andromedaprotocol.io/galileo-4/tx/F3C65D7E99994E767C17914858D2D260569B98AA1F3FF4B9E62DD5082DCA3476

Tx hash for sending 200000000uandr which is 200ANDR (3rd threshold)
https://explorer.testnet.andromedaprotocol.io/galileo-4/tx/8F86D8DE4342BFD8AC0DC55700CB0F7FC3526D04A39DA780DD2F93F2453E4765

Notes

lock_time in instantiation could use the new Expiry type.
It wasn't clear to me how many decimal places I should have included while attaching funds to the Send msg

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Introduced a Conditional Splitter contract for fund distribution with instantiation, execution, and configuration update functions.
  • Documentation

    • Improved JSON schemas for contract messages and response objects.
  • Tests

    • Expanded test coverage for contract functionalities including instantiation, execution, and configuration querying.

@joemonem joemonem linked an issue Apr 29, 2024 that may be closed by this pull request
5 tasks
@joemonem joemonem requested a review from crnbarr93 April 29, 2024 15:39
Copy link
Contributor

@crnbarr93 crnbarr93 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass looks good, just a few small changes

// Can't call this function while the lock isn't expired
if let Some(conditional_splitter_lock) = conditional_splitter.lock_time {
ensure!(
conditional_splitter_lock.is_expired(&env.block),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and the above comment are applicable to the regular splitter as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should remove it from both, remove it here and then we can remove it from the basic splitter in a separate PR. Seems odd to lock yourself out of the contract.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same goes for above

packages/andromeda-finance/src/conditional_splitter.rs Outdated Show resolved Hide resolved
);

min_value_set.insert(min_value);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if no threshold is set for Uint128::zero()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this unit test illustrates that case: test_execute_send_threshold_not_found

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to require a 0 threshold or is that too limiting?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be too limiting, but I think we should make it clear to the users that any funds sent below their lowest minimum will cause an error.

…heck for recipient's percentage, EmptyClassId error adjustment, add EmptyThresholdsList error
.generate_amp_msg(&deps.as_ref(), Some(vec_coin))?;
pkt = pkt.add_message(amp_msg);

// Non-zero checks have already been made for the incoming coins, so we check if the recipient's percentage is above zero.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rounding may cause a non-zero percentage to incur a zero send:

1% of 10 would generate 0.1, rounding would produce a 0 amount

Unless we always round up but that may cause issues with requiring more than 100% of the funds.

let mut vec_coin: Vec<Coin> = Vec::new();

let mut recip_coin: Coin = coin.clone();
recip_coin.amount = coin.amount * recipient_percent;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

recipient_percent is Decimal here and coin.amount is Uint128? Do we have any concerns of multiplying two differing types here?

Decimal is a Uint128 but with the last few digits being the "decimal".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In CosmWasm 2.0 they recommend doing the following:

let a = Uint128::new(123);
let b = Decimal::percent(150)

-let c = a * b;
+let c = a.mul_floor(b);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this definitely opens up a zero send edge case, we should protect against that.

@joemonem joemonem merged commit dc09dc3 into development May 20, 2024
9 checks passed
@joemonem joemonem deleted the joe/conditional-splitter branch May 20, 2024 12:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[EPIC] Conditional Splitter Contract
2 participants