o1js
Version:
TypeScript framework for zk-SNARKs and zkApps
162 lines (132 loc) • 4.12 kB
text/typescript
import { Bool } from '../../provable/bool.js';
import { Field } from '../../provable/field.js';
import { Provable } from '../../provable/types/provable-intf.js';
import * as Bindings from '../../../bindings/mina-transaction/v2/index.js';
import { bytesToBits, stringToBytes } from '../../../bindings/lib/binable.js';
import { GenericHashInput } from '../../../bindings/lib/generic.js';
import { hashWithPrefix, packToFields } from '../../../lib/provable/crypto/poseidon.js';
import { prefixes } from '../../../bindings/crypto/constants.js';
import { Types } from '../../../bindings/mina-transaction/v1/types.js';
export {
Option,
Range,
mapUndefined,
Empty,
Update,
Compare,
Eq,
ToFields,
Tuple,
ProvableTuple,
ProvableInstance,
ProvableTupleInstances,
TokenId,
ZkappUri,
mapObject,
};
// boo typescript
function mapObject<In extends { [key: string]: any }, Out extends { [key in keyof In]: any }>(
object: In,
f: <Key extends keyof In>(key: Key) => Out[Key]
): { [key in keyof In]: Out[key] } {
const newObject: Partial<{ [key in keyof In]: Out[key] }> = {};
for (const key in object) {
newObject[key] = f(key);
}
return newObject as { [key in keyof In]: Out[key] };
}
const { Option, Range } = Bindings.Leaves;
type Option<T> = Bindings.Leaves.Option<T>;
type Range<T> = Bindings.Leaves.Range<T>;
class ZkappUri {
readonly data: string;
readonly hash: Field;
constructor(uri: string | { data: string; hash: Field }) {
if (typeof uri === 'object') {
this.data = uri.data;
this.hash = uri.hash;
} else {
this.data = uri;
let packed: Field[];
if (uri.length === 0) {
packed = [new Field(0), new Field(0)];
} else {
const bits = bytesToBits(stringToBytes(uri));
bits.push(true);
const input: GenericHashInput<Field> = {
packed: bits.map((b) => [new Field(Number(b)), 1]),
};
packed = packToFields(input);
}
this.hash = hashWithPrefix(prefixes.zkappUri, packed);
}
}
toJSON(): Types.Json.AccountUpdate['body']['update']['zkappUri'] {
return this.data.toString();
}
static empty(): ZkappUri {
return new ZkappUri('');
}
static from(uri: ZkappUri | string): ZkappUri {
return uri instanceof ZkappUri ? uri : new ZkappUri(uri);
}
}
class TokenId {
// TODO: construct this from it's parts, don't pass in the raw Field directly
constructor(public value: Field) {}
equals(x: TokenId): Bool {
return this.value.equals(x.value);
}
toString(): string {
return this.value.toString();
}
static MINA: TokenId = new TokenId(new Field(1));
}
function mapUndefined<A, B>(value: A | undefined, f: (a: A) => B): B | undefined {
return value === undefined ? undefined : f(value);
}
interface Empty<T> {
empty: () => T;
}
interface Eq<T> {
equals(x: T): Bool;
}
type Compare<T extends Compare<T>> = Eq<T> & {
lessThan(x: T): Bool;
lessThanOrEqual(x: T): Bool;
greaterThan(x: T): Bool;
greaterThanOrEqual(x: T): Bool;
};
interface ToFields {
toFields(): Field[];
}
type Tuple<T> = [T, ...T[]] | [];
type ProvableTuple = Tuple<Provable<any>>;
type ProvableInstance<P> = P extends Provable<infer T> ? (unknown extends T ? T : never) : never;
type ProvableTupleInstances<T extends ProvableTuple> = {
[I in keyof T]: ProvableInstance<T[I]>;
};
class Update<T> {
constructor(public set: Bool, public value: T) {}
toOption(): Option<T> {
return { isSome: this.set, value: this.value };
}
static fromOption<T>(option: Option<T>): Update<T> {
return new Update(option.isSome, option.value);
}
static disabled<T>(defaultValue: T): Update<T> {
return new Update(new Bool(false), defaultValue);
}
static set<T>(value: T): Update<T> {
return new Update(new Bool(true), value);
}
static from<T>(value: Update<T> | T | undefined, defaultValue: T): Update<T> {
if (value instanceof Update) {
return value;
} else if (value !== undefined) {
return Update.set(value);
} else {
return Update.disabled(defaultValue);
}
}
}