From e7101cfe024f34803e243e3633d6f691ed58fd05 Mon Sep 17 00:00:00 2001 From: igorroncevic <57319163+igorroncevic@users.noreply.github.com> Date: Wed, 15 Jul 2026 16:03:22 +0200 Subject: [PATCH 1/4] feat(composable): add JIT poller helpers --- packages/composable/README.md | 30 +++++ .../composable/src/ComposableCowPoller.ts | 43 +++++++ .../src/abis/ComposableCowPollerAbi.ts | 109 ++++++++++++++++++ packages/composable/src/index.ts | 1 + packages/composable/src/types.ts | 13 +++ .../tests/ComposableCowPoller.spec.ts | 84 ++++++++++++++ 6 files changed, 280 insertions(+) create mode 100644 packages/composable/src/ComposableCowPoller.ts create mode 100644 packages/composable/src/abis/ComposableCowPollerAbi.ts create mode 100644 packages/composable/tests/ComposableCowPoller.spec.ts diff --git a/packages/composable/README.md b/packages/composable/README.md index eb434d08c..7cbb9a837 100644 --- a/packages/composable/README.md +++ b/packages/composable/README.md @@ -58,6 +58,36 @@ class CustomOrder extends ConditionalOrder { } ``` +### JIT Poller + +Build the calls for a just-in-time funded TWAP. The application owns the deployed poller address, which must use this ABI. + +```typescript +import { + ComposableCowPollerSchedule, + encodePollFunds, + encodeRegister, + encodeRevoke, + getScheduleId, +} from '@cowprotocol/sdk-composable' +import { setGlobalAdapter } from '@cowprotocol/sdk-common' + +setGlobalAdapter(adapter) + +const schedule: ComposableCowPollerSchedule = { + handler: twapHandler, + funder: eoa, + owner: cowShed, + salt, + staticInput, +} + +const id = getScheduleId(schedule) +const registerCalldata = encodeRegister(schedule) +const preHook = { target: pollerAddress, callData: encodePollFunds(id) } +const revokeCalldata = encodeRevoke(id) +``` + ## Usage ```typescript diff --git a/packages/composable/src/ComposableCowPoller.ts b/packages/composable/src/ComposableCowPoller.ts new file mode 100644 index 000000000..5f64a4191 --- /dev/null +++ b/packages/composable/src/ComposableCowPoller.ts @@ -0,0 +1,43 @@ +import { getGlobalAdapter } from '@cowprotocol/sdk-common' + +import { ComposableCowPollerAbi } from './abis/ComposableCowPollerAbi' +import { ComposableCowPollerSchedule, ComposableCowPollerScheduleKey } from './types' + +export { ComposableCowPollerAbi } from './abis/ComposableCowPollerAbi' + +const SCHEDULE_ID_ABI = ['address', 'address', 'address', 'bytes32'] + +/** + * Calculates the app-data-independent poller schedule ID. + */ +export function getScheduleId(schedule: ComposableCowPollerScheduleKey): string { + const encoded = getGlobalAdapter().utils.encodeAbi(SCHEDULE_ID_ABI, [ + schedule.funder, + schedule.handler, + schedule.owner, + schedule.salt, + ]) + + return getGlobalAdapter().utils.keccak256(encoded) +} + +/** + * Encodes a transaction that registers a JIT funding schedule. + */ +export function encodeRegister(schedule: ComposableCowPollerSchedule): string { + return getGlobalAdapter().utils.encodeFunction(ComposableCowPollerAbi, 'register', [schedule]) as string +} + +/** + * Encodes the app-data pre-hook that pulls funds for one active TWAP part. + */ +export function encodePollFunds(id: string): string { + return getGlobalAdapter().utils.encodeFunction(ComposableCowPollerAbi, 'pollFunds', [id]) as string +} + +/** + * Encodes a transaction that disables a JIT funding schedule. + */ +export function encodeRevoke(id: string): string { + return getGlobalAdapter().utils.encodeFunction(ComposableCowPollerAbi, 'revoke', [id]) as string +} diff --git a/packages/composable/src/abis/ComposableCowPollerAbi.ts b/packages/composable/src/abis/ComposableCowPollerAbi.ts new file mode 100644 index 000000000..7976e8ff3 --- /dev/null +++ b/packages/composable/src/abis/ComposableCowPollerAbi.ts @@ -0,0 +1,109 @@ +export const ComposableCowPollerAbi = [ + { + inputs: [{ internalType: 'contract ComposableCoW', name: '_composableCow', type: 'address' }], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { inputs: [], name: 'NoSchedule', type: 'error' }, + { inputs: [], name: 'OnlyFunder', type: 'error' }, + { inputs: [], name: 'OrderNotLive', type: 'error' }, + { + inputs: [], + name: 'composableCow', + outputs: [{ internalType: 'contract ComposableCoW', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + name: 'lastFunded', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes32', name: 'id', type: 'bytes32' }], + name: 'pollFunds', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { internalType: 'contract IConditionalOrderGenerator', name: 'handler', type: 'address' }, + { internalType: 'address', name: 'funder', type: 'address' }, + { internalType: 'address', name: 'owner', type: 'address' }, + { internalType: 'bytes32', name: 'salt', type: 'bytes32' }, + { internalType: 'bytes', name: 'staticInput', type: 'bytes' }, + ], + internalType: 'struct ComposableCowPoller.Schedule', + name: 'schedule', + type: 'tuple', + }, + ], + name: 'register', + outputs: [{ internalType: 'bytes32', name: 'id', type: 'bytes32' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes32', name: 'id', type: 'bytes32' }], + name: 'revoke', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'funder', type: 'address' }, + { internalType: 'contract IConditionalOrderGenerator', name: 'handler', type: 'address' }, + { internalType: 'address', name: 'owner', type: 'address' }, + { internalType: 'bytes32', name: 'salt', type: 'bytes32' }, + ], + name: 'scheduleId', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + name: 'schedules', + outputs: [ + { internalType: 'contract IConditionalOrderGenerator', name: 'handler', type: 'address' }, + { internalType: 'address', name: 'funder', type: 'address' }, + { internalType: 'address', name: 'owner', type: 'address' }, + { internalType: 'bytes32', name: 'salt', type: 'bytes32' }, + { internalType: 'bytes', name: 'staticInput', type: 'bytes' }, + ], + stateMutability: 'view', + type: 'function', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'bytes32', name: 'id', type: 'bytes32' }, + { indexed: false, internalType: 'bytes32', name: 'orderDigest', type: 'bytes32' }, + { indexed: false, internalType: 'uint256', name: 'amount', type: 'uint256' }, + ], + name: 'Pulled', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'bytes32', name: 'id', type: 'bytes32' }, + { indexed: true, internalType: 'address', name: 'owner', type: 'address' }, + { indexed: true, internalType: 'address', name: 'funder', type: 'address' }, + ], + name: 'ScheduleRegistered', + type: 'event', + }, + { + anonymous: false, + inputs: [{ indexed: true, internalType: 'bytes32', name: 'id', type: 'bytes32' }], + name: 'ScheduleRevoked', + type: 'event', + }, +] as const diff --git a/packages/composable/src/index.ts b/packages/composable/src/index.ts index ea7e7f484..b440d3f67 100644 --- a/packages/composable/src/index.ts +++ b/packages/composable/src/index.ts @@ -3,4 +3,5 @@ export * from './utils' export * from './ConditionalOrder' export * from './Multiplexer' export * from './ConditionalOrderFactory' +export * from './ComposableCowPoller' export * from './orderTypes' diff --git a/packages/composable/src/types.ts b/packages/composable/src/types.ts index c75744469..69562d746 100644 --- a/packages/composable/src/types.ts +++ b/packages/composable/src/types.ts @@ -83,6 +83,19 @@ export type ConditionalOrderParams = { readonly staticInput: string } +/** Fields that determine a JIT poller schedule ID. */ +export type ComposableCowPollerScheduleKey = { + readonly handler: string + readonly funder: string + readonly owner: string + readonly salt: string +} + +/** A JIT funding schedule stored by the Composable CoW poller. */ +export type ComposableCowPollerSchedule = ComposableCowPollerScheduleKey & { + readonly staticInput: string +} + export enum ProofLocation { // The location of the proofs is private to the caller. PRIVATE = 0, diff --git a/packages/composable/tests/ComposableCowPoller.spec.ts b/packages/composable/tests/ComposableCowPoller.spec.ts new file mode 100644 index 000000000..94672e0b1 --- /dev/null +++ b/packages/composable/tests/ComposableCowPoller.spec.ts @@ -0,0 +1,84 @@ +import { setGlobalAdapter } from '@cowprotocol/sdk-common' + +import { + ComposableCowPollerAbi, + encodePollFunds, + encodeRegister, + encodeRevoke, + getScheduleId, +} from '../src/ComposableCowPoller' +import { ComposableCowPollerSchedule } from '../src/types' +import { createAdapters } from './setup' + +const SCHEDULE: ComposableCowPollerSchedule = { + handler: '0x1111111111111111111111111111111111111111', + funder: '0x2222222222222222222222222222222222222222', + owner: '0x3333333333333333333333333333333333333333', + salt: '0x0000000000000000000000000000000000000000000000000000000000000001', + staticInput: '0x1234', +} + +const SCHEDULE_ID = '0x7b1516d117fa5dd96fddfb9489b52af1c3cca64e1bc88c32324bdd6a92c6057c' +const REGISTER_CALLDATA = + '0x80313a250000000000000000000000000000000000000000000000000000000000000020000000000000000000000000111111111111111111111111111111111111111100000000000000000000000022222222222222222222222222222222222222220000000000000000000000003333333333333333333333333333333333333333000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000021234000000000000000000000000000000000000000000000000000000000000' +const POLL_FUNDS_CALLDATA = '0xf83740307b1516d117fa5dd96fddfb9489b52af1c3cca64e1bc88c32324bdd6a92c6057c' +const REVOKE_CALLDATA = '0xb75c7dc67b1516d117fa5dd96fddfb9489b52af1c3cca64e1bc88c32324bdd6a92c6057c' + +describe('ComposableCowPoller - Multi-Adapter Tests', () => { + const adapters = createAdapters() + + test('derives the Solidity schedule ID across adapters', () => { + for (const adapter of Object.values(adapters)) { + setGlobalAdapter(adapter) + expect(getScheduleId(SCHEDULE)).toEqual(SCHEDULE_ID) + } + }) + + test('does not include staticInput in the schedule ID', () => { + const updatedStaticInput = { ...SCHEDULE, staticInput: '0xdeadbeef' } + + for (const adapter of Object.values(adapters)) { + setGlobalAdapter(adapter) + expect(getScheduleId(updatedStaticInput)).toEqual(SCHEDULE_ID) + } + }) + + test('encodes final poller calls across adapters', () => { + for (const adapter of Object.values(adapters)) { + setGlobalAdapter(adapter) + expect(encodeRegister(SCHEDULE)).toEqual(REGISTER_CALLDATA) + expect(encodePollFunds(SCHEDULE_ID)).toEqual(POLL_FUNDS_CALLDATA) + expect(encodeRevoke(SCHEDULE_ID)).toEqual(REVOKE_CALLDATA) + } + }) + + test('exports the combined poller interface, not the removed topUp method', () => { + const functionNames = ComposableCowPollerAbi.filter((item) => item.type === 'function') + .map((item) => item.name) + .sort() + const errorNames = ComposableCowPollerAbi.filter((item) => item.type === 'error') + .map((item) => item.name) + .sort() + const eventNames = ComposableCowPollerAbi.filter((item) => item.type === 'event') + .map((item) => item.name) + .sort() + const constructor = ComposableCowPollerAbi.find((item) => item.type === 'constructor') + + expect(functionNames).toEqual([ + 'composableCow', + 'lastFunded', + 'pollFunds', + 'register', + 'revoke', + 'scheduleId', + 'schedules', + ]) + expect(errorNames).toEqual(['NoSchedule', 'OnlyFunder', 'OrderNotLive']) + expect(eventNames).toEqual(['Pulled', 'ScheduleRegistered', 'ScheduleRevoked']) + expect(constructor).toEqual({ + inputs: [{ internalType: 'contract ComposableCoW', name: '_composableCow', type: 'address' }], + stateMutability: 'nonpayable', + type: 'constructor', + }) + }) +}) From e640f374fe377ab562b32adc5aaffc7f6c45eb73 Mon Sep 17 00:00:00 2001 From: igorroncevic <57319163+igorroncevic@users.noreply.github.com> Date: Thu, 23 Jul 2026 20:39:08 +0300 Subject: [PATCH 2/4] fix(composable): sync final Poller ABI --- .../src/abis/ComposableCowPollerAbi.ts | 137 +++++++++++------- .../tests/ComposableCowPoller.spec.ts | 35 ++++- 2 files changed, 113 insertions(+), 59 deletions(-) diff --git a/packages/composable/src/abis/ComposableCowPollerAbi.ts b/packages/composable/src/abis/ComposableCowPollerAbi.ts index 7976e8ff3..ae445e795 100644 --- a/packages/composable/src/abis/ComposableCowPollerAbi.ts +++ b/packages/composable/src/abis/ComposableCowPollerAbi.ts @@ -1,109 +1,136 @@ export const ComposableCowPollerAbi = [ { - inputs: [{ internalType: 'contract ComposableCoW', name: '_composableCow', type: 'address' }], - stateMutability: 'nonpayable', type: 'constructor', + inputs: [ + { name: 'composableCow', type: 'address', internalType: 'contract ComposableCoW' }, + { name: 'cowShedFactory', type: 'address', internalType: 'contract ICowShedFactory' }, + ], + stateMutability: 'nonpayable', }, - { inputs: [], name: 'NoSchedule', type: 'error' }, - { inputs: [], name: 'OnlyFunder', type: 'error' }, - { inputs: [], name: 'OrderNotLive', type: 'error' }, { + type: 'function', + name: 'COMPOSABLE_COW', inputs: [], - name: 'composableCow', - outputs: [{ internalType: 'contract ComposableCoW', name: '', type: 'address' }], + outputs: [{ name: '', type: 'address', internalType: 'contract ComposableCoW' }], stateMutability: 'view', - type: 'function', }, { - inputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], - name: 'lastFunded', - outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + type: 'function', + name: 'COW_SHED_FACTORY', + inputs: [], + outputs: [{ name: '', type: 'address', internalType: 'contract ICowShedFactory' }], stateMutability: 'view', + }, + { type: 'function', + name: 'funded', + inputs: [ + { name: '', type: 'bytes32', internalType: 'bytes32' }, + { name: '', type: 'bytes32', internalType: 'bytes32' }, + ], + outputs: [{ name: '', type: 'bool', internalType: 'bool' }], + stateMutability: 'view', }, { - inputs: [{ internalType: 'bytes32', name: 'id', type: 'bytes32' }], + type: 'function', name: 'pollFunds', + inputs: [{ name: 'id', type: 'bytes32', internalType: 'bytes32' }], outputs: [], stateMutability: 'nonpayable', - type: 'function', }, { + type: 'function', + name: 'register', inputs: [ { - components: [ - { internalType: 'contract IConditionalOrderGenerator', name: 'handler', type: 'address' }, - { internalType: 'address', name: 'funder', type: 'address' }, - { internalType: 'address', name: 'owner', type: 'address' }, - { internalType: 'bytes32', name: 'salt', type: 'bytes32' }, - { internalType: 'bytes', name: 'staticInput', type: 'bytes' }, - ], - internalType: 'struct ComposableCowPoller.Schedule', name: 'schedule', type: 'tuple', + internalType: 'struct ComposableCowPoller.Schedule', + components: [ + { name: 'handler', type: 'address', internalType: 'contract IConditionalOrderGenerator' }, + { name: 'funder', type: 'address', internalType: 'address' }, + { name: 'owner', type: 'address', internalType: 'address' }, + { name: 'salt', type: 'bytes32', internalType: 'bytes32' }, + { name: 'staticInput', type: 'bytes', internalType: 'bytes' }, + ], }, ], - name: 'register', - outputs: [{ internalType: 'bytes32', name: 'id', type: 'bytes32' }], + outputs: [{ name: 'id', type: 'bytes32', internalType: 'bytes32' }], stateMutability: 'nonpayable', - type: 'function', }, { - inputs: [{ internalType: 'bytes32', name: 'id', type: 'bytes32' }], + type: 'function', name: 'revoke', + inputs: [{ name: 'id', type: 'bytes32', internalType: 'bytes32' }], outputs: [], stateMutability: 'nonpayable', - type: 'function', }, { + type: 'function', + name: 'scheduleId', inputs: [ - { internalType: 'address', name: 'funder', type: 'address' }, - { internalType: 'contract IConditionalOrderGenerator', name: 'handler', type: 'address' }, - { internalType: 'address', name: 'owner', type: 'address' }, - { internalType: 'bytes32', name: 'salt', type: 'bytes32' }, + { + name: 'schedule', + type: 'tuple', + internalType: 'struct ComposableCowPoller.Schedule', + components: [ + { name: 'handler', type: 'address', internalType: 'contract IConditionalOrderGenerator' }, + { name: 'funder', type: 'address', internalType: 'address' }, + { name: 'owner', type: 'address', internalType: 'address' }, + { name: 'salt', type: 'bytes32', internalType: 'bytes32' }, + { name: 'staticInput', type: 'bytes', internalType: 'bytes' }, + ], + }, ], - name: 'scheduleId', - outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + outputs: [{ name: '', type: 'bytes32', internalType: 'bytes32' }], stateMutability: 'pure', - type: 'function', }, { - inputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + type: 'function', name: 'schedules', + inputs: [{ name: '', type: 'bytes32', internalType: 'bytes32' }], outputs: [ - { internalType: 'contract IConditionalOrderGenerator', name: 'handler', type: 'address' }, - { internalType: 'address', name: 'funder', type: 'address' }, - { internalType: 'address', name: 'owner', type: 'address' }, - { internalType: 'bytes32', name: 'salt', type: 'bytes32' }, - { internalType: 'bytes', name: 'staticInput', type: 'bytes' }, + { name: 'handler', type: 'address', internalType: 'contract IConditionalOrderGenerator' }, + { name: 'funder', type: 'address', internalType: 'address' }, + { name: 'owner', type: 'address', internalType: 'address' }, + { name: 'salt', type: 'bytes32', internalType: 'bytes32' }, + { name: 'staticInput', type: 'bytes', internalType: 'bytes' }, ], stateMutability: 'view', - type: 'function', }, { - anonymous: false, + type: 'event', + name: 'Pulled', inputs: [ - { indexed: true, internalType: 'bytes32', name: 'id', type: 'bytes32' }, - { indexed: false, internalType: 'bytes32', name: 'orderDigest', type: 'bytes32' }, - { indexed: false, internalType: 'uint256', name: 'amount', type: 'uint256' }, + { name: 'id', type: 'bytes32', indexed: true, internalType: 'bytes32' }, + { name: 'orderDigest', type: 'bytes32', indexed: false, internalType: 'bytes32' }, + { name: 'amount', type: 'uint256', indexed: false, internalType: 'uint256' }, ], - name: 'Pulled', - type: 'event', + anonymous: false, }, { - anonymous: false, + type: 'event', + name: 'ScheduleRegistered', inputs: [ - { indexed: true, internalType: 'bytes32', name: 'id', type: 'bytes32' }, - { indexed: true, internalType: 'address', name: 'owner', type: 'address' }, - { indexed: true, internalType: 'address', name: 'funder', type: 'address' }, + { name: 'id', type: 'bytes32', indexed: true, internalType: 'bytes32' }, + { name: 'owner', type: 'address', indexed: true, internalType: 'address' }, + { name: 'funder', type: 'address', indexed: true, internalType: 'address' }, ], - name: 'ScheduleRegistered', - type: 'event', + anonymous: false, }, { - anonymous: false, - inputs: [{ indexed: true, internalType: 'bytes32', name: 'id', type: 'bytes32' }], - name: 'ScheduleRevoked', type: 'event', + name: 'ScheduleRevoked', + inputs: [ + { name: 'id', type: 'bytes32', indexed: true, internalType: 'bytes32' }, + { name: 'owner', type: 'address', indexed: true, internalType: 'address' }, + { name: 'funder', type: 'address', indexed: true, internalType: 'address' }, + ], + anonymous: false, }, + { type: 'error', name: 'InvalidComposableCow', inputs: [] }, + { type: 'error', name: 'InvalidCowShedFactory', inputs: [] }, + { type: 'error', name: 'NoSchedule', inputs: [] }, + { type: 'error', name: 'OrderNotLive', inputs: [] }, + { type: 'error', name: 'UnauthorizedCaller', inputs: [] }, ] as const diff --git a/packages/composable/tests/ComposableCowPoller.spec.ts b/packages/composable/tests/ComposableCowPoller.spec.ts index 94672e0b1..c208c4f3a 100644 --- a/packages/composable/tests/ComposableCowPoller.spec.ts +++ b/packages/composable/tests/ComposableCowPoller.spec.ts @@ -63,22 +63,49 @@ describe('ComposableCowPoller - Multi-Adapter Tests', () => { .map((item) => item.name) .sort() const constructor = ComposableCowPollerAbi.find((item) => item.type === 'constructor') + const register = ComposableCowPollerAbi.find((item) => item.type === 'function' && item.name === 'register') + const scheduleId = ComposableCowPollerAbi.find((item) => item.type === 'function' && item.name === 'scheduleId') + const funded = ComposableCowPollerAbi.find((item) => item.type === 'function' && item.name === 'funded') + const scheduleRevoked = ComposableCowPollerAbi.find( + (item) => item.type === 'event' && item.name === 'ScheduleRevoked', + ) expect(functionNames).toEqual([ - 'composableCow', - 'lastFunded', + 'COMPOSABLE_COW', + 'COW_SHED_FACTORY', + 'funded', 'pollFunds', 'register', 'revoke', 'scheduleId', 'schedules', ]) - expect(errorNames).toEqual(['NoSchedule', 'OnlyFunder', 'OrderNotLive']) + expect(errorNames).toEqual([ + 'InvalidComposableCow', + 'InvalidCowShedFactory', + 'NoSchedule', + 'OrderNotLive', + 'UnauthorizedCaller', + ]) expect(eventNames).toEqual(['Pulled', 'ScheduleRegistered', 'ScheduleRevoked']) expect(constructor).toEqual({ - inputs: [{ internalType: 'contract ComposableCoW', name: '_composableCow', type: 'address' }], + inputs: [ + { internalType: 'contract ComposableCoW', name: 'composableCow', type: 'address' }, + { internalType: 'contract ICowShedFactory', name: 'cowShedFactory', type: 'address' }, + ], stateMutability: 'nonpayable', type: 'constructor', }) + expect(scheduleId?.inputs).toEqual(register?.inputs) + expect(funded?.inputs).toEqual([ + { internalType: 'bytes32', name: '', type: 'bytes32' }, + { internalType: 'bytes32', name: '', type: 'bytes32' }, + ]) + expect(funded?.outputs).toEqual([{ internalType: 'bool', name: '', type: 'bool' }]) + expect(scheduleRevoked?.inputs).toEqual([ + { indexed: true, internalType: 'bytes32', name: 'id', type: 'bytes32' }, + { indexed: true, internalType: 'address', name: 'owner', type: 'address' }, + { indexed: true, internalType: 'address', name: 'funder', type: 'address' }, + ]) }) }) From 90ee3de431926e5b8fb8c307963caceb21a8ca55 Mon Sep 17 00:00:00 2001 From: igorroncevic <57319163+igorroncevic@users.noreply.github.com> Date: Tue, 28 Jul 2026 13:02:16 +0200 Subject: [PATCH 3/4] fix(composable): sync Poller SDK with CowShed authorization --- packages/composable/README.md | 7 ++++++- packages/composable/src/abis/ComposableCowPollerAbi.ts | 2 -- packages/composable/tests/ComposableCowPoller.spec.ts | 8 +------- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/composable/README.md b/packages/composable/README.md index 7cbb9a837..dc25a6bed 100644 --- a/packages/composable/README.md +++ b/packages/composable/README.md @@ -83,8 +83,13 @@ const schedule: ComposableCowPollerSchedule = { } const id = getScheduleId(schedule) +// register and revoke may be called by the funder or its canonical CowShed const registerCalldata = encodeRegister(schedule) -const preHook = { target: pollerAddress, callData: encodePollFunds(id) } +const preHook = { + target: pollerAddress, + callData: encodePollFunds(id), + gasLimit: '350000', +} const revokeCalldata = encodeRevoke(id) ``` diff --git a/packages/composable/src/abis/ComposableCowPollerAbi.ts b/packages/composable/src/abis/ComposableCowPollerAbi.ts index ae445e795..dffcac8c3 100644 --- a/packages/composable/src/abis/ComposableCowPollerAbi.ts +++ b/packages/composable/src/abis/ComposableCowPollerAbi.ts @@ -128,8 +128,6 @@ export const ComposableCowPollerAbi = [ ], anonymous: false, }, - { type: 'error', name: 'InvalidComposableCow', inputs: [] }, - { type: 'error', name: 'InvalidCowShedFactory', inputs: [] }, { type: 'error', name: 'NoSchedule', inputs: [] }, { type: 'error', name: 'OrderNotLive', inputs: [] }, { type: 'error', name: 'UnauthorizedCaller', inputs: [] }, diff --git a/packages/composable/tests/ComposableCowPoller.spec.ts b/packages/composable/tests/ComposableCowPoller.spec.ts index c208c4f3a..9e93e98e7 100644 --- a/packages/composable/tests/ComposableCowPoller.spec.ts +++ b/packages/composable/tests/ComposableCowPoller.spec.ts @@ -80,13 +80,7 @@ describe('ComposableCowPoller - Multi-Adapter Tests', () => { 'scheduleId', 'schedules', ]) - expect(errorNames).toEqual([ - 'InvalidComposableCow', - 'InvalidCowShedFactory', - 'NoSchedule', - 'OrderNotLive', - 'UnauthorizedCaller', - ]) + expect(errorNames).toEqual(['NoSchedule', 'OrderNotLive', 'UnauthorizedCaller']) expect(eventNames).toEqual(['Pulled', 'ScheduleRegistered', 'ScheduleRevoked']) expect(constructor).toEqual({ inputs: [ From a40eb99fd617954943560647f5c912d1870989f3 Mon Sep 17 00:00:00 2001 From: igorroncevic <57319163+igorroncevic@users.noreply.github.com> Date: Wed, 29 Jul 2026 13:26:07 +0200 Subject: [PATCH 4/4] test(composable): exercise Poller public exports --- packages/composable/tests/ComposableCowPoller.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/composable/tests/ComposableCowPoller.spec.ts b/packages/composable/tests/ComposableCowPoller.spec.ts index 9e93e98e7..504c29445 100644 --- a/packages/composable/tests/ComposableCowPoller.spec.ts +++ b/packages/composable/tests/ComposableCowPoller.spec.ts @@ -2,12 +2,12 @@ import { setGlobalAdapter } from '@cowprotocol/sdk-common' import { ComposableCowPollerAbi, + type ComposableCowPollerSchedule, encodePollFunds, encodeRegister, encodeRevoke, getScheduleId, -} from '../src/ComposableCowPoller' -import { ComposableCowPollerSchedule } from '../src/types' +} from '../src' import { createAdapters } from './setup' const SCHEDULE: ComposableCowPollerSchedule = {