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

Add Conditional Order factory #151

Merged
merged 3 commits into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cowprotocol/cow-sdk",
"version": "3.0.0-rc.1",
"version": "3.0.0-rc.3",
"license": "(MIT OR Apache-2.0)",
"files": [
"/dist"
Expand Down
2 changes: 1 addition & 1 deletion src/composable/ConditionalOrder.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ConditionalOrder } from './ConditionalOrder'
import { IsValidResult, PollResultErrors } from './types'
import { Twap } from './types/Twap'
import { Twap } from './orderTypes/Twap'
import { encodeParams } from './utils'

const TWAP_SERIALIZED = (salt?: string, handler?: string): string => {
Expand Down
2 changes: 1 addition & 1 deletion src/composable/ConditionalOrder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
PollResultCode,
PollResultErrors,
} from './types'
import { SupportedChainId } from 'src/common'
import { SupportedChainId } from '../common'
import { getComposableCow, getComposableCowInterface } from './contracts'

/**
Expand Down Expand Up @@ -345,7 +345,7 @@
s: string,
handler: string,
orderDataTypes: string[],
callback: (d: any, salt: string) => T

Check warning on line 348 in src/composable/ConditionalOrder.ts

View workflow job for this annotation

GitHub Actions / eslint

Unexpected any. Specify a different type
): T {
try {
// First, decode the `IConditionalOrder.Params` struct
Expand All @@ -359,7 +359,7 @@

// Create a new instance of the class
return callback(d, salt)
} catch (e: any) {

Check warning on line 362 in src/composable/ConditionalOrder.ts

View workflow job for this annotation

GitHub Actions / eslint

Unexpected any. Specify a different type
if (e.message === 'HandlerMismatch') {
throw e
} else {
Expand Down
24 changes: 24 additions & 0 deletions src/composable/ConditionalOrderFactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { type ConditionalOrder } from './ConditionalOrder'
import { ConditionalOrderParams } from './types'

export type FromParams<D, S> = (params: ConditionalOrderParams) => ConditionalOrder<D, S>
export type ConditionalOrderRegistry = Record<string, FromParams<unknown, unknown>>

export class ConditionalOrderFactory {
public knownOrderTypes

constructor(registry: ConditionalOrderRegistry) {
this.knownOrderTypes = registry
}

public fromParams(params: ConditionalOrderParams): ConditionalOrder<unknown, unknown> | undefined {
const { handler } = params

const factory = this.knownOrderTypes[handler]
if (!factory) {
return undefined
}

return factory(params)
}
}
4 changes: 2 additions & 2 deletions src/composable/Multiplexer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Multiplexer, Orders } from './Multiplexer'
import { SupportedChainId } from '../common'
import { ProofLocation } from './types'
import { Twap } from './types/Twap'
import { TWAP_PARAMS_TEST, generateRandomTWAPData } from './types/Twap.spec'
import { Twap } from './orderTypes/Twap'
import { TWAP_PARAMS_TEST, generateRandomTWAPData } from './orderTypes/Twap.spec'
import { getComposableCowInterface } from './contracts'
import { BigNumber } from 'ethers'

Expand Down Expand Up @@ -85,7 +85,7 @@
expect(m.orderIds.length).toEqual(1)

// Update the second order, in that we'll just replace it with the first order
m.update(twap2.id, (_o) => twap)

Check warning on line 88 in src/composable/Multiplexer.spec.ts

View workflow job for this annotation

GitHub Actions / eslint

'_o' is defined but never used

// Confirm that the multiplexer has one order
expect(m.orderIds.length).toEqual(1)
Expand Down Expand Up @@ -259,7 +259,7 @@
}

// define an async upload function
const upload = async (_data: string): Promise<string> => {

Check warning on line 262 in src/composable/Multiplexer.spec.ts

View workflow job for this annotation

GitHub Actions / eslint

'_data' is defined but never used
return 'baddata'
}

Expand All @@ -270,7 +270,7 @@
}

// define an upload function that throws an error
const upload2 = async (_data: string): Promise<string> => {

Check warning on line 273 in src/composable/Multiplexer.spec.ts

View workflow job for this annotation

GitHub Actions / eslint

'_data' is defined but never used
throw new Error('bad')
}

Expand Down
17 changes: 10 additions & 7 deletions src/composable/Multiplexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

const PAYLOAD_EMITTED_ABI = ['tuple(bytes32[] proof, tuple(address handler, bytes32 salt, bytes staticInput) params)[]']

export type Orders = Record<string, ConditionalOrder<any, any>>
export type Orders = Record<string, ConditionalOrder<unknown, unknown>>

/**
* Multiplexer for conditional orders - using `ComposableCoW`!
Expand All @@ -24,7 +24,7 @@
* - Support for passing an optional upload function to upload the proofs to a decentralized storage network
*/
export class Multiplexer {
static orderTypeRegistry: Record<string, new (...args: any[]) => ConditionalOrder<any, any>> = {}
static orderTypeRegistry: Record<string, new (...args: unknown[]) => ConditionalOrder<unknown, unknown>> = {}

public chain: SupportedChainId
public location: ProofLocation
Expand Down Expand Up @@ -97,7 +97,7 @@
*/
static fromJSON(s: string): Multiplexer {
// reviver function to deserialize the orders
const reviver = (k: string, v: any) => {

Check warning on line 100 in src/composable/Multiplexer.ts

View workflow job for this annotation

GitHub Actions / eslint

Unexpected any. Specify a different type
if (k === 'orders' && typeof v === 'object' && v !== null) {
const orders: Orders = {}

Expand Down Expand Up @@ -148,7 +148,7 @@
// filter out the merkle tree
if (k === 'tree') return undefined
if (typeof v === 'object' && v !== null && 'orderType' in v) {
const conditionalOrder = v as ConditionalOrder<any, any>
const conditionalOrder = v as ConditionalOrder<unknown, unknown>
return {
...conditionalOrder,
orderType: conditionalOrder.orderType,
Expand Down Expand Up @@ -186,7 +186,10 @@
* @param id The id of the `ConditionalOrder` to update.
* @param updater A function that takes the existing `ConditionalOrder` and context, returning an updated `ConditionalOrder`.
*/
update<T, P>(id: string, updater: (order: ConditionalOrder<T, P>, ctx?: string) => ConditionalOrder<T, P>): void {
update(
id: string,
updater: (order: ConditionalOrder<unknown, unknown>, ctx?: string) => ConditionalOrder<unknown, unknown>
): void {
// copy the existing order and update it, given the existing context (if any)
const order = updater(this.orders[id], this.ctx)
// delete the existing order
Expand All @@ -204,7 +207,7 @@
* @param id The `id` of the `ConditionalOrder` to retrieve.
* @returns A `ConditionalOrder` with the given `id`.
*/
getById(id: string): ConditionalOrder<any, any> {
getById(id: string): ConditionalOrder<unknown, unknown> {
return this.orders[id]
}

Expand All @@ -213,7 +216,7 @@
* @param i The index of the `ConditionalOrder` to retrieve.
* @returns A `ConditionalOrder` at the given index.
*/
getByIndex(i: number): ConditionalOrder<any, any> {
getByIndex(i: number): ConditionalOrder<unknown, unknown> {
return this.orders[this.orderIds[i]]
}

Expand Down Expand Up @@ -431,7 +434,7 @@
*/
public static registerOrderType(
orderType: string,
conditionalOrderClass: new (...args: any[]) => ConditionalOrder<any, any>
conditionalOrderClass: new (...args: unknown[]) => ConditionalOrder<unknown, unknown>
) {
Multiplexer.orderTypeRegistry[orderType] = conditionalOrderClass
}
Expand Down
2 changes: 2 additions & 0 deletions src/composable/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ export * from './types'
export * from './utils'
export * from './ConditionalOrder'
export * from './Multiplexer'
export * from './ConditionalOrderFactory'
export * from './orderTypes'
26 changes: 21 additions & 5 deletions src/composable/types/Twap.ts → src/composable/orderTypes/Twap.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { BigNumber, constants, providers } from 'ethers'

import { ConditionalOrder } from '../ConditionalOrder'
import { ConditionalOrderArguments, ContextFactory, IsNotValid, IsValid, PollResultErrors } from '../types'
import {
ConditionalOrderArguments,
ConditionalOrderParams,
ContextFactory,
IsNotValid,
IsValid,
PollResultErrors,
} from '../types'
import { encodeParams, isValidAbi } from '../utils'
import { SupportedChainId } from 'src/common'
import { SupportedChainId } from '../../common'
alfetopito marked this conversation as resolved.
Show resolved Hide resolved

// The type of Conditional Order
const TWAP_ORDER_TYPE = 'twap'
Expand Down Expand Up @@ -179,6 +186,15 @@
return new Twap({ handler: TWAP_ADDRESS, data })
}

/**
* Create a TWAP order with sound defaults.
* @param data The TWAP order parameters in a more user-friendly format.
* @returns An instance of the TWAP order.
*/
static fromParams(params: ConditionalOrderParams): Twap {
return Twap.deserialize(encodeParams(params))
}

/**
* Enforces that TWAPs will commence at the beginning of a block by use of the
* `CurrentBlockTimestampFactory` contract to provide the current block timestamp
Expand Down Expand Up @@ -256,9 +272,9 @@
* @returns true if the owner authorized the order, false otherwise.
*/
protected async pollValidate(
_owner: string,

Check warning on line 275 in src/composable/orderTypes/Twap.ts

View workflow job for this annotation

GitHub Actions / eslint

'_owner' is defined but never used
_chain: SupportedChainId,

Check warning on line 276 in src/composable/orderTypes/Twap.ts

View workflow job for this annotation

GitHub Actions / eslint

'_chain' is defined but never used
_provider: providers.Provider

Check warning on line 277 in src/composable/orderTypes/Twap.ts

View workflow job for this annotation

GitHub Actions / eslint

'_provider' is defined but never used
): Promise<PollResultErrors | undefined> {
// TODO: Do not check again expired order
// TODO: Calculate the next part start time, signal to not check again until then
Expand All @@ -283,12 +299,12 @@

/**
* Deserialize a TWAP order from it's ABI-encoded form.
* @param {string} s ABI-encoded TWAP order to deserialize.
* @param {string} twapSerialized ABI-encoded TWAP order to deserialize.
* @returns A deserialized TWAP order.
*/
static deserialize(s: string): Twap {
static deserialize(twapSerialized: string): Twap {
return super.deserializeHelper(
s,
twapSerialized,
TWAP_ADDRESS,
TWAP_STRUCT_ABI,
(struct: TwapStruct, salt: string) =>
Expand Down
8 changes: 8 additions & 0 deletions src/composable/orderTypes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ConditionalOrderRegistry } from '../ConditionalOrderFactory'
import { TWAP_ADDRESS, Twap } from './Twap'
export * from './Twap'

export const DEFAULT_CONDITIONAL_ORDER_REGSTRY: ConditionalOrderRegistry = {
// Registry of all known order types
[TWAP_ADDRESS]: (params) => Twap.fromParams(params),
}
4 changes: 2 additions & 2 deletions src/composable/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export type ContextFactory = {
address: string
// Any arguments that will be passed to the `IValueFactory` to resolve the context.
factoryArgs?: {
args: any[]
args: unknown[]
argsType: string[]
}
}
Expand Down Expand Up @@ -104,7 +104,7 @@ export interface PollResultSuccess {

export interface PollResultUnexpectedError {
readonly result: PollResultCode.UNEXPECTED_ERROR
readonly error: any
readonly error: unknown
}

export interface PollResultTryNextBlock {
Expand Down
1 change: 0 additions & 1 deletion src/composable/types/index.ts

This file was deleted.

21 changes: 19 additions & 2 deletions src/composable/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
import { decodeParams, encodeParams, isValidAbi } from './utils'
import { TwapStruct, transformDataToStruct } from './types/Twap'
import { TWAP_PARAMS_TEST } from './types/twap.spec'
import { DurationType, StartTimeValue, TwapData, TwapStruct, transformDataToStruct } from './orderTypes/Twap'
import { BigNumber, utils } from 'ethers'

export const TWAP_PARAMS_TEST: TwapData = {
sellToken: '0x6810e776880C02933D47DB1b9fc05908e5386b96',
buyToken: '0xDAE5F1590db13E3B40423B5b5c5fbf175515910b',
receiver: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
sellAmount: utils.parseEther('1'),
buyAmount: utils.parseEther('1'),
timeBetweenParts: BigNumber.from(60 * 60),
numberOfParts: BigNumber.from(10),
durationOfPart: {
durationType: DurationType.AUTO,
},
startTime: {
startType: StartTimeValue.AT_MINING_TIME,
},
appData: '0xd51f28edffcaaa76be4a22f6375ad289272c037f3cc072345676e88d92ced8b5',
}

const TWAP_STRUCT_ABI = [
'tuple(address sellToken, address buyToken, address receiver, uint256 partSellAmount, uint256 minPartLimit, uint256 t0, uint256 n, uint256 t, uint256 span, bytes32 appData)',
Expand Down
Loading