diff --git a/actions/checkForAndPlaceOrder.ts b/actions/checkForAndPlaceOrder.ts index 1ff3dd0..67833e7 100644 --- a/actions/checkForAndPlaceOrder.ts +++ b/actions/checkForAndPlaceOrder.ts @@ -98,30 +98,36 @@ const _checkForAndPlaceOrder: ActionFn = async ( ); const error = pollResult !== undefined; - console.log( - `[checkForAndPlaceOrder] Check conditional order result: ${ - pollResult !== undefined - ? `❌ Result: ${pollResult.result}` + pollResult.reason - ? `. Reason: ${pollResult.reason}` - : "" - : "✅ SUCCESS" - }` - ); - - hasErrors ||= error; - + // Specific handling for each error if (pollResult) { + // Dont try again the same order if (pollResult.result === PollResultCode.DONT_TRY_AGAIN) { ordersPendingDelete.push(conditionalOrder); } + // Unexpected error + if (pollResult.result === PollResultCode.UNEXPECTED_ERROR) { + console.error( + `[checkForAndPlaceOrder] Unexpected error`, + pollResult.error + ); + } + // TODO: Handle the other errors :) --> Store them in the registry and ignore blocks until the moment is right - // SUCCESS - // UNEXPECTED_ERROR - // TRY_NEXT_BLOCK // TRY_ON_BLOCK // TRY_AT_EPOCH } + console[error ? "error" : "log"]( + `[checkForAndPlaceOrder] Check conditional order result: ${ + pollResult !== undefined + ? `❌ Result: ${pollResult.result} " ${ + pollResult.reason ? `. Reason: ${pollResult.reason}` : "" + }` + : "✅ SUCCESS" + }` + ); + + hasErrors ||= error; } for (const conditionalOrder of ordersPendingDelete) { @@ -160,6 +166,14 @@ async function _processConditionalOrder( const { handler, salt, staticInput } = conditionalOrder.params; return Promise.all([handler, salt, staticInput]); })(); + + console.log("TODO: Why now this parameters seem broken????? ", { + handler, + salt, + staticInput, + params: conditionalOrder.params, + }); + let pollResult = await pollConditionalOrder({ owner, chainId, diff --git a/actions/package.json b/actions/package.json index 7ce78f1..448d0f3 100644 --- a/actions/package.json +++ b/actions/package.json @@ -20,12 +20,13 @@ }, "dependencies": { "@cowprotocol/contracts": "^1.4.0", - "@cowprotocol/cow-sdk": "file:.yalc/@cowprotocol/cow-sdk", + "@cowprotocol/cow-sdk": "^3.0.0-rc.3", "@sentry/integrations": "^7.64.0", "@sentry/node": "^7.64.0", "@tenderly/actions": "^0.0.13", "axios": "^1.4.0", "ethers": "^5.7.2", + "graphql-request": "^6.1.0", "node-fetch": "2", "node-slack": "^0.0.7", "typescript": "^5.0.4" diff --git a/actions/test/run_local.ts b/actions/test/run_local.ts index 95647bc..2c75184 100644 --- a/actions/test/run_local.ts +++ b/actions/test/run_local.ts @@ -119,7 +119,7 @@ async function processBlock( // Block watcher for creating new orders const testBlockEvent = new TestBlockEvent(); testBlockEvent.blockNumber = blockNumber; - testBlockEvent.blockDifficulty = block.difficulty.toString(); + testBlockEvent.blockDifficulty = block.difficulty?.toString(); testBlockEvent.blockHash = block.hash; testBlockEvent.network = chainId.toString(); diff --git a/actions/utils.ts b/actions/utils.ts index ee19c9b..abe4d59 100644 --- a/actions/utils.ts +++ b/actions/utils.ts @@ -384,43 +384,43 @@ export function isComposableCowCompatible(code: string): boolean { type ParsedError = { errorNameOrSelector?: string; message?: string; -} +}; /** * Given a raw ABI-encoded custom error returned from a revert, extract the selector and optionally a message. * @param abi of the custom error, which may or may not be parameterised. * @returns an empty parsed error if assumptions don't hold, otherwise the selector and message if applicable. */ -const rawErrorDecode = (abi: string): ParsedError => { +const rawErrorDecode = (abi: string): ParsedError => { if (abi.length === 10) { - return { errorNameOrSelector: abi } + return { errorNameOrSelector: abi }; } else { try { const selector = abi.slice(0, 10); const message = ethers.utils.defaultAbiCoder.decode( ["string"], - '0x' + abi.slice(10) // trim off the selector + "0x" + abi.slice(10) // trim off the selector )[0]; return { errorNameOrSelector: selector, message }; } catch { // some weird parameter, just return and let the caller deal with it return {}; - } + } } -} +}; /** * Parse custom reversion errors, irrespective of the RPC node's software - * + * * Background: `ComposableCoW` makes extensive use of `revert` to provide custom error messages. Unfortunately, * different RPC nodes handle these errors differently. For example, Nethermind returns a zero-bytes - * `error.data` in all cases, and the error selector is buried in `error.error.error.data`. Other + * `error.data` in all cases, and the error selector is buried in `error.error.error.data`. Other * nodes return the error selector in `error.data`. - * + * * In all cases, if the error selector contains a parameterised error message, the error message is * encoded in the `error.data` field. For example, `OrderNotValid` contains a parameterised error * message, and the error message is encoded in `error.data`. - * + * * Assumptions: * - `error.data` exists for all tested RPC nodes, and parameterised / non-parameterised custom errors. * - All calls to the smart contract if they revert, return a non-zero result at **EVM** level. @@ -451,25 +451,25 @@ export const parseCustomError = (error: any): ParsedError => { // If error.data is not zero-bytes, then it's not a Nethermind node, assume it's a string parameterised // custom error. Attempt to decode and return. if (data !== "0x") { - return rawErrorDecode(data) + return rawErrorDecode(data); } else { // This is a Nethermind node, as `data` *must* be equal to `0x`, but we know we always revert with an // message, so - we have to go digging ⛏️🙄 // // Verify our assumption that `error.error.error.data` is defined and is a string. - const rawNethermind = error?.error?.error?.data + const rawNethermind = error?.error?.error?.data; if (typeof rawNethermind === "string") { - // For some reason, Nethermind pad their message with `Reverted `, so, we need to slice off the + // For some reason, Nethermind pad their message with `Reverted `, so, we need to slice off the // extraneous part of the message, and just get the data - that we wanted in the first place! - const nethermindData = rawNethermind.slice('Reverted '.length) - return rawErrorDecode(nethermindData) + const nethermindData = rawNethermind.slice("Reverted ".length); + return rawErrorDecode(nethermindData); } else { // the nested error-ception for some reason failed and our assumptions are therefore incorrect. // return the unknown state to the caller. - return {} + return {}; } } -} +}; export class LowLevelError extends Error { data: string; @@ -478,4 +478,4 @@ export class LowLevelError extends Error { this.data = data; Object.setPrototypeOf(this, LowLevelError.prototype); } -} \ No newline at end of file +} diff --git a/actions/yarn.lock b/actions/yarn.lock index bda7101..91c05be 100644 --- a/actions/yarn.lock +++ b/actions/yarn.lock @@ -295,10 +295,10 @@ resolved "https://registry.yarnpkg.com/@cowprotocol/contracts/-/contracts-1.4.0.tgz#e93e5f25aac76feeaa348fa57231903274676247" integrity sha512-XLs3SlPmXD4lbiWIO7mxxuCn1eE5isuO6EUlE1cj17HqN/wukDAN0xXYPx6umOH/XdjGS33miMiPHELEyY9siw== -"@cowprotocol/cow-sdk@^3.0.0-rc.0": - version "3.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@cowprotocol/cow-sdk/-/cow-sdk-3.0.0-rc.0.tgz#2583d3726a0f559b2a2faf86ed86261820b93311" - integrity sha512-hdAkLKdda7kPXHZxhDKvRo01MbFMHM+WV8okPJL0xgpVsjzQTCitKkitUf3e9kSdyUebdaGe3iWVZviCiI72ew== +"@cowprotocol/cow-sdk@^3.0.0-rc.3": + version "3.0.0-rc.3" + resolved "https://registry.yarnpkg.com/@cowprotocol/cow-sdk/-/cow-sdk-3.0.0-rc.3.tgz#505ce52cb6e823c9a16c607ebd88e58ac3ef13ca" + integrity sha512-XaUm5xLoR6sKHYoTF9eUkvIErzLMJ9k3sQFnDdc95WlkJ4fn8BNfcwcbecakmCp9N26QTTv3S585GTh+rVPABw== dependencies: "@cowprotocol/contracts" "^1.4.0" "@ethersproject/abstract-signer" "^5.7.0" @@ -657,6 +657,11 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/strings" "^5.7.0" +"@graphql-typed-document-node/core@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" + integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -2129,6 +2134,14 @@ graphql-request@^4.3.0: extract-files "^9.0.0" form-data "^3.0.0" +graphql-request@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-6.1.0.tgz#f4eb2107967af3c7a5907eb3131c671eac89be4f" + integrity sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw== + dependencies: + "@graphql-typed-document-node/core" "^3.2.0" + cross-fetch "^3.1.5" + har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" diff --git a/yarn.lock b/yarn.lock index df1d6d5..e90320b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -577,6 +577,11 @@ grapheme-splitter@^1.0.4: resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== +graphql@^16.8.0: + version "16.8.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.0.tgz#374478b7f27b2dc6153c8f42c1b80157f79d79d4" + integrity sha512-0oKGaR+y3qcS5mCu1vb7KG+a89vjn06C7Ihq/dDl3jA+A8B3TKomvi3CiEcVLJQGalbu8F52LxkOym7U5sSfbg== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"