neo-project / proposals

NEO Enhancement Proposals
Creative Commons Attribution 4.0 International
136 stars 113 forks source link

[feature] Charity address generator #53

Closed vncoelho closed 5 years ago

vncoelho commented 6 years ago

Hi, everyone.

@Lerider commented about his idea to design a donation address, which would be able to send GAS but do not send Neo assets (claim would be a source of tokens for the charity and is, consequently, needed. Thus, send NEO to itself should be allowed).

The first idea (@igormcoelho) was to design something like this:

// NEP Charity Donations - Remote GAS Claim
using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Services.Neo;
using Neo.SmartContract.Framework.Services.System;
using System;

namespace Neo.SmartContract
{
    public class NepCharityDonation : Framework.SmartContract
    {
        private static readonly byte[] Owner = "AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y".ToScriptHash();
        private static readonly byte[] Charity = "APLJBPhtRg2XLhtpxEHd6aRNL7YSLGH2ZL".ToScriptHash();
        private static readonly byte[] NeoAssetId = { 155, 124, 255, 218, 166, 116, 190, 174, 15, 147, 14, 190, 96, 133, 175, 144, 147, 229, 254, 86, 179, 74, 92, 34, 12, 205, 207, 110, 252, 51, 111, 197 };
        private static readonly byte[] GasAssetId = { 231, 45, 40, 105, 121, 238, 108, 177, 183, 230, 93, 253, 223, 178, 227, 132, 16, 11, 141, 20, 142, 119, 88, 222, 66, 228, 22, 139, 113, 121, 44, 96 };

        // Verification Contract (no need for deploy)
        public static bool Main()
        {
            // Owner can manage all funds
            if(Runtime.CheckWitness(Owner))
               return true;
            // Verify if it's the Charity address   
            if(Runtime.CheckWitness(Charity))
            {
                // Get outputs
                Transaction tx = (Transaction)ExecutionEngine.ScriptContainer;
                TransactionOutput[] outputs = tx.GetOutputs();
                // Verify if this is a self transfer of NEO
                if((outputs.Length == 1) && (outputs[0].AssetId == NeoAssetId) && (outputs[0].ScriptHash == ExecutionEngine.ExecutingScriptHash))
                    return true;
                // Verifing if all outputs are GAS type
                foreach (TransactionOutput output in outputs)
                    if (output.AssetId != GasAssetId)
                        return false;
                return true;
            }

            return false;
        }
    }
}

However, we realized that we should use VerifySignature instead of Runtime.CheckWitness, which requires us to send signature as a parameter, right?

What do you recommend, @erikzhang ?

A1) VerifySignature would imply in an adjustment on the wallet for sending from this type of address. A2) We could design other type of contract that blocks sending to other addresses. But, perhaps, a password should be used for avoiding malicious transfer back to the OWNER (which would bother the charity address).

using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Services.Neo;
using Neo.SmartContract.Framework.Services.System;
using System;
using System.ComponentModel;
using System.Numerics;

namespace NeoContract1
{
    public class CharitySimpleExample : SmartContract
    {

        private static readonly byte[] neo_asset_id = { 155, 124, 255, 218, 166, 116, 190, 174, 15, 147, 14, 190, 96, 133, 175, 144, 147, 229, 254, 86, 179, 74, 92, 34, 12, 205, 207, 110, 252, 51, 111, 197 };
    private static readonly byte[] gas_asset_id = { 231, 45, 40, 105, 121, 238, 108, 177, 183, 230, 93, 253, 223, 178, 227, 132, 16, 11, 141, 20, 142, 119, 88, 222, 66, 228, 22, 139, 113, 121, 44, 96 };

    //The guy who donate the NEO for charity and can without anytime
    public static readonly byte[] Owner = "ATrzHaicmhRj15C3Vv6e6gLfLqhSD2PtTr".ToScriptHash();

    //This is the unic addres able to transfer the GAS
    public static readonly byte[] RegisteredClaimAddres = "ATrzHaicmhRj15C3Vv6e6gLfLqhSD2PtTr".ToScriptHash();

        public static object Main(string operation, params object[] args)
        {
            if (Runtime.Trigger == TriggerType.Verification)
            {

                if (operation == "ownerWithdrawn")
                {
                    // if param Owner is script hash
                    return Runtime.CheckWitness(Owner);
                }

               Transaction tx = (Transaction)ExecutionEngine.ScriptContainer;
               TransactionOutput[] outputs = tx.GetOutputs();
               TransactionInput[] inputs = tx.GetInputs();

               bool canWithdraw = true;
               foreach (TransactionOutput output in outputs)
               {
                    if (output.AssetId == gas_asset_id && output.ScriptHash != RegisteredClaimAddres)
                    {
                canWithdraw = false;
            }

                    if (output.AssetId == neo_asset_id && output.ScriptHash != Owner)
                    {
                canWithdraw = false;
            }
               } 

               return canWithdraw;
            }//finish trigger verification, the only one able to withdraw

            return false;         
        }

    }
}
erikzhang commented 6 years ago

Is this a proposal? It's not a dapp?

vncoelho commented 6 years ago

Hi, Erik. In fact, maybe it should be a standard. We would use this "dapp" for generating addresses, which, if used, should interact with light wallets. In this verification only dapp:

erikzhang commented 6 years ago

I think this could be a template, not a standard.

vncoelho commented 6 years ago

Yes, a template. You are right.

We just worry, a little bit, if the Wallet Clients would know how to handle such contracts. For a better user experience, if it is a kind of standard, the invocation could be a "native" call of from wallets.

erikzhang commented 6 years ago

Wallets can handle it with its ABI. See https://github.com/neo-project/proposals/blob/master/nep-3.mediawiki

vncoelho commented 6 years ago

Precise as a :dagger:

The ABI template is useful and well-described, the C# ABI info is used at https://neocompiler.io/#/ecolab Unfortunately, perhaps, the only language that supports it. We already tried to motivate other developers to include it in their projects. But now we will keep recommending them to follow NEP-3.

A template + its standard generated ABI should be enough. For this contract, it would be kind of empty (also because it is very simple template):

ScriptHash (reversed): 0x6498ad39351b4363bf3f8c22def9f338462200bd
Entry Point:Main
Functions:
    Any Main(String passwordForClaimingAllNeoBackToOwner_OneTimeCall_Then_Discarded);
Events:

It needs to be split in some additional functions, which would help comprehension.

igormcoelho commented 6 years ago

@vncoelho I think we can do that as a regular wallet as @erikzhang mentioned (using some OpCode magic tricks):

// NEP Charity Donations - Remote GAS Claim
using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Services.Neo;
using Neo.SmartContract.Framework.Services.System;
using System;
using Neo.VM;

namespace Neo.SmartContract
{
    public class NepCharityDonation : Framework.SmartContract
    {
        [OpCode(OpCode.CHECKSIG)]
        protected extern static bool VerifySignature2(byte[] pubkey);

        [OpCode(OpCode.DUP)]
        protected extern static void Duplicate();

        [OpCode(OpCode.DROP)]
        protected extern static void Drop();

        //private static readonly byte[] OwnerSH = "AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y".ToScriptHash();
        //private static readonly byte[] CharitySH = "APLJBPhtRg2XLhtpxEHd6aRNL7YSLGH2ZL".ToScriptHash();
        public static readonly byte[] Owner = "031a6c6fbbdf02ca351745fa86b9ba5a9452d785ac4f7fc2b7548ca2a46c4fcf4a".HexToBytes();
        public static readonly byte[] Charity = "036245f426b4522e8a2901be6ccc1f71e37dc376726cc6665d80c5997e240568fb".HexToBytes();

        private static readonly byte[] NeoAssetId = { 155, 124, 255, 218, 166, 116, 190, 174, 15, 147, 14, 190, 96, 133, 175, 144, 147, 229, 254, 86, 179, 74, 92, 34, 12, 205, 207, 110, 252, 51, 111, 197 };
        private static readonly byte[] GasAssetId = { 231, 45, 40, 105, 121, 238, 108, 177, 183, 230, 93, 253, 223, 178, 227, 132, 16, 11, 141, 20, 142, 119, 88, 222, 66, 228, 22, 139, 113, 121, 44, 96 };

        // Verification Contract (no need for deploy)
        public static bool Main()
        {
            if (Runtime.Trigger != TriggerType.Verification) // see NEP-7 final situation
                throw new Exception();

            Duplicate(); // duplicate signature on main stack

            // Owner can manage all funds
            //if(Runtime.CheckWitness(Owner))
            if(VerifySignature2(Owner)) {
                Drop(); // eliminate second signature from main stack
                return true;
            }

            // Verify if it's the Charity address   
            //if(Runtime.CheckWitness(Charity))
            if(VerifySignature2(Charity)) {
                // Get outputs
                Transaction tx = (Transaction)ExecutionEngine.ScriptContainer;
                TransactionOutput[] outputs = tx.GetOutputs();
                // Verify if this is a self transfer of NEO
                if((outputs.Length == 1) && (outputs[0].AssetId == NeoAssetId) && (outputs[0].ScriptHash == ExecutionEngine.ExecutingScriptHash))
                    return true;
                // Verifing if all outputs are GAS type
                foreach (TransactionOutput output in outputs)
                    if (output.AssetId != GasAssetId)
                        return false;
                return true;
            }

            return false;
        }
    }
}
igormcoelho commented 6 years ago

@vncoelho @lerider Finally, this example is working under SMACCO logic: https://github.com/neoresearch/smacco (https://neoresearch.io/smacco-demo)

{
  "standard": "smacco-1.0",
  "input_type" : "single",
  "pubkey_list" : ["031a6c6fbbdf02ca351745fa86b9ba5a9452d785ac4f7fc2b7548ca2a46c4fcf4a", "036245f426b4522e8a2901be6ccc1f71e37dc376726cc6665d80c5997e240568fb"],
  "rules" : [
    {
      "rule_type": "ALLOW_IF",
      "condition" : {
        "condition_type" : "CHECKSIG",
        "pubkey" : "0"
      },
    },
    {
      "rule_type": "ALLOW_IF",
      "condition" : {
        "condition_type" : "AND",
        "conditions" : [
          {
            "condition_type" : "CHECKSIG",
            "pubkey" : "1"
          },
          {
            "condition_type" : "OR",
            "conditions" : [
              {
                "condition_type" : "AND",
                "conditions" : [
                  {
                    "condition_type" : "SELF_TRANSFER"
                  },
                  {
                    "condition_type" : "ONLY_NEO"
                  }
                ]
              },
              {
                "condition_type" : "ONLY_GAS"
              }
            ]
          },
        ]
      },
    },
  ],
  "default_rule" : "DENY_ALL"
}

It can also be compiled and generate Address online at: https://neoresearch.io/smacco-demo

vncoelho commented 6 years ago

Incredible, brother. You did this like a Leopard. Impressive. This deserve a nice tutorial.

Lets include this in our course for the 4th quarter of 2018

igormcoelho commented 6 years ago

It generates C# and flowchart automatically now ;) Classic timelock (https://neoresearch.io/smacco):

image

vncoelho commented 6 years ago

This issue was reopened due to the great effort and work done for reaching this impressive Smart Account Composer. As soon as we finish the report we can close it again :dagger: Thanks for this great insight, as well as the fast and precise work, Aiiigor.

igormcoelho commented 6 years ago

neo-smacco project is freely available at: https://neoresearch.io/smacco

Perhaps we can propose a NEP to replace smacco specification Vitor... then community may contribute with features that could be useful on most smart accounts. We already have timelock, multisig, asset limits, but we can think of many more. It would be nice to replace "standard": "smacco-1.0", with something more meaninful to the community, such as "standard": "NEP-1X", (perhaps together with Smart Transactions proposal? https://github.com/neo-project/proposals/pull/67)

vncoelho commented 6 years ago

Perfect, Igor. Coming back to Brazil tomorrow, let's work on it! I do not like to use "very", but, It is surely a very very important feature for putting Neo competitive with other Blockchains.

vncoelho commented 5 years ago

Time to close this...aheuiaheuaea SMACCO was a great tool and idea,@igormcoelho.

I still believe we should evolve the language and the tool further in a near future.

shargon commented 5 years ago

If we make verification turing incomplete, this never could be done

vncoelho commented 5 years ago

No @shargon, it can be done, this was a template for UTXOs complex operation. Now with native NEO and GAS it will be even easier.