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 2 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 @@ import {
PollResultCode,
PollResultErrors,
} from './types'
import { SupportedChainId } from 'src/common'
import { SupportedChainId } from '../common'
import { getComposableCow, getComposableCowInterface } from './contracts'

/**
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
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 CONDITIONAL_ORDER_LEAF_ABI = ['address', 'bytes32', 'bytes']

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 @@ export type Orders = Record<string, ConditionalOrder<any, any>>
* - 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 @@ -148,7 +148,7 @@ export class Multiplexer {
// 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 @@ export class Multiplexer {
* @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 @@ export class Multiplexer {
* @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 @@ export class Multiplexer {
* @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 @@ export class Multiplexer {
*/
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'
27 changes: 22 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,16 @@ export class Twap extends ConditionalOrder<TwapData, TwapStruct> {
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 {
const twap = Twap.deserialize(encodeParams(params))
return twap
anxolin marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* 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 @@ -283,12 +300,12 @@ export class Twap extends ConditionalOrder<TwapData, TwapStruct> {

/**
* 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 = {
// Register of all known order types
anxolin marked this conversation as resolved.
Show resolved Hide resolved
[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