UNPKG

o1js

Version:

TypeScript framework for zk-SNARKs and zkApps

817 lines (689 loc) 26.6 kB
import { Compare, Eq, Option, Range } from './core.js'; import { GenericStatePreconditions, StatePreconditions, StateDefinition, StateLayout, } from './state.js'; import { Bool } from '../../provable/bool.js'; import { Field } from '../../provable/field.js'; import { UInt32, UInt64 } from '../../provable/int.js'; import { PublicKey } from '../../provable/crypto/signature.js'; import { HashInput } from '../../provable/types/provable-derivers.js'; // TODO: pull last remanants of old transaction leavs into v2 bindings import { Actions } from '../../../bindings/mina-transaction/v1/transaction-leaves.js'; import * as BindingsLayout from '../../../bindings/mina-transaction/gen/v2/js-layout.js'; import { ZkappConstants } from '../v1/constants.js'; import { MinaAmount } from './currency.js'; export { Preconditions, Precondition, PreconditionsDescription, EpochDataPreconditions, EpochLedgerPreconditions, }; namespace Precondition { export class Equals<T extends Eq<T>> { constructor( public isEnabled: Bool, public value: T ) {} toStringHuman(): string { if (!this.isEnabled.toBoolean()) { return 'disabled'; } else { return `== ${this.value}`; } } toValue<D>(defaultValue: D): T | D { if (this.isEnabled.toBoolean()) { return this.value; } else { return defaultValue; } } mapToValue<D, R>(defaultValue: D, f: (t: T) => R): R | D { if (this.isEnabled.toBoolean()) { return f(this.value); } else { return defaultValue; } } toOption(): Option<T> { return { isSome: this.isEnabled, value: this.value }; } isSatisfied(x: T): Bool { return Bool.or(this.isEnabled.not(), this.value.equals(x)); } static disabled<T extends Eq<T>>(defaultValue: T): Equals<T> { return new Equals(new Bool(false), defaultValue); } static equals<T extends Eq<T>>(value: T): Equals<T> { return new Equals(new Bool(true), value); } static fromOption<T extends Eq<T>>(option: Option<T>): Equals<T> { return new Equals(option.isSome, option.value); } static from<T extends Eq<T>>(value: Equals<T> | T | undefined, defaultValue: T): Equals<T> { if (value instanceof Equals) { return value; } else if (value !== undefined) { return Equals.equals(value); } else { return Equals.disabled(defaultValue); } } } export class InRange<T extends Compare<T>> { constructor( public isEnabled: Bool, public lower: T, public upper: T ) {} toStringHuman(): string { if (!this.isEnabled.toBoolean()) { return 'disabled'; } else if (this.lower.equals(this.upper).toBoolean()) { return `== ${this.lower}`; } else { return `between (${this.lower}, ${this.upper})`; } } toValue<D>(defaultValue: D): { lower: T; upper: T } | D { if (this.isEnabled.toBoolean()) { return { lower: this.lower, upper: this.upper }; } else { return defaultValue; } } mapToValue<D, R>(defaultValue: D, f: (t: T) => R): { lower: R; upper: R } | D { if (this.isEnabled.toBoolean()) { return { lower: f(this.lower), upper: f(this.upper) }; } else { return defaultValue; } } toOption(): Option<Range<T>> { return { isSome: this.isEnabled, value: { lower: this.lower, upper: this.upper, }, }; } isSatisfied(x: T): Bool { return Bool.or( this.isEnabled.not(), Bool.and(this.lower.lessThanOrEqual(x), this.upper.greaterThanOrEqual(x)) ); } static disabled<T extends Compare<T>>(defaultValue: T | { lower: T; upper: T }): InRange<T> { const isDefaultRange = typeof defaultValue === 'object' && defaultValue !== null && 'lower' in defaultValue && 'upper' in defaultValue; const lower = isDefaultRange ? defaultValue.lower : defaultValue; const upper = isDefaultRange ? defaultValue.upper : defaultValue; return new InRange(new Bool(false), lower, upper); } static equals<T extends Compare<T>>(value: T): InRange<T> { return new InRange(new Bool(true), value, value); } static betweenInclusive<T extends Compare<T>>(lower: T, upper: T): InRange<T> { return new InRange(new Bool(true), lower, upper); } static fromOption<T extends Compare<T>>(option: Option<Range<T>>): InRange<T> { return new InRange(option.isSome, option.value.lower, option.value.upper); } // TODO: lessThan, greaterThan static from<T extends Compare<T>>( value: InRange<T> | T | undefined, defaultValue: T | { lower: T; upper: T } ): InRange<T> { if (value instanceof InRange) { return value; } else if (value !== undefined) { return InRange.equals(value); } else { return InRange.disabled(defaultValue); } } } } type PreconditionsDescription<State extends StateLayout> = { network?: NetworkPreconditionsDescription | NetworkPreconditions; account?: AccountPreconditionsDescription<State> | AccountPreconditions<State>; validWhile?: UInt32 | Precondition.InRange<UInt32>; }; class Preconditions<State extends StateLayout = 'GenericState'> { readonly network: NetworkPreconditions; readonly account: AccountPreconditions<State>; readonly validWhile: Precondition.InRange<UInt32>; constructor(State: StateDefinition<State>, descr?: PreconditionsDescription<State>) { this.network = NetworkPreconditions.from(descr?.network); this.account = AccountPreconditions.from(State, descr?.account); this.validWhile = Precondition.InRange.from(descr?.validWhile, { lower: UInt32.empty(), upper: UInt32.MAXINT(), }); } toGeneric(): Preconditions { return new Preconditions<'GenericState'>('GenericState', { ...this, account: this.account.toGeneric(), }); } static fromGeneric<State extends StateLayout>( x: Preconditions, State: StateDefinition<State> ): Preconditions<State> { return new Preconditions(State, { ...this, account: AccountPreconditions.fromGeneric(x.account, State), }); } toInternalRepr(): BindingsLayout.Preconditions { return { network: this.network.toInternalRepr(), account: this.account.toInternalRepr(), validWhile: this.validWhile.toOption(), }; } static fromInternalRepr(x: BindingsLayout.Preconditions): Preconditions { return new Preconditions('GenericState', { network: NetworkPreconditions.fromInternalRepr(x.network), account: AccountPreconditions.fromInternalRepr(x.account), validWhile: Precondition.InRange.fromOption(x.validWhile), }); } toJSON(): any { return Preconditions.toJSON(this); } toInput(): HashInput { return Preconditions.toInput(this); } toFields(): Field[] { return Preconditions.toFields(this); } static sizeInFields(): number { return BindingsLayout.Preconditions.sizeInFields(); } static emptyPoly<State extends StateLayout>(State: StateDefinition<State>): Preconditions<State> { return new Preconditions(State); } static empty(): Preconditions { return new Preconditions('GenericState'); } static check<State extends StateLayout>(_x: Preconditions<State>) { throw new Error('TODO'); } static toJSON<State extends StateLayout>(x: Preconditions<State>): any { return BindingsLayout.Preconditions.toJSON(x.toInternalRepr()); } static toInput<State extends StateLayout>(x: Preconditions<State>): HashInput { return BindingsLayout.Preconditions.toInput(x.toInternalRepr()); } static toFields<State extends StateLayout>(x: Preconditions<State>): Field[] { return BindingsLayout.Preconditions.toFields(x.toInternalRepr()); } static fromFields(fields: Field[], aux: any[]): Preconditions { return Preconditions.fromInternalRepr(BindingsLayout.Preconditions.fromFields(fields, aux)); } static toAuxiliary<State extends StateLayout>(x?: Preconditions<State>): any[] { return BindingsLayout.Preconditions.toAuxiliary(x?.toInternalRepr()); } static toValue<State extends StateLayout>(x: Preconditions<State>): Preconditions<State> { return x; } static fromValue<State extends StateLayout>(x: Preconditions<State>): Preconditions<State> { return x; } static from<State extends StateLayout>( State: StateDefinition<State>, value: Preconditions<State> | PreconditionsDescription<State> | undefined ): Preconditions<State> { if (value instanceof Preconditions) { return value; } else if (value === undefined) { return Preconditions.emptyPoly(State); } else { return new Preconditions(State, value); } } } type EpochLedgerPreconditionsDescription = { hash?: Field | Precondition.Equals<Field>; totalCurrency?: MinaAmount | Precondition.InRange<MinaAmount>; }; class EpochLedgerPreconditions { readonly hash: Precondition.Equals<Field>; readonly totalCurrency: Precondition.InRange<MinaAmount>; constructor(descr?: EpochLedgerPreconditionsDescription) { this.hash = Precondition.Equals.from(descr?.hash, new Field(0)); this.totalCurrency = Precondition.InRange.from(descr?.totalCurrency, { lower: UInt64.empty(), upper: UInt64.MAXINT(), }); } toInternalRepr(): BindingsLayout.EpochLedgerPrecondition { return { hash: this.hash.toOption(), totalCurrency: this.totalCurrency.toOption(), }; } static fromInternalRepr(x: BindingsLayout.EpochLedgerPrecondition): EpochLedgerPreconditions { return new EpochLedgerPreconditions({ hash: Precondition.Equals.fromOption(x.hash), totalCurrency: Precondition.InRange.fromOption(x.totalCurrency), }); } toJSON(): any { return EpochLedgerPreconditions.toJSON(this); } toInput(): HashInput { return EpochLedgerPreconditions.toInput(this); } toFields(): Field[] { return EpochLedgerPreconditions.toFields(this); } static sizeInFields(): number { return BindingsLayout.EpochLedgerPrecondition.sizeInFields(); } static empty(): EpochLedgerPreconditions { return new EpochLedgerPreconditions(); } static check(_x: EpochLedgerPreconditions) { throw new Error('TODO'); } static toJSON(x: EpochLedgerPreconditions): any { return BindingsLayout.EpochLedgerPrecondition.toJSON(x.toInternalRepr()); } static toInput(x: EpochLedgerPreconditions): HashInput { return BindingsLayout.EpochLedgerPrecondition.toInput(x.toInternalRepr()); } static toFields(x: EpochLedgerPreconditions): Field[] { return BindingsLayout.EpochLedgerPrecondition.toFields(x.toInternalRepr()); } static fromFields(fields: Field[], aux: any[]): EpochLedgerPreconditions { return EpochLedgerPreconditions.fromInternalRepr( BindingsLayout.EpochLedgerPrecondition.fromFields(fields, aux) ); } static toAuxiliary(x?: EpochLedgerPreconditions): any[] { return BindingsLayout.EpochLedgerPrecondition.toAuxiliary(x?.toInternalRepr()); } static toValue(x: EpochLedgerPreconditions): EpochLedgerPreconditions { return x; } static fromValue(x: EpochLedgerPreconditions): EpochLedgerPreconditions { return x; } static from( value: EpochLedgerPreconditions | EpochLedgerPreconditionsDescription | undefined ): EpochLedgerPreconditions { if (value instanceof EpochLedgerPreconditions) { return value; } else if (value === undefined) { return EpochLedgerPreconditions.empty(); } else { return new EpochLedgerPreconditions(value); } } } type EpochDataPreconditionsDescription = { ledger?: EpochLedgerPreconditions | EpochLedgerPreconditionsDescription; seed?: Field | Precondition.Equals<Field>; startCheckpoint?: Field | Precondition.Equals<Field>; lockCheckpoint?: Field | Precondition.Equals<Field>; epochLength?: UInt32 | Precondition.InRange<UInt32>; }; class EpochDataPreconditions { readonly ledger: EpochLedgerPreconditions; readonly seed: Precondition.Equals<Field>; readonly startCheckpoint: Precondition.Equals<Field>; readonly lockCheckpoint: Precondition.Equals<Field>; readonly epochLength: Precondition.InRange<UInt32>; constructor(descr?: EpochDataPreconditionsDescription) { this.ledger = EpochLedgerPreconditions.from(descr?.ledger); this.seed = Precondition.Equals.from(descr?.seed, new Field(0)); this.startCheckpoint = Precondition.Equals.from(descr?.startCheckpoint, new Field(0)); this.lockCheckpoint = Precondition.Equals.from(descr?.lockCheckpoint, new Field(0)); this.epochLength = Precondition.InRange.from(descr?.epochLength, { lower: UInt32.empty(), upper: UInt32.MAXINT(), }); } toInternalRepr(): BindingsLayout.EpochDataPrecondition { return { ledger: this.ledger.toInternalRepr(), seed: this.seed.toOption(), startCheckpoint: this.startCheckpoint.toOption(), lockCheckpoint: this.lockCheckpoint.toOption(), epochLength: this.epochLength.toOption(), }; } static fromInternalRepr(x: BindingsLayout.EpochDataPrecondition): EpochDataPreconditions { return new EpochDataPreconditions({ ledger: EpochLedgerPreconditions.fromInternalRepr(x.ledger), seed: Precondition.Equals.fromOption(x.seed), startCheckpoint: Precondition.Equals.fromOption(x.startCheckpoint), lockCheckpoint: Precondition.Equals.fromOption(x.lockCheckpoint), epochLength: Precondition.InRange.fromOption(x.epochLength), }); } toJSON(): any { return EpochDataPreconditions.toJSON(this); } toInput(): HashInput { return EpochDataPreconditions.toInput(this); } toFields(): Field[] { return EpochDataPreconditions.toFields(this); } static sizeInFields(): number { return BindingsLayout.EpochDataPrecondition.sizeInFields(); } static empty(): EpochDataPreconditions { return new EpochDataPreconditions(); } static check(_x: EpochDataPreconditions) { throw new Error('TODO'); } static toJSON(x: EpochDataPreconditions): any { return BindingsLayout.EpochDataPrecondition.toJSON(x.toInternalRepr()); } static toInput(x: EpochDataPreconditions): HashInput { return BindingsLayout.EpochDataPrecondition.toInput(x.toInternalRepr()); } static toFields(x: EpochDataPreconditions): Field[] { return BindingsLayout.EpochDataPrecondition.toFields(x.toInternalRepr()); } static fromFields(fields: Field[], aux: any[]): EpochDataPreconditions { return EpochDataPreconditions.fromInternalRepr( BindingsLayout.EpochDataPrecondition.fromFields(fields, aux) ); } static toAuxiliary(x?: EpochDataPreconditions): any[] { return BindingsLayout.EpochDataPrecondition.toAuxiliary(x?.toInternalRepr()); } static toValue(x: EpochDataPreconditions): EpochDataPreconditions { return x; } static fromValue(x: EpochDataPreconditions): EpochDataPreconditions { return x; } static from( value: EpochDataPreconditions | EpochDataPreconditionsDescription | undefined ): EpochDataPreconditions { if (value instanceof EpochDataPreconditions) { return value; } else if (value === undefined) { return EpochDataPreconditions.empty(); } else { return new EpochDataPreconditions(value); } } } type NetworkPreconditionsDescription = { snarkedLedgerHash?: Field | Precondition.Equals<Field>; blockchainLength?: UInt32 | Precondition.InRange<UInt32>; minWindowDensity?: UInt32 | Precondition.InRange<UInt32>; totalCurrency?: MinaAmount | Precondition.InRange<MinaAmount>; globalSlotSinceGenesis?: UInt32 | Precondition.InRange<UInt32>; stakingEpochData?: EpochDataPreconditions | EpochDataPreconditionsDescription; nextEpochData?: EpochDataPreconditions | EpochDataPreconditionsDescription; }; class NetworkPreconditions { readonly snarkedLedgerHash: Precondition.Equals<Field>; readonly blockchainLength: Precondition.InRange<UInt32>; readonly minWindowDensity: Precondition.InRange<UInt32>; readonly totalCurrency: Precondition.InRange<MinaAmount>; readonly globalSlotSinceGenesis: Precondition.InRange<UInt32>; readonly stakingEpochData: EpochDataPreconditions; readonly nextEpochData: EpochDataPreconditions; constructor(descr?: NetworkPreconditionsDescription) { this.snarkedLedgerHash = Precondition.Equals.from(descr?.snarkedLedgerHash, Field.empty()); this.blockchainLength = Precondition.InRange.from(descr?.blockchainLength, { lower: UInt32.empty(), upper: UInt32.MAXINT(), }); this.minWindowDensity = Precondition.InRange.from(descr?.minWindowDensity, { lower: UInt32.empty(), upper: UInt32.MAXINT(), }); this.totalCurrency = Precondition.InRange.from(descr?.totalCurrency, { lower: UInt64.empty(), upper: UInt64.MAXINT(), }); this.globalSlotSinceGenesis = Precondition.InRange.from(descr?.globalSlotSinceGenesis, { lower: UInt32.empty(), upper: UInt32.MAXINT(), }); this.stakingEpochData = EpochDataPreconditions.from(descr?.stakingEpochData); this.nextEpochData = EpochDataPreconditions.from(descr?.nextEpochData); } toInternalRepr(): BindingsLayout.NetworkPrecondition { return { snarkedLedgerHash: this.snarkedLedgerHash.toOption(), blockchainLength: this.blockchainLength.toOption(), minWindowDensity: this.minWindowDensity.toOption(), totalCurrency: this.totalCurrency.toOption(), globalSlotSinceGenesis: this.globalSlotSinceGenesis.toOption(), stakingEpochData: this.stakingEpochData.toInternalRepr(), nextEpochData: this.nextEpochData.toInternalRepr(), }; } static fromInternalRepr(x: BindingsLayout.NetworkPrecondition): NetworkPreconditions { return new NetworkPreconditions({ snarkedLedgerHash: Precondition.Equals.fromOption(x.snarkedLedgerHash), blockchainLength: Precondition.InRange.fromOption(x.blockchainLength), minWindowDensity: Precondition.InRange.fromOption(x.minWindowDensity), totalCurrency: Precondition.InRange.fromOption(x.totalCurrency), globalSlotSinceGenesis: Precondition.InRange.fromOption(x.globalSlotSinceGenesis), stakingEpochData: EpochDataPreconditions.fromInternalRepr(x.stakingEpochData), nextEpochData: EpochDataPreconditions.fromInternalRepr(x.nextEpochData), }); } static empty(): NetworkPreconditions { return new NetworkPreconditions(); } toJSON(): any { return NetworkPreconditions.toJSON(this); } toInput(): HashInput { return NetworkPreconditions.toInput(this); } toFields(): Field[] { return NetworkPreconditions.toFields(this); } static sizeInFields(): number { return BindingsLayout.NetworkPrecondition.sizeInFields(); } static check(_x: NetworkPreconditions) { throw new Error('TODO'); } static toJSON(x: NetworkPreconditions): any { return BindingsLayout.NetworkPrecondition.toJSON(x.toInternalRepr()); } static toInput(x: NetworkPreconditions): HashInput { return BindingsLayout.NetworkPrecondition.toInput(x.toInternalRepr()); } static toFields(x: NetworkPreconditions): Field[] { return BindingsLayout.NetworkPrecondition.toFields(x.toInternalRepr()); } static fromFields(fields: Field[], aux: any[]): NetworkPreconditions { return NetworkPreconditions.fromInternalRepr( BindingsLayout.NetworkPrecondition.fromFields(fields, aux) ); } static toAuxiliary(x?: NetworkPreconditions): any[] { return BindingsLayout.NetworkPrecondition.toAuxiliary(x?.toInternalRepr()); } static toValue(x: NetworkPreconditions): NetworkPreconditions { return x; } static fromValue(x: NetworkPreconditions): NetworkPreconditions { return x; } static from( value: NetworkPreconditions | NetworkPreconditionsDescription | undefined ): NetworkPreconditions { if (value instanceof NetworkPreconditions) { return value; } else if (value === undefined) { return NetworkPreconditions.empty(); } else { return new NetworkPreconditions(value); } } } type AccountPreconditionsDescription<State extends StateLayout> = { balance?: MinaAmount | Precondition.InRange<MinaAmount>; nonce?: UInt32 | Precondition.InRange<UInt32>; receiptChainHash?: Field | Precondition.Equals<Field>; delegate?: PublicKey | Precondition.Equals<PublicKey>; state?: StatePreconditions<State>; actionState?: Field | Precondition.Equals<Field>; // NB: renamed from the protocol's type name of `provenState` isProven?: Bool | Precondition.Equals<Bool>; isNew?: Bool | Precondition.Equals<Bool>; }; class AccountPreconditions<State extends StateLayout = 'GenericState'> { // TODO: should these really be read-only? readonly State: StateDefinition<State>; readonly balance: Precondition.InRange<MinaAmount>; readonly nonce: Precondition.InRange<UInt32>; readonly receiptChainHash: Precondition.Equals<Field>; readonly delegate: Precondition.Equals<PublicKey>; readonly state: StatePreconditions<State>; readonly actionState: Precondition.Equals<Field>; readonly isProven: Precondition.Equals<Bool>; readonly isNew: Precondition.Equals<Bool>; constructor(State: StateDefinition<State>, descr?: AccountPreconditionsDescription<State>) { this.State = State; this.balance = Precondition.InRange.from(descr?.balance, { lower: UInt64.empty(), upper: UInt64.MAXINT(), }); this.nonce = Precondition.InRange.from(descr?.nonce, { lower: UInt32.empty(), upper: UInt32.MAXINT(), }); this.receiptChainHash = Precondition.Equals.from(descr?.receiptChainHash, Field.empty()); this.delegate = Precondition.Equals.from(descr?.delegate, PublicKey.empty()); this.state = descr?.state ?? StatePreconditions.empty(State); this.actionState = Precondition.Equals.from(descr?.actionState, Actions.emptyActionState()); this.isProven = Precondition.Equals.from(descr?.isProven, Bool.empty()); this.isNew = Precondition.Equals.from(descr?.isNew, Bool.empty()); } toGeneric(): AccountPreconditions { return AccountPreconditions.generic({ ...this, state: StatePreconditions.toGeneric(this.State, this.state), }); } static fromGeneric<State extends StateLayout>( x: AccountPreconditions, State: StateDefinition<State> ): AccountPreconditions<State> { return new AccountPreconditions(State, { ...this, state: StatePreconditions.fromGeneric(x.state, State), }); } toInternalRepr(): BindingsLayout.AccountPrecondition { const statePreconditions = StatePreconditions.toFieldPreconditions(this.State, this.state); if (statePreconditions.length !== ZkappConstants.MAX_ZKAPP_STATE_FIELDS) { throw new Error('invalid number of zkapp state field constraints'); } return { balance: this.balance.toOption(), nonce: this.nonce.toOption(), receiptChainHash: this.receiptChainHash.toOption(), delegate: this.delegate.toOption(), state: statePreconditions.map((c) => c.toOption()), actionState: this.actionState.toOption(), provedState: this.isProven.toOption(), isNew: this.isNew.toOption(), }; } static fromInternalRepr(x: BindingsLayout.AccountPrecondition): AccountPreconditions { return new AccountPreconditions<'GenericState'>('GenericState', { balance: Precondition.InRange.fromOption(x.balance), nonce: Precondition.InRange.fromOption(x.nonce), receiptChainHash: Precondition.Equals.fromOption(x.receiptChainHash), delegate: Precondition.Equals.fromOption(x.delegate), state: new GenericStatePreconditions(x.state.map(Precondition.Equals.fromOption<Field>)), actionState: Precondition.Equals.fromOption(x.actionState), isProven: Precondition.Equals.fromOption(x.provedState), isNew: Precondition.Equals.fromOption(x.isNew), }); } toJSON(): any { return AccountPreconditions.toJSON(this); } toInput(): HashInput { return AccountPreconditions.toInput(this); } toFields(): Field[] { return AccountPreconditions.toFields(this); } static generic(descr?: AccountPreconditionsDescription<'GenericState'>): AccountPreconditions { return new AccountPreconditions<'GenericState'>('GenericState', descr); } static sizeInFields(): number { return BindingsLayout.AccountPrecondition.sizeInFields(); } static emptyPoly<State extends StateLayout>( State: StateDefinition<State> ): AccountPreconditions<State> { return new AccountPreconditions(State); } static empty(): AccountPreconditions { return this.emptyPoly('GenericState'); } static check<State extends StateLayout>(_x: AccountPreconditions<State>) { throw new Error('TODO'); } static toJSON<State extends StateLayout>(x: AccountPreconditions<State>): any { return BindingsLayout.AccountPrecondition.toJSON(x.toInternalRepr()); } static toInput<State extends StateLayout>(x: AccountPreconditions<State>): HashInput { return BindingsLayout.AccountPrecondition.toInput(x.toInternalRepr()); } static toFields<State extends StateLayout>(x: AccountPreconditions<State>): Field[] { return BindingsLayout.AccountPrecondition.toFields(x.toInternalRepr()); } static fromFields(fields: Field[], aux: any[]): AccountPreconditions { return AccountPreconditions.fromInternalRepr( BindingsLayout.AccountPrecondition.fromFields(fields, aux) ); } static toAuxiliary<State extends StateLayout>(x?: AccountPreconditions<State>): any[] { return BindingsLayout.AccountPrecondition.toAuxiliary(x?.toInternalRepr()); } static toValue<State extends StateLayout>( x: AccountPreconditions<State> ): AccountPreconditions<State> { return x; } static fromValue<State extends StateLayout>( x: AccountPreconditions<State> ): AccountPreconditions<State> { return x; } static from<State extends StateLayout>( State: StateDefinition<State>, value: AccountPreconditions<State> | AccountPreconditionsDescription<State> | undefined ): AccountPreconditions<State> { if (value instanceof AccountPreconditions) { return value; } else if (value === undefined) { return AccountPreconditions.emptyPoly(State); } else { return new AccountPreconditions(State, value); } } }