Skip to content

Commit

Permalink
ticket literal
Browse files Browse the repository at this point in the history
  • Loading branch information
e-asphyx committed Apr 26, 2024
1 parent 12996df commit 6eafb11
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 78 deletions.
7 changes: 4 additions & 3 deletions packages/taquito-michel-codec/src/binary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ const primitives: PrimID[] = [
'TICKET',
'BYTES',
'NAT',
'Ticket',
];

const primTags: { [key in PrimID]?: number } & { [key: string]: number | undefined } =
Expand Down Expand Up @@ -263,7 +264,7 @@ class Reader {
private buffer: number[] | Uint8Array,
private idx: number = 0,
private cap: number = buffer.length
) {}
) { }

/** Remaining length */
get length(): number {
Expand Down Expand Up @@ -577,8 +578,8 @@ function writeExpr(expr: Expr, wr: Writer, tf: WriteTransformFunc): void {
const tag =
(e.args?.length || 0) < 3
? Tag.Prim0 +
(e.args?.length || 0) * 2 +
(e.annots === undefined || e.annots.length === 0 ? 0 : 1)
(e.args?.length || 0) * 2 +
(e.annots === undefined || e.annots.length === 0 ? 0 : 1)
: Tag.Prim;

wr.writeUint8(tag);
Expand Down
115 changes: 63 additions & 52 deletions packages/taquito-michel-codec/src/michelson-typecheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,7 @@ function assertScalarTypesEqual(a: MichelsonType, b: MichelsonType, field = fals
if (parseInt(a.args[0].int, 10) !== parseInt((b as typeof a).args[0].int, 10)) {
throw new MichelsonTypeError(
a,
`${typeID(a)}: type argument mismatch: ${a.args[0].int} != ${
(b as typeof a).args[0].int
`${typeID(a)}: type argument mismatch: ${a.args[0].int} != ${(b as typeof a).args[0].int
}`,
undefined
);
Expand Down Expand Up @@ -429,7 +428,7 @@ function assertDataValidInternal(d: MichelsonData, t: MichelsonType, ctx: Contex
if (
'string' in d &&
checkDecodeTezosID(d.string, 'ED25519PublicKey', 'SECP256K1PublicKey', 'P256PublicKey') !==
null
null
) {
return;
} else if ('bytes' in d) {
Expand Down Expand Up @@ -549,15 +548,27 @@ function assertDataValidInternal(d: MichelsonData, t: MichelsonType, ctx: Contex
throw new MichelsonTypeError(t, `sapling state expected: ${JSON.stringify(d)}`, d);

case 'ticket':
assertDataValidInternal(
d,
{
prim: 'pair',
args: [{ prim: 'address' }, t.args[0], { prim: 'nat' }],
},
ctx
);
return;
if ('prim' in d) {
if (d.prim === 'Pair') {
// backward compatibility
assertDataValidInternal(
d,
{
prim: 'pair',
args: [{ prim: 'address' }, t.args[0], { prim: 'nat' }],
},
ctx
);
return;
} else if (d.prim === 'Ticket') {
assertDataValidInternal(d.args[0], { prim: 'address' }, ctx);
assertTypesEqual(d.args[1], t.args[0]);
assertDataValidInternal(d.args[2], t.args[0], ctx);
assertDataValidInternal(d.args[3], { prim: 'nat' }, ctx);
return;
}
}
throw new MichelsonTypeError(t, `ticket expected: ${JSON.stringify(d)}`, d);

default:
throw new MichelsonTypeError(
Expand Down Expand Up @@ -732,10 +743,10 @@ function functionTypeInternal(
const ann =
a.v !== undefined || a.t !== undefined || a.f !== undefined
? [
...((a.v === null ? src.v : a.v) || []),
...((a.t === null ? src.t : a.t) || []),
...((a.f === null ? src.f : a.f) || []),
]
...((a.v === null ? src.v : a.v) || []),
...((a.t === null ? src.t : a.t) || []),
...((a.f === null ? src.f : a.f) || []),
]
: undefined;

const { annots: _annots, ...rest } = t;
Expand Down Expand Up @@ -783,12 +794,12 @@ function functionTypeInternal(
? ['@' + fieldAnn.slice(1)]
: undefined
: insVarAnn === '@%%'
? varAnn
? ['@' + varAnn.slice(1) + '.' + (fieldAnn ? fieldAnn.slice(1) : defField)]
: fieldAnn
? ['@' + fieldAnn.slice(1)]
: undefined
: [insVarAnn]
? varAnn
? ['@' + varAnn.slice(1) + '.' + (fieldAnn ? fieldAnn.slice(1) : defField)]
: fieldAnn
? ['@' + fieldAnn.slice(1)]
: undefined
: [insVarAnn]
: null,
});
}
Expand Down Expand Up @@ -1689,8 +1700,8 @@ function functionTypeInternal(
return s.prim === 'list'
? [annotateVar({ prim: 'list', args: [body[0]] }), ...tail]
: s.prim === 'map'
? [annotateVar({ prim: 'map', args: [s.args[0], body[0]] }), ...tail]
: [annotateVar({ prim: 'option', args: [body[0]] }), ...tail];
? [annotateVar({ prim: 'map', args: [s.args[0], body[0]] }), ...tail]
: [annotateVar({ prim: 'option', args: [body[0]] }), ...tail];
}

case 'ITER': {
Expand Down Expand Up @@ -1988,35 +1999,35 @@ function functionTypeInternal(
}
return ProtoInferiorTo(proto, Protocol.PtJakarta)
? [
annotateVar({
prim: 'option',
args: [
{
prim: 'pair',
args: [{ prim: 'int' }, annotate(s[1], { t: null })],
},
],
}),
...stack.slice(2),
]
annotateVar({
prim: 'option',
args: [
{
prim: 'pair',
args: [{ prim: 'int' }, annotate(s[1], { t: null })],
},
],
}),
...stack.slice(2),
]
: [
annotateVar({
prim: 'option',
args: [
{
prim: 'pair',
args: [
{ prim: 'bytes' },
{
prim: 'pair',
args: [{ prim: 'int' }, annotate(s[1], { t: null })],
},
],
},
],
}),
...stack.slice(2),
];
annotateVar({
prim: 'option',
args: [
{
prim: 'pair',
args: [
{ prim: 'bytes' },
{
prim: 'pair',
args: [{ prim: 'int' }, annotate(s[1], { t: null })],
},
],
},
],
}),
...stack.slice(2),
];
}

case 'OPEN_CHEST':
Expand Down
47 changes: 26 additions & 21 deletions packages/taquito-michel-codec/src/michelson-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ type Instr0<PT extends MichelsonNoArgInstructionID> = Prim0<PT>;
type InstrX<PT extends MichelsonRegularInstructionID, AT extends Expr[]> = PrimX<PT, AT>;

export type MichelsonCode = InstructionList | MichelsonInstruction;
export interface InstructionList extends List<MichelsonCode> {}
export interface InstructionList extends List<MichelsonCode> { }

export type MichelsonNoArgInstruction = Instr0<MichelsonNoArgInstructionID>;
export type MichelsonInstruction =
Expand Down Expand Up @@ -224,23 +224,23 @@ export type MichelsonTypeChest = Type0<'chest'>;
type TypeList<T extends MichelsonType[]> = T & Node;
export type MichelsonTypePair<T extends MichelsonType[]> = TypeX<'pair', T> | TypeList<T>;

export interface MichelsonTypeOption<T extends MichelsonType> extends TypeX<'option', [T]> {}
export interface MichelsonTypeList<T extends MichelsonType> extends TypeX<'list', [T]> {}
export interface MichelsonTypeContract<T extends MichelsonType> extends TypeX<'contract', [T]> {}
export interface MichelsonTypeOr<T extends [MichelsonType, MichelsonType]> extends TypeX<'or', T> {}
export interface MichelsonTypeOption<T extends MichelsonType> extends TypeX<'option', [T]> { }
export interface MichelsonTypeList<T extends MichelsonType> extends TypeX<'list', [T]> { }
export interface MichelsonTypeContract<T extends MichelsonType> extends TypeX<'contract', [T]> { }
export interface MichelsonTypeOr<T extends [MichelsonType, MichelsonType]> extends TypeX<'or', T> { }
export interface MichelsonTypeLambda<Arg extends MichelsonType, Ret extends MichelsonType>
extends TypeX<'lambda', [Arg, Ret]> {}
extends TypeX<'lambda', [Arg, Ret]> { }

export interface MichelsonTypeSet<T extends MichelsonType> extends TypeX<'set', [T]> {}
export interface MichelsonTypeSet<T extends MichelsonType> extends TypeX<'set', [T]> { }
export interface MichelsonTypeMap<K extends MichelsonType, V extends MichelsonType>
extends TypeX<'map', [K, V]> {}
extends TypeX<'map', [K, V]> { }
export interface MichelsonTypeBigMap<K extends MichelsonType, V extends MichelsonType>
extends TypeX<'big_map', [K, V]> {}
extends TypeX<'big_map', [K, V]> { }
export interface MichelsonTypeSaplingState<S extends string = string>
extends TypeX<'sapling_state', [IntLiteral<S>]> {}
extends TypeX<'sapling_state', [IntLiteral<S>]> { }
export interface MichelsonTypeSaplingTransaction<S extends string = string>
extends TypeX<'sapling_transaction', [IntLiteral<S>]> {}
export interface MichelsonTypeTicket<T extends MichelsonType> extends TypeX<'ticket', [T]> {}
extends TypeX<'sapling_transaction', [IntLiteral<S>]> { }
export interface MichelsonTypeTicket<T extends MichelsonType> extends TypeX<'ticket', [T]> { }

export type MichelsonType<T extends MichelsonTypeID = MichelsonTypeID> = T extends 'int'
? MichelsonTypeInt
Expand Down Expand Up @@ -317,7 +317,8 @@ export type MichelsonDataID =
| 'Left'
| 'Right'
| 'Some'
| 'Lambda_rec';
| 'Lambda_rec'
| 'Ticket';

type Data0<PT extends MichelsonDataID> = Prim0<PT>;
type DataX<PT extends MichelsonDataID, AT extends MichelsonData[]> = PrimX<PT, AT>;
Expand All @@ -329,6 +330,7 @@ export type MichelsonDataPair<T extends MichelsonData[]> = DataX<'Pair', T> | Da
export type MichelsonMapElt = PrimX<'Elt', [MichelsonData, MichelsonData]>;
export type MichelsonMapEltList = List<MichelsonMapElt>;
export type MichelsonLambdaRec = DataX<'Lambda_rec', [InstructionList]>;
export type MichelsonTicket = PrimX<'Ticket', [StringLiteral | BytesLiteral, MichelsonType, MichelsonData, IntLiteral]>;

export type MichelsonData =
| IntLiteral
Expand All @@ -341,7 +343,8 @@ export type MichelsonData =
| MichelsonDataPair<MichelsonData[]>
| InstructionList
| MichelsonMapEltList
| MichelsonLambdaRec;
| MichelsonLambdaRec
| MichelsonTicket;

// Top level script sections

Expand All @@ -360,12 +363,12 @@ export type MichelsonContract = MichelsonContractSection[];

export type MichelsonContractSection<T extends MichelsonSectionID = MichelsonSectionID> =
T extends 'parameter'
? MichelsonContractParameter
: T extends 'storage'
? MichelsonContractStorage
: T extends 'view'
? MichelsonContractView
: MichelsonContractCode;
? MichelsonContractParameter
: T extends 'storage'
? MichelsonContractStorage
: T extends 'view'
? MichelsonContractView
: MichelsonContractCode;

// Code analysis types
export interface MichelsonTypeFailed {
Expand Down Expand Up @@ -401,6 +404,7 @@ export enum Protocol {
PtMumbai2 = 'PtMumbai2TmsJHNGRkD8v8YDbtao7BLUC3wjASn1inAKLFCjaH1',
PtNairobi = 'PtNairobiyssHuh87hEhfVBGCVrK3WnS8Z2FT4ymB5tAa4r1nQf',
ProxfordY = 'ProxfordYmVfjWnRcgjWH36fW6PArwqykTFzotUxRs6gmTcZDuH',
PtParisB = 'PtParisBQscdCm6Cfow6ndeU6wKJyA3aV1j4D3gQBQMsTQyJCrz',
ProtoALpha = 'ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK', // temporary protocol hash
}

Expand Down Expand Up @@ -433,7 +437,8 @@ const protoLevel: Record<ProtocolID, number> = {
PtMumbaiiFFEGbew1rRjzSPyzRbA51Tm3RVZL5suHPxSZYDhCEc: 16,
PtMumbai2TmsJHNGRkD8v8YDbtao7BLUC3wjASn1inAKLFCjaH1: 16,
PtNairobiyssHuh87hEhfVBGCVrK3WnS8Z2FT4ymB5tAa4r1nQf: 17,
ProxfordYmVfjWnRcgjWH36fW6PArwqykTFzotUxRs6gmTcZDuH: 19,
ProxfordYmVfjWnRcgjWH36fW6PArwqykTFzotUxRs6gmTcZDuH: 18,
PtParisBQscdCm6Cfow6ndeU6wKJyA3aV1j4D3gQBQMsTQyJCrz: 19,
ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK: 20,
};

Expand Down
19 changes: 18 additions & 1 deletion packages/taquito-michel-codec/src/michelson-validator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Prim, Expr, IntLiteral, StringLiteral } from './micheline';
import { Prim, Expr, IntLiteral, StringLiteral, BytesLiteral } from './micheline';
import { Tuple, NoArgs, ReqArgs, MichelsonError } from './utils';
import {
MichelsonCode,
Expand Down Expand Up @@ -232,6 +232,14 @@ function assertStringLiteral(ex: Expr): ex is StringLiteral {
throw new MichelsonValidationError(ex, 'string literal expected');
}

// usually an address
function assertStringOrBytes(ex: Expr): ex is StringLiteral | BytesLiteral {
if ('string' in ex || 'bytes' in ex) {
return true;
}
throw new MichelsonValidationError(ex, 'string or bytes literal expected');
}

function assertArgs<N extends number>(
ex: Prim,
n: N
Expand Down Expand Up @@ -733,6 +741,15 @@ export function assertMichelsonData(ex: Expr): ex is MichelsonData {
}
break;

case 'Ticket':
if (assertArgs(ex, 4)) {
assertStringOrBytes(ex.args[0]);
assertMichelsonType(ex.args[1]);
assertMichelsonData(ex.args[2]);
assertIntLiteral(ex.args[3]);
}
break;

default:
if (Object.prototype.hasOwnProperty.call(instructionIDs, ex.prim)) {
assertMichelsonInstruction(ex);
Expand Down
16 changes: 15 additions & 1 deletion packages/taquito-michel-codec/test/typecheck.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ describe('Typecheck', () => {
assertDataValid(data, typedef);
});

it('assertDataValid: ticket', () => {
it('assertDataValid: legacy ticket', () => {
const typedef: MichelsonType = { prim: 'ticket', args: [{ prim: 'bytes' }] };
const data: MichelsonData = [
{ string: 'KT1ThEdxfUcWUwqsdergy3QnbCWGHSUHeHJq' },
Expand All @@ -141,6 +141,20 @@ describe('Typecheck', () => {
assertDataValid(data, typedef);
});

it('assertDataValid: ticket', () => {
const typedef: MichelsonType = { prim: 'ticket', args: [{ prim: 'string' }] };
const data: MichelsonData = {
prim: 'Ticket',
args: [
{ string: 'KT1ThEdxfUcWUwqsdergy3QnbCWGHSUHeHJq' },
{ prim: 'string' },
{ string: 'TicketTicket' },
{ int: '42' },
]
};
assertDataValid(data, typedef);
});

it('assertTypesEqual: identical', () => {
const pair: MichelsonType = {
prim: 'pair',
Expand Down

0 comments on commit 6eafb11

Please sign in to comment.