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 CompactX solver #125

Open
wants to merge 42 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
3b61627
feat: websocket listener
fernandomg Mar 11, 2025
e17aba3
feat(compactX): add solver config
fernandomg Mar 12, 2025
525d442
feat(compactX): add rules directory
fernandomg Mar 12, 2025
c5aaf0b
feat: add contract abi
fernandomg Mar 12, 2025
e41ac96
feat: extend intentSources to support multiple origins
fernandomg Mar 12, 2025
3717b0e
chore: prettier
fernandomg Mar 12, 2025
cb8a8e8
fix: type
fernandomg Mar 12, 2025
4027e5a
feat(compactX): listener minimum implementation
fernandomg Mar 12, 2025
3b65f55
chore: prettier
fernandomg Mar 12, 2025
cd3d1dc
feat(compactX): mvp (no fill)
fernandomg Mar 12, 2025
ad18786
fix: websocket listener shutdown
lmcorbalan Mar 13, 2025
a82d076
wip: add CompactX filler logic
lmcorbalan Mar 14, 2025
cb2ff7f
refactor: rename CompactSchema to CompactMessageSchema
fernandomg Mar 17, 2025
ce25c8e
refactor: replace viem with ethers equivalences
fernandomg Mar 17, 2025
104baac
fix: update signature to latest changes
fernandomg Mar 17, 2025
0e8d201
chore: prettier
fernandomg Mar 17, 2025
59c21d4
wip: fill logic
lmcorbalan Mar 17, 2025
4f172de
feat(compactX): WIP filler
fernandomg Mar 17, 2025
48827cb
chore: prettier
fernandomg Mar 17, 2025
e849ad5
feat: less agressive price polling
fernandomg Mar 18, 2025
6e33bd2
fix: be specific on the enncode data parameters
fernandomg Mar 18, 2025
fa43c22
refactor: comapctX filler
fernandomg Mar 19, 2025
be70e91
fix: properly identify native tokens
fernandomg Mar 19, 2025
0ab938a
refactor(compactX): organize filler flow
fernandomg Mar 19, 2025
2e4c38a
fix: minor errors preventing the build from working
lmcorbalan Mar 20, 2025
66b9d4b
refactor(compactX): move util functions to utils file
fernandomg Mar 20, 2025
38354b8
refactor(compactX): move constants to metadata
fernandomg Mar 20, 2025
79f41d5
refactor(compactX): TheCompactService
fernandomg Mar 20, 2025
31b4087
refactor(compactX): move buffer values to config/metadata
fernandomg Mar 20, 2025
42356d0
feat(compactX): extract checks to rules and simplify
fernandomg Mar 20, 2025
1024dd2
feat(compactX): extract verifySignatures rules
fernandomg Mar 20, 2025
de526a0
feat(compactX): extract checkExpirations rule
fernandomg Mar 20, 2025
1daa79a
feat(compactX): extract arbiter and tribunal checks
fernandomg Mar 21, 2025
7181283
feat(compactX): extract nonce check
fernandomg Mar 21, 2025
a04728e
refactor(compactX): code reorg
fernandomg Mar 21, 2025
7b29244
feat(compactX): move zod checks/parse into listener parser
fernandomg Mar 21, 2025
00840e0
fix: wrong message
fernandomg Mar 21, 2025
bcc18b3
feat: better handle errors
fernandomg Mar 21, 2025
aa393d0
chore(compactX): reduce TheCompact abi size
fernandomg Mar 21, 2025
cfd98aa
chore: reduce noise
fernandomg Mar 21, 2025
d5ab159
reenable all solvers
fernandomg Mar 21, 2025
133f1bb
Merge branch 'main' into feat/compactX
fernandomg Mar 21, 2025
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
94 changes: 70 additions & 24 deletions typescript/solver/NonceKeeperWallet.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { BigNumber } from "@ethersproject/bignumber";
import { defaultPath, HDNode } from "@ethersproject/hdnode";
import type { Deferrable } from "@ethersproject/properties";
import type {
Expand Down Expand Up @@ -36,7 +37,7 @@ export class NonceKeeperWallet extends Wallet {
// this check is necessary in order to not generate new nonces when a tx is going to fail
await super.estimateGas(transaction);
} catch (error) {
checkError(error, {transaction});
checkError(error, { transaction });
}

if (transaction.nonce == null) {
Expand All @@ -48,6 +49,14 @@ export class NonceKeeperWallet extends Wallet {
return super.sendTransaction(transaction);
}

async estimateGas(
transaction: Deferrable<TransactionRequest>,
): Promise<BigNumber> {
return super
.estimateGas(transaction)
.catch((error) => checkError(error, { transaction }));
}

static override fromMnemonic(
mnemonic: string,
path?: string,
Expand All @@ -67,47 +76,84 @@ function checkError(error: any, params: any): any {
const transaction = params.transaction || params.signedTransaction;

let message = error.message;
if (error.code === Logger.errors.SERVER_ERROR && error.error && typeof(error.error.message) === "string") {
message = error.error.message;
} else if (typeof(error.body) === "string") {
message = error.body;
} else if (typeof(error.responseText) === "string") {
message = error.responseText;
if (
error.code === Logger.errors.SERVER_ERROR &&
error.error &&
typeof error.error.message === "string"
) {
message = error.error.message;
} else if (typeof error.body === "string") {
message = error.body;
} else if (typeof error.responseText === "string") {
message = error.responseText;
}
message = (message || "").toLowerCase();

// "insufficient funds for gas * price + value + cost(data)"
if (message.match(/insufficient funds|base fee exceeds gas limit/i)) {
ethersLogger.throwError("insufficient funds for intrinsic transaction cost", Logger.errors.INSUFFICIENT_FUNDS, {
error, transaction
});
ethersLogger.throwError(
"insufficient funds for intrinsic transaction cost",
Logger.errors.INSUFFICIENT_FUNDS,
{
error,
transaction,
},
);
}

// "nonce too low"
if (message.match(/nonce (is )?too low/i)) {
ethersLogger.throwError("nonce has already been used", Logger.errors.NONCE_EXPIRED, {
error, transaction
});
ethersLogger.throwError(
"nonce has already been used",
Logger.errors.NONCE_EXPIRED,
{
error,
transaction,
},
);
}

// "replacement transaction underpriced"
if (message.match(/replacement transaction underpriced|transaction gas price.*too low/i)) {
ethersLogger.throwError("replacement fee too low", Logger.errors.REPLACEMENT_UNDERPRICED, {
error, transaction
});
if (
message.match(
/replacement transaction underpriced|transaction gas price.*too low/i,
)
) {
ethersLogger.throwError(
"replacement fee too low",
Logger.errors.REPLACEMENT_UNDERPRICED,
{
error,
transaction,
},
);
}

// "replacement transaction underpriced"
if (message.match(/only replay-protected/i)) {
ethersLogger.throwError("legacy pre-eip-155 transactions not supported", Logger.errors.UNSUPPORTED_OPERATION, {
error, transaction
});
ethersLogger.throwError(
"legacy pre-eip-155 transactions not supported",
Logger.errors.UNSUPPORTED_OPERATION,
{
error,
transaction,
},
);
}

if (message.match(/gas required exceeds allowance|always failing transaction|execution reverted/)) {
ethersLogger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", Logger.errors.UNPREDICTABLE_GAS_LIMIT, {
error, transaction
});
if (
message.match(
/gas required exceeds allowance|always failing transaction|execution reverted/,
)
) {
ethersLogger.throwError(
"cannot estimate gas; transaction may fail or may require manual gas limit",
Logger.errors.UNPREDICTABLE_GAS_LIMIT,
{
error,
transaction,
},
);
}

throw error;
Expand Down
3 changes: 3 additions & 0 deletions typescript/solver/config/solvers.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@
},
"hyperlane7683": {
"enabled": true
},
"compactX": {
"enabled": true
}
}
2 changes: 1 addition & 1 deletion typescript/solver/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { getMultiProvider } from "./solvers/utils.js";

const main = async () => {
const multiProvider = await getMultiProvider(chainMetadata).catch(
(error) => (log.error(error.reason ?? error.message), process.exit(1))
(error) => (log.error(error.reason ?? error.message), process.exit(1)),
);

log.info("🙍 Intent Solver 📝");
Expand Down
4 changes: 3 additions & 1 deletion typescript/solver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@inquirer/prompts": "^7.2.0",
"@typechain/ethers-v5": "^11.1.2",
"@types/copyfiles": "^2",
"@types/ws": "^8",
"copyfiles": "^2.4.1",
"prettier": "^3.3.3",
"tsx": "^4.19.2",
Expand All @@ -45,6 +46,7 @@
"pino": "^9.5.0",
"pino-pretty": "^13.0.0",
"pino-socket": "^7.4.0",
"uniqolor": "^1.1.1"
"uniqolor": "^1.1.1",
"ws": "^8.18.1"
}
}
13 changes: 11 additions & 2 deletions typescript/solver/solvers/BaseFiller.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { BigNumber } from "@ethersproject/bignumber";
import type { MultiProvider } from "@hyperlane-xyz/sdk";
import type { Result } from "@hyperlane-xyz/utils";
import {
Expand Down Expand Up @@ -82,11 +83,19 @@ export abstract class BaseFiller<
await this.fill(parsedArgs, data, originChainName, blockNumber);

await this.settleOrder(parsedArgs, data, originChainName);
} catch (error) {
} catch (error: any) {
this.log.error({
msg: `Failed processing intent`,
intent: `${this.metadata.protocolName}-${parsedArgs.orderId}`,
error: JSON.stringify(error),
error: {
stack: error.stack,
details: JSON.stringify(error, (_, value) => {
if (value instanceof BigNumber || typeof value === "bigint") {
return value.toString();
}
return value;
}),
},
});
}
};
Expand Down
5 changes: 2 additions & 3 deletions typescript/solver/solvers/BaseListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export abstract class BaseListener<
confirmationBlocks,
),
pollInterval ?? this.defaultPollInterval,
)
),
);

contract.provider.getNetwork().then((network) => {
Expand All @@ -118,9 +118,8 @@ export abstract class BaseListener<
clearInterval(this.pollIntervals[i]);
}
this.pollIntervals = [];
}
};
};

}

protected async pollEvents(
Expand Down
13 changes: 5 additions & 8 deletions typescript/solver/solvers/SolverManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,29 @@ type SolverModule = {
create: () => Promise<ListenerFn>;
};
filler: {
create: (
multiProvider: MultiProvider,
rules?: any
) => FillerFn;
create: (multiProvider: MultiProvider, rules?: any) => FillerFn;
};
rules?: any;
};

type ListenerFn = <T>(
handler: (args: T, originChainName: string, blockNumber: number) => void
handler: (args: T, originChainName: string, blockNumber: number) => void,
) => ShutdownFn;

type ShutdownFn = () => void;

type FillerFn = <T>(
args: T,
originChainName: string,
blockNumber: number
blockNumber: number,
) => Promise<void>;

export class SolverManager {
private activeListeners: Array<() => void> = [];

constructor(
private readonly multiProvider: MultiProvider,
private readonly log: Logger
private readonly log: Logger,
) {}

async initializeSolvers() {
Expand All @@ -47,7 +44,7 @@ export class SolverManager {
await this.initializeSolver(solverName as SolverName);
} catch (error: any) {
this.log.error(
`Failed to initialize solver ${solverName}: ${error.message}`
`Failed to initialize solver ${solverName}: ${error.message}`,
);
throw error;
}
Expand Down
Loading