Skip to content
15 changes: 5 additions & 10 deletions packages/common/src/compiling/CompileRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,17 @@ export class CompileRegistry {
return result;
}

public async compile(target: CompileTarget, proverNeeded: boolean = true) {
if (this.artifacts[target.name] === undefined || this.inForceProverBlock) {
public async compile(target: CompileTarget, nameOverride?: string) {
const name = nameOverride ?? target.name;
if (this.artifacts[name] === undefined || this.inForceProverBlock) {
const artifact = await this.compiler.compileContract(target);
this.artifacts[target.name] = artifact;
this.artifacts[name] = artifact;
return artifact;
}
return this.artifacts[target.name];
return this.artifacts[name];
}

public getArtifact(name: string): CompileArtifact | undefined {
if (this.artifacts[name] === undefined) {
throw new Error(
`Artifact for ${name} not available, did you compile it via the CompileRegistry?`
);
}

return this.artifacts[name];
}

Expand Down
12 changes: 11 additions & 1 deletion packages/common/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
// allows to reference interfaces as 'classes' rather than instances
import { Bool, DynamicProof, Field, Proof, ProofBase, PublicKey } from "o1js";
import {
Bool,
DynamicProof,
Field,
Proof,
ProofBase,
PublicKey,
Option,
} from "o1js";

export type TypedClass<Class> = new (...args: any[]) => Class;

Expand Down Expand Up @@ -56,3 +64,5 @@ export type InferProofBase<
: ProofType extends DynamicProof<infer PI, infer PO>
? ProofBase<PI, PO>
: undefined;

export class O1PublicKeyOption extends Option(PublicKey) {}
4 changes: 2 additions & 2 deletions packages/protocol/src/hooks/NoopSettlementHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import {
ProvableSettlementHook,
SettlementHookInputs,
} from "../settlement/modularity/ProvableSettlementHook";
import { SettlementSmartContractBase } from "../settlement/contracts/SettlementSmartContract";
import { SettlementContractType } from "../settlement/contracts/settlement/SettlementBase";

@injectable()
export class NoopSettlementHook extends ProvableSettlementHook<
Record<string, never>
> {
public async beforeSettlement(
contract: SettlementSmartContractBase,
contract: SettlementContractType,
state: SettlementHookInputs
) {
noop();
Expand Down
8 changes: 6 additions & 2 deletions packages/protocol/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,11 @@ export * from "./state/assert/assert";
export * from "./settlement/contracts/authorizations/ContractAuthorization";
export * from "./settlement/contracts/authorizations/UpdateMessagesHashAuth";
export * from "./settlement/contracts/authorizations/TokenBridgeDeploymentAuth";
export * from "./settlement/contracts/SettlementSmartContract";
export * from "./settlement/contracts/SettlementContractProtocolModule";
export * from "./settlement/contracts/settlement/SettlementBase";
export * from "./settlement/contracts/settlement/SettlementContract";
export * from "./settlement/contracts/settlement/BridgingSettlementContract";
export * from "./settlement/contracts/BridgingSettlementContractModule";
export * from "./settlement/contracts/SettlementSmartContractModule";
export * from "./settlement/contracts/DispatchSmartContract";
export * from "./settlement/contracts/DispatchContractProtocolModule";
export * from "./settlement/contracts/BridgeContract";
Expand All @@ -60,6 +63,7 @@ export * from "./settlement/messages/OutgoingMessageArgument";
export * from "./settlement/messages/OutgoingMessage";
export * from "./settlement/modules/NetworkStateSettlementModule";
export * from "./settlement/messages/Deposit";
export * from "./settlement/ContractArgsRegistry";
export { constants as ProtocolConstants } from "./Constants";
export * from "./hashing/protokit-prefixes";
export * from "./hashing/mina-prefixes";
60 changes: 60 additions & 0 deletions packages/protocol/src/settlement/ContractArgsRegistry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { injectable, singleton } from "tsyringe";
import merge from "lodash/merge";

export interface StaticInitializationContract<Args> {
getInitializationArgs(): Args;
}

export type NaiveObjectSchema<Obj> = {
[Key in keyof Obj]: undefined extends Obj[Key] ? "Optional" : "Required";
};

/*
interface Test {
one: string;
two?: string;
}

const x: NaiveObjectSchema<Test> = {
one: "Required",
two: "Optional",
};
*/

@injectable()
@singleton()
export class ContractArgsRegistry {
args: Record<string, any> = {};

public addArgs<Type>(name: string, addition: Partial<Type>) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const args: Partial<Type> = this.args[name] ?? {};
this.args[name] = merge(args, addition);
}

public resetArgs(name: string) {
delete this.args[name];
}

public getArgs<Type>(name: string, schema: NaiveObjectSchema<Type>): Type {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const args = this.args[name] ?? {};

const missing = Object.entries<"Optional" | "Required">(schema).filter(
([key, type]) => {
// We filter only if the key is required and isn't present
return type === "Required" && args[key] === undefined;
}
);

if (missing.length > 0) {
const missingKeys = missing.map(([key]) => key);
throw new Error(
`Contract args for ${name} not all present, ${missingKeys} are missing`
);
} else {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return args as Type;
}
}
}
107 changes: 56 additions & 51 deletions packages/protocol/src/settlement/SettlementContractModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,19 @@ import { ProtocolModule } from "../protocol/ProtocolModule";
import { ContractModule } from "./ContractModule";
import { DispatchContractProtocolModule } from "./contracts/DispatchContractProtocolModule";
import { DispatchContractType } from "./contracts/DispatchSmartContract";
import {
SettlementContractConfig,
SettlementContractProtocolModule,
} from "./contracts/SettlementContractProtocolModule";
import { SettlementContractType } from "./contracts/SettlementSmartContract";
import { BridgingSettlementContractModule } from "./contracts/BridgingSettlementContractModule";
import { BridgeContractType } from "./contracts/BridgeContract";
import {
BridgeContractConfig,
BridgeContractProtocolModule,
} from "./contracts/BridgeContractProtocolModule";
import { GetContracts } from "./modularity/types";
import { GetContracts, InferContractType } from "./modularity/types";
import { BridgingSettlementContractType } from "./contracts/settlement/BridgingSettlementContract";
import { SettlementContractType } from "./contracts/settlement/SettlementBase";
import {
SettlementContractConfig,
SettlementSmartContractModule,
} from "./contracts/SettlementSmartContractModule";

export type SettlementModulesRecord = ModulesRecord<
TypedClass<ContractModule<unknown, unknown>>
Expand All @@ -36,6 +38,12 @@ export type MandatorySettlementModulesRecord = {
SettlementContract: TypedClass<
ContractModule<SettlementContractType, SettlementContractConfig>
>;
};

export type BridgingSettlementModulesRecord = {
SettlementContract: TypedClass<
ContractModule<BridgingSettlementContractType, SettlementContractConfig>
>;
DispatchContract: TypedClass<ContractModule<DispatchContractType, unknown>>;
BridgeContract: TypedClass<
ContractModule<BridgeContractType, BridgeContractConfig>
Expand All @@ -44,8 +52,7 @@ export type MandatorySettlementModulesRecord = {

@injectable()
export class SettlementContractModule<
SettlementModules extends SettlementModulesRecord &
MandatorySettlementModulesRecord,
SettlementModules extends SettlementModulesRecord,
>
extends ModuleContainer<SettlementModules>
implements ProtocolModule<unknown>
Expand All @@ -54,10 +61,7 @@ export class SettlementContractModule<
super(definition);
}

public static from<
SettlementModules extends SettlementModulesRecord &
MandatorySettlementModulesRecord,
>(
public static from<SettlementModules extends SettlementModulesRecord>(
modules: SettlementModules
): TypedClass<SettlementContractModule<SettlementModules>> {
return class ScopedSettlementContractModule extends SettlementContractModule<SettlementModules> {
Expand All @@ -67,27 +71,18 @@ export class SettlementContractModule<
};
}

public static mandatoryModules() {
public static settlementOnly() {
return {
SettlementContract: SettlementContractProtocolModule,
DispatchContract: DispatchContractProtocolModule,
BridgeContract: BridgeContractProtocolModule,
SettlementContract: SettlementSmartContractModule,
} as const;
}

public static fromDefaults() {
return SettlementContractModule.from(
SettlementContractModule.mandatoryModules()
);
}

public static with<AdditionalModules extends SettlementModulesRecord>(
additionalModules: AdditionalModules
) {
return SettlementContractModule.from({
...SettlementContractModule.mandatoryModules(),
...additionalModules,
} as const);
public static settlementAndBridging() {
return {
SettlementContract: BridgingSettlementContractModule,
DispatchContract: DispatchContractProtocolModule,
BridgeContract: BridgeContractProtocolModule,
} as const;
}

// ** For protocol module
Expand Down Expand Up @@ -116,30 +111,40 @@ export class SettlementContractModule<
return Object.fromEntries(contracts);
}

public createContracts(addresses: {
settlement: PublicKey;
dispatch: PublicKey;
}): {
settlement: SettlementContractType & SmartContract;
dispatch: DispatchContractType & SmartContract;
} {
const { DispatchContract, SettlementContract } = this.getContractClasses();

const dispatchInstance = new DispatchContract(addresses.dispatch);
const settlementInstance = new SettlementContract(addresses.settlement);

return {
dispatch: dispatchInstance,
settlement: settlementInstance,
};
}

public createBridgeContract(
public createContract<ContractName extends StringKeyOf<SettlementModules>>(
contractName: ContractName,
address: PublicKey,
tokenId?: Field
): BridgeContractType & SmartContract {
const { BridgeContract } = this.getContractClasses();
): InferContractType<SettlementModules[ContractName]> {
const module = this.resolve(contractName);
const ContractClass = module.contractFactory();
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return new ContractClass(address, tokenId) as InferContractType<
SettlementModules[ContractName]
>;
}

return new BridgeContract(address, tokenId);
public createContracts<
ContractName extends keyof SettlementModules,
>(addresses: {
[Key in ContractName]: PublicKey;
}): {
[Key in ContractName]: SmartContract &
InferContractType<SettlementModules[Key]>;
} {
const classes = this.getContractClasses();

const obj: Record<string, SmartContract> = {};
// eslint-disable-next-line guard-for-in
for (const key in addresses) {
const ContractClass = classes[key];
obj[key] = new ContractClass(addresses[key]);
}

// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return obj as {
[Key in keyof SettlementModules]: SmartContract &
InferContractType<SettlementModules[Key]>;
};
}
}
Loading