diff --git a/packages/sequencer/src/settlement/SettlementModule.ts b/packages/sequencer/src/settlement/SettlementModule.ts
index a80cfdb50..7e2b44a7e 100644
--- a/packages/sequencer/src/settlement/SettlementModule.ts
+++ b/packages/sequencer/src/settlement/SettlementModule.ts
@@ -206,13 +206,15 @@ export class SettlementModule
this.utils.signTransaction(tx, [feepayer], this.getContractKeys());
- await this.transactionSender.proveAndSendTransaction(tx, "included");
+ const { hash: transactionHash } =
+ await this.transactionSender.proveAndSendTransaction(tx, "included");
log.info("Settlement transaction send queued");
const settlement = {
batches: [batch.height],
promisedMessagesHash: latestSequenceStateHash.toString(),
+ transactionHash,
};
await this.settlementStorage.pushSettlement(settlement);
diff --git a/packages/sequencer/src/settlement/transactions/MinaTransactionSender.ts b/packages/sequencer/src/settlement/transactions/MinaTransactionSender.ts
index 551476616..ac20a8ad1 100644
--- a/packages/sequencer/src/settlement/transactions/MinaTransactionSender.ts
+++ b/packages/sequencer/src/settlement/transactions/MinaTransactionSender.ts
@@ -25,6 +25,9 @@ export interface TxEvents extends EventsRecord {
rejected: [any];
}
+export type TxSendResult =
+ Input extends "none" ? void : { hash: string };
+
@injectable()
export class MinaTransactionSender {
private txStatusEmitters: Record> = {};
@@ -113,10 +116,12 @@ export class MinaTransactionSender {
return eventEmitter;
}
- public async proveAndSendTransaction(
+ public async proveAndSendTransaction<
+ Wait extends "sent" | "included" | "none",
+ >(
transaction: Transaction,
- waitOnStatus: "sent" | "included" | "none" = "none"
- ) {
+ waitOnStatus: Wait
+ ): Promise> {
const { publicKey, nonce } = transaction.transaction.feePayer.body;
log.debug(
@@ -167,16 +172,24 @@ export class MinaTransactionSender {
const txStatus = await this.sendOrQueue(result.transaction);
if (waitOnStatus !== "none") {
- await new Promise((resolve, reject) => {
- txStatus.on(waitOnStatus, () => {
- log.info("Tx included");
- resolve();
- });
- txStatus.on("rejected", (error) => {
- reject(error);
- });
- });
+ const waitInstruction: "sent" | "included" = waitOnStatus;
+ const hash = await new Promise>(
+ (resolve, reject) => {
+ txStatus.on(waitInstruction, (txSendResult) => {
+ log.info(`Tx ${txSendResult.hash} included`);
+ resolve(txSendResult);
+ });
+ txStatus.on("rejected", (error) => {
+ reject(error);
+ });
+ }
+ );
+
+ // Yeah that's not super clean, but couldn't figure out a better way tbh
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
+ return hash as TxSendResult;
}
- return txStatus;
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
+ return undefined as TxSendResult;
}
}
diff --git a/packages/sequencer/src/settlement/transactions/MinaTransactionSimulator.ts b/packages/sequencer/src/settlement/transactions/MinaTransactionSimulator.ts
index babbbc898..00fdee20f 100644
--- a/packages/sequencer/src/settlement/transactions/MinaTransactionSimulator.ts
+++ b/packages/sequencer/src/settlement/transactions/MinaTransactionSimulator.ts
@@ -11,10 +11,14 @@ import {
UInt32,
Transaction,
} from "o1js";
-import { ReturnType } from "@proto-kit/protocol";
+import {
+ ACTIONS_EMPTY_HASH,
+ MINA_EVENT_PREFIXES,
+ ReturnType,
+} from "@proto-kit/protocol";
import { match } from "ts-pattern";
import { inject, injectable } from "tsyringe";
-import { noop } from "@proto-kit/common";
+import { hashWithPrefix, noop, range } from "@proto-kit/common";
import { distinctByPredicate } from "../../helpers/utils";
import type { MinaBaseLayer } from "../../protocol/baselayer/MinaBaseLayer";
@@ -277,6 +281,13 @@ export class MinaTransactionSimulator {
}).verificationKey = update.verificationKey.value;
}
+ this.applyZkApp(account, au.body);
+ }
+
+ private applyZkApp(
+ account: Account,
+ { update, actions }: AccountUpdate["body"]
+ ) {
if (account.zkapp !== undefined) {
const { appState } = update;
for (let i = 0; i < 8; i++) {
@@ -284,6 +295,18 @@ export class MinaTransactionSimulator {
account.zkapp.appState[i] = appState[i].value;
}
}
+
+ if (actions.data.length > 0) {
+ // We don't care about the correct historical array, so we just
+ // populate the full array with the current value
+ const previousActionState =
+ account.zkapp.actionState.at(0) ?? ACTIONS_EMPTY_HASH;
+ const newActionsHash = hashWithPrefix(
+ MINA_EVENT_PREFIXES.sequenceEvents,
+ [previousActionState, actions.hash]
+ );
+ account.zkapp.actionState = range(0, 5).map(() => newActionsHash);
+ }
}
}
}