diff --git a/src/smartcontracts/argSerializer.ts b/src/smartcontracts/argSerializer.ts index bd4a21bf..164ed9dc 100644 --- a/src/smartcontracts/argSerializer.ts +++ b/src/smartcontracts/argSerializer.ts @@ -68,42 +68,48 @@ export class ArgSerializer { // This is a recursive function. function readValue(type: Type): TypedValue { - // TODO: Use matchers. - if (type.hasExactClass(OptionalType.ClassName)) { - let typedValue = readValue(type.getFirstTypeParameter()); + const typedValue = readValue(type.getFirstTypeParameter()); return new OptionalValue(type, typedValue); - } else if (type.hasExactClass(VariadicType.ClassName)) { - const variadicType = type; - const typedValues = []; - - if (variadicType.isCounted) { - const count: number = readValue(new U32Type()).valueOf().toNumber(); + } - for (let i = 0; i < count; i++) { - typedValues.push(readValue(type.getFirstTypeParameter())); - } - } else { - while (!hasReachedTheEnd()) { - typedValues.push(readValue(type.getFirstTypeParameter())); - } - } + if (type.hasExactClass(VariadicType.ClassName)) { + return readVariadicValue(type); + } - return new VariadicValue(variadicType, typedValues); - } else if (type.hasExactClass(CompositeType.ClassName)) { - let typedValues = []; + if (type.hasExactClass(CompositeType.ClassName)) { + const typedValues = []; for (const typeParameter of type.getTypeParameters()) { typedValues.push(readValue(typeParameter)); } return new CompositeValue(type, typedValues); + } + + // Non-composite (singular), non-variadic (fixed) type. + // The only branching without a recursive call. + const typedValue = decodeNextBuffer(type); + return typedValue!; + } + + function readVariadicValue(type: Type): TypedValue { + const variadicType = type; + const typedValues = []; + + if (variadicType.isCounted) { + const count: number = readValue(new U32Type()).valueOf().toNumber(); + + for (let i = 0; i < count; i++) { + typedValues.push(readValue(type.getFirstTypeParameter())); + } } else { - // Non-composite (singular), non-variadic (fixed) type. - // The only branching without a recursive call. - let typedValue = decodeNextBuffer(type); - return typedValue!; + while (!hasReachedTheEnd()) { + typedValues.push(readValue(type.getFirstTypeParameter())); + } } + + return new VariadicValue(variadicType, typedValues); } function decodeNextBuffer(type: Type): TypedValue | null { @@ -150,7 +156,7 @@ export class ArgSerializer { // TODO: Refactor, split (function is quite complex). const self = this; - let buffers: Buffer[] = []; + const buffers: Buffer[] = []; for (const value of values) { handleValue(value); @@ -158,35 +164,47 @@ export class ArgSerializer { // This is a recursive function. It appends to the "buffers" variable. function handleValue(value: TypedValue): void { - // TODO: Use matchers. - if (value.hasExactClass(OptionalValue.ClassName)) { - let valueAsOptional = value; + const valueAsOptional = value; + if (valueAsOptional.isSet()) { handleValue(valueAsOptional.getTypedValue()); } - } else if (value.hasExactClass(VariadicValue.ClassName)) { - const valueAsVariadic = value; - const variadicType = valueAsVariadic.getType(); - if (variadicType.isCounted) { - const countValue = new U32Value(valueAsVariadic.getItems().length); - buffers.push(self.codec.encodeTopLevel(countValue)); - } + return; + } + + if (value.hasExactClass(VariadicValue.ClassName)) { + handleVariadicValue(value); + return; + } + + if (value.hasExactClass(CompositeValue.ClassName)) { + const valueAsComposite = value; - for (const item of valueAsVariadic.getItems()) { - handleValue(item); - } - } else if (value.hasExactClass(CompositeValue.ClassName)) { - let valueAsComposite = value; for (const item of valueAsComposite.getItems()) { handleValue(item); } - } else { - // Non-composite (singular), non-variadic (fixed) type. - // The only branching without a recursive call. - let buffer: Buffer = self.codec.encodeTopLevel(value); - buffers.push(buffer); + + return + } + + // Non-composite (singular), non-variadic (fixed) type. + // The only branching without a recursive call. + const buffer: Buffer = self.codec.encodeTopLevel(value); + buffers.push(buffer); + } + + function handleVariadicValue(value: VariadicValue): void { + const variadicType = value.getType(); + + if (variadicType.isCounted) { + const countValue = new U32Value(value.getItems().length); + buffers.push(self.codec.encodeTopLevel(countValue)); + } + + for (const item of value.getItems()) { + handleValue(item); } } diff --git a/src/smartcontracts/nativeSerializer.ts b/src/smartcontracts/nativeSerializer.ts index 120a5fef..7e08cc37 100644 --- a/src/smartcontracts/nativeSerializer.ts +++ b/src/smartcontracts/nativeSerializer.ts @@ -61,23 +61,18 @@ export namespace NativeSerializer { // Furthermore, multiple counted-variadic arguments cannot be expressed in the current variant. // E.g. now, it's unreasonable to decide that `foo([1, 2, 3, "a", "b", "c"])` calls `foo(counted-variadic, counted-variadic)`. function repackNonCountedVariadicParameters(args: any[], endpoint: EndpointDefinition) { - let parameters = endpoint.input; - - // TODO: Remove after first review. Temporarily left this way to make the review easier. - if (true) { - const lastEndpointParamIndex = parameters.length - 1; - const argAtIndex = args[lastEndpointParamIndex]; - - if (argAtIndex?.belongsToTypesystem) { - const isVariadicValue = argAtIndex.hasClassOrSuperclass(VariadicValue.ClassName); - if (!isVariadicValue) { - throw new ErrInvalidArgument(`Wrong argument type for endpoint ${endpoint.name}: typed value provided; expected variadic type, have ${argAtIndex.getClassName()}`); - } + const lastEndpointParamIndex = endpoint.input.length - 1; + const argAtIndex = args[lastEndpointParamIndex]; - // Do not repack. - } else { - args[lastEndpointParamIndex] = args.slice(lastEndpointParamIndex); + if (argAtIndex?.belongsToTypesystem) { + const isVariadicValue = argAtIndex.hasClassOrSuperclass(VariadicValue.ClassName); + if (!isVariadicValue) { + throw new ErrInvalidArgument(`Wrong argument type for endpoint ${endpoint.name}: typed value provided; expected variadic type, have ${argAtIndex.getClassName()}`); } + + // Do not repack. + } else { + args[lastEndpointParamIndex] = args.slice(lastEndpointParamIndex); } return args;