-
Notifications
You must be signed in to change notification settings - Fork 10
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
Conversation
CLA Assistant Lite bot: I have read the CLA Document and I hereby sign the CLA You can retrigger this bot by commenting recheck in this Pull Request |
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.
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.
src/composable/types/Twap.ts
Outdated
return !o.n.isZero() | ||
? { | ||
partSellAmount: o.sellAmount.div(o.n), | ||
minPartLimit: o.buyAmount.div(o.n), | ||
} | ||
: { | ||
partSellAmount: BigNumber.from(0), | ||
minPartLimit: BigNumber.from(0), | ||
} |
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.
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.
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.
I guess it's a protection for division by zero
error
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.
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/Twap.ts
Outdated
// 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') |
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.
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).
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.
Great point!
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.
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.
Haven't tested, but code looks perfect!
Unit tests are not happy |
*/ | ||
export type TwapData = { | ||
export type TwapDataBase = { |
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.
Shared model between the struct and the data
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.
🚀🚀
fa68c36
to
433615e
Compare
433615e
to
9931e1e
Compare
@anxolin unit tests were still broken |
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.
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', |
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.
Nit: consistency
import { ComposableCoW, ComposableCoW__factory } from './generated' | ||
import { ComposableCoWInterface } from './generated/ComposableCoW' | ||
|
||
let iCcomposableCow: ComposableCoWInterface | undefined |
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.
nit: suspected typo for isComposableCow
?
* Poll a conditional order to see if it is tradeable. | ||
* | ||
* @param owner The owner of the conditional order. | ||
* @param p The proof and parameters. |
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.
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) |
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.
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) { |
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.
EPOCH typo
|
||
const startTime: StartTime = span.isZero() | ||
? { startType: StartTimeValue.AT_MINING_TIME } | ||
: { startType: StartTimeValue.AT_EPOC, epoch: startEpoch } |
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.
Typo
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') | ||
}) | ||
|
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.
🚀
expect( | ||
Twap.fromData({ | ||
...TWAP_PARAMS_TEST, | ||
startTime: { startType: StartTimeValue.AT_EPOC, epoch: BigNumber.from(-1) }, |
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.
typo 👍
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:
reason
).undefined
if the polling checks should continue, otherwise it will instruct that is not time to create an order. For this, it can signal:TRY_NEXT_BLOCK
: This block is not good, but next one mightTRY_ON_BLOCK
: This block is not good, but try again in the givenblockNumber
TRY_AT_DATE
: This block is not good, but try again after a givendate
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!isAuthorised
Method in ComposableCow to check if the order is authorised.
Exposed as public method, but also convenient for the
polling
logic.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 likepoll
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:
Generics for ConditionalOrders
Changed back to
T
andP
as suggested in #147Not 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: