Skip to content

Commit

Permalink
nep-validation (#466)
Browse files Browse the repository at this point in the history
  • Loading branch information
chenzhitong authored Sep 2, 2024
1 parent fad2135 commit 148ea45
Show file tree
Hide file tree
Showing 2 changed files with 239 additions and 126 deletions.
293 changes: 181 additions & 112 deletions src/neoxp/Extensions/ContractManifestExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,128 +9,197 @@
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using Microsoft.AspNetCore.Diagnostics;
using Neo.SmartContract;
using Neo.SmartContract.Manifest;

namespace NeoExpress;

internal static class ContractManifestExtensions
{
public static bool IsNep11Compliant(this ContractManifest manifest)
public static List<string> Nep11CompliantErrors(this ContractManifest manifest)
{
try
{
var symbolMethod = manifest.Abi.GetMethod("symbol", 0);
var decimalsMethod = manifest.Abi.GetMethod("decimals", 0);
var totalSupplyMethod = manifest.Abi.GetMethod("totalSupply", 0);
var balanceOfMethod1 = manifest.Abi.GetMethod("balanceOf", 1);
var balanceOfMethod2 = manifest.Abi.GetMethod("balanceOf", 2);
var tokensOfMethod = manifest.Abi.GetMethod("tokensOf", 1);
var ownerOfMethod = manifest.Abi.GetMethod("ownerOf", 1);
var transferMethod1 = manifest.Abi.GetMethod("transfer", 3);
var transferMethod2 = manifest.Abi.GetMethod("transfer", 5);

var symbolValid = symbolMethod.Safe == true &&
symbolMethod.ReturnType == ContractParameterType.String;
var decimalsValid = decimalsMethod.Safe == true &&
decimalsMethod.ReturnType == ContractParameterType.Integer;
var totalSupplyValid = totalSupplyMethod.Safe == true &&
totalSupplyMethod.ReturnType == ContractParameterType.Integer;
var balanceOfValid1 = balanceOfMethod1.Safe == true &&
balanceOfMethod1.ReturnType == ContractParameterType.Integer &&
balanceOfMethod1.Parameters[0].Type == ContractParameterType.Hash160;
var balanceOfValid2 = balanceOfMethod2?.Safe == true &&
balanceOfMethod2?.ReturnType == ContractParameterType.Integer &&
balanceOfMethod2?.Parameters[0].Type == ContractParameterType.Hash160 &&
balanceOfMethod2?.Parameters[0].Type == ContractParameterType.ByteArray;
var tokensOfValid = tokensOfMethod.Safe == true &&
tokensOfMethod.ReturnType == ContractParameterType.InteropInterface &&
tokensOfMethod.Parameters[0].Type == ContractParameterType.Hash160;
var ownerOfValid1 = ownerOfMethod.Safe == true &&
ownerOfMethod.ReturnType == ContractParameterType.Hash160 &&
ownerOfMethod.Parameters[0].Type == ContractParameterType.ByteArray;
var ownerOfValid2 = ownerOfMethod.Safe == true &&
ownerOfMethod.ReturnType == ContractParameterType.InteropInterface &&
ownerOfMethod.Parameters[0].Type == ContractParameterType.ByteArray;
var transferValid1 = transferMethod1.Safe == false &&
transferMethod1.ReturnType == ContractParameterType.Boolean &&
transferMethod1.Parameters[0].Type == ContractParameterType.Hash160 &&
transferMethod1.Parameters[1].Type == ContractParameterType.ByteArray &&
transferMethod1.Parameters[2].Type == ContractParameterType.Any;
var transferValid2 = transferMethod2?.Safe == false &&
transferMethod2?.ReturnType == ContractParameterType.Boolean &&
transferMethod2?.Parameters[0].Type == ContractParameterType.Hash160 &&
transferMethod2?.Parameters[1].Type == ContractParameterType.Hash160 &&
transferMethod2?.Parameters[2].Type == ContractParameterType.Integer &&
transferMethod2?.Parameters[3].Type == ContractParameterType.ByteArray &&
transferMethod2?.Parameters[4].Type == ContractParameterType.Any;
var transferEvent = manifest.Abi.Events.Any(a =>
a.Name == "Transfer" &&
a.Parameters.Length == 4 &&
a.Parameters[0].Type == ContractParameterType.Hash160 &&
a.Parameters[1].Type == ContractParameterType.Hash160 &&
a.Parameters[2].Type == ContractParameterType.Integer &&
a.Parameters[3].Type == ContractParameterType.ByteArray);

// Waiting on issue https://github.com/neo-project/neo-devpack-dotnet/issues/812

return (symbolValid &&
decimalsValid &&
totalSupplyValid &&
(balanceOfValid2 || balanceOfValid1) &&
tokensOfValid &&
(ownerOfValid2 || ownerOfValid1) &&
(transferValid2 || transferValid1) &&
transferEvent);
}
catch
{
return false;
}
var errors = new List<string>();
var symbolMethod = manifest.Abi.GetMethod("symbol", 0);
var decimalsMethod = manifest.Abi.GetMethod("decimals", 0);
var totalSupplyMethod = manifest.Abi.GetMethod("totalSupply", 0);
var balanceOfMethod1 = manifest.Abi.GetMethod("balanceOf", 1);
var balanceOfMethod2 = manifest.Abi.GetMethod("balanceOf", 2);
var tokensOfMethod = manifest.Abi.GetMethod("tokensOf", 1);
var ownerOfMethod = manifest.Abi.GetMethod("ownerOf", 1);
var transferMethod1 = manifest.Abi.GetMethod("transfer", 3);
var transferMethod2 = manifest.Abi.GetMethod("transfer", 5);

var symbolValid = symbolMethod != null && symbolMethod.Safe &&
symbolMethod.ReturnType == ContractParameterType.String;
var decimalsValid = decimalsMethod != null && decimalsMethod.Safe &&
decimalsMethod.ReturnType == ContractParameterType.Integer;
var totalSupplyValid = totalSupplyMethod != null && totalSupplyMethod.Safe &&
totalSupplyMethod.ReturnType == ContractParameterType.Integer;
var balanceOfValid1 = balanceOfMethod1 != null && balanceOfMethod1.Safe &&
balanceOfMethod1.ReturnType == ContractParameterType.Integer &&
balanceOfMethod1.Parameters.Length == 1 &&
balanceOfMethod1.Parameters[0].Type == ContractParameterType.Hash160;
var balanceOfValid2 = balanceOfMethod2?.Safe == true &&
balanceOfMethod2?.ReturnType == ContractParameterType.Integer &&
balanceOfMethod2?.Parameters.Length == 2 &&
balanceOfMethod2?.Parameters[0].Type == ContractParameterType.Hash160 &&
balanceOfMethod2?.Parameters[0].Type == ContractParameterType.ByteArray;
var tokensOfValid = tokensOfMethod != null && tokensOfMethod.Safe &&
tokensOfMethod.ReturnType == ContractParameterType.InteropInterface &&
tokensOfMethod.Parameters.Length == 1 &&
tokensOfMethod.Parameters[0].Type == ContractParameterType.Hash160;
var ownerOfValid1 = ownerOfMethod != null && ownerOfMethod.Safe &&
ownerOfMethod.ReturnType == ContractParameterType.Hash160 &&
ownerOfMethod.Parameters.Length == 1 &&
ownerOfMethod.Parameters[0].Type == ContractParameterType.ByteArray;
var ownerOfValid2 = ownerOfMethod != null && ownerOfMethod.Safe &&
ownerOfMethod.ReturnType == ContractParameterType.InteropInterface &&
ownerOfMethod.Parameters.Length == 1 &&
ownerOfMethod.Parameters[0].Type == ContractParameterType.ByteArray;
var transferValid1 = transferMethod1 != null && transferMethod1.Safe == false &&
transferMethod1.ReturnType == ContractParameterType.Boolean &&
transferMethod1.Parameters.Length == 3 &&
transferMethod1.Parameters[0].Type == ContractParameterType.Hash160 &&
transferMethod1.Parameters[1].Type == ContractParameterType.ByteArray &&
transferMethod1.Parameters[2].Type == ContractParameterType.Any;
var transferValid2 = transferMethod2?.Safe == false &&
transferMethod2?.ReturnType == ContractParameterType.Boolean &&
transferMethod2.Parameters.Length == 5 &&
transferMethod2?.Parameters[0].Type == ContractParameterType.Hash160 &&
transferMethod2?.Parameters[1].Type == ContractParameterType.Hash160 &&
transferMethod2?.Parameters[2].Type == ContractParameterType.Integer &&
transferMethod2?.Parameters[3].Type == ContractParameterType.ByteArray &&
transferMethod2?.Parameters[4].Type == ContractParameterType.Any;
var transferEvent = manifest.Abi.Events.Any(a =>
a.Name == "Transfer" &&
a.Parameters.Length == 4 &&
a.Parameters[0].Type == ContractParameterType.Hash160 &&
a.Parameters[1].Type == ContractParameterType.Hash160 &&
a.Parameters[2].Type == ContractParameterType.Integer &&
a.Parameters[3].Type == ContractParameterType.ByteArray);


if (!symbolValid)
errors.Add($"Incomplete or unsafe NEP standard NEP-11 implementation: symbol");
if (!decimalsValid)
errors.Add($"Incomplete or unsafe NEP standard NEP-11 implementation: decimals");

if (!totalSupplyValid)
errors.Add($"Incomplete or unsafe NEP standard NEP-11 implementation: totalSupply");

if (!balanceOfValid1 && !balanceOfValid2)
errors.Add($"Incomplete or unsafe NEP standard NEP-11 implementation: balanceOf");

if (!tokensOfValid)
errors.Add($"Incomplete or unsafe NEP standard NEP-11 implementation: tokensOf");

if (!ownerOfValid1 && !ownerOfValid2)
errors.Add($"Incomplete or unsafe NEP standard NEP-11 implementation: ownerOf");

if (!transferValid1 && !transferValid2)
errors.Add($"Incomplete NEP standard NEP-11 implementation: transfer");

if (!transferEvent)
errors.Add($"Incomplete NEP standard NEP-11 implementation: {nameof(transferEvent)}");

return errors;
}

public static List<string> Nep17CompliantErrors(this ContractManifest manifest)
{
var errors = new List<string>();
var symbolMethod = manifest.Abi.GetMethod("symbol", 0);
var decimalsMethod = manifest.Abi.GetMethod("decimals", 0);
var totalSupplyMethod = manifest.Abi.GetMethod("totalSupply", 0);
var balanceOfMethod = manifest.Abi.GetMethod("balanceOf", 1);
var transferMethod = manifest.Abi.GetMethod("transfer", 4);

var symbolValid = symbolMethod != null && symbolMethod.Safe &&
symbolMethod.ReturnType == ContractParameterType.String;
var decimalsValid = decimalsMethod != null && decimalsMethod.Safe &&
decimalsMethod.ReturnType == ContractParameterType.Integer;
var totalSupplyValid = totalSupplyMethod != null && totalSupplyMethod.Safe &&
totalSupplyMethod.ReturnType == ContractParameterType.Integer;
var balanceOfValid = balanceOfMethod != null && balanceOfMethod.Safe &&
balanceOfMethod.ReturnType == ContractParameterType.Integer &&
balanceOfMethod.Parameters.Length == 1 &&
balanceOfMethod.Parameters[0].Type == ContractParameterType.Hash160;
var transferValid = transferMethod != null && transferMethod.Safe == false &&
transferMethod.ReturnType == ContractParameterType.Boolean &&
transferMethod.Parameters.Length == 4 &&
transferMethod.Parameters[0].Type == ContractParameterType.Hash160 &&
transferMethod.Parameters[1].Type == ContractParameterType.Hash160 &&
transferMethod.Parameters[2].Type == ContractParameterType.Integer &&
transferMethod.Parameters[3].Type == ContractParameterType.Any;
var transferEvent = manifest.Abi.Events.Any(s =>
s.Name == "Transfer" &&
s.Parameters.Length == 3 &&
s.Parameters[0].Type == ContractParameterType.Hash160 &&
s.Parameters[1].Type == ContractParameterType.Hash160 &&
s.Parameters[2].Type == ContractParameterType.Integer);

if (!symbolValid)
errors.Add("Incomplete or unsafe NEP standard NEP-17 implementation: symbol");
if (!decimalsValid)
errors.Add("Incomplete or unsafe NEP standard NEP-17 implementation: decimals");
if (!totalSupplyValid)
errors.Add("Incomplete or unsafe NEP standard NEP-17 implementation: totalSupply");
if (!balanceOfValid)
errors.Add("Incomplete or unsafe NEP standard NEP-17 implementation: balanceOf");
if (!transferValid)
errors.Add("Incomplete NEP standard NEP-17 implementation: transfer");

return errors;
}

public static List<string> Nep24CompliantErrors(this ContractManifest manifest)
{
var errors = new List<string>();
var royaltyInfoMethod = manifest.Abi.GetMethod("royaltyInfo", 0);

var royaltyInfoValid = royaltyInfoMethod != null && royaltyInfoMethod.Safe &&
royaltyInfoMethod.ReturnType == ContractParameterType.Array &&
royaltyInfoMethod.Parameters.Length == 3 &&
royaltyInfoMethod.Parameters[0].Type == ContractParameterType.ByteArray &&
royaltyInfoMethod.Parameters[1].Type == ContractParameterType.Hash160 &&
royaltyInfoMethod.Parameters[2].Type == ContractParameterType.Integer;

if (!royaltyInfoValid)
errors.Add("Incomplete or unsafe NEP standard NEP-24 implementation: royaltyInfo");
return errors;
}

public static bool IsNep17Compliant(this ContractManifest manifest)

public static List<string> Nep26CompliantErrors(this ContractManifest manifest)
{
try
{
var symbolMethod = manifest.Abi.GetMethod("symbol", 0);
var decimalsMethod = manifest.Abi.GetMethod("decimals", 0);
var totalSupplyMethod = manifest.Abi.GetMethod("totalSupply", 0);
var balanceOfMethod = manifest.Abi.GetMethod("balanceOf", 1);
var transferMethod = manifest.Abi.GetMethod("transfer", 4);

var symbolValid = symbolMethod.Safe == true &&
symbolMethod.ReturnType == ContractParameterType.String;
var decimalsValid = decimalsMethod.Safe == true &&
decimalsMethod.ReturnType == ContractParameterType.Integer;
var totalSupplyValid = totalSupplyMethod.Safe == true &&
totalSupplyMethod.ReturnType == ContractParameterType.Integer;
var balanceOfValid = balanceOfMethod.Safe == true &&
balanceOfMethod.ReturnType == ContractParameterType.Integer &&
balanceOfMethod.Parameters[0].Type == ContractParameterType.Hash160;
var transferValid = transferMethod.Safe == false &&
transferMethod.ReturnType == ContractParameterType.Boolean &&
transferMethod.Parameters[0].Type == ContractParameterType.Hash160 &&
transferMethod.Parameters[1].Type == ContractParameterType.Hash160 &&
transferMethod.Parameters[2].Type == ContractParameterType.Integer &&
transferMethod.Parameters[3].Type == ContractParameterType.Any;
var transferEvent = manifest.Abi.Events.Any(s =>
s.Name == "Transfer" &&
s.Parameters.Length == 3 &&
s.Parameters[0].Type == ContractParameterType.Hash160 &&
s.Parameters[1].Type == ContractParameterType.Hash160 &&
s.Parameters[2].Type == ContractParameterType.Integer);

return (symbolValid &&
decimalsValid &&
totalSupplyValid &&
balanceOfValid &&
transferValid &&
transferEvent);
}
catch
{
return false;
}
var errors = new List<string>();
var onNEP11PaymentMethod = manifest.Abi.GetMethod("onNEP11Payment", 4);
var onNEP11PaymentValid = onNEP11PaymentMethod is { ReturnType: ContractParameterType.Void } &&
onNEP11PaymentMethod.Parameters.Length == 4 &&
onNEP11PaymentMethod.Parameters[0].Type == ContractParameterType.Hash160 &&
onNEP11PaymentMethod.Parameters[1].Type == ContractParameterType.Integer &&
onNEP11PaymentMethod.Parameters[2].Type == ContractParameterType.String &&
onNEP11PaymentMethod.Parameters[3].Type == ContractParameterType.Any;

if (!onNEP11PaymentValid)
errors.Add("Incomplete NEP standard NEP-26 implementation: onNEP11Payment");
return errors;
}


public static List<string> Nep27CompliantErrors(this ContractManifest manifest)
{
var errors = new List<string>();
var onNEP17PaymentMethod = manifest.Abi.GetMethod("onNEP17Payment", 3);
var onNEP17PaymentValid = onNEP17PaymentMethod is { ReturnType: ContractParameterType.Void } &&
onNEP17PaymentMethod.Parameters.Length == 3 &&
onNEP17PaymentMethod.Parameters[0].Type == ContractParameterType.Hash160 &&
onNEP17PaymentMethod.Parameters[1].Type == ContractParameterType.Integer &&
onNEP17PaymentMethod.Parameters[2].Type == ContractParameterType.Any;

if (!onNEP17PaymentValid)
errors.Add("Incomplete NEP standard NEP-27 implementation: onNEP17Payment");
return errors;
}
}
Loading

0 comments on commit 148ea45

Please sign in to comment.