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

Poll conditional orders + Allow custom logic to delay checks to a given date, block, or forever #149

Merged
merged 17 commits into from
Aug 24, 2023

Conversation

anxolin
Copy link
Contributor

@anxolin anxolin commented Aug 23, 2023

Implement some basic Polling
Also, applies some follow-ups from: comments in #147

Implement a Polling (as a Template Method in ComposableCow)

This generic polling logic will check the following:

  • 1. Validate concrete order: The order might have wrong parameters (or malformed ones). This method verifies it. In case it fils it will describe what was the issue (returns a reason).
  • 2. Poll validate: Let's concretely order apply some polling validation. It will return undefined if the polling checks should continue, otherwise it will instruct that is not time to create an order. For this, it can signal:
    • 2.1 TRY_NEXT_BLOCK: This block is not good, but next one might
    • 2.2 TRY_ON_BLOCK: This block is not good, but try again in the given blockNumber
    • 2.3 TRY_AT_DATE: This block is not good, but try again after a given date
    • 2.4 DONT_TRY_AGAIN: This block is not good, but also the following blocks. Please don't try again because it will keep not being the right time!
  • 3. Is Authorised: Verify if the owner authorised the order
  • 4. Lastly, CALL getTradeableOrderWithSignature: Last check is to call and obtain the order. Ideally, most of the errors should have been handled before calling this function, this way, we only do this call when we are almost sure it will succeed.

isAuthorised

Method in ComposableCow to check if the order is authorised.

Exposed as public method, but also convenient for the polling logic.
image

Removed validation from constructor

I thought it was best to not do a validation in the constructor of the order, so we can programmatically call to isValid

Also the method isValid doesn't throw any more, instead returns the reason. This reasons are convenient for other methods like poll to give a good description of why the order is not yet ready.

Now polling can instruct to never poll again that smart order, and return a good reason why:
image

Generics for ConditionalOrders

Changed back to T and P as suggested in #147

Not implemented in this PR (follow up coming)

Custom logic in Twap conditional order to postpone some checks for the future (instead of checking on each block)

I left some TODOs:
image

@github-actions
Copy link

CLA Assistant Lite bot:
Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution. You can sign the CLA by just posting a Pull Request Comment same as the below format.


I have read the CLA Document and I hereby sign the CLA


You can retrigger this bot by commenting recheck in this Pull Request

@anxolin anxolin changed the base branch from main to small-nit-suggestions August 23, 2023 15:51
@coveralls
Copy link
Collaborator

coveralls commented Aug 23, 2023

Coverage Status

coverage: 77.586% (-3.8%) from 81.422% when pulling e7f2ae0 on poll-conditional-orders into a4c398c on small-nit-suggestions.

@anxolin anxolin changed the title Poll conditional orders Poll conditional orders + Allow custom logic to delay checks to a given date, block, or forever Aug 23, 2023
@anxolin anxolin requested review from mfw78 and a team August 23, 2023 17:06
Copy link
Contributor

@mfw78 mfw78 left a comment

Choose a reason for hiding this comment

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

Looks good overall. A few nits. Specifically with reference to ConditionalOrder, there does seem some ability for SDK users to confuse staticInput and data.

While comments are left suggesting to have a sharp delineation between SDK user and the SDK's internals (ie. data passed by the user, everything within the SDK talking about staticInput), if there's a strong opinion to go this way, that's cool, but I'd suggest documenting this in a @remark JSdoc note in the class' constructor so that SDK maintainers can link between the SDK and the smart contract mentally.

Comment on lines 308 to 374
return !o.n.isZero()
? {
partSellAmount: o.sellAmount.div(o.n),
minPartLimit: o.buyAmount.div(o.n),
}
: {
partSellAmount: BigNumber.from(0),
minPartLimit: BigNumber.from(0),
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure about this. I don't think a TWAP should ever be able to be instantiated with invalid data, and it would be invalid if the condition o.n >= 2 isn't satisfied.

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess it's a protection for division by zero error

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, it is a protection from division by zero.

I feel like, to make this generic, it would be nice to allow to create an invalid Twap class, and then validate it and get the error you have.

This is why I prefer to not throw in the constructor, and let the SDK user decide.

This way, you can blindly create the order from the staticInput and make use of the methods of the class.
I can experiment later using this in WatchTower, and we can decide to move it back to the constructor if we see is a bad idea.

src/composable/types.ts Outdated Show resolved Hide resolved
src/composable/types.ts Outdated Show resolved Hide resolved
src/composable/types/Twap.spec.ts Show resolved Hide resolved
src/composable/ConditionalOrder.ts Outdated Show resolved Hide resolved
src/composable/ConditionalOrder.ts Show resolved Hide resolved
Comment on lines 130 to 137
// Second, verify that the order params are logically valid
Twap.isValid(staticInput)

// Third, construct the base class using transformed parameters
super({ handler: TWAP_ADDRESS, salt, staticInput, hasOffChainInput })

// Finally, verify that the transformed data is ABI-encodable
if (!isValidAbi(TWAP_DATA_ABI, [this.staticInput])) throw new Error('InvalidData')
Copy link
Contributor

Choose a reason for hiding this comment

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

If we can instantiate a concrete order that isn't valid at all times, I'd suggest that in Multiplexer within the add function that validation takes place to avoid SDK users inserting invalid orders (ideally, these should be caught well before the merkle tree attempts to generate itself).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great point!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added the check, and a test for it (great catch):

image

src/composable/types/Twap.ts Show resolved Hide resolved
Copy link
Contributor

@shoom3301 shoom3301 left a comment

Choose a reason for hiding this comment

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

Haven't tested, but code looks perfect!

@alfetopito
Copy link
Contributor

Unit tests are not happy

*/
export type TwapData = {
export type TwapDataBase = {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Shared model between the struct and the data

Copy link
Contributor

Choose a reason for hiding this comment

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

🚀🚀

@anxolin anxolin marked this pull request as ready for review August 24, 2023 11:45
@anxolin anxolin mentioned this pull request Aug 24, 2023
2 tasks
@anxolin anxolin changed the base branch from small-nit-suggestions to main August 24, 2023 12:57
@anxolin anxolin merged commit 019865a into main Aug 24, 2023
1 of 3 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Aug 24, 2023
@alfetopito alfetopito deleted the poll-conditional-orders branch August 24, 2023 14:11
@alfetopito
Copy link
Contributor

@anxolin unit tests were still broken

Copy link
Contributor

@mfw78 mfw78 left a comment

Choose a reason for hiding this comment

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

Excellent work! Some small nits on typos, and methodology for authorizing proofs.

UNEXPECTED_ERROR = 'UNEXPECTED_ERROR',
TRY_NEXT_BLOCK = 'TRY_NEXT_BLOCK',
TRY_ON_BLOCK = 'TRY_ON_BLOCK',
TRY_AT_EPOCH = 'TRY_AT_DATE',
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: consistency

import { ComposableCoW, ComposableCoW__factory } from './generated'
import { ComposableCoWInterface } from './generated/ComposableCoW'

let iCcomposableCow: ComposableCoWInterface | undefined
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: suspected typo for isComposableCow ?

src/composable/ConditionalOrder.ts Show resolved Hide resolved
* Poll a conditional order to see if it is tradeable.
*
* @param owner The owner of the conditional order.
* @param p The proof and parameters.
Copy link
Contributor

Choose a reason for hiding this comment

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

The proof isn't potentially passed in. Suggest that this be an optional parameter (array of strings).

}

// Check if the owner authorised the order
const isAuthorized = await this.isAuthorized(owner, chain, provider)
Copy link
Contributor

Choose a reason for hiding this comment

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

At this point, the proof parameter would be passed as an optional parameter.

if (!(sellToken != constants.AddressZero && buyToken != constants.AddressZero)) return 'InvalidToken'
if (!sellAmount.gt(constants.Zero)) return 'InvalidSellAmount'
if (!buyAmount.gt(constants.Zero)) return 'InvalidMinBuyAmount'
if (startTime.startType === StartTimeValue.AT_EPOC) {
Copy link
Contributor

Choose a reason for hiding this comment

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

EPOCH typo


const startTime: StartTime = span.isZero()
? { startType: StartTimeValue.AT_MINING_TIME }
: { startType: StartTimeValue.AT_EPOC, epoch: startEpoch }
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo

src/composable/Multiplexer.spec.ts Show resolved Hide resolved
Comment on lines +102 to +108
test("Can't add invalid conditional orders", () => {
// Given an invalid order, don't allow to add it to the multiplexer
const m = new Multiplexer(SupportedChainId.GNOSIS_CHAIN)
const invalidTwap = Twap.fromData({ ...generateRandomTWAPData(), timeBetweenParts: BigNumber.from(-1) })
expect(() => m.add(invalidTwap)).toThrow('Invalid order: InvalidFrequency')
})

Copy link
Contributor

Choose a reason for hiding this comment

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

🚀

expect(
Twap.fromData({
...TWAP_PARAMS_TEST,
startTime: { startType: StartTimeValue.AT_EPOC, epoch: BigNumber.from(-1) },
Copy link
Contributor

Choose a reason for hiding this comment

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

typo 👍

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

Successfully merging this pull request may close these issues.

5 participants