Skip to content

Commit 148ea45

Browse files
authored
nep-validation (#466)
1 parent fad2135 commit 148ea45

File tree

2 files changed

+239
-126
lines changed

2 files changed

+239
-126
lines changed

src/neoxp/Extensions/ContractManifestExtensions.cs

+181-112
Original file line numberDiff line numberDiff line change
@@ -9,128 +9,197 @@
99
// Redistribution and use in source and binary forms with or without
1010
// modifications are permitted.
1111

12+
using Microsoft.AspNetCore.Diagnostics;
1213
using Neo.SmartContract;
1314
using Neo.SmartContract.Manifest;
1415

1516
namespace NeoExpress;
1617

1718
internal static class ContractManifestExtensions
1819
{
19-
public static bool IsNep11Compliant(this ContractManifest manifest)
20+
public static List<string> Nep11CompliantErrors(this ContractManifest manifest)
2021
{
21-
try
22-
{
23-
var symbolMethod = manifest.Abi.GetMethod("symbol", 0);
24-
var decimalsMethod = manifest.Abi.GetMethod("decimals", 0);
25-
var totalSupplyMethod = manifest.Abi.GetMethod("totalSupply", 0);
26-
var balanceOfMethod1 = manifest.Abi.GetMethod("balanceOf", 1);
27-
var balanceOfMethod2 = manifest.Abi.GetMethod("balanceOf", 2);
28-
var tokensOfMethod = manifest.Abi.GetMethod("tokensOf", 1);
29-
var ownerOfMethod = manifest.Abi.GetMethod("ownerOf", 1);
30-
var transferMethod1 = manifest.Abi.GetMethod("transfer", 3);
31-
var transferMethod2 = manifest.Abi.GetMethod("transfer", 5);
32-
33-
var symbolValid = symbolMethod.Safe == true &&
34-
symbolMethod.ReturnType == ContractParameterType.String;
35-
var decimalsValid = decimalsMethod.Safe == true &&
36-
decimalsMethod.ReturnType == ContractParameterType.Integer;
37-
var totalSupplyValid = totalSupplyMethod.Safe == true &&
38-
totalSupplyMethod.ReturnType == ContractParameterType.Integer;
39-
var balanceOfValid1 = balanceOfMethod1.Safe == true &&
40-
balanceOfMethod1.ReturnType == ContractParameterType.Integer &&
41-
balanceOfMethod1.Parameters[0].Type == ContractParameterType.Hash160;
42-
var balanceOfValid2 = balanceOfMethod2?.Safe == true &&
43-
balanceOfMethod2?.ReturnType == ContractParameterType.Integer &&
44-
balanceOfMethod2?.Parameters[0].Type == ContractParameterType.Hash160 &&
45-
balanceOfMethod2?.Parameters[0].Type == ContractParameterType.ByteArray;
46-
var tokensOfValid = tokensOfMethod.Safe == true &&
47-
tokensOfMethod.ReturnType == ContractParameterType.InteropInterface &&
48-
tokensOfMethod.Parameters[0].Type == ContractParameterType.Hash160;
49-
var ownerOfValid1 = ownerOfMethod.Safe == true &&
50-
ownerOfMethod.ReturnType == ContractParameterType.Hash160 &&
51-
ownerOfMethod.Parameters[0].Type == ContractParameterType.ByteArray;
52-
var ownerOfValid2 = ownerOfMethod.Safe == true &&
53-
ownerOfMethod.ReturnType == ContractParameterType.InteropInterface &&
54-
ownerOfMethod.Parameters[0].Type == ContractParameterType.ByteArray;
55-
var transferValid1 = transferMethod1.Safe == false &&
56-
transferMethod1.ReturnType == ContractParameterType.Boolean &&
57-
transferMethod1.Parameters[0].Type == ContractParameterType.Hash160 &&
58-
transferMethod1.Parameters[1].Type == ContractParameterType.ByteArray &&
59-
transferMethod1.Parameters[2].Type == ContractParameterType.Any;
60-
var transferValid2 = transferMethod2?.Safe == false &&
61-
transferMethod2?.ReturnType == ContractParameterType.Boolean &&
62-
transferMethod2?.Parameters[0].Type == ContractParameterType.Hash160 &&
63-
transferMethod2?.Parameters[1].Type == ContractParameterType.Hash160 &&
64-
transferMethod2?.Parameters[2].Type == ContractParameterType.Integer &&
65-
transferMethod2?.Parameters[3].Type == ContractParameterType.ByteArray &&
66-
transferMethod2?.Parameters[4].Type == ContractParameterType.Any;
67-
var transferEvent = manifest.Abi.Events.Any(a =>
68-
a.Name == "Transfer" &&
69-
a.Parameters.Length == 4 &&
70-
a.Parameters[0].Type == ContractParameterType.Hash160 &&
71-
a.Parameters[1].Type == ContractParameterType.Hash160 &&
72-
a.Parameters[2].Type == ContractParameterType.Integer &&
73-
a.Parameters[3].Type == ContractParameterType.ByteArray);
74-
75-
// Waiting on issue https://github.com/neo-project/neo-devpack-dotnet/issues/812
76-
77-
return (symbolValid &&
78-
decimalsValid &&
79-
totalSupplyValid &&
80-
(balanceOfValid2 || balanceOfValid1) &&
81-
tokensOfValid &&
82-
(ownerOfValid2 || ownerOfValid1) &&
83-
(transferValid2 || transferValid1) &&
84-
transferEvent);
85-
}
86-
catch
87-
{
88-
return false;
89-
}
22+
var errors = new List<string>();
23+
var symbolMethod = manifest.Abi.GetMethod("symbol", 0);
24+
var decimalsMethod = manifest.Abi.GetMethod("decimals", 0);
25+
var totalSupplyMethod = manifest.Abi.GetMethod("totalSupply", 0);
26+
var balanceOfMethod1 = manifest.Abi.GetMethod("balanceOf", 1);
27+
var balanceOfMethod2 = manifest.Abi.GetMethod("balanceOf", 2);
28+
var tokensOfMethod = manifest.Abi.GetMethod("tokensOf", 1);
29+
var ownerOfMethod = manifest.Abi.GetMethod("ownerOf", 1);
30+
var transferMethod1 = manifest.Abi.GetMethod("transfer", 3);
31+
var transferMethod2 = manifest.Abi.GetMethod("transfer", 5);
32+
33+
var symbolValid = symbolMethod != null && symbolMethod.Safe &&
34+
symbolMethod.ReturnType == ContractParameterType.String;
35+
var decimalsValid = decimalsMethod != null && decimalsMethod.Safe &&
36+
decimalsMethod.ReturnType == ContractParameterType.Integer;
37+
var totalSupplyValid = totalSupplyMethod != null && totalSupplyMethod.Safe &&
38+
totalSupplyMethod.ReturnType == ContractParameterType.Integer;
39+
var balanceOfValid1 = balanceOfMethod1 != null && balanceOfMethod1.Safe &&
40+
balanceOfMethod1.ReturnType == ContractParameterType.Integer &&
41+
balanceOfMethod1.Parameters.Length == 1 &&
42+
balanceOfMethod1.Parameters[0].Type == ContractParameterType.Hash160;
43+
var balanceOfValid2 = balanceOfMethod2?.Safe == true &&
44+
balanceOfMethod2?.ReturnType == ContractParameterType.Integer &&
45+
balanceOfMethod2?.Parameters.Length == 2 &&
46+
balanceOfMethod2?.Parameters[0].Type == ContractParameterType.Hash160 &&
47+
balanceOfMethod2?.Parameters[0].Type == ContractParameterType.ByteArray;
48+
var tokensOfValid = tokensOfMethod != null && tokensOfMethod.Safe &&
49+
tokensOfMethod.ReturnType == ContractParameterType.InteropInterface &&
50+
tokensOfMethod.Parameters.Length == 1 &&
51+
tokensOfMethod.Parameters[0].Type == ContractParameterType.Hash160;
52+
var ownerOfValid1 = ownerOfMethod != null && ownerOfMethod.Safe &&
53+
ownerOfMethod.ReturnType == ContractParameterType.Hash160 &&
54+
ownerOfMethod.Parameters.Length == 1 &&
55+
ownerOfMethod.Parameters[0].Type == ContractParameterType.ByteArray;
56+
var ownerOfValid2 = ownerOfMethod != null && ownerOfMethod.Safe &&
57+
ownerOfMethod.ReturnType == ContractParameterType.InteropInterface &&
58+
ownerOfMethod.Parameters.Length == 1 &&
59+
ownerOfMethod.Parameters[0].Type == ContractParameterType.ByteArray;
60+
var transferValid1 = transferMethod1 != null && transferMethod1.Safe == false &&
61+
transferMethod1.ReturnType == ContractParameterType.Boolean &&
62+
transferMethod1.Parameters.Length == 3 &&
63+
transferMethod1.Parameters[0].Type == ContractParameterType.Hash160 &&
64+
transferMethod1.Parameters[1].Type == ContractParameterType.ByteArray &&
65+
transferMethod1.Parameters[2].Type == ContractParameterType.Any;
66+
var transferValid2 = transferMethod2?.Safe == false &&
67+
transferMethod2?.ReturnType == ContractParameterType.Boolean &&
68+
transferMethod2.Parameters.Length == 5 &&
69+
transferMethod2?.Parameters[0].Type == ContractParameterType.Hash160 &&
70+
transferMethod2?.Parameters[1].Type == ContractParameterType.Hash160 &&
71+
transferMethod2?.Parameters[2].Type == ContractParameterType.Integer &&
72+
transferMethod2?.Parameters[3].Type == ContractParameterType.ByteArray &&
73+
transferMethod2?.Parameters[4].Type == ContractParameterType.Any;
74+
var transferEvent = manifest.Abi.Events.Any(a =>
75+
a.Name == "Transfer" &&
76+
a.Parameters.Length == 4 &&
77+
a.Parameters[0].Type == ContractParameterType.Hash160 &&
78+
a.Parameters[1].Type == ContractParameterType.Hash160 &&
79+
a.Parameters[2].Type == ContractParameterType.Integer &&
80+
a.Parameters[3].Type == ContractParameterType.ByteArray);
81+
82+
83+
if (!symbolValid)
84+
errors.Add($"Incomplete or unsafe NEP standard NEP-11 implementation: symbol");
85+
if (!decimalsValid)
86+
errors.Add($"Incomplete or unsafe NEP standard NEP-11 implementation: decimals");
87+
88+
if (!totalSupplyValid)
89+
errors.Add($"Incomplete or unsafe NEP standard NEP-11 implementation: totalSupply");
90+
91+
if (!balanceOfValid1 && !balanceOfValid2)
92+
errors.Add($"Incomplete or unsafe NEP standard NEP-11 implementation: balanceOf");
93+
94+
if (!tokensOfValid)
95+
errors.Add($"Incomplete or unsafe NEP standard NEP-11 implementation: tokensOf");
96+
97+
if (!ownerOfValid1 && !ownerOfValid2)
98+
errors.Add($"Incomplete or unsafe NEP standard NEP-11 implementation: ownerOf");
99+
100+
if (!transferValid1 && !transferValid2)
101+
errors.Add($"Incomplete NEP standard NEP-11 implementation: transfer");
102+
103+
if (!transferEvent)
104+
errors.Add($"Incomplete NEP standard NEP-11 implementation: {nameof(transferEvent)}");
105+
106+
return errors;
107+
}
108+
109+
public static List<string> Nep17CompliantErrors(this ContractManifest manifest)
110+
{
111+
var errors = new List<string>();
112+
var symbolMethod = manifest.Abi.GetMethod("symbol", 0);
113+
var decimalsMethod = manifest.Abi.GetMethod("decimals", 0);
114+
var totalSupplyMethod = manifest.Abi.GetMethod("totalSupply", 0);
115+
var balanceOfMethod = manifest.Abi.GetMethod("balanceOf", 1);
116+
var transferMethod = manifest.Abi.GetMethod("transfer", 4);
117+
118+
var symbolValid = symbolMethod != null && symbolMethod.Safe &&
119+
symbolMethod.ReturnType == ContractParameterType.String;
120+
var decimalsValid = decimalsMethod != null && decimalsMethod.Safe &&
121+
decimalsMethod.ReturnType == ContractParameterType.Integer;
122+
var totalSupplyValid = totalSupplyMethod != null && totalSupplyMethod.Safe &&
123+
totalSupplyMethod.ReturnType == ContractParameterType.Integer;
124+
var balanceOfValid = balanceOfMethod != null && balanceOfMethod.Safe &&
125+
balanceOfMethod.ReturnType == ContractParameterType.Integer &&
126+
balanceOfMethod.Parameters.Length == 1 &&
127+
balanceOfMethod.Parameters[0].Type == ContractParameterType.Hash160;
128+
var transferValid = transferMethod != null && transferMethod.Safe == false &&
129+
transferMethod.ReturnType == ContractParameterType.Boolean &&
130+
transferMethod.Parameters.Length == 4 &&
131+
transferMethod.Parameters[0].Type == ContractParameterType.Hash160 &&
132+
transferMethod.Parameters[1].Type == ContractParameterType.Hash160 &&
133+
transferMethod.Parameters[2].Type == ContractParameterType.Integer &&
134+
transferMethod.Parameters[3].Type == ContractParameterType.Any;
135+
var transferEvent = manifest.Abi.Events.Any(s =>
136+
s.Name == "Transfer" &&
137+
s.Parameters.Length == 3 &&
138+
s.Parameters[0].Type == ContractParameterType.Hash160 &&
139+
s.Parameters[1].Type == ContractParameterType.Hash160 &&
140+
s.Parameters[2].Type == ContractParameterType.Integer);
141+
142+
if (!symbolValid)
143+
errors.Add("Incomplete or unsafe NEP standard NEP-17 implementation: symbol");
144+
if (!decimalsValid)
145+
errors.Add("Incomplete or unsafe NEP standard NEP-17 implementation: decimals");
146+
if (!totalSupplyValid)
147+
errors.Add("Incomplete or unsafe NEP standard NEP-17 implementation: totalSupply");
148+
if (!balanceOfValid)
149+
errors.Add("Incomplete or unsafe NEP standard NEP-17 implementation: balanceOf");
150+
if (!transferValid)
151+
errors.Add("Incomplete NEP standard NEP-17 implementation: transfer");
152+
153+
return errors;
154+
}
155+
156+
public static List<string> Nep24CompliantErrors(this ContractManifest manifest)
157+
{
158+
var errors = new List<string>();
159+
var royaltyInfoMethod = manifest.Abi.GetMethod("royaltyInfo", 0);
160+
161+
var royaltyInfoValid = royaltyInfoMethod != null && royaltyInfoMethod.Safe &&
162+
royaltyInfoMethod.ReturnType == ContractParameterType.Array &&
163+
royaltyInfoMethod.Parameters.Length == 3 &&
164+
royaltyInfoMethod.Parameters[0].Type == ContractParameterType.ByteArray &&
165+
royaltyInfoMethod.Parameters[1].Type == ContractParameterType.Hash160 &&
166+
royaltyInfoMethod.Parameters[2].Type == ContractParameterType.Integer;
167+
168+
if (!royaltyInfoValid)
169+
errors.Add("Incomplete or unsafe NEP standard NEP-24 implementation: royaltyInfo");
170+
return errors;
90171
}
91172

92-
public static bool IsNep17Compliant(this ContractManifest manifest)
173+
174+
public static List<string> Nep26CompliantErrors(this ContractManifest manifest)
93175
{
94-
try
95-
{
96-
var symbolMethod = manifest.Abi.GetMethod("symbol", 0);
97-
var decimalsMethod = manifest.Abi.GetMethod("decimals", 0);
98-
var totalSupplyMethod = manifest.Abi.GetMethod("totalSupply", 0);
99-
var balanceOfMethod = manifest.Abi.GetMethod("balanceOf", 1);
100-
var transferMethod = manifest.Abi.GetMethod("transfer", 4);
101-
102-
var symbolValid = symbolMethod.Safe == true &&
103-
symbolMethod.ReturnType == ContractParameterType.String;
104-
var decimalsValid = decimalsMethod.Safe == true &&
105-
decimalsMethod.ReturnType == ContractParameterType.Integer;
106-
var totalSupplyValid = totalSupplyMethod.Safe == true &&
107-
totalSupplyMethod.ReturnType == ContractParameterType.Integer;
108-
var balanceOfValid = balanceOfMethod.Safe == true &&
109-
balanceOfMethod.ReturnType == ContractParameterType.Integer &&
110-
balanceOfMethod.Parameters[0].Type == ContractParameterType.Hash160;
111-
var transferValid = transferMethod.Safe == false &&
112-
transferMethod.ReturnType == ContractParameterType.Boolean &&
113-
transferMethod.Parameters[0].Type == ContractParameterType.Hash160 &&
114-
transferMethod.Parameters[1].Type == ContractParameterType.Hash160 &&
115-
transferMethod.Parameters[2].Type == ContractParameterType.Integer &&
116-
transferMethod.Parameters[3].Type == ContractParameterType.Any;
117-
var transferEvent = manifest.Abi.Events.Any(s =>
118-
s.Name == "Transfer" &&
119-
s.Parameters.Length == 3 &&
120-
s.Parameters[0].Type == ContractParameterType.Hash160 &&
121-
s.Parameters[1].Type == ContractParameterType.Hash160 &&
122-
s.Parameters[2].Type == ContractParameterType.Integer);
123-
124-
return (symbolValid &&
125-
decimalsValid &&
126-
totalSupplyValid &&
127-
balanceOfValid &&
128-
transferValid &&
129-
transferEvent);
130-
}
131-
catch
132-
{
133-
return false;
134-
}
176+
var errors = new List<string>();
177+
var onNEP11PaymentMethod = manifest.Abi.GetMethod("onNEP11Payment", 4);
178+
var onNEP11PaymentValid = onNEP11PaymentMethod is { ReturnType: ContractParameterType.Void } &&
179+
onNEP11PaymentMethod.Parameters.Length == 4 &&
180+
onNEP11PaymentMethod.Parameters[0].Type == ContractParameterType.Hash160 &&
181+
onNEP11PaymentMethod.Parameters[1].Type == ContractParameterType.Integer &&
182+
onNEP11PaymentMethod.Parameters[2].Type == ContractParameterType.String &&
183+
onNEP11PaymentMethod.Parameters[3].Type == ContractParameterType.Any;
184+
185+
if (!onNEP11PaymentValid)
186+
errors.Add("Incomplete NEP standard NEP-26 implementation: onNEP11Payment");
187+
return errors;
188+
}
189+
190+
191+
public static List<string> Nep27CompliantErrors(this ContractManifest manifest)
192+
{
193+
var errors = new List<string>();
194+
var onNEP17PaymentMethod = manifest.Abi.GetMethod("onNEP17Payment", 3);
195+
var onNEP17PaymentValid = onNEP17PaymentMethod is { ReturnType: ContractParameterType.Void } &&
196+
onNEP17PaymentMethod.Parameters.Length == 3 &&
197+
onNEP17PaymentMethod.Parameters[0].Type == ContractParameterType.Hash160 &&
198+
onNEP17PaymentMethod.Parameters[1].Type == ContractParameterType.Integer &&
199+
onNEP17PaymentMethod.Parameters[2].Type == ContractParameterType.Any;
200+
201+
if (!onNEP17PaymentValid)
202+
errors.Add("Incomplete NEP standard NEP-27 implementation: onNEP17Payment");
203+
return errors;
135204
}
136205
}

0 commit comments

Comments
 (0)