Skip to content
Open
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
5 changes: 1 addition & 4 deletions package-lock.json

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

94 changes: 55 additions & 39 deletions src/core/modes/intra/simulation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,43 +125,59 @@ export class IntraOrderbookTradeSimulator extends TradeSimulatorBase {
)!;

// build clear function call data and withdraw tasks
const taskBytecodeResult = await getEnsureBountyTaskBytecode(
{
type: EnsureBountyTaskType.Internal,
botAddress: this.tradeArgs.signer.account.address,
inputToken: this.tradeArgs.orderDetails.buyToken,
outputToken: this.tradeArgs.orderDetails.sellToken,
orgInputBalance: this.tradeArgs.inputBalance,
orgOutputBalance: this.tradeArgs.outputBalance,
inputToEthPrice: parseUnits(this.tradeArgs.inputToEthPrice, 18),
outputToEthPrice: parseUnits(this.tradeArgs.outputToEthPrice, 18),
minimumExpected: params.minimumExpected,
sender: this.tradeArgs.signer.account.address,
},
this.tradeArgs.solver.state.client,
addresses.dispair,
);
if (taskBytecodeResult.isErr()) {
const errMsg = await errorSnapshot("", taskBytecodeResult.error);
this.spanAttributes["isNodeError"] =
taskBytecodeResult.error.type === EnsureBountyTaskErrorType.ParseError;
this.spanAttributes["error"] = errMsg;
const result = {
type: TradeType.IntraOrderbook,
spanAttributes: this.spanAttributes,
reason: SimulationHaltReason.FailedToGetTaskBytecode,
// When gasCoveragePercentage is "0", the bounty task isn't
// included in the withdraw call, so skip the expensive on-chain
// compilation that requires dispair addresses.
const noBounty = this.tradeArgs.solver.appOptions.gasCoveragePercentage === "0";
let task: TaskType;
if (noBounty) {
task = {
evaluable: {
interpreter: "0x0000000000000000000000000000000000000000",
store: "0x0000000000000000000000000000000000000000",
bytecode: "0x",
},
signedContext: [],
};
} else {
const taskBytecodeResult = await getEnsureBountyTaskBytecode(
{
type: EnsureBountyTaskType.Internal,
botAddress: this.tradeArgs.signer.account.address,
inputToken: this.tradeArgs.orderDetails.buyToken,
outputToken: this.tradeArgs.orderDetails.sellToken,
orgInputBalance: this.tradeArgs.inputBalance,
orgOutputBalance: this.tradeArgs.outputBalance,
inputToEthPrice: parseUnits(this.tradeArgs.inputToEthPrice, 18),
outputToEthPrice: parseUnits(this.tradeArgs.outputToEthPrice, 18),
minimumExpected: params.minimumExpected,
sender: this.tradeArgs.signer.account.address,
},
this.tradeArgs.solver.state.client,
addresses.dispair,
);
if (taskBytecodeResult.isErr()) {
const errMsg = await errorSnapshot("", taskBytecodeResult.error);
this.spanAttributes["isNodeError"] =
taskBytecodeResult.error.type === EnsureBountyTaskErrorType.ParseError;
this.spanAttributes["error"] = errMsg;
const result = {
type: TradeType.IntraOrderbook,
spanAttributes: this.spanAttributes,
reason: SimulationHaltReason.FailedToGetTaskBytecode,
};
this.spanAttributes["duration"] = performance.now() - this.startTime;
return Result.err(result);
}
task = {
evaluable: {
interpreter: addresses.dispair.interpreter as `0x${string}`,
store: addresses.dispair.store as `0x${string}`,
bytecode: taskBytecodeResult.value,
},
signedContext: [],
};
this.spanAttributes["duration"] = performance.now() - this.startTime;
return Result.err(result);
}
const task = {
evaluable: {
interpreter: addresses.dispair.interpreter as `0x${string}`,
store: addresses.dispair.store as `0x${string}`,
bytecode: taskBytecodeResult.value,
},
signedContext: [],
};

params.rawtx.data = this.getCalldata(task);
return Result.ok(void 0);
Expand Down Expand Up @@ -253,8 +269,8 @@ export class IntraOrderbookTradeSimulator extends TradeSimulatorBase {
aliceBountyVaultId: BigInt(this.inputBountyVaultId),
bobBountyVaultId: BigInt(this.outputBountyVaultId),
},
[],
[],
this.tradeArgs.orderDetails.takeOrder.struct.signedContext,
this.tradeArgs.counterpartyOrderDetails.struct.signedContext,
],
});
return encodeFunctionData({
Expand Down Expand Up @@ -311,8 +327,8 @@ export class IntraOrderbookTradeSimulator extends TradeSimulatorBase {
aliceBountyVaultId: this.inputBountyVaultId,
bobBountyVaultId: this.outputBountyVaultId,
},
[],
[],
this.tradeArgs.orderDetails.takeOrder.struct.signedContext,
this.tradeArgs.counterpartyOrderDetails.struct.signedContext,
],
});
return encodeFunctionData({
Expand Down
41 changes: 41 additions & 0 deletions src/oracle/fetch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Order, Pair } from "../order/types";
import { SharedState } from "../state";
import { Result } from "../common";
import { fetchSignedContext } from ".";

/**
* If the order has an oracle URL, fetch signed context and inject it
* into the takeOrder struct. Called with SharedState as `this` to access
* the oracle health map.
*
* Returns Result — callers decide how to handle failures.
*/
export async function fetchOracleContext(
this: SharedState,
orderDetails: Pair,
): Promise<Result<void, string>> {
const oracleUrl = orderDetails.oracleUrl;
if (!oracleUrl) return Result.ok(undefined);

// Oracle signed context only supported for V4 orders
const order = orderDetails.takeOrder.struct.order;
if (order.type !== Order.Type.V4) return Result.ok(undefined);

const result = await fetchSignedContext(
oracleUrl,
{
order: order as Order.V4,
inputIOIndex: orderDetails.takeOrder.struct.inputIOIndex,
outputIOIndex: orderDetails.takeOrder.struct.outputIOIndex,
counterparty: "0x0000000000000000000000000000000000000000",
},
this.oracleHealth,
);

if (result.isErr()) {
return Result.err(result.error);
}

orderDetails.takeOrder.struct.signedContext = [result.value];
return Result.ok(undefined);
}
Loading
Loading