Skip to content
41 changes: 22 additions & 19 deletions tee-apps/sealed-bid-auction/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions tee-apps/sealed-bid-auction/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
},
"dependencies": {
"@jest/globals": "^30.0.5",
"bun": "^1.2.19",
"bun": "^1.3.5",
"dotenv": "^17.2.1",
"immutable": "^5.1.3",
"jest": "^30.0.5",
"ts-jest": "^29.4.0",
"viem": "^2.33.1",
"viem": "^2.43.3",
"winston": "^3.17.0"
}
}
5 changes: 2 additions & 3 deletions tee-apps/sealed-bid-auction/src/api/AuctionApiServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {serialize, WinstonLogger} from "../utils/WinstonLogger.ts";
import {SolverPriceBook} from "../core/SolverPriceBook.ts";
import {AuctionService} from "../core/AuctionService.ts";
import type {AuctionResult} from "./types.ts";
import type {OrderData} from "../blockchain/types.ts";
import type {PriceListItem} from "../core/types.ts";
import {AuthController} from "./AuthController.ts";
import {AuthService} from "../core/AuthService.ts";
Expand Down Expand Up @@ -120,11 +119,11 @@ export class AuctionApiServer {
ws.send(`Error when updating price: ${e.message || e}`);
}
},
close: (ws, _code, _reason) => {
close: (ws, code, reason) => {
const addr = ws.data.solverAddress;
const user = ws.data.username;
ws.unsubscribe('intent-auction');
websocketLogger.info(`🔒 Solver disconnected: ${user} (${addr})`);
websocketLogger.info(`🔒 Solver disconnected: ${user} (${addr}) . Code: ${code} Reason: ${reason || '<no reason>'}.`);
authService.logout(addr);
},
},
Expand Down
10 changes: 7 additions & 3 deletions tee-apps/sealed-bid-auction/src/blockchain/BlockchainClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@ export class BlockchainClient {
this._publicClient = createPublicClient({
chain: chain,
transport: webSocket(wsUrl, {
reconnect: true,
keepAlive: true,
retryDelay: 1000,
reconnect: {
attempts: Infinity,
delay: 1000,
},
keepAlive: {
interval: 15000,
},
}),
});
}
Expand Down
38 changes: 23 additions & 15 deletions tee-apps/sealed-bid-auction/src/blockchain/ViemIntentObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
decodeAbiParameters,
parseEventLogs,
trim,
type Log,
type WatchEventOnLogsParameter,
} from "viem";

Expand All @@ -21,6 +20,9 @@ const HISTORICAL_BLOCK_CHUNK_SIZE = 100n;

export class ViemIntentObserver {
private logger: WinstonLogger;

private websocketError: boolean = false;
private lastProcessedBlock: bigint | null = null;

constructor(
private readonly sourceChainClient: BlockchainClient,
Expand All @@ -30,16 +32,16 @@ export class ViemIntentObserver {
private readonly destinationChainId: number,
private readonly destinationChainT1Erc7683ContractAddress: `0x${string}`,
private readonly auctionPollingInterval: number = 500,
private readonly fromBlock: bigint | null
private readonly initialFromBlock: bigint | null
) {
this.logger = new WinstonLogger(
`${ViemIntentObserver.name}[${this.sourceChainClient.publicClient.chain.name}]`
);
}

public async start() {
if (this.fromBlock !== null) {
await this.fetchHistoricalLogs();
if (this.initialFromBlock !== null) {
await this.fetchHistoricalLogs(this.initialFromBlock);
}

this.startWatching();
Expand All @@ -49,25 +51,31 @@ export class ViemIntentObserver {
this.sourceChainClient.publicClient.watchEvent({
address: this.sourceChainT1Erc7683ContractAddress,
event: OPEN_INTENT_ABI_EVENT,
onLogs: (logs) => this.processIntentLogs(logs),
onError: (error) => this.logger.error(`Error from publicClient.watchEvent: ${error}`),
onLogs: async (logs) => {
if (this.websocketError && this.lastProcessedBlock) {
this.logger.info(`I recovered from websocket error! Fetching historical logs from block ${this.lastProcessedBlock + 1n}`);
await this.fetchHistoricalLogs(this.lastProcessedBlock + 1n);
this.websocketError = false;
}
await this.processIntentLogs(logs);
},
onError: (error) => {
this.websocketError = true;
this.logger.error(`Error from publicClient.watchEvent: ${error}`);
},
});

this.logger.info(
`Watching for Open Intent events on chain [${this.sourceChainClient.publicClient.chain.name}] and contract [${this.sourceChainT1Erc7683ContractAddress}]`
);
}

private async fetchHistoricalLogs() {
if (this.fromBlock === null) return;

private async fetchHistoricalLogs(fromBlock: bigint) {
const currentBlock = await this.sourceChainClient.publicClient.getBlockNumber();
this.logger.info(
`Fetching historical logs from block ${this.fromBlock} to ${currentBlock}`
`Fetching historical logs from block ${fromBlock} to ${currentBlock}`
);

let fromBlock = this.fromBlock;

while (fromBlock <= currentBlock) {
const toBlock = fromBlock + HISTORICAL_BLOCK_CHUNK_SIZE - 1n > currentBlock
? currentBlock
Expand Down Expand Up @@ -103,7 +111,7 @@ export class ViemIntentObserver {

for (let i = 0; i < parsedLogs.length; i++) {
const order = parsedLogs[i];
const rawLog = logs[i];
const rawLog = logs[i]!;

// Convert raw log to eth_getLogs hex format for tokka-filler
const openEvent: OpenEventLog = {
Expand All @@ -126,7 +134,7 @@ export class ViemIntentObserver {

const orderData = decodedOrder as OrderData;

await this.runAuctionAndNotifySolver(
this.runAuctionAndNotifySolver(
{
sender: trim(orderData.sender),
recipient: trim(orderData.recipient),
Expand All @@ -144,7 +152,7 @@ export class ViemIntentObserver {
},
order.args.orderId,
openEvent
);
).then(() => this.lastProcessedBlock = BigInt(rawLog.blockNumber));
}
}
}
Expand Down
Loading