From 78719422e34de0d3833b388c6f93e88eb6838207 Mon Sep 17 00:00:00 2001 From: Anxo Rodriguez Date: Tue, 7 Nov 2023 18:21:39 +0000 Subject: [PATCH 1/4] Add widget meta-data --- src/generatedTypes/index.ts | 9 ++- src/generatedTypes/v0.11.0.ts | 140 +++++++++++++++++++++++++++++++++ src/schemas/v0.11.0.json | 62 +++++++++++++++ src/schemas/widget/v0.1.0.json | 23 ++++++ 4 files changed, 231 insertions(+), 3 deletions(-) create mode 100644 src/generatedTypes/v0.11.0.ts create mode 100644 src/schemas/v0.11.0.json create mode 100644 src/schemas/widget/v0.1.0.json diff --git a/src/generatedTypes/index.ts b/src/generatedTypes/index.ts index e9f40af..ce9dd4c 100644 --- a/src/generatedTypes/index.ts +++ b/src/generatedTypes/index.ts @@ -2,6 +2,7 @@ import * as v0_1_0 from './v0.1.0' import * as v0_10_0 from './v0.10.0' +import * as v0_11_0 from './v0.11.0' import * as v0_2_0 from './v0.2.0' import * as v0_3_0 from './v0.3.0' import * as v0_4_0 from './v0.4.0' @@ -11,9 +12,9 @@ import * as v0_7_0 from './v0.7.0' import * as v0_8_0 from './v0.8.0' import * as v0_9_0 from './v0.9.0' -export * as latest from './v0.10.0' +export * as latest from './v0.11.0' -export const LATEST_APP_DATA_VERSION = '0.10.0' +export const LATEST_APP_DATA_VERSION = '0.11.0' export const LATEST_QUOTE_METADATA_VERSION = '0.3.0' export const LATEST_REFERRER_METADATA_VERSION = '0.2.0' export const LATEST_ORDER_CLASS_METADATA_VERSION = '0.3.0' @@ -21,8 +22,9 @@ export const LATEST_UTM_METADATA_VERSION = '0.2.0' export const LATEST_HOOKS_METADATA_VERSION = '0.1.0' export const LATEST_SIGNER_METADATA_VERSION = '0.1.0' -export type LatestAppDataDocVersion = v0_10_0.AppDataRootSchema +export type LatestAppDataDocVersion = v0_11_0.AppDataRootSchema export type AnyAppDataDocVersion = + | v0_11_0.AppDataRootSchema | v0_10_0.AppDataRootSchema | v0_9_0.AppDataRootSchema | v0_8_0.AppDataRootSchema @@ -35,6 +37,7 @@ export type AnyAppDataDocVersion = | v0_1_0.AppDataRootSchema export { + v0_11_0, v0_10_0, v0_9_0, v0_8_0, diff --git a/src/generatedTypes/v0.11.0.ts b/src/generatedTypes/v0.11.0.ts new file mode 100644 index 0000000..ba62dd9 --- /dev/null +++ b/src/generatedTypes/v0.11.0.ts @@ -0,0 +1,140 @@ +/* tslint:disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +/** + * Semantic versioning of document. + */ +export type Version = string; +/** + * The code identifying the CLI, UI, service generating the order. + */ +export type AppCode = string; +/** + * Environment from which the order came from. + */ +export type Environment = string; +/** + * The address of the trader who signs the CoW Swap order. This field should normally be omitted; it is recommended to use it if the signer is a smart-contract wallet using EIP-1271 signatures. + */ +export type Signer = string; +export type ReferrerAddress = string; +/** + * Tracks in which medium the traffic originated from (twitter, facebook, etc.) + */ +export type UTMSource = string; +/** + * Tracks in which medium the traffic originated from (mail, CPC, social, etc.) + */ +export type UTMMedium = string; +/** + * Track the performance of a specific campaign + */ +export type UTMCampaign = string; +/** + * Track which link was clicked + */ +export type UTMContent = string; +/** + * Track which keyword term a website visitor came from + */ +export type UTMKeywordTerm = string; +/** + * Slippage tolerance that was applied to the order to get the limit price. Expressed in Basis Points (BIPS) + */ +export type SlippageBips = string; +/** + * Indicator of the order class. + */ +export type OrderClass1 = "market" | "limit" | "liquidity" | "twap"; +/** + * Semantic versioning of document. + */ +export type Version1 = string; +/** + * The contract to call for the hook + */ +export type HookTarget = string; +/** + * The calldata to use when calling the hook + */ +export type HookCallData = string; +/** + * The gas limit (in gas units) for the hook + */ +export type HookGasLimit = string; +/** + * CoW Hooks to call before an order executes + */ +export type PreHooks = CoWHook[]; +/** + * CoW Hooks to call after an order executes + */ +export type PostHooks = CoWHook[]; +/** + * The code identifying the UI powering the widget + */ +export type AppCode1 = string; +/** + * Environment from which the order came from. + */ +export type Environment1 = string; + +/** + * Metadata JSON document for adding information to orders. + */ +export interface AppDataRootSchema { + version: Version; + appCode?: AppCode; + environment?: Environment; + metadata: Metadata; +} +/** + * Each metadata will specify one aspect of the order. + */ +export interface Metadata { + signer?: Signer; + referrer?: Referrer; + utm?: UTMCodes; + quote?: Quote; + orderClass?: OrderClass; + hooks?: OrderInteractionHooks; + widget?: Widget; +} +export interface Referrer { + address: ReferrerAddress; +} +export interface UTMCodes { + utmSource?: UTMSource; + utmMedium?: UTMMedium; + utmCampaign?: UTMCampaign; + utmContent?: UTMContent; + utmTerm?: UTMKeywordTerm; +} +export interface Quote { + slippageBips: SlippageBips; +} +export interface OrderClass { + orderClass: OrderClass1; +} +/** + * Optional Pre and Post order interaction hooks attached to a single order + */ +export interface OrderInteractionHooks { + version?: Version1; + pre?: PreHooks; + post?: PostHooks; +} +export interface CoWHook { + target: HookTarget; + callData: HookCallData; + gasLimit: HookGasLimit; +} +export interface Widget { + appCode?: AppCode1; + environment?: Environment1; + [k: string]: unknown; +} diff --git a/src/schemas/v0.11.0.json b/src/schemas/v0.11.0.json new file mode 100644 index 0000000..4560e96 --- /dev/null +++ b/src/schemas/v0.11.0.json @@ -0,0 +1,62 @@ +{ + "$id": "https://cowswap.exchange/schemas/app-data/v0.10.0.json", + "$schema": "http://json-schema.org/draft-07/schema", + "description": "Metadata JSON document for adding information to orders.", + "required": ["version", "metadata"], + "title": "AppData Root Schema", + "type": "object", + "additionalProperties": false, + "properties": { + "version": { + "$ref": "definitions.json#/definitions/version", + "readOnly": true, + "default": "0.11.0" + }, + "appCode": { + "$id": "#/properties/appCode", + "description": "The code identifying the CLI, UI, service generating the order.", + "examples": ["CoW Swap"], + "title": "App Code", + "type": "string" + }, + "environment": { + "$id": "#/properties/environment", + "description": "Environment from which the order came from.", + "title": "Environment", + "type": "string", + "examples": ["production", "development", "staging", "ens"] + }, + "metadata": { + "$id": "#/properties/metadata", + "default": {}, + "description": "Each metadata will specify one aspect of the order.", + "required": [], + "title": "Metadata", + "type": "object", + "additionalProperties": false, + "properties": { + "signer": { + "$ref": "signer/v0.1.0.json#" + }, + "referrer": { + "$ref": "referrer/v0.2.0.json#" + }, + "utm": { + "$ref": "utm/v0.2.0.json#" + }, + "quote": { + "$ref": "quote/v0.3.0.json#" + }, + "orderClass": { + "$ref": "orderClass/v0.3.0.json#" + }, + "hooks": { + "$ref": "hooks/v0.1.0.json#" + }, + "widget": { + "$ref": "widget/v0.1.0.json#" + } + } + } + } +} diff --git a/src/schemas/widget/v0.1.0.json b/src/schemas/widget/v0.1.0.json new file mode 100644 index 0000000..001a41c --- /dev/null +++ b/src/schemas/widget/v0.1.0.json @@ -0,0 +1,23 @@ +{ + "$id": "#utm/v0.1.0.json", + "$schema": "http://json-schema.org/draft-07/schema", + "required": [], + "title": "Widget", + "type": "object", + "properties": { + "appCode": { + "$id": "#/properties/appCodeWidget", + "description": "The code identifying the UI powering the widget", + "examples": ["CoW Swap"], + "title": "App Code", + "type": "string" + }, + "environment": { + "$id": "#/properties/environmentWidget", + "description": "Environment from which the order came from.", + "title": "Environment", + "type": "string", + "examples": ["production", "development", "staging", "ens"] + } + } +} From dd16c6a366d0a2ae16dc96224ecaf12a74e9453c Mon Sep 17 00:00:00 2001 From: Anxo Rodriguez Date: Tue, 7 Nov 2023 18:34:14 +0000 Subject: [PATCH 2/4] Fix wrong schema --- src/schemas/v0.11.0.json | 2 +- src/schemas/widget/v0.1.0.json | 2 +- test/schema.spec.ts | 51 ++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/schemas/v0.11.0.json b/src/schemas/v0.11.0.json index 4560e96..5dcd00f 100644 --- a/src/schemas/v0.11.0.json +++ b/src/schemas/v0.11.0.json @@ -1,5 +1,5 @@ { - "$id": "https://cowswap.exchange/schemas/app-data/v0.10.0.json", + "$id": "https://cowswap.exchange/schemas/app-data/v0.11.0.json", "$schema": "http://json-schema.org/draft-07/schema", "description": "Metadata JSON document for adding information to orders.", "required": ["version", "metadata"], diff --git a/src/schemas/widget/v0.1.0.json b/src/schemas/widget/v0.1.0.json index 001a41c..3c8357a 100644 --- a/src/schemas/widget/v0.1.0.json +++ b/src/schemas/widget/v0.1.0.json @@ -1,5 +1,5 @@ { - "$id": "#utm/v0.1.0.json", + "$id": "#widget/v0.1.0.json", "$schema": "http://json-schema.org/draft-07/schema", "required": [], "title": "Widget", diff --git a/test/schema.spec.ts b/test/schema.spec.ts index fc9941e..0440efa 100644 --- a/test/schema.spec.ts +++ b/test/schema.spec.ts @@ -8,6 +8,7 @@ import schemaV0_5_0 from '../schemas/v0.5.0.json' import schemaV0_6_0 from '../schemas/v0.6.0.json' import schemaV0_9_0 from '../schemas/v0.9.0.json' import schemaV0_10_0 from '../schemas/v0.10.0.json' +import schemaV0_11_0 from '../schemas/v0.11.0.json' const ADDRESS = '0xb6BAd41ae76A11D10f7b0E664C5007b908bC77C9' const REFERRER_V0_1_0 = { address: ADDRESS, version: '0.1.0' } @@ -552,6 +553,56 @@ describe('Schema v0.10.0', () => { ) }) +describe('Schema v0.11.0', () => { + const ajv = new Ajv() + const validator = ajv.compile(schemaV0_11_0) + + const BASE_DOCUMENT = { + version: '0.11.0', + metadata: {}, + } + + test('Minimal valid schema', _buildAssertValidFn(validator, BASE_DOCUMENT)) + + test( + 'With widget v0.11.0', + _buildAssertValidFn(validator, { + ...BASE_DOCUMENT, + metadata: { widget: { appCode: 'Pig Swap', environment: 'production' } }, + }) + ) + + // test( + // 'Widget with no appCode v0.11.0', + // _buildAssertValidFn(validator, { + // ...BASE_DOCUMENT, + // metadata: { widget: { environment: 'production' } }, + // }) + // ) + + // test( + // 'Signer with invalid address', + // _buildAssertInvalidFn( + // validator, + // { + // ...BASE_DOCUMENT, + // metadata: { + // signer: '0xinvalid', + // }, + // }, + // [ + // { + // instancePath: '/metadata/signer', + // keyword: 'pattern', + // message: 'must match pattern "^0x[a-fA-F0-9]{40}$"', + // params: { pattern: '^0x[a-fA-F0-9]{40}$' }, + // schemaPath: '#/properties/metadata/properties/signer/pattern', + // }, + // ] + // ) + // ) +}) + function _buildAssertValidFn(validator: ValidateFunction, doc: any) { return () => { // when From 3001970bfb39d69f581c9d07803236df84d7b7fb Mon Sep 17 00:00:00 2001 From: Anxo Rodriguez Date: Tue, 7 Nov 2023 18:43:51 +0000 Subject: [PATCH 3/4] Add tests --- src/generatedTypes/v0.11.0.ts | 2 +- src/schemas/widget/v0.1.0.json | 2 +- test/schema.spec.ts | 82 ++++++++++++++++++++++------------ 3 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/generatedTypes/v0.11.0.ts b/src/generatedTypes/v0.11.0.ts index ba62dd9..2e0d42c 100644 --- a/src/generatedTypes/v0.11.0.ts +++ b/src/generatedTypes/v0.11.0.ts @@ -134,7 +134,7 @@ export interface CoWHook { gasLimit: HookGasLimit; } export interface Widget { - appCode?: AppCode1; + appCode: AppCode1; environment?: Environment1; [k: string]: unknown; } diff --git a/src/schemas/widget/v0.1.0.json b/src/schemas/widget/v0.1.0.json index 3c8357a..47a442e 100644 --- a/src/schemas/widget/v0.1.0.json +++ b/src/schemas/widget/v0.1.0.json @@ -1,7 +1,7 @@ { "$id": "#widget/v0.1.0.json", "$schema": "http://json-schema.org/draft-07/schema", - "required": [], + "required": ["appCode"], "title": "Widget", "type": "object", "properties": { diff --git a/test/schema.spec.ts b/test/schema.spec.ts index 0440efa..9c9de7a 100644 --- a/test/schema.spec.ts +++ b/test/schema.spec.ts @@ -572,35 +572,59 @@ describe('Schema v0.11.0', () => { }) ) - // test( - // 'Widget with no appCode v0.11.0', - // _buildAssertValidFn(validator, { - // ...BASE_DOCUMENT, - // metadata: { widget: { environment: 'production' } }, - // }) - // ) - - // test( - // 'Signer with invalid address', - // _buildAssertInvalidFn( - // validator, - // { - // ...BASE_DOCUMENT, - // metadata: { - // signer: '0xinvalid', - // }, - // }, - // [ - // { - // instancePath: '/metadata/signer', - // keyword: 'pattern', - // message: 'must match pattern "^0x[a-fA-F0-9]{40}$"', - // params: { pattern: '^0x[a-fA-F0-9]{40}$' }, - // schemaPath: '#/properties/metadata/properties/signer/pattern', - // }, - // ] - // ) - // ) + test( + 'With widget and no environment v0.11.0', + _buildAssertValidFn(validator, { + ...BASE_DOCUMENT, + metadata: { widget: { appCode: 'Pig Swap' } }, + }) + ) + + test( + 'Widget with no appCode v0.11.0', + _buildAssertInvalidFn( + validator, + { + ...BASE_DOCUMENT, + metadata: { + widget: { + environment: 'production', + }, + }, + }, + [ + { + instancePath: '/metadata/widget', + keyword: 'required', + message: "must have required property 'appCode'", + params: { missingProperty: 'appCode' }, + schemaPath: '#/properties/metadata/properties/widget/required', + }, + ] + ) + ) + + test( + 'Signer with invalid address', + _buildAssertInvalidFn( + validator, + { + ...BASE_DOCUMENT, + metadata: { + signer: '0xinvalid', + }, + }, + [ + { + instancePath: '/metadata/signer', + keyword: 'pattern', + message: 'must match pattern "^0x[a-fA-F0-9]{40}$"', + params: { pattern: '^0x[a-fA-F0-9]{40}$' }, + schemaPath: '#/properties/metadata/properties/signer/pattern', + }, + ] + ) + ) }) function _buildAssertValidFn(validator: ValidateFunction, doc: any) { From aeef8a58e7bbd2a53664ce396011cb157a18406d Mon Sep 17 00:00:00 2001 From: Anxo Rodriguez Date: Wed, 8 Nov 2023 14:40:32 +0000 Subject: [PATCH 4/4] Export the latest version of the widget metadata --- src/generatedTypes/index.ts | 1 + src/scripts/compile.ts | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/generatedTypes/index.ts b/src/generatedTypes/index.ts index ce9dd4c..d762afd 100644 --- a/src/generatedTypes/index.ts +++ b/src/generatedTypes/index.ts @@ -21,6 +21,7 @@ export const LATEST_ORDER_CLASS_METADATA_VERSION = '0.3.0' export const LATEST_UTM_METADATA_VERSION = '0.2.0' export const LATEST_HOOKS_METADATA_VERSION = '0.1.0' export const LATEST_SIGNER_METADATA_VERSION = '0.1.0' +export const LATEST_WIDGET_METADATA_VERSION = '0.1.0' export type LatestAppDataDocVersion = v0_11_0.AppDataRootSchema export type AnyAppDataDocVersion = diff --git a/src/scripts/compile.ts b/src/scripts/compile.ts index a738734..85aa083 100644 --- a/src/scripts/compile.ts +++ b/src/scripts/compile.ts @@ -63,6 +63,7 @@ async function compile(): Promise { const latestUtmVersion = await getLatestMetadataDocVersion('utm') const latestHooksVersion = await getLatestMetadataDocVersion('hooks') const latestSignerVersion = await getLatestMetadataDocVersion('signer') + const latestWidgetVersion = await getLatestMetadataDocVersion('widget') const additionalTypesExport = ` export * as latest from './${latest}' @@ -74,6 +75,7 @@ export const LATEST_ORDER_CLASS_METADATA_VERSION = '${extractSemver(latestOrderC export const LATEST_UTM_METADATA_VERSION = '${extractSemver(latestUtmVersion)}' export const LATEST_HOOKS_METADATA_VERSION = '${extractSemver(latestHooksVersion)}' export const LATEST_SIGNER_METADATA_VERSION = '${extractSemver(latestSignerVersion)}' +export const LATEST_WIDGET_METADATA_VERSION = '${extractSemver(latestWidgetVersion)}' export type LatestAppDataDocVersion = ${latestExport}.AppDataRootSchema export type AnyAppDataDocVersion = ${allVersions} @@ -98,7 +100,7 @@ function extractSemver(name: string): string { } async function getLatestMetadataDocVersion( - metadataDocName: 'quote' | 'referrer' | 'orderClass' | 'utm' | 'hooks' | 'signer' + metadataDocName: 'quote' | 'referrer' | 'orderClass' | 'utm' | 'hooks' | 'signer' | 'widget' ): Promise { const metadataPath = path.join(SCHEMAS_SRC_PATH, metadataDocName) const versions = await fs.promises.readdir(metadataPath)