Skip to content
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

[Framework Add] implement payable #990

Merged
merged 16 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions src/Neo.Compiler.CSharp/ContractManifestExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,44 @@ private static void CheckNep17Compliant(this ContractManifest manifest)
}
}

private static void CheckNep11PayableCompliant(this ContractManifest manifest)
{
try
{
var onNEP11PaymentMethod = manifest.Abi.GetMethod("onNEP11Payment", 3);
shargon marked this conversation as resolved.
Show resolved Hide resolved
shargon marked this conversation as resolved.
Show resolved Hide resolved
var onNEP11PaymentValid = onNEP11PaymentMethod is { Safe: false, ReturnType: ContractParameterType.Void } &&
shargon marked this conversation as resolved.
Show resolved Hide resolved
onNEP11PaymentMethod.Parameters[0].Type == ContractParameterType.Hash160 &&
onNEP11PaymentMethod.Parameters[1].Type == ContractParameterType.Integer &&
onNEP11PaymentMethod.Parameters[2].Type == ContractParameterType.Any;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parameter names should also be checked, they are a part of the standard. Take a look at https://github.com/nspcc-dev/neo-go/blob/319880e2014ebbe8abd8ce58dcf212869c22604b/pkg/smartcontract/manifest/standard/comply.go#L68.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be very strict, maybe we want to call to our token myTokenId, I think that names are not needed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@roman-khimov, what do you think?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking of transfer(to Hash160, from Hash160, amount Integer, id ByteString, _ Any) and Comply() preventing it.


if (!onNEP11PaymentValid) throw new CompilationException(DiagnosticId.IncorrectNEPStandard,
$"Incomplete NEP standard {NepStandard.Nep11Payable.ToStandard()} implementation: onNEP11Payment");
}
catch (Exception ex) when (ex is not CompilationException)
{
throw new CompilationException(DiagnosticId.IncorrectNEPStandard, $"Incomplete NEP standard {NepStandard.Nep11Payable.ToStandard()} implementation: Unidentified issue.");
}
}

private static void CheckNep17PayableCompliant(this ContractManifest manifest)
shargon marked this conversation as resolved.
Show resolved Hide resolved
{
try
{
var onNEP17PaymentMethod = manifest.Abi.GetMethod("onNEP17Payment", 3);
var onNEP17PaymentValid = onNEP17PaymentMethod is { Safe: false, ReturnType: ContractParameterType.Void } &&
onNEP17PaymentMethod.Parameters[0].Type == ContractParameterType.Hash160 &&
onNEP17PaymentMethod.Parameters[1].Type == ContractParameterType.Integer &&
onNEP17PaymentMethod.Parameters[2].Type == ContractParameterType.Any;

if (!onNEP17PaymentValid) throw new CompilationException(DiagnosticId.IncorrectNEPStandard,
$"Incomplete NEP standard {NepStandard.Nep17Payable.ToStandard()} implementation: onNEP17Payment");
}
catch (Exception ex) when (ex is not CompilationException)
{
throw new CompilationException(DiagnosticId.IncorrectNEPStandard, $"Incomplete NEP standard {NepStandard.Nep17Payable.ToStandard()} implementation: Unidentified issue.");
}
}

internal static ContractManifest CheckStandards(this ContractManifest manifest)
{
if (manifest.SupportedStandards.Contains(NepStandard.Nep11.ToStandard()))
Expand All @@ -175,6 +213,16 @@ internal static ContractManifest CheckStandards(this ContractManifest manifest)
manifest.CheckNep17Compliant();
}

if (manifest.SupportedStandards.Contains(NepStandard.Nep11Payable.ToStandard()))
{
manifest.CheckNep11PayableCompliant();
}

if (manifest.SupportedStandards.Contains(NepStandard.Nep17Payable.ToStandard()))
{
manifest.CheckNep17PayableCompliant();
}

return manifest;
}
}
Expand Down
20 changes: 19 additions & 1 deletion src/Neo.SmartContract.Framework/NEPStandard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,19 @@ public enum NepStandard
Nep11,
// The NEP-17 standard is used for fungible tokens.
// Defined at https://github.com/neo-project/proposals/blob/master/nep-17.mediawiki
Nep17
Nep17,
// Smart contract transfer callback for non-fungible tokens (NFTs).
// This is an extension standard of NEP-11.
// Defined at https://github.com/neo-project/proposals/pull/169/files#diff-2b5f7c12a23f7dbe4cb46bbf4be6936882f8e0f0b3a4db9d8c58eb294b02e6ed
Nep11_Y,
// This is the nick name of NEP-11-Y.
Nep11Payable,
Jim8y marked this conversation as resolved.
Show resolved Hide resolved
// Smart contract transfer callback for fungible tokens.
// This is an extension standard of NEP-17.
// Defined at https://github.com/neo-project/proposals/pull/169/files#diff-70768f307c9aa84f8c94e790495a76d47fffeca2331444592ebba6f13b1e6460
Nep17_Z,
// This is the nick name of NEP-17-Z.
Nep17Payable,
}

public static class NepStandardExtensions
Expand All @@ -20,6 +32,12 @@ public static string ToStandard(this NepStandard standard)
return "NEP-11";
case NepStandard.Nep17:
return "NEP-17";
case NepStandard.Nep11Payable:
case NepStandard.Nep11_Y:
return "NEP-11-Y";
shargon marked this conversation as resolved.
Show resolved Hide resolved
case NepStandard.Nep17Payable:
case NepStandard.Nep17_Z:
return "NEP-17-Z";
default:
return standard.ToString();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Neo.SmartContract.Framework.Attributes;
using System.ComponentModel;
using System.Numerics;
using Neo.SmartContract.Framework.Interfaces;

namespace Neo.SmartContract.Framework.TestContracts
{
[DisplayName(nameof(Contract_SupportedStandard11Payable))]
[ContractDescription("<Description Here>")]
[ContractAuthor("<Your Name Or Company Here>", "<Your Public Email Here>")]
[ContractVersion("<Version String Here>")]
[ContractPermission(Permission.WildCard, Method.WildCard)]
shargon marked this conversation as resolved.
Show resolved Hide resolved
[SupportedStandards(NepStandard.Nep11Payable)]
public class Contract_SupportedStandard11Payable : SmartContract, INep11Payable
{
public void OnNEP11Payment(UInt160 from, BigInteger amount, object? data = null)
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Neo.SmartContract.Framework.Attributes;
using System.ComponentModel;
using System.Numerics;
using Neo.SmartContract.Framework.Interfaces;

namespace Neo.SmartContract.Framework.TestContracts
{
[DisplayName(nameof(Contract_SupportedStandard17Payable))]
[ContractDescription("<Description Here>")]
[ContractAuthor("<Your Name Or Company Here>", "<Your Public Email Here>")]
[ContractVersion("<Version String Here>")]
[ContractPermission(Permission.WildCard, Method.WildCard)]
shargon marked this conversation as resolved.
Show resolved Hide resolved
[SupportedStandards(NepStandard.Nep17Payable)]
public class Contract_SupportedStandard17Payable : SmartContract, INep17Payable
{
public void OnNEP17Payment(UInt160 from, BigInteger amount, object? data = null)
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,17 @@ public void TestStandardNEP17AttributeEnum()
{
CollectionAssert.AreEqual(Contract_SupportedStandard17Enum.Manifest.SupportedStandards, new string[] { "NEP-17" });
}

[TestMethod]
public void TestStandardNEP11PayableAttribute()
{
CollectionAssert.AreEqual(Contract_SupportedStandard11Payable.Manifest.SupportedStandards, new string[] { "NEP-11-Y" });
}

[TestMethod]
public void TestStandardNEP17PayableAttribute()
{
CollectionAssert.AreEqual(Contract_SupportedStandard17Payable.Manifest.SupportedStandards, new string[] { "NEP-17-Z" });
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Neo.Cryptography.ECC;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Numerics;

namespace Neo.SmartContract.Testing;

public abstract class Contract_SupportedStandard11Payable : Neo.SmartContract.Testing.SmartContract
{
#region Compiled data

public static readonly Neo.SmartContract.Manifest.ContractManifest Manifest = Neo.SmartContract.Manifest.ContractManifest.Parse(@"{""name"":""Contract_SupportedStandard11Payable"",""groups"":[],""features"":{},""supportedstandards"":[""NEP-11-Y""],""abi"":{""methods"":[{""name"":""onNEP11Payment"",""parameters"":[{""name"":""from"",""type"":""Hash160""},{""name"":""amount"",""type"":""Integer""},{""name"":""data"",""type"":""Any""}],""returntype"":""Void"",""offset"":15,""safe"":false}],""events"":[]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""extra"":{""Description"":""\u003CDescription Here\u003E"",""Author"":""\u003CYour Name Or Company Here\u003E"",""Version"":""\u003CVersion String Here\u003E""}}");

public static readonly Neo.SmartContract.NefFile Nef = Neo.IO.Helper.AsSerializable<Neo.SmartContract.NefFile>(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVXAARAVwABeDQDQFcAAUDCSjTzIu3rbva0"));

#endregion

#region Unsafe methods

/// <summary>
/// Unsafe method
/// </summary>
[DisplayName("onNEP11Payment")]
public abstract void OnNEP11Payment(UInt160? from, BigInteger? amount, object? data = null);
shargon marked this conversation as resolved.
Show resolved Hide resolved

#endregion

#region Constructor for internal use only

protected Contract_SupportedStandard11Payable(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) { }

#endregion
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Neo.Cryptography.ECC;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Numerics;

namespace Neo.SmartContract.Testing;

public abstract class Contract_SupportedStandard17Payable : Neo.SmartContract.Testing.SmartContract
{
#region Compiled data

public static readonly Neo.SmartContract.Manifest.ContractManifest Manifest = Neo.SmartContract.Manifest.ContractManifest.Parse(@"{""name"":""Contract_SupportedStandard17Payable"",""groups"":[],""features"":{},""supportedstandards"":[""NEP-17-Z""],""abi"":{""methods"":[{""name"":""onNEP17Payment"",""parameters"":[{""name"":""from"",""type"":""Hash160""},{""name"":""amount"",""type"":""Integer""},{""name"":""data"",""type"":""Any""}],""returntype"":""Void"",""offset"":15,""safe"":false}],""events"":[]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""extra"":{""Description"":""\u003CDescription Here\u003E"",""Author"":""\u003CYour Name Or Company Here\u003E"",""Version"":""\u003CVersion String Here\u003E""}}");

public static readonly Neo.SmartContract.NefFile Nef = Neo.IO.Helper.AsSerializable<Neo.SmartContract.NefFile>(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVXAARAVwABeDQDQFcAAUDCSjTzIu3rbva0"));

#endregion

#region Unsafe methods

/// <summary>
/// Unsafe method
/// </summary>
[DisplayName("onNEP17Payment")]
public abstract void OnNEP17Payment(UInt160? from, BigInteger? amount, object? data = null);

#endregion

#region Constructor for internal use only

protected Contract_SupportedStandard17Payable(Neo.SmartContract.Testing.SmartContractInitialize initialize) : base(initialize) { }

#endregion
}
Loading