发行NEO的NEP-5合约代币

NEO常见的资产有三种

  1. TOKEN (全局资产)
  2. Share (全局资产,股份 )
  3. NEP-5 (合约代币,相当于ETH的ERC20)
NEP-5 合约代码

https://github.com/ANDIT-Solutions/NEO-NEP5.1

这里发行Name为Five的代币,代币Symbol为FFF. 共发行1000000000个单位。

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

namespace Neo.SmartContract
{
    public class ICO_Template : Framework.SmartContract
    {

        //Token Settings
        public static string Name() => "Five";
        public static string Symbol() => "FFF";
        public static readonly byte[] Owner = "AdNjgXiDU1imfKoCSQcgcd4HmBSn2qsHfe".ToScriptHash();//translates 
        //to: 0x20f0a44d41c659a49651823ac19794dda45bd4d9., it's the ScriptHash of your public address ,you can view it in neo-gui(for example)
        public static byte Decimals() => 8;
        private const ulong factor = 100000000; //decided by Decimals()
        //Since we don't want to deal with floating points sending 555 tokens with 8 Decimals (100000000) 
        //would actually mean that you want to  send 55500000000 tokens.
        private const ulong total_amount = 1000000000 * factor; //token amount

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


        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 == "totalSupply") return TotalSupply();
                if (operation == "name") return Name();
                if (operation == "symbol") return Symbol();
                if (operation == "decimals") return Decimals();
                if (operation == "approve") if (args.Length >= 3) return Approve((byte[])args[0], (byte[])args[1], (BigInteger)args[2]); else return NotifyErrorAndReturn0("argument count must be atleast 3");
                if (operation == "allowance") if (args.Length >= 2) return Allowance((byte[])args[0], (byte[])args[1]); else return NotifyErrorAndReturn0("argument count must be atleast 2");
                if (operation == "transferFrom") if (args.Length >= 4) return TransferFrom((byte[])args[0], (byte[])args[1], (byte[])args[2], (BigInteger)args[3]); else return NotifyErrorAndReturn0("argument count must be atleast 4");
                if (operation == "transfer")
                {
                    if (args.Length != 3 || args[0] == null || ((byte[])args[0]).Length == 0 || args[1] == null || ((byte[])args[1]).Length == 0) return NotifyErrorAndReturnFalse("argument count must be 3 and they must not be null");
                    byte[] from = (byte[])args[0];
                    byte[] to = (byte[])args[1];
                    BigInteger value = (BigInteger)args[2];
                    return Transfer(from, to, value, false);
                }
                if (operation == "balanceOf")
                {
                    if (args.Length != 1 || args[0] == null || ((byte[])args[0]).Length == 0) return NotifyErrorAndReturn0("argument count must be 1 and they must not be null");
                    byte[] account = (byte[])args[0];
                    return BalanceOf(account);
                }
            }
            return NotifyErrorAndReturnFalse("Operation not found");
        }

        /// <summary>
        /// Can only be called by the Owner
        /// Puts total_amount value under "totalSupply" key and ,this function can be used only once ,unless the total amount is 0.
        /// </summary>
        /// <returns></returns>
        public static bool Deploy()
        {
            if (!Runtime.CheckWitness(Owner)) //ensure that it is the owner calling this method
                return NotifyErrorAndReturnFalse("You are not the Owner of this Smart Contract");

            byte[] total_supply = Storage.Get(Storage.CurrentContext, "totalSupply");

            if (total_supply.Length != 0)
                return NotifyErrorAndReturnFalse("Looks like this method has been allready used");

            Storage.Put(Storage.CurrentContext, Owner, total_amount);
            Storage.Put(Storage.CurrentContext, "totalSupply", total_amount);
            Transferred(null, Owner, total_amount);
            return true;
        }
        /// <summary>
        /// Returns the Total Supply of Tokens
        /// </summary>
        /// <returns></returns>
        public static BigInteger TotalSupply()
        {
            return Storage.Get(Storage.CurrentContext, "totalSupply").AsBigInteger();
        }
        /// <summary>
        ///   Checks the TransferFrom approval of two accounts.
        /// </summary>
        /// <param name="from">
        ///   The account which funds can be transfered from.
        /// </param>
        /// <param name="to">
        ///   The account which is granted usage of the account.
        /// </param>
        /// <returns>
        ///   The amount allocated for TransferFrom.
        /// </returns>
        public static BigInteger Allowance(byte[] from, byte[] to)
        {
            if (from == null || from.Length != 20)
                return NotifyErrorAndReturn0("From value must not be empty and have size of 20");

            if (to == null || to.Length != 20)
                return NotifyErrorAndReturn0("To value must not be empty and have size of 20");

            return Storage.Get(Storage.CurrentContext, from.Concat(to)).AsBigInteger();
        }
        /// <summary>
        ///   Approves another user to use the TransferFrom
        ///   function on the invoker's account.
        ///   TransferFrom 
        /// </summary>
        /// <param name="originator">
        ///   The contract invoker.
        /// </param>
        /// <param name="to">
        ///   The account to grant TransferFrom access to.
        ///   所批准的账户
        /// </param>
        /// <param name="amount">
        ///   The amount to grant TransferFrom access for.
        /// </param>
        /// <returns>
        ///   Transaction Successful?
        /// </returns>
        public static bool Approve(byte[] originator, byte[] to, BigInteger amount)
        {
            if (to == null || to.Length != 20)
                return NotifyErrorAndReturnFalse("To value must not be empty and have size of 20");

            if (originator == null || originator.Length != 20)
                return NotifyErrorAndReturnFalse("Originator value must not be empty and have size of 20");

            if (amount < 0)
                return NotifyErrorAndReturnFalse("Amount is lower than zero");

            if (!(Runtime.CheckWitness(originator)))
                return NotifyErrorAndReturnFalse("Originator isn't associated with this invoke");


            Storage.Put(Storage.CurrentContext, originator.Concat(to), amount);
            return true;

        }
        /// <summary>
        ///   Transfers a balance from one account to another
        ///   on behalf of the account owner.
        /// </summary>
        /// <param name="originator">
        ///   The contract invoker.
        /// </param>
        /// <param name="from">
        ///   The account to transfer a balance from.
        /// </param>
        /// <param name="to">
        ///   The account to transfer a balance to.
        /// </param>
        /// <param name="amount">
        ///   The amount to transfer.
        /// </param>
        /// <returns>
        ///   Transaction successful?
        /// </returns>
        public static bool TransferFrom(byte[] originator, byte[] from, byte[] to, BigInteger amountToSend)
        {

            if (originator == null || originator.Length != 20)
                return NotifyErrorAndReturnFalse("Originator value must not be empty and have size of 20");
            if (from == null || from.Length != 20)
                return NotifyErrorAndReturnFalse("From value must not be empty and have size of 20");
            if (to == null || to.Length != 20)
                return NotifyErrorAndReturnFalse("To value must not be empty and have size of 20");

            if (!(Runtime.CheckWitness(originator)))
                return NotifyErrorAndReturnFalse("Originator isn't associated with this invoke");

            if (amountToSend <= 0)
                return NotifyErrorAndReturnFalse("You need to send more than 0 tokens");

            BigInteger ownerAmount = BalanceOf(from);

            if (ownerAmount < amountToSend)
                return NotifyErrorAndReturnFalse("Owner doesn't have this kind amount of tokens");

            if (ownerAmount <= 0)
                return NotifyErrorAndReturnFalse("Owner doesn't have positive balance");

            BigInteger allowedAmount = Allowance(from, originator);

            if (allowedAmount < amountToSend)
                return NotifyErrorAndReturnFalse("You are trying to send more than you are allowed to");

            if (!(Transfer(from, to, amountToSend, true)))//This does the actual transfer.
                return NotifyErrorAndReturnFalse("Failed to Transfer");



            BigInteger amountLeft = allowedAmount - amountToSend;
            if (amountLeft <= 0)//There should not be an situation where someone holds an negative ballance ,but for safety sake I did add this.
            {
                Storage.Delete(Storage.CurrentContext, from.Concat(originator));
            }
            else
            {
                Storage.Put(Storage.CurrentContext, from.Concat(originator), amountLeft);
            }
            return true;
        }
        /// <summary>
        /// function that is always called when someone wants to transfer tokens.
        /// </summary>
        /// <param name="from"></param>
        /// wallet from which we send the tokens.
        /// <param name="to"></param>
        /// wallet to which we send the tokens.
        /// <param name="value"></param>
        /// amount that we will send
        /// <param name="transferFrom"></param>
        /// Checks if the function is called from TransferFrom methods ,if so then there is no need to Check Witness.
        /// <returns>
        /// Returns if the tranfer process has succeded or not.
        /// </returns>
        public static bool Transfer(byte[] from, byte[] to, BigInteger value, bool transferFrom)
        {
            if (to == null || to.Length != 20)
                return NotifyErrorAndReturnFalse("To value must not be empty and have size of 20");

            if (from == null || from.Length != 20)
                return NotifyErrorAndReturnFalse("From value must not be empty and have size of 20");

            if (value <= 0) return NotifyErrorAndReturnFalse("Try to send more than 0 tokens");
            if (!transferFrom && !Runtime.CheckWitness(from)) return NotifyErrorAndReturnFalse("Owner of the wallet is not involved in this invoke");
            if (from == to) return true;
            BigInteger from_value = Storage.Get(Storage.CurrentContext, from).AsBigInteger();
            if (from_value < value) return NotifyErrorAndReturnFalse("Insufficient funds");
            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;
        }
        /// <summary>
        /// Get the account balance of another account with address,uses wallets address scripthash.
        /// </summary>
        /// <param name="address"></param>
        /// The Adress that we want to know blance of
        /// <returns>
        /// Amount of tokens associated with this address
        /// </returns>
        public static BigInteger BalanceOf(byte[] address)
        {
            return Storage.Get(Storage.CurrentContext, address).AsBigInteger();
        }
        /// <summary>
        /// Used when we want to Notify Error for debbuging and return false
        /// </summary>
        /// <param name="value"></param>
        /// String that will be notified
        /// <returns>
        /// Allways False
        /// </returns>
        public static bool NotifyErrorAndReturnFalse(string value)
        {
            Runtime.Notify(value);
            return false;
        }
        /// <summary>
        /// Used when we want to Notify Error for debbuging and return 0
        /// </summary>
        /// <param name="value"></param>
        /// String that will be notified
        /// <returns>
        /// Allways 0
        /// </returns>
        public static int NotifyErrorAndReturn0(string value)
        {
            Runtime.Notify(value);
            return 0;
        }
    }
}
需要定义的参数:

参数说明:
  • Owner 合约部署后,代币所有者
  • factor 小数位数,Decimal
  • total_amount 总发行量
  • Name 合约名称
  • Sympol 代币名称
编译部署

把C#代码放到https://neocompiler.io/#/ecolab,线上编译即可

下载AVM的16进制格式编码和Script hash:

hex code:

54c56b6c766b00527ac46c766b51527ac46168164e656f2e52756e74696d652e47657454726967676572639a006114ecf28d2236dab6c09da8352821780215e890d7cfc00114907c907c9e6339006114ecf28d2236dab6c09da8352821780215e890d7cf6168184e656f2e52756e74696d652e436865636b5769746e657373616c75666114ecf28d2236dab6c09da8352821780215e890d7cfc00121907c907c9e6357036c766b00c36114ecf28d2236dab6c09da8352821780215e890d7cfac616c75666168164e656f2e52756e74696d652e4765745472696767657260907c907c9e6315036c766b00c3066465706c6f7987640b0061653c03616c75666c766b00c30b746f74616c537570706c7987640b006165d304616c75666c766b00c3046e616d6587640b006165ea02616c75666c766b00c30673796d626f6c87640b006165de02616c75666c766b00c308646563696d616c7387640b006165cf02616c75666c766b00c307617070726f7665876456006c766b51c3c0539f6322006c766b51c300c36c766b51c351c36c766b51c352c3615272657305616c756620617267756d656e7420636f756e74206d7573742062652061746c65617374203361658a0d616c75666c766b00c309616c6c6f77616e636587644e006c766b51c3c0529f631a006c766b51c300c36c766b51c351c3617c653104616c756620617267756d656e7420636f756e74206d7573742062652061746c65617374203261652c0d616c75666c766b00c30c7472616e7366657246726f6d87646f006c766b51c3c0549f633b006c766b51c300c36c766b51c351c36c766b51c352c36c766b51c353c3615379517955727551727552795279547275527275650f06616c756620617267756d656e7420636f756e74206d7573742062652061746c6561737420346165aa0c616c75666c766b00c3087472616e736665728764c1006c766b51c3c053907c907c9e632d006c766b51c300c36423006c766b51c300c3c06418006c766b51c351c3640e006c766b51c351c3c0633e0032617267756d656e7420636f756e74206d757374206265203320616e642074686579206d757374206e6f74206265206e756c6c6165f60b616c75666c766b51c300c36c766b51c351c36c766b52527ac46c766b51c352c36c766b53527ac46c766b52c36c766b53c300615379517955727551727552795279547275527275657908616c75666c766b00c30962616c616e63654f66876471006c766b51c3c051907c907c9e6318006c766b51c300c3640e006c766b51c300c3c0633e0032617267756d656e7420636f756e74206d757374206265203120616e642074686579206d757374206e6f74206265206e756c6c6165680b616c75666c766b51c300c36165ec0a616c7566134f7065726174696f6e206e6f7420666f756e6461650f0b616c756600c56b0446697665616c756600c56b03464646616c756600c56b58616c756600c56b6114ecf28d2236dab6c09da8352821780215e890d7cf6168184e656f2e52756e74696d652e436865636b5769746e6573736338002c596f7520617265206e6f7420746865204f776e6572206f66207468697320536d61727420436f6e74726163746165840a616c75666168164e656f2e53746f726167652e476574436f6e746578740b746f74616c537570706c79617c680f4e656f2e53746f726167652e476574c06439002d4c6f6f6b73206c696b652074686973206d6574686f6420686173206265656e20616c6c726561647920757365646165120a616c75666168164e656f2e53746f726167652e476574436f6e746578746114ecf28d2236dab6c09da8352821780215e890d7cf0800008a5d78456301615272680f4e656f2e53746f726167652e5075746168164e656f2e53746f726167652e476574436f6e746578740b746f74616c537570706c790800008a5d78456301615272680f4e656f2e53746f726167652e50757461006114ecf28d2236dab6c09da8352821780215e890d7cf0800008a5d78456301615272087472616e7366657254c168124e656f2e52756e74696d652e4e6f7469667951616c756600c56b6168164e656f2e53746f726167652e476574436f6e746578740b746f74616c537570706c79617c680f4e656f2e53746f726167652e476574616c756652c56b6c766b00527ac46c766b51527ac46c766b00c3640f006c766b00c3c001149c633c003046726f6d2076616c7565206d757374206e6f7420626520656d70747920616e6420686176652073697a65206f662032306165cd08616c75666c766b51c3640f006c766b51c3c001149c633a002e546f2076616c7565206d757374206e6f7420626520656d70747920616e6420686176652073697a65206f6620323061658208616c75666168164e656f2e53746f726167652e476574436f6e746578746c766b00c36c766b51c37e617c680f4e656f2e53746f726167652e476574616c756653c56b6c766b00527ac46c766b51527ac46c766b52527ac46c766b51c3640f006c766b51c3c001149c633a002e546f2076616c7565206d757374206e6f7420626520656d70747920616e6420686176652073697a65206f662032306165b607616c75666c766b00c3640f006c766b00c3c001149c634200364f726967696e61746f722076616c7565206d757374206e6f7420626520656d70747920616e6420686176652073697a65206f6620323061656307616c75666c766b52c3009f64250019416d6f756e74206973206c6f776572207468616e207a65726f61653707616c75666c766b00c36168184e656f2e52756e74696d652e436865636b5769746e6573736338002c4f726967696e61746f722069736e2774206173736f6369617465642077697468207468697320696e766f6b656165df06616c75666168164e656f2e53746f726167652e476574436f6e746578746c766b00c36c766b51c37e6c766b52c3615272680f4e656f2e53746f726167652e50757451616c756657c56b6c766b00527ac46c766b51527ac46c766b52527ac46c766b53527ac46c766b00c3640f006c766b00c3c001149c634200364f726967696e61746f722076616c7565206d757374206e6f7420626520656d70747920616e6420686176652073697a65206f6620323061652b06616c75666c766b51c3640f006c766b51c3c001149c633c003046726f6d2076616c7565206d757374206e6f7420626520656d70747920616e6420686176652073697a65206f662032306165de05616c75666c766b52c3640f006c766b52c3c001149c633a002e546f2076616c7565206d757374206e6f7420626520656d70747920616e6420686176652073697a65206f6620323061659305616c75666c766b00c36168184e656f2e52756e74696d652e436865636b5769746e6573736338002c4f726967696e61746f722069736e2774206173736f6369617465642077697468207468697320696e766f6b6561653b05616c75666c766b53c300a1642f0023596f75206e65656420746f2073656e64206d6f7265207468616e203020746f6b656e7361650505616c75666c766b51c36165b9046c766b54527ac46c766b54c36c766b53c39f6439002d4f776e657220646f65736e277420686176652074686973206b696e6420616d6f756e74206f6620746f6b656e736165b104616c75666c766b54c300a1642f00234f776e657220646f65736e2774206861766520706f7369746976652062616c616e636561657b04616c75666c766b51c36c766b00c3617c6572fb6c766b55527ac46c766b55c36c766b53c39f643f0033596f752061726520747279696e6720746f2073656e64206d6f7265207468616e20796f752061726520616c6c6f77656420746f61651b04616c75666c766b51c36c766b52c36c766b53c35161537951795572755172755279527954727552727565bc00631e00124661696c656420746f205472616e736665726165d503616c75666c766b55c36c766b53c3946c766b56527ac46c766b56c300a16440006168164e656f2e53746f726167652e476574436f6e746578746c766b51c36c766b00c37e617c68124e656f2e53746f726167652e44656c6574656240006168164e656f2e53746f726167652e476574436f6e746578746c766b51c36c766b00c37e6c766b56c3615272680f4e656f2e53746f726167652e50757451616c756656c56b6c766b00527ac46c766b51527ac46c766b52527ac46c766b53527ac46c766b51c3640f006c766b51c3c001149c633a002e546f2076616c7565206d757374206e6f7420626520656d70747920616e6420686176652073697a65206f662032306165d002616c75666c766b00c3640f006c766b00c3c001149c633c003046726f6d2076616c7565206d757374206e6f7420626520656d70747920616e6420686176652073697a65206f6620323061658302616c75666c766b52c300a1642a001e54727920746f2073656e64206d6f7265207468616e203020746f6b656e7361655202616c75666c766b53c36361006c766b00c36168184e656f2e52756e74696d652e436865636b5769746e657373633e00324f776e6572206f66207468652077616c6c6574206973206e6f7420696e766f6c76656420696e207468697320696e766f6b656165ec01616c75666c766b00c36c766b51c3907c907c9e63080051616c75666168164e656f2e53746f726167652e476574436f6e746578746c766b00c3617c680f4e656f2e53746f726167652e4765746c766b54527ac46c766b54c36c766b52c39f641e0012496e73756666696369656e742066756e647361657401616c75666c766b54c36c766b52c39c643a006168164e656f2e53746f726167652e476574436f6e746578746c766b00c3617c68124e656f2e53746f726167652e44656c6574656240006168164e656f2e53746f726167652e476574436f6e746578746c766b00c36c766b54c36c766b52c394615272680f4e656f2e53746f726167652e5075746168164e656f2e53746f726167652e476574436f6e746578746c766b51c3617c680f4e656f2e53746f726167652e4765746c766b55527ac46168164e656f2e53746f726167652e476574436f6e746578746c766b51c36c766b55c36c766b52c393615272680f4e656f2e53746f726167652e507574616c766b00c36c766b51c36c766b52c3615272087472616e7366657254c168124e656f2e52756e74696d652e4e6f7469667951616c756651c56b6c766b00527ac46168164e656f2e53746f726167652e476574436f6e746578746c766b00c3617c680f4e656f2e53746f726167652e476574616c756651c56b6c766b00527ac451c576006c766b00c3c46168124e656f2e52756e74696d652e4e6f7469667900616c756651c56b6c766b00527ac451c576006c766b00c3c46168124e656f2e52756e74696d652e4e6f7469667900616c7566

####### Script Hash

b2e50c6a25fdc5c690992c36d9b9f2978b7062fd 
部署合约

高级-部署合约

部署NEP-5合约花费490GAS 交易类型为InvocationTransaction

高级-合约调用-调用合约内deploy函数

NEP-5 转账

先在neo-gui添加代币资产

Advanced
Options
Add Five Scripthash: b2e50c6a25fdc5c690992c36d9b9f2978b7062fd
Apply/Ok

可以看到资产中有刚才发行的Five代币

NEP-5 代币转账

交易所对接NEP-5
  1. 节点开启log日志
dotnet neo-cli.dll --rpc --log --nopeers

  1. 解析log中NEP-5交易
root@test:/data/app/neo-cli/ApplicationLogs_74746E41# cat 0x5a59e800a82ca8baabd4dad7fcd8b6690eb475c539651f0e3d54034f419efdf3.json  
{"txid":"0x5a59e800a82ca8baabd4dad7fcd8b6690eb475c539651f0e3d54034f419efdf3","vmstate":"HALT, BREAK","gas_consumed":"2.739","stack":[],"notifications":[{"contract":"0xb2e50c6a25fdc5c690992c36d9b9f2978b7062fd","state":{"type":"Array","value":[{"type":"ByteArray","value":"7472616e73666572"},{"type":"ByteArray","value":"ecf28d2236dab6c09da8352821780215e890d7cf"},{"type":"ByteArray","value":"586853337b382a817c163b965eb57c1b57046519"},{"type":"ByteArray","value":"00e8764817"}]}}]}
  1. 调用NEP-5合约balaceOf() 函数确认余额
posted @ 2018-08-08 20:59  小小leo  阅读(481)  评论(0编辑  收藏