-
Notifications
You must be signed in to change notification settings - Fork 2
Expose lt, eq, and gt #58
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -135,7 +135,6 @@ where | |
| pub struct Float(FixedBytes<32>); | ||
|
|
||
| impl Float { | ||
| #[allow(dead_code)] // will be used in future tests | ||
| #[cfg(test)] | ||
| fn pack_lossless(coefficient: I224, exponent: i32) -> Result<Self, FloatError> { | ||
| let calldata = DecimalFloat::packLosslessCall { | ||
|
|
@@ -150,6 +149,27 @@ impl Float { | |
| }) | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| fn unpack(self) -> Result<(I224, i32), FloatError> { | ||
| let Float(float) = self; | ||
| let calldata = DecimalFloat::unpackCall { float }.abi_encode(); | ||
|
|
||
| execute_call(Bytes::from(calldata), |output| { | ||
| let DecimalFloat::unpackReturn { | ||
| _0: coefficient, | ||
| _1: exponent, | ||
| } = DecimalFloat::unpackCall::abi_decode_returns(output.as_ref())?; | ||
|
|
||
| Ok((coefficient, exponent)) | ||
| }) | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| fn show_unpacked(self) -> Result<String, FloatError> { | ||
| let (coefficient, exponent) = self.unpack()?; | ||
| Ok(format!("{coefficient}e{exponent}")) | ||
| } | ||
|
|
||
| pub fn parse(str: String) -> Result<Self, FloatError> { | ||
| let calldata = DecimalFloat::parseCall { str }.abi_encode(); | ||
|
|
||
|
|
@@ -177,6 +197,39 @@ impl Float { | |
| Ok(decoded) | ||
| }) | ||
| } | ||
|
|
||
| pub fn lt(self, b: Self) -> Result<bool, FloatError> { | ||
| let Float(a) = self; | ||
| let Float(b) = b; | ||
| let calldata = DecimalFloat::ltCall { a, b }.abi_encode(); | ||
|
|
||
| execute_call(Bytes::from(calldata), |output| { | ||
| let decoded = DecimalFloat::ltCall::abi_decode_returns(output.as_ref())?; | ||
| Ok(decoded) | ||
| }) | ||
| } | ||
|
|
||
| pub fn eq(self, b: Self) -> Result<bool, FloatError> { | ||
| let Float(a) = self; | ||
| let Float(b) = b; | ||
| let calldata = DecimalFloat::eqCall { a, b }.abi_encode(); | ||
|
|
||
| execute_call(Bytes::from(calldata), |output| { | ||
| let decoded = DecimalFloat::eqCall::abi_decode_returns(output.as_ref())?; | ||
| Ok(decoded) | ||
| }) | ||
| } | ||
|
|
||
| pub fn gt(self, b: Self) -> Result<bool, FloatError> { | ||
| let Float(a) = self; | ||
| let Float(b) = b; | ||
| let calldata = DecimalFloat::gtCall { a, b }.abi_encode(); | ||
|
|
||
| execute_call(Bytes::from(calldata), |output| { | ||
| let decoded = DecimalFloat::gtCall::abi_decode_returns(output.as_ref())?; | ||
| Ok(decoded) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| impl Add for Float { | ||
|
|
@@ -305,4 +358,61 @@ mod tests { | |
| ); | ||
| } | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_lt_eq_gt() { | ||
| let negone = Float::parse("-1".to_string()).unwrap(); | ||
| let zero = Float::parse("0".to_string()).unwrap(); | ||
| let three = Float::parse("3".to_string()).unwrap(); | ||
|
|
||
| assert!(negone.lt(zero).unwrap()); | ||
| assert!(!negone.eq(zero).unwrap()); | ||
| assert!(!negone.gt(zero).unwrap()); | ||
|
|
||
| assert!(!three.lt(zero).unwrap()); | ||
| assert!(!three.eq(zero).unwrap()); | ||
| assert!(three.gt(zero).unwrap()); | ||
|
|
||
| assert!(zero.lt(three).unwrap()); | ||
| assert!(!zero.eq(three).unwrap()); | ||
| assert!(!zero.gt(three).unwrap()); | ||
| } | ||
|
|
||
| proptest! { | ||
| #[test] | ||
| fn test_lt_eq_gt_with_add(a in reasonable_float()) { | ||
| let b = a; | ||
| let eq = a.eq(b).unwrap(); | ||
| prop_assert!(eq); | ||
|
|
||
| let one = Float::parse("1".to_string()).unwrap(); | ||
|
|
||
| let a = (a - one).unwrap(); | ||
| let lt = a.lt(b).unwrap(); | ||
| prop_assert!(lt); | ||
|
|
||
| let a = (a + one).unwrap(); | ||
| let eq = a.eq(b).unwrap(); | ||
| prop_assert!(eq); | ||
|
|
||
| let a = (a + one).unwrap(); | ||
| let gt = a.gt(b).unwrap(); | ||
| prop_assert!(gt); | ||
| } | ||
|
Comment on lines
+382
to
+401
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Minor readability nit – heavy variable shadowing in property test Within let a = (a - one).unwrap(); // shadows
...
let a = (a + one).unwrap(); // shadows againUsing distinct identifiers ( 🤖 Prompt for AI Agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the current version is fine for the purpose of this test
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @0xgleb Understood! I'll respect your decision on the variable shadowing pattern in this property test. | 😔 |✏️ Learnings added
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is happening with ai in here lol
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| #[test] | ||
| fn test_exactly_one_lt_eq_gt(a in arb_float(), b in arb_float()) { | ||
| let eq = a.eq(b).unwrap(); | ||
| let lt = a.lt(b).unwrap(); | ||
| let gt = a.gt(b).unwrap(); | ||
|
|
||
| let a_str = a.show_unpacked().unwrap(); | ||
| let b_str = b.show_unpacked().unwrap(); | ||
|
|
||
| prop_assert!(lt || eq || gt, "a: {a_str}, b: {b_str}"); | ||
| prop_assert!(!(lt && eq), "both less than and equal: a: {a_str}, b: {b_str}"); | ||
| prop_assert!(!(eq && gt), "both equal and greater than: a: {a_str}, b: {b_str}"); | ||
| prop_assert!(!(lt && gt), "both less than and greater than: a: {a_str}, b: {b_str}"); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -171,4 +171,13 @@ contract DecimalFloat { | |||||||||||||||||||||||||||||||||
| function packLossless(int224 coefficient, int32 exponent) external pure returns (Float) { | ||||||||||||||||||||||||||||||||||
| return LibDecimalFloat.packLossless(coefficient, exponent); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /// Exposes `LibDecimalFloat.unpack` for offchain use. | ||||||||||||||||||||||||||||||||||
| /// @param float The float to unpack. | ||||||||||||||||||||||||||||||||||
| /// @return coefficient The coefficient of the float. | ||||||||||||||||||||||||||||||||||
| /// @return exponent The exponent of the float. | ||||||||||||||||||||||||||||||||||
| function unpack(Float float) external pure returns (int224, int32) { | ||||||||||||||||||||||||||||||||||
| (int256 coefficient, int256 exponent) = LibDecimalFloat.unpack(float); | ||||||||||||||||||||||||||||||||||
| return (int224(coefficient), int32(exponent)); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+175
to
+182
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Rename the parameter to avoid shadowing the Using -function unpack(Float float) external pure returns (int224, int32) {
- (int256 coefficient, int256 exponent) = LibDecimalFloat.unpack(float);
+function unpack(Float value) external pure returns (int224, int32) {
+ (int256 coefficient, int256 exponent) = LibDecimalFloat.unpack(value);
return (int224(coefficient), int32(exponent));
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is consistent with
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: Length of output: 31333 @0xgleb You're absolutely right! I can see that This establishes a clear naming convention that prioritizes consistency across the codebase. Thank you for the clarification! ✏️ Learnings added
|
||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Three comparison helpers duplicate boilerplate – consider a small macro
lt,eq, andgtshare identical call/decoding scaffolding. A tiny macro (or a privatefn cmp(self, b, Selector)) would remove six near-identical bodies and centralise potential future changes.Not blocking, just a DRY suggestion.
🤖 Prompt for AI Agents
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what
execute_callis forThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@0xgleb You're absolutely right! Looking at the code,
execute_callalready provides the appropriate abstraction layer by handling all the EVM execution boilerplate, error handling, and result processing. The remaining differences betweenlt,eq, andgtare minimal and necessary - each method needs to make a different contract call (ltCall,eqCall,gtCall) and decode the corresponding result type.The pattern is consistent throughout the codebase where
execute_callhandles the heavy lifting while each public method focuses on its specific call encoding and result decoding. Further abstraction would likely over-engineer the solution without meaningful benefit.✏️ Learnings added