Skip to content

Commit 0a0d284

Browse files
committed
Made baselayer contracts more extensible using inheritance
1 parent 61f7f17 commit 0a0d284

File tree

5 files changed

+103
-42
lines changed

5 files changed

+103
-42
lines changed

packages/protocol/src/settlement/contracts/DispatchContractProtocolModule.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import {
1010
DispatchSmartContract,
1111
DispatchContractType,
12+
DispatchSmartContractBase,
1213
} from "./DispatchSmartContract";
1314

1415
export type DispatchContractConfig = {
@@ -29,7 +30,7 @@ export class DispatchContractProtocolModule extends ContractModule<
2930
const { incomingMessagesMethods } = this.config;
3031
const methodIdMappings = this.runtime.methodIdResolver.methodIdMap();
3132

32-
DispatchSmartContract.args = {
33+
DispatchSmartContractBase.args = {
3334
incomingMessagesPaths: incomingMessagesMethods,
3435
methodIdMappings,
3536
};

packages/protocol/src/settlement/contracts/DispatchSmartContract.ts

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,23 +32,19 @@ export interface DispatchContractType {
3232
promisedMessagesHash: State<Field>;
3333
}
3434

35-
export class DispatchSmartContract
36-
extends SmartContract
37-
implements DispatchContractType
38-
{
35+
export abstract class DispatchSmartContractBase extends SmartContract {
3936
public static args: {
4037
methodIdMappings: RuntimeMethodIdMapping;
4138
incomingMessagesPaths: Record<string, `${string}.${string}`>;
4239
};
4340

44-
@state(Field) public promisedMessagesHash = State<Field>();
41+
abstract promisedMessagesHash: State<Field>;
4542

46-
@state(Field) public honoredMessagesHash = State<Field>();
43+
abstract honoredMessagesHash: State<Field>;
4744

48-
@state(PublicKey) public settlementContract = State<PublicKey>();
45+
abstract settlementContract: State<PublicKey>;
4946

50-
@method
51-
public async updateMessagesHash(
47+
protected async updateMessagesHashBase(
5248
executedMessagesHash: Field,
5349
newPromisedMessagesHash: Field
5450
) {
@@ -65,8 +61,7 @@ export class DispatchSmartContract
6561
this.promisedMessagesHash.set(newPromisedMessagesHash);
6662
}
6763

68-
@method
69-
public async initialize(settlementContract: PublicKey) {
64+
protected async initializeBase(settlementContract: PublicKey) {
7065
this.promisedMessagesHash.getAndRequireEquals().assertEquals(Field(0));
7166
this.honoredMessagesHash.getAndRequireEquals().assertEquals(Field(0));
7267
this.settlementContract
@@ -78,7 +73,7 @@ export class DispatchSmartContract
7873
this.settlementContract.set(settlementContract);
7974
}
8075

81-
private dispatchMessage<Type>(
76+
protected dispatchMessage<Type>(
8277
methodId: Field,
8378
value: Type,
8479
valueType: ProvableExtended<Type>
@@ -106,6 +101,33 @@ export class DispatchSmartContract
106101
data: [args],
107102
};
108103
}
104+
}
105+
106+
export class DispatchSmartContract
107+
extends DispatchSmartContractBase
108+
implements DispatchContractType
109+
{
110+
@state(Field) public promisedMessagesHash = State<Field>();
111+
112+
@state(Field) public honoredMessagesHash = State<Field>();
113+
114+
@state(PublicKey) public settlementContract = State<PublicKey>();
115+
116+
@method
117+
public async updateMessagesHash(
118+
executedMessagesHash: Field,
119+
newPromisedMessagesHash: Field
120+
) {
121+
return await this.updateMessagesHashBase(
122+
executedMessagesHash,
123+
newPromisedMessagesHash
124+
);
125+
}
126+
127+
@method
128+
public async initialize(settlementContract: PublicKey) {
129+
return await this.initializeBase(settlementContract);
130+
}
109131

110132
@method
111133
public async deposit(amount: UInt64) {
@@ -126,7 +148,7 @@ export class DispatchSmartContract
126148
});
127149

128150
const { methodIdMappings, incomingMessagesPaths } =
129-
DispatchSmartContract.args;
151+
DispatchSmartContractBase.args;
130152

131153
const methodId = Field(
132154
methodIdMappings[incomingMessagesPaths.deposit].methodId

packages/protocol/src/settlement/contracts/SettlementContractProtocolModule.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
LazyBlockProof,
1515
SettlementContractType,
1616
SettlementSmartContract,
17+
SettlementSmartContractBase,
1718
} from "./SettlementSmartContract";
1819

1920
export type SettlementContractConfig = {
@@ -55,7 +56,7 @@ export class SettlementContractProtocolModule extends ContractModule<
5556
const escapeHatchSlotsInterval =
5657
config.escapeHatchSlotsInterval ?? DEFAULT_ESCAPE_HATCH;
5758

58-
SettlementSmartContract.args = {
59+
SettlementSmartContractBase.args = {
5960
DispatchContract: dispatchContract,
6061
hooks,
6162
withdrawalStatePath: withdrawalStatePathSplit,

packages/protocol/src/settlement/contracts/SettlementSmartContract.ts

Lines changed: 62 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,7 @@ export interface SettlementContractType {
8383
// Some random prefix for the sequencer signature
8484
export const BATCH_SIGNATURE_PREFIX = prefixToField("pk-batchSignature");
8585

86-
export class SettlementSmartContract
87-
extends TokenContract
88-
implements SettlementContractType
89-
{
86+
export abstract class SettlementSmartContractBase extends TokenContract {
9087
// This pattern of injecting args into a smartcontract is currently the only
9188
// viable solution that works given the inheritance issues of o1js
9289
public static args: {
@@ -96,23 +93,18 @@ export class SettlementSmartContract
9693
escapeHatchSlotsInterval: number;
9794
};
9895

99-
@state(Field) public sequencerKey = State<Field>();
100-
@state(UInt32) public lastSettlementL1BlockHeight = State<UInt32>();
101-
102-
@state(Field) public stateRoot = State<Field>();
103-
@state(Field) public networkStateHash = State<Field>();
104-
@state(Field) public blockHashRoot = State<Field>();
105-
106-
@state(Field) public dispatchContractAddressX = State<Field>();
107-
108-
@state(Field) public outgoingMessageCursor = State<Field>();
96+
abstract sequencerKey: State<Field>;
97+
abstract lastSettlementL1BlockHeight: State<UInt32>;
98+
abstract stateRoot: State<Field>;
99+
abstract networkStateHash: State<Field>;
100+
abstract blockHashRoot: State<Field>;
101+
abstract dispatchContractAddressX: State<Field>;
102+
abstract outgoingMessageCursor: State<Field>;
109103

110-
@method async approveBase(forest: AccountUpdateForest) {
111-
this.checkZeroBalanceChange(forest);
112-
}
113-
114-
@method
115-
public async initialize(sequencer: PublicKey, dispatchContract: PublicKey) {
104+
protected async initializeBase(
105+
sequencer: PublicKey,
106+
dispatchContract: PublicKey
107+
) {
116108
this.sequencerKey.getAndRequireEquals().assertEquals(Field(0));
117109
this.stateRoot.getAndRequireEquals().assertEquals(Field(0));
118110
this.blockHashRoot.getAndRequireEquals().assertEquals(Field(0));
@@ -125,13 +117,12 @@ export class SettlementSmartContract
125117
this.networkStateHash.set(NetworkState.empty().hash());
126118
this.dispatchContractAddressX.set(dispatchContract.x);
127119

128-
const { DispatchContract } = SettlementSmartContract.args;
120+
const { DispatchContract } = SettlementSmartContractBase.args;
129121
const contractInstance = new DispatchContract(dispatchContract);
130122
await contractInstance.initialize(this.address);
131123
}
132124

133-
@method
134-
public async settle(
125+
protected async settleBase(
135126
blockProof: LazyBlockProof,
136127
signature: Signature,
137128
dispatchContractAddress: PublicKey,
@@ -159,7 +150,7 @@ export class SettlementSmartContract
159150
);
160151

161152
const { DispatchContract, escapeHatchSlotsInterval, hooks } =
162-
SettlementSmartContract.args;
153+
SettlementSmartContractBase.args;
163154

164155
// Get dispatch contract values
165156
// These values are witnesses but will be checked later on the AU
@@ -265,14 +256,60 @@ export class SettlementSmartContract
265256

266257
this.lastSettlementL1BlockHeight.set(minBlockHeightIncluded);
267258
}
259+
}
260+
261+
export class SettlementSmartContract
262+
extends SettlementSmartContractBase
263+
implements SettlementContractType
264+
{
265+
@state(Field) public sequencerKey = State<Field>();
266+
@state(UInt32) public lastSettlementL1BlockHeight = State<UInt32>();
267+
268+
@state(Field) public stateRoot = State<Field>();
269+
@state(Field) public networkStateHash = State<Field>();
270+
@state(Field) public blockHashRoot = State<Field>();
271+
272+
@state(Field) public dispatchContractAddressX = State<Field>();
273+
274+
@state(Field) public outgoingMessageCursor = State<Field>();
275+
276+
@method async approveBase(forest: AccountUpdateForest) {
277+
this.checkZeroBalanceChange(forest);
278+
}
279+
280+
@method
281+
public async initialize(sequencer: PublicKey, dispatchContract: PublicKey) {
282+
return await this.initializeBase(sequencer, dispatchContract);
283+
}
284+
285+
@method
286+
public async settle(
287+
blockProof: LazyBlockProof,
288+
signature: Signature,
289+
dispatchContractAddress: PublicKey,
290+
publicKey: PublicKey,
291+
inputNetworkState: NetworkState,
292+
outputNetworkState: NetworkState,
293+
newPromisedMessagesHash: Field
294+
) {
295+
return await this.settleBase(
296+
blockProof,
297+
signature,
298+
dispatchContractAddress,
299+
publicKey,
300+
inputNetworkState,
301+
outputNetworkState,
302+
newPromisedMessagesHash
303+
);
304+
}
268305

269306
@method
270307
public async rollupOutgoingMessages(batch: OutgoingMessageArgumentBatch) {
271308
let counter = this.outgoingMessageCursor.getAndRequireEquals();
272309
const stateRoot = this.stateRoot.getAndRequireEquals();
273310

274311
const [withdrawalModule, withdrawalStateName] =
275-
SettlementSmartContract.args.withdrawalStatePath;
312+
SettlementSmartContractBase.args.withdrawalStatePath;
276313
const mapPath = Path.fromProperty(withdrawalModule, withdrawalStateName);
277314

278315
let accountCreationFeePaid = Field(0);

packages/protocol/src/settlement/modularity/ProvableSettlementHook.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Field, PublicKey, UInt32 } from "o1js";
33
import { ProtocolModule } from "../../protocol/ProtocolModule";
44
import { NetworkState } from "../../model/network/NetworkState";
55
import type { BlockProof } from "../../prover/block/BlockProver";
6-
import type { SettlementSmartContract } from "../contracts/SettlementSmartContract";
6+
import type { SettlementSmartContractBase } from "../contracts/SettlementSmartContract";
77

88
export type SettlementStateRecord = {
99
sequencerKey: PublicKey;
@@ -27,7 +27,7 @@ export abstract class ProvableSettlementHook<
2727
Config,
2828
> extends ProtocolModule<Config> {
2929
public abstract beforeSettlement(
30-
smartContract: SettlementSmartContract,
30+
smartContract: SettlementSmartContractBase,
3131
inputs: SettlementHookInputs
3232
): Promise<void>;
3333
}

0 commit comments

Comments
 (0)