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: migrate limit orders to utilize redux for state management #8112

Open
wants to merge 23 commits into
base: develop
Choose a base branch
from

Conversation

woodenfurniture
Copy link
Member

@woodenfurniture woodenfurniture commented Nov 11, 2024

Description

Migrates the WIP limit orders feature to utilize redux for state management. As the inputs of spot and limit trades are basically identical and contain extremely high risk code, a higher-order slice pattern has been adopted to deduplicate the logic and minimise surface area.

Also includes 2 fixes suggested by @NeOMakinG in #8095:

Issue (if applicable)

closes #8111

Risk

High Risk PRs Require 2 approvals

High risk. The migration to use of a new design pattern for trades means that although the core logic is left totally untouched, we should review and test this with extreme caution.

What protocols, transaction types, wallets or contract interactions might be affected by this PR?

All trades for all protocols, specifically trade input (including receive address, slippage, everything).

Testing

⚠️ For trades, no change from prod should be observed.

A complete regression test of trades should be completed, including various inputs, configs, swappers, multi-hop, custom recipient, different accounts, etc.

Engineering

Operations

  • 🏁 My feature is behind a flag and doesn't require operations testing (yet)

Screenshots (if applicable)

Swap via THORChain to manual receive address

Swap via LiFi to custom account number (#1) and custom slippage (1.5%)

Swap via CoW with custom slippage (1.5%)

Swap via 0x

*/
export const createTradeInputBaseSelectors = (sliceName: keyof ReduxState) => {
// Base selector to get the slice
const selectBaseSlice = (state: ReduxState) => state[sliceName] as TradeInputBaseState
Copy link
Contributor

Choose a reason for hiding this comment

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

ser that's turbo brain time 🧠

@woodenfurniture woodenfurniture changed the base branch from develop to limit-orders-more-input-wiring November 11, 2024 21:19
Base automatically changed from limit-orders-more-input-wiring to develop November 12, 2024 23:42
@woodenfurniture woodenfurniture marked this pull request as ready for review November 13, 2024 01:06
@woodenfurniture woodenfurniture requested a review from a team as a code owner November 13, 2024 01:06
Copy link
Collaborator

@NeOMakinG NeOMakinG left a comment

Choose a reason for hiding this comment

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

Pretty straighforward, there is no so much risks tbh it's basically taking the trade input slices and make it reusable so we don't duplicate things limit order logic (I'm not saying that it's not a big amount of work, nicely done @woodenfurniture 🐐 )

Small review, pending runtime testing that I'm going to do right now

Comment on lines 42 to 74
dispatch(limitOrderInput.actions.setManualReceiveAddress(undefined))
}, [dispatch])

const handleEditManualReceiveAddress = useCallback(() => {
setIsManualReceiveAddressEditing(true)
}, [])
dispatch(limitOrderInput.actions.setIsManualReceiveAddressEditing(true))
}, [dispatch])

const handleCancelManualReceiveAddress = useCallback(() => {
setIsManualReceiveAddressEditing(false)
dispatch(limitOrderInput.actions.setIsManualReceiveAddressEditing(false))
// Reset form value and valid state on cancel so the valid check doesn't wrongly evaluate to false after bailing out of editing an invalid address
setIsManualReceiveAddressValid(undefined)
}, [])
dispatch(limitOrderInput.actions.setIsManualReceiveAddressValid(undefined))
}, [dispatch])

const handleResetManualReceiveAddress = useCallback(() => {
// Reset the manual receive address in store
setManualReceiveAddress(undefined)
dispatch(limitOrderInput.actions.setManualReceiveAddress(undefined))
// Reset the valid state in store
setIsManualReceiveAddressValid(undefined)
}, [])
dispatch(limitOrderInput.actions.setIsManualReceiveAddressValid(undefined))
}, [dispatch])

const handleSubmitManualReceiveAddress = useCallback(
(address: string) => {
dispatch(limitOrderInput.actions.setManualReceiveAddress(address))
dispatch(limitOrderInput.actions.setIsManualReceiveAddressEditing(false))
},
[dispatch],
)

const handleIsManualReceiveAddressValidatingChange = useCallback(
(isValidating: boolean) => {
dispatch(limitOrderInput.actions.setIsManualReceiveAddressValidating(isValidating))
},
[dispatch],
)

const handleSubmitManualReceiveAddress = useCallback((address: string) => {
setManualReceiveAddress(address)
setIsManualReceiveAddressEditing(false)
}, [])
const handleIsManualReceiveAddressValidChange = useCallback(
(isValid: boolean) => {
dispatch(limitOrderInput.actions.setIsManualReceiveAddressValid(isValid))
},
[dispatch],
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

q: don't you want to use your new super hook?

Copy link
Member Author

Choose a reason for hiding this comment

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

OoOoOoooh actually yes will do for this one!

Copy link
Member Author

Choose a reason for hiding this comment

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

ebc7b62 🎉

@@ -29,14 +29,14 @@ export const RecipientAddress = ({

const handleIsValidatingChange = useCallback(
(isValidating: boolean) => {
dispatch(tradeInput.actions.setManualReceiveAddressIsValidating(isValidating))
dispatch(tradeInput.actions.setIsManualReceiveAddressValidating(isValidating))
Copy link
Collaborator

Choose a reason for hiding this comment

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

rubber: surely you didn't use your new hook pattern because you want to avoid too much diffs, what's the plan for these, should we plan to refactor them at some point or it will just be used in the future as a more convenient way?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes we could refactor them later, or when convenient. But yeah, avoided doing it here to minimise diff on this PR.

const dispatch = useDispatch()

return useMemo(() => bindActionCreators(actions, dispatch), [actions, dispatch])
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

sexy

Comment on lines 59 to +61
const tradeAmountUsd = bn(FEE_CURVE_NO_FEE_THRESHOLD_USD + 0.01)
const foxHeld = bn(0)
const isSnapshotApiQueriesRejected = selectIsSnapshotApiQueriesRejected(store.getState())
Copy link
Collaborator

Choose a reason for hiding this comment

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

very-nitpick: pretty sure you could do it in a beforeEach instead

@@ -64,7 +69,7 @@ export const calculateFees: CalculateFeeBps = ({ tradeAmountUsd, foxHeld, feeMod
new Date().getUTCFullYear() < THORSWAP_MAXIMUM_YEAR_TRESHOLD

// failure to fetch fox discount results in free trades.
const isFallbackFees = selectIsSnapshotApiQueriesRejected(store.getState())
const isFallbackFees = isSnapshotApiQueriesRejected
Copy link
Collaborator

Choose a reason for hiding this comment

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

rubber-duck: oh, now I get it, it's way saner like this from a functional programming perspective, did you change it for this reason or there were a limitation I can't find?

Copy link
Member Author

Choose a reason for hiding this comment

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

There were circular dependencies because this file was importing redux, but redux slice was import this file ♻️. To break the cycle I opted to just add a parameter

Copy link
Collaborator

@NeOMakinG NeOMakinG left a comment

Choose a reason for hiding this comment

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

✅ THORChain => ARB

https://jam.dev/c/794b1c7b-ae13-446c-829a-158f3316a8ce

✅ Li.Fi Multi hop

https://jam.dev/c/13233bb7-e02b-4457-8fd3-ab62cd6bd93d
⚠️ I had a problem with the second hop but I think it's unrelated, can you confirm @woodenfurniture ?

✅ 0x single hop

https://jam.dev/c/2535485d-f872-4f3d-9359-1c4a54caaefb

✅ Portals swap with custom slippage (1.5%)

https://jam.dev/c/224ad78d-84df-40fc-bc18-ba402023114b

✅ Custom receive address

https://jam.dev/c/4a4765ad-f4c2-4ba1-b0e1-92b33153082f

General smoke test

image

Small visual issue, the centered content is sticked to the top (not blocking)
Learn more text is bigger than regular text

https://jam.dev/c/96b774bb-f0b8-46b3-9007-8c591cc9cb3d

Looks good to me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Redux slice for limit orders input
3 participants