GithubHelp home page GithubHelp logo

Comments (10)

saltyskip avatar saltyskip commented on July 18, 2024 1
ScriptHash (big endian): 0x746d6cc63dacd7b275bb3a3a06d54859661591a6
Entry Point:Main
Functions:
	String Name();
	String Symbol();
	Integer Decimals();
	ByteArray Main(String operation, Array args);
	Boolean Deploy();
	Boolean MintTokens();
	Integer TotalSupply();
	Boolean Transfer(ByteArray from, ByteArray to, Integer value);
	Integer BalanceOf(ByteArray address);
Events:
	Void transfer(ByteArray arg1, ByteArray arg2, Integer arg3);
	Void refund(ByteArray arg1, Integer arg2);

Here is an example of ABI output from NEO C# compiler for an ICO template

@ixje CityOfZion/neo-python#908

from neo-boa.

localhuman avatar localhuman commented on July 18, 2024

I think its a good idea! Probably related to this new functionality here: #31

from neo-boa.

igormcoelho avatar igormcoelho commented on July 18, 2024

It would be nice to have some advances here... although I don't think it's easy to do :)

from neo-boa.

ixje avatar ixje commented on July 18, 2024

I'm guessing the biggest hurdle is going to be supporting type hints. @saltyskip can you also link the C# template that matches this ABI output?

from neo-boa.

saltyskip avatar saltyskip commented on July 18, 2024
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 Neo.SmartContract
{
    public class ICO_Template : Framework.SmartContract
    {
        //Token Settings
        public static string Name() => "name of the token";
        public static string Symbol() => "SymbolOfTheToken";
        public static readonly byte[] Owner = "AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y".ToScriptHash();
        public static byte Decimals() => 8;
        private const ulong factor = 100000000; //decided by Decimals()
        private const ulong neo_decimals = 100000000;

        //ICO Settings
        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 const ulong total_amount = 100000000 * factor; // total token amount
        private const ulong pre_ico_cap = 30000000 * factor; // pre ico token amount
        private const ulong basic_rate = 1000 * factor;
        private const int ico_start_time = 1506787200;
        private const int ico_end_time = 1538323200;

        [DisplayName("transfer")]
        public static event Action<byte[], byte[], BigInteger> Transferred;

        [DisplayName("refund")]
        public static event Action<byte[], BigInteger> Refund;

        public static Object Main(string operation, params object[] args)
        {
            if (Runtime.Trigger == TriggerType.Verification)
            {
                if (Owner.Length == 20)
                {
                    // if param Owner is script hash
                    return Runtime.CheckWitness(Owner);
                }
                else if (Owner.Length == 33)
                {
                    // if param Owner is public key
                    byte[] signature = operation.AsByteArray();
                    return VerifySignature(signature, Owner);
                }
            }
            else if (Runtime.Trigger == TriggerType.Application)
            {
                if (operation == "deploy") return Deploy();
                if (operation == "mintTokens") return MintTokens();
                if (operation == "totalSupply") return TotalSupply();
                if (operation == "name") return Name();
                if (operation == "symbol") return Symbol();
                if (operation == "transfer")
                {
                    if (args.Length != 3) return false;
                    byte[] from = (byte[])args[0];
                    byte[] to = (byte[])args[1];
                    BigInteger value = (BigInteger)args[2];
                    return Transfer(from, to, value);
                }
                if (operation == "balanceOf")
                {
                    if (args.Length != 1) return 0;
                    byte[] account = (byte[])args[0];
                    return BalanceOf(account);
                }
                if (operation == "decimals") return Decimals();
            }
            //you can choice refund or not refund
            byte[] sender = GetSender();
            ulong contribute_value = GetContributeValue();
            if (contribute_value > 0 && sender.Length != 0)
            {
                Refund(sender, contribute_value);
            }
            return false;
        }

        // initialization parameters, only once
        // 初始化参数
        public static bool Deploy()
        {
            byte[] total_supply = Storage.Get(Storage.CurrentContext, "totalSupply");
            if (total_supply.Length != 0) return false;
            Storage.Put(Storage.CurrentContext, Owner, pre_ico_cap);
            Storage.Put(Storage.CurrentContext, "totalSupply", pre_ico_cap);
            Transferred(null, Owner, pre_ico_cap);
            return true;
        }

        // The function MintTokens is only usable by the chosen wallet
        // contract to mint a number of tokens proportional to the
        // amount of neo sent to the wallet contract. The function
        // can only be called during the tokenswap period
        // 将众筹的neo转化为等价的ico代币
        public static bool MintTokens()
        {
            byte[] sender = GetSender();
            // contribute asset is not neo
            if (sender.Length == 0)
            {
                return false;
            }
            ulong contribute_value = GetContributeValue();
            // the current exchange rate between ico tokens and neo during the token swap period
            // 获取众筹期间ico token和neo间的转化率
            ulong swap_rate = CurrentSwapRate();
            // crowdfunding failure
            // 众筹失败
            if (swap_rate == 0)
            {
                Refund(sender, contribute_value);
                return false;
            }
            // you can get current swap token amount
            ulong token = CurrentSwapToken(sender, contribute_value, swap_rate);
            if (token == 0)
            {
                return false;
            }
            // crowdfunding success
            // 众筹成功
            BigInteger balance = Storage.Get(Storage.CurrentContext, sender).AsBigInteger();
            Storage.Put(Storage.CurrentContext, sender, token + balance);
            BigInteger totalSupply = Storage.Get(Storage.CurrentContext, "totalSupply").AsBigInteger();
            Storage.Put(Storage.CurrentContext, "totalSupply", token + totalSupply);
            Transferred(null, sender, token);
            return true;
        }

        // get the total token supply
        // 获取已发行token总量
        public static BigInteger TotalSupply()
        {
            return Storage.Get(Storage.CurrentContext, "totalSupply").AsBigInteger();
        }

        // function that is always called when someone wants to transfer tokens.
        // 流转token调用
        public static bool Transfer(byte[] from, byte[] to, BigInteger value)
        {
            if (value <= 0) return false;
            if (!Runtime.CheckWitness(from)) return false;
            if (to.Length != 20) return false;

            BigInteger from_value = Storage.Get(Storage.CurrentContext, from).AsBigInteger();
            if (from_value < value) return false;
            if (from == to) return true;
            if (from_value == value)
                Storage.Delete(Storage.CurrentContext, from);
            else
                Storage.Put(Storage.CurrentContext, from, from_value - value);
            BigInteger to_value = Storage.Get(Storage.CurrentContext, to).AsBigInteger();
            Storage.Put(Storage.CurrentContext, to, to_value + value);
            Transferred(from, to, value);
            return true;
        }

        // get the account balance of another account with address
        // 根据地址获取token的余额
        public static BigInteger BalanceOf(byte[] address)
        {
            return Storage.Get(Storage.CurrentContext, address).AsBigInteger();
        }

        // The function CurrentSwapRate() returns the current exchange rate
        // between ico tokens and neo during the token swap period
        private static ulong CurrentSwapRate()
        {
            const int ico_duration = ico_end_time - ico_start_time;
            uint now = Runtime.Time;
            int time = (int)now - ico_start_time;
            if (time < 0)
            {
                return 0;
            }
            else if (time < ico_duration)
            {
                return basic_rate;
            }
            else
            {
                return 0;
            }
        }

        //whether over contribute capacity, you can get the token amount
        private static ulong CurrentSwapToken(byte[] sender, ulong value, ulong swap_rate)
        {
            ulong token = value / neo_decimals * swap_rate;
            BigInteger total_supply = Storage.Get(Storage.CurrentContext, "totalSupply").AsBigInteger();
            BigInteger balance_token = total_amount - total_supply;
            if (balance_token <= 0)
            {
                Refund(sender, value);
                return 0;
            }
            else if (balance_token < token)
            {
                Refund(sender, (token - balance_token) / swap_rate * neo_decimals);
                token = (ulong)balance_token;
            }
            return token;
        }

        // check whether asset is neo and get sender script hash
        private static byte[] GetSender()
        {
            Transaction tx = (Transaction)ExecutionEngine.ScriptContainer;
            TransactionOutput[] reference = tx.GetReferences();
            // you can choice refund or not refund
            foreach (TransactionOutput output in reference)
            {
                if (output.AssetId == neo_asset_id) return output.ScriptHash;
            }
            return new byte[]{};
        }

        // get smart contract script hash
        private static byte[] GetReceiver()
        {
            return ExecutionEngine.ExecutingScriptHash;
        }

        // get all you contribute neo amount
        private static ulong GetContributeValue()
        {
            Transaction tx = (Transaction)ExecutionEngine.ScriptContainer;
            TransactionOutput[] outputs = tx.GetOutputs();
            ulong value = 0;
            // get the total amount of Neo
            // 获取转入智能合约地址的Neo总量
            foreach (TransactionOutput output in outputs)
            {
                if (output.ScriptHash == GetReceiver() && output.AssetId == neo_asset_id)
                {
                    value += (ulong)output.Value;
                }
            }
            return value;
        }
    }
}

from neo-boa.

saltyskip avatar saltyskip commented on July 18, 2024

Apologies for the direct code post, It is the template on neocompilereco, and I could not find where it is actually hosted 😅

from neo-boa.

ixje avatar ixje commented on July 18, 2024

Is it me or is the ABI output missing an entry for

 public static readonly byte[] Owner = "AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y".ToScriptHash();

as it looks to output all public accessors.

Perhaps I'm a bit skeptical, but is this ABI output not kind of useless without knowing a mapping of "operation name => function"? e.g. the operation "deploy" maps to Boolean Deploy();.

It also seems to force you into using a fixed Main signature and implementation structure of

public static Object Main(string operation, params object[] args)
   if (operation == 'name') return Name()

which is severely limited due to the 16 objects max array length of args. Any thoughts?
Or are there perhaps plans to move to an "Ethereum model" where you can call the public functions directly? Then the ABI actually makes sense.

from neo-boa.

ixje avatar ixje commented on July 18, 2024

I just noticed that the sample ABI doesn't follow NEP3

sample ABI:

Events:
	Void transfer(ByteArray arg1, ByteArray arg2, Integer arg3);

NEP3 suggestion

{
	"hash": "0x746d6cc63dacd7b275bb3a3a06d54859661591a6",
	"entrypoint": "main",
	"functions": [],
	"events": [
		{
			"name": "refund",
			"parameters": [
				{
					"name": "arg1"
					"type": "ByteArray"
				},
				{
					"name": "arg2"
					"type": "ByteArray"
				},
						{
					"name": "arg3"
					"type": "Integer"
				},
			]
		}
	]
}

I believe we need more alignment before this can be considered.

from neo-boa.

saltyskip avatar saltyskip commented on July 18, 2024

I think that is correct because it only outputs functions not publicly accessible static variables. Although that would be a nice addition.

@igormcoelho do you do any custom formatting on neocompiler eco?

from neo-boa.

hal0x2328 avatar hal0x2328 commented on July 18, 2024

@igormcoelho do you do any custom formatting on neocompiler eco?

From my testing it looks like NeoCompiler Eco takes the ABI output from the neon compiler with all the function names, then assumes that the operation name will be the same name (only in camelCase) when it comes time to choose one to invoke.

Of course, there's no guideline for function vs operation naming in NEP-3 so a lot of contract authors are going to name their operations one thing and their corresponding functions another, and their generated ABI will be fairly useless to NeoCompiler Eco or other tools that parse the ABI.

For neo-boa, I like the idea of using Pythonic type hints and building the ABI based on any function or event definition that contains hints, using the name of the function verbatim as the operation name.

Then, we need to amend NEP-3 with guidance to require any operation that is meant to be included in the ABI have a function name with its exact match.

Given the top-down-from-Main invocation pattern built in to the Neo VM I don't see a perfect way to solve the problem without requiring some diligence on the part of contract authors, but at least this way it will at least be easy enough for contract authors to implement after some light reading.

Edit: I see Erik had replied in the NEP-3 PR to the issue of function names and case with the following:

C# methods starts with upper case.

While you can certainly write a valid C# function name that starts with lower-case, it is technically part of the C# convention to use PascalCase for everything except parameter names. So I doubt he'll want to amend NEP-3 to suggest making a C# contract use bool transferFrom( instead of bool TransferFrom

However the C# compiler could be modified to automatically switch the ABI function names to camelCase instead of relying on the parser to do so, at least this way the different compilers could be made to be consistent in their ABI output if nothing else.

from neo-boa.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.