-
Notifications
You must be signed in to change notification settings - Fork 1k
NEP-25 #4043
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NEP-25 #4043
Changes from 2 commits
b5b0a26
9fa095d
ddba39e
46ea96f
18a250c
368cfdc
418a8ab
d0f8d21
d392f50
55ec5e8
7ab0c64
b36370a
2e0152f
5e47abc
8929079
1f8d488
d21d906
7c073f2
a1248b2
b0cd9b1
d3c8564
0e85e4a
65f27ec
cfd07b4
f6aa6aa
890dcd4
5ffeb94
de230cc
a7967e5
c3759a8
8c6aa4b
3b20380
d093162
2fa6247
761ca46
2ac2da1
d2e9871
14a9176
7cd74e6
35229d4
8718ed4
3b56be4
e2ac006
ac21144
242dbb5
7c3a377
3fb806a
20965c4
b9cfdb6
c0fd6f2
b6a80d1
c45eecf
51adba8
3b0ab01
4ca1f65
0118b4c
09c4839
41782d5
afa0632
d327be8
a8408f4
169ea7b
60eac04
c4bf05a
ad1ffde
c49499d
4e1efa0
054e5de
aca22c0
81b7b5a
7be35bd
a4a3d3d
a23ee2d
c719313
56ea443
533d472
fefdb95
f9e1526
88b861b
a799ca6
c575449
9b4cccc
2d3e1fe
20aa730
0c5d4c6
ba009ea
3fd4f14
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,227 @@ | ||
| // Copyright (C) 2015-2025 The Neo Project. | ||
| // | ||
| // ExtendedType.cs file belongs to the neo project and is free | ||
| // software distributed under the MIT software license, see the | ||
| // accompanying file LICENSE in the main directory of the | ||
| // repository or http://www.opensource.org/licenses/mit-license.php | ||
| // for more details. | ||
| // | ||
| // Redistribution and use in source and binary forms with or without | ||
| // modifications are permitted. | ||
|
|
||
| using Neo.Json; | ||
| using Neo.VM; | ||
| using Neo.VM.Types; | ||
| using System; | ||
|
|
||
| namespace Neo.SmartContract.Manifest | ||
| { | ||
| #nullable enable | ||
|
|
||
| public class ExtendedType : IInteroperable, IEquatable<ExtendedType> | ||
| { | ||
| /// <summary> | ||
| /// The type of the parameter. It can be any value of <see cref="ContractParameterType"/> except <see cref="ContractParameterType.Void"/>. | ||
| /// </summary> | ||
| public ContractParameterType Type { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// NamedType is used to refer to one of the types defined in the namedtypes object of Contract, | ||
| /// so namedtypes MUST contain a field named name. | ||
| /// This field is only used for structures (ordered set of named values of diffent types), | ||
shargon marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
shargon marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// if used other fields MUST NOT be set, except for the type which MUST be an Array. | ||
| /// Value string MUST start with a letter and can contain alphanumeric characters and dots. | ||
| /// It MUST NOT be longer than 64 characters. | ||
| /// </summary> | ||
| public string? NamedType { get; set; } | ||
shargon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /// <summary> | ||
| /// length is an optional field that can be used for Integer, ByteArray, String or Array types and MUST NOT be used for other types. | ||
| /// When used it specifies the maximum possible byte length of an integer/byte array/string or number of array elements. | ||
| /// Any of these lengths MUST NOT exceed NeoVM limitations that are relevant for the current version of it. | ||
| /// Length 0 means "unlimited". | ||
| /// </summary> | ||
| public int? Length { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// forbidnull is an optional field that can be used for Hash160, Hash256, | ||
| /// ByteArray, String, Array, Map or InteropInterface types and MUST NOT be used for other types. | ||
| /// It allows to specify that the method accepts or event emits only non-null values for this field. | ||
| /// The default (if not specified) is "false", meaning that null can be used. | ||
| /// </summary> | ||
| public bool? ForbidNull { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// interface is only used in conjuction with the InteropInterface type and MUST NOT be used for other types, | ||
shargon marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
shargon marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// when used it specifies which interop interface is used. | ||
| /// The only valid defined value for it is "IIterator" which means an iterator object. | ||
| /// When used it MUST be accompanied with the value object that specifies the type of each individual element returned from the iterator. | ||
| /// </summary> | ||
| public Nep25Interface? Interface { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// key is only used along with the Map type (MUST NOT be used for other types) and can have Signature, Boolean, Integer, | ||
| /// Hash160, Hash256, ByteArray, PublicKey or String value, that is all the basic types that can be used as a map key. | ||
| /// </summary> | ||
| public Nep25Key? Key { get; set; } | ||
|
|
||
| void IInteroperable.FromStackItem(StackItem stackItem) | ||
| { | ||
| FromStackItem((VM.Types.Array)stackItem, 0); | ||
| } | ||
|
|
||
| internal void FromStackItem(VM.Types.Array @struct, int startIndex) | ||
| { | ||
| Type = (ContractParameterType)(byte)@struct[startIndex++].GetInteger(); | ||
| if (!Enum.IsDefined(typeof(ContractParameterType), Type)) throw new FormatException(); | ||
shargon marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| NamedType = @struct[startIndex++].GetString(); | ||
|
|
||
| if (@struct[startIndex++] is Integer length) | ||
| { | ||
| Length = checked((int)length.GetInteger()); | ||
| if (Length < 0) throw new FormatException("Length must be non-negative."); | ||
| if (Length > ExecutionEngineLimits.Default.MaxItemSize) throw new FormatException($"Length must less than {ExecutionEngineLimits.Default.MaxItemSize}."); | ||
| } | ||
| else | ||
| { | ||
| Length = null; | ||
| } | ||
|
|
||
| if (@struct[startIndex++] is VM.Types.Boolean forbidnull) | ||
| { | ||
| ForbidNull = forbidnull.GetBoolean(); | ||
| } | ||
| else | ||
| { | ||
| ForbidNull = null; | ||
| } | ||
|
|
||
| if (@struct[startIndex++] is ByteString interf) | ||
| { | ||
| if (!Enum.TryParse<Nep25Interface>(interf.GetString(), false, out var inferValue)) | ||
| throw new FormatException(); | ||
|
|
||
| Interface = inferValue; | ||
| } | ||
| else | ||
| { | ||
| Interface = null; | ||
| } | ||
|
|
||
| if (@struct[startIndex++] is ByteString key) | ||
| { | ||
| if (!Enum.TryParse<Nep25Key>(key.GetString(), false, out var keyValue)) | ||
| throw new FormatException(); | ||
|
|
||
| Key = keyValue; | ||
| } | ||
| else | ||
| { | ||
| Key = null; | ||
| } | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we need to add a verification method that will be used by both For example, according to NEP-25
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should enumerate these checks in NEP-25
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @AnnaShaleva this property it's also optional in the proposal
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The question is more about semantic checks, almost all fields are optional, but not all combinations of fields are valid. This is described in NEP-25 and both deserialization methods should check for it.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still here and #4187 (comment) is relevant, we can check a lot of things in ExtendedType without external data and this can be leveraged, then an additional ABI-level check on |
||
|
|
||
| internal StackItem ToStackItem(IReferenceCounter referenceCounter, Struct @struct) | ||
| { | ||
| @struct.Add((byte)Type); | ||
| @struct.Add(NamedType ?? StackItem.Null); | ||
| @struct.Add(Length ?? StackItem.Null); | ||
| @struct.Add(ForbidNull ?? StackItem.Null); | ||
| @struct.Add(Interface?.ToString() ?? StackItem.Null); | ||
| @struct.Add(Key?.ToString() ?? StackItem.Null); | ||
| return @struct; | ||
| } | ||
|
|
||
| StackItem IInteroperable.ToStackItem(IReferenceCounter referenceCounter) | ||
| { | ||
| var @struct = new Struct(referenceCounter); | ||
| ToStackItem(referenceCounter, @struct); | ||
| return @struct; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Converts the type from a JSON object. | ||
| /// </summary> | ||
| /// <param name="json">The method represented by a JSON object.</param> | ||
| /// <returns>The extended type.</returns> | ||
| public static ExtendedType FromJson(JObject json) | ||
| { | ||
| ExtendedType type = new() | ||
| { | ||
| Type = Enum.Parse<ContractParameterType>(json["type"]?.GetString() ?? throw new FormatException()), | ||
| NamedType = json["namedtype"]?.GetString(), | ||
| }; | ||
| if (!Enum.IsDefined(typeof(ContractParameterType), type.Type)) throw new FormatException(); | ||
| if (json["length"] != null) | ||
| { | ||
| type.Length = json["length"]!.GetInt32(); | ||
| if (type.Length < 0) throw new FormatException("Length must be non-negative."); | ||
| if (type.Length > ExecutionEngineLimits.Default.MaxItemSize) throw new FormatException($"Length must less than {ExecutionEngineLimits.Default.MaxItemSize}."); | ||
| } | ||
| if (json["forbidnull"] != null) | ||
| { | ||
| type.ForbidNull = json["forbidnull"]!.GetBoolean(); | ||
| } | ||
| if (json["interface"] != null) | ||
| { | ||
| if (!Enum.TryParse<Nep25Interface>(json["interface"]!.GetString(), true, out var interfaceValue)) | ||
| throw new FormatException("Invalid interface value."); | ||
| type.Interface = interfaceValue; | ||
| } | ||
| if (json["key"] != null) | ||
| { | ||
| if (!Enum.TryParse<Nep25Key>(json["key"]!.GetString(), true, out var keyValue)) | ||
| throw new FormatException("Invalid key value."); | ||
| type.Key = keyValue; | ||
| } | ||
| return type; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Converts the parameter to a JSON object. | ||
| /// </summary> | ||
| /// <returns>The parameter represented by a JSON object.</returns> | ||
| public virtual JObject ToJson() | ||
| { | ||
| var json = new JObject(); | ||
| json["type"] = Type.ToString(); | ||
| json["namedtype"] = NamedType; | ||
| if (Length.HasValue) | ||
| { | ||
| json["length"] = Length.Value; | ||
| } | ||
| if (ForbidNull.HasValue) | ||
| { | ||
| json["forbidnull"] = ForbidNull.Value; | ||
| } | ||
| if (Interface.HasValue) | ||
| { | ||
| json["interface"] = Interface.Value.ToString(); | ||
| } | ||
| if (Key.HasValue) | ||
| { | ||
| json["key"] = Key.Value.ToString(); | ||
| } | ||
| return json; | ||
| } | ||
|
|
||
| public override bool Equals(object? obj) => Equals(obj as ExtendedType); | ||
|
|
||
| public override int GetHashCode() => HashCode.Combine(Type, NamedType, Length, ForbidNull, Interface, Key); | ||
|
|
||
| public bool Equals(ExtendedType? other) | ||
| { | ||
| if (other is null) return false; | ||
| if (ReferenceEquals(this, other)) return true; | ||
|
|
||
| return Type == other.Type | ||
| && NamedType == other.NamedType | ||
| && Length == other.Length | ||
| && ForbidNull == other.ForbidNull | ||
| && Interface == other.Interface | ||
| && Key == other.Key; | ||
| } | ||
| } | ||
| #nullable disable | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| // Copyright (C) 2015-2025 The Neo Project. | ||
| // | ||
| // Nep25Interface.cs file belongs to the neo project and is free | ||
| // software distributed under the MIT software license, see the | ||
| // accompanying file LICENSE in the main directory of the | ||
| // repository or http://www.opensource.org/licenses/mit-license.php | ||
| // for more details. | ||
| // | ||
| // Redistribution and use in source and binary forms with or without | ||
| // modifications are permitted. | ||
|
|
||
| namespace Neo.SmartContract.Manifest | ||
| { | ||
| /// <summary> | ||
| /// interface is only used in conjuction with the InteropInterface type and MUST NOT be used for other types, when used it specifies which interop interface is used. | ||
| /// The only valid defined value for it is "IIterator" which means an iterator object. | ||
| /// When used it MUST be accompanied with the value object that specifies the type of each individual element returned from the iterator. | ||
| /// </summary> | ||
| public enum Nep25Interface | ||
| { | ||
| /// <summary> | ||
| /// Iterator object | ||
| /// </summary> | ||
| IIterator | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| // Copyright (C) 2015-2025 The Neo Project. | ||
| // | ||
| // Nep25Key.cs file belongs to the neo project and is free | ||
| // software distributed under the MIT software license, see the | ||
| // accompanying file LICENSE in the main directory of the | ||
| // repository or http://www.opensource.org/licenses/mit-license.php | ||
| // for more details. | ||
| // | ||
| // Redistribution and use in source and binary forms with or without | ||
| // modifications are permitted. | ||
|
|
||
| namespace Neo.SmartContract.Manifest | ||
| { | ||
| /// <summary> | ||
| /// key is only used along with the Map type (MUST NOT be used for other types) and can have Signature, Boolean, | ||
| /// Integer, Hash160, Hash256, ByteArray, PublicKey or String value. | ||
| /// That is all the basic types that can be used as a map key. | ||
| /// </summary> | ||
| public enum Nep25Key | ||
shargon marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| Signature, | ||
| Boolean, | ||
| Integer, | ||
| Hash160, | ||
| Hash256, | ||
| ByteArray, | ||
| PublicKey, | ||
| String | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.