Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion tee-apps/intent-pauser/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ bun install
To configure:

```bash
cp .env.example .env
cp .env.template .env
```

... and fill in the values in `.env`.

To run:
Expand Down
5 changes: 5 additions & 0 deletions tee-apps/sealed-bid-auction/.env.template
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ SOLVER_PRICE_TTL_SECONDS=600
NEXT_NONCE_URL=
IS_MAINNET=false

# optional from blocks for historical event logging
# these are useful if we miss events and want to rewind
INTENT_OBSERVER_FROM_BLOCK_BASE=
Comment thread
kss-t1 marked this conversation as resolved.
INTENT_OBSERVER_FROM_BLOCK_ARBITRUM=

#Arbitrum
ARBITRUM_WS=
ARBITRUM_T1_ERC7683_CONTRACT_ADDRESS=
Expand Down
7 changes: 7 additions & 0 deletions tee-apps/sealed-bid-auction/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ bun install
```
Save TLS key in `key.pem` and certificate in `cert.pem` . Consider using CloudFlare Origin Server Certificate (of course if you use CloudFlare)

To configure:

```bash
cp .env.template .env
```
... and fill in the values in `.env`.

### To run:

Start server:
Expand Down
15 changes: 13 additions & 2 deletions tee-apps/sealed-bid-auction/script/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,32 @@ const baseClient = new BlockchainClient(
IS_MAINNET ? base : baseSepolia,
process.env.BASE_SIGNER_PRIVATE_KEY as `0x${string}`
);

const fromBlockEnvArbitrum = process.env.INTENT_OBSERVER_FROM_BLOCK_ARBITRUM;
const fromBlockArbitrum = fromBlockEnvArbitrum ? BigInt(fromBlockEnvArbitrum) : null;
const fromBlockEnvBase = process.env.INTENT_OBSERVER_FROM_BLOCK_BASE;
const fromBlockBase = fromBlockEnvBase ? BigInt(fromBlockEnvBase) : null;
const auctionPollingInterval = 500;

const arbitrumSepoliaIntentObserver = new ViemIntentObserver(
arbitrumClient,
ARBITRUM_T1_ERC_7683_CONTRACT_ADDRESS,
auctionService,
httpServer,
baseClient.publicClient.chain.id,
BASE_T1_ERC_7683_CONTRACT_ADDRESS
BASE_T1_ERC_7683_CONTRACT_ADDRESS,
auctionPollingInterval,
fromBlockArbitrum
);
const baseSepoliaIntentObserver = new ViemIntentObserver(
baseClient,
BASE_T1_ERC_7683_CONTRACT_ADDRESS,
auctionService,
httpServer,
arbitrumClient.publicClient.chain.id,
ARBITRUM_T1_ERC_7683_CONTRACT_ADDRESS
ARBITRUM_T1_ERC_7683_CONTRACT_ADDRESS,
auctionPollingInterval,
fromBlockBase
);

async function main() {
Expand Down
13 changes: 13 additions & 0 deletions tee-apps/sealed-bid-auction/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,25 @@ export interface AuctionQuote {
timestamp: number;
}

export interface OpenEventLog {
address: string;
topics: string[];
data: string;
blockNumber: string;
transactionHash: string;
transactionIndex: string;
blockHash: string;
logIndex: string;
removed: boolean;
}

export interface AuctionResult {
type: string;
orderId: string;
settlementReceiverAddress: string;
amountOut: bigint;
signature: string;
openEvent: OpenEventLog;
}

export interface AuthAttempt {
Expand Down
96 changes: 84 additions & 12 deletions tee-apps/sealed-bid-auction/src/blockchain/ViemIntentObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
decodeAbiParameters,
parseEventLogs,
trim,
type Log,
type WatchEventOnLogsParameter,
} from "viem";

Expand All @@ -14,26 +15,37 @@ import {
import type { AuctionApiServer } from "../api/AuctionApiServer.ts";
import { serialize, WinstonLogger } from "../utils/WinstonLogger.ts";
import type { BlockchainClient } from "./BlockchainClient.ts";
import type { AuctionResult } from "../api/types.ts";
import type { AuctionResult, OpenEventLog } from "../api/types.ts";

const HISTORICAL_BLOCK_CHUNK_SIZE = 100n;

export class ViemIntentObserver {
private logger: WinstonLogger;

constructor(
private readonly sourceChainClient: BlockchainClient,
private readonly sourceChainT1Erc7683ContractAddress: `0x${string}`,
private readonly auctionService: AuctionService,
private readonly apiServer: AuctionApiServer,
private readonly destinationChainId: number,
private readonly destinationChainT1Erc7683ContractAddress: `0x${string}`,
private readonly auctionPollingInterval: number = 500
private readonly auctionPollingInterval: number = 500,
private readonly fromBlock: bigint | null
) {
this.logger = new WinstonLogger(
`${ViemIntentObserver.name}[${this.sourceChainClient.publicClient.chain.name}]`
);
}

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

this.startWatching();
}

private startWatching() {
this.sourceChainClient.publicClient.watchEvent({
address: this.sourceChainT1Erc7683ContractAddress,
event: OPEN_INTENT_ABI_EVENT,
Expand All @@ -46,6 +58,41 @@ export class ViemIntentObserver {
);
}

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

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

let fromBlock = this.fromBlock;

while (fromBlock <= currentBlock) {
const toBlock = fromBlock + HISTORICAL_BLOCK_CHUNK_SIZE - 1n > currentBlock
? currentBlock
: fromBlock + HISTORICAL_BLOCK_CHUNK_SIZE - 1n;

this.logger.info(`Fetching logs from block ${fromBlock} to ${toBlock}`);

const logs = await this.sourceChainClient.publicClient.getLogs({
address: this.sourceChainT1Erc7683ContractAddress,
event: OPEN_INTENT_ABI_EVENT,
fromBlock,
toBlock,
});

if (logs.length > 0) {
this.logger.info(`Found ${logs.length} historical logs in blocks ${fromBlock}-${toBlock}`);
await this.processIntentLogs(logs as unknown as WatchEventOnLogsParameter);
}

fromBlock = toBlock + 1n;
}

this.logger.info(`Finished fetching historical logs, caught up to block ${currentBlock}`);
}

private async processIntentLogs(logs: WatchEventOnLogsParameter) {
this.logger.info("Intent was Open-ed!");

Expand All @@ -54,7 +101,23 @@ export class ViemIntentObserver {
logs,
});

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

// Convert raw log to eth_getLogs hex format for tokka-filler
const openEvent: OpenEventLog = {
address: rawLog.address,
topics: rawLog.topics as string[],
data: rawLog.data,
blockNumber: `0x${rawLog.blockNumber.toString(16)}`,
transactionHash: rawLog.transactionHash,
transactionIndex: `0x${rawLog.transactionIndex.toString(16)}`,
blockHash: rawLog.blockHash,
logIndex: `0x${rawLog.logIndex.toString(16)}`,
removed: rawLog.removed,
};

for (const fillInstruction of order.args.resolvedOrder.fillInstructions) {
const [decodedOrder] = decodeAbiParameters(
ORDER_DATA_ABI_PARAMETERS_WRAPPED_IN_TUPLE,
Expand All @@ -79,26 +142,34 @@ export class ViemIntentObserver {
closedAuction: orderData.closedAuction,
data: orderData.data,
},
order.args.orderId
order.args.orderId,
openEvent
);
}
}
}

private async runAuctionAndNotifySolver(
orderData: OrderData,
orderId: `0x${string}`
orderId: `0x${string}`,
openEvent: OpenEventLog
) {
this.logger.info(`Running auction for order ${orderId}`);

this.logger.debug(`Running auction for orderData ${serialize(orderData)}`);

while (Date.now() / 1000 < orderData.fillDeadline) {
const winningPrice = this.auctionService.auction(
orderData.inputToken,
orderData.outputToken,
orderData.amountIn
);
let winningPrice;
try {
winningPrice = this.auctionService.auction(
orderData.inputToken,
orderData.outputToken,
orderData.amountIn
);
} catch (e) {
this.logger.error(`Auction error: ${e}`);
break;
}

this.logger.debug(`Auction winner: ${serialize(winningPrice)}`);

Expand All @@ -116,6 +187,7 @@ export class ViemIntentObserver {
winningPrice.settlementReceiverAddress as `0x${string}`,
winningPrice.amountOut
),
openEvent,
};

await this.apiServer.notifySolvers(
Expand Down