Skip to content
tanyuan edited this page Aug 11, 2017 · 28 revisions
using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Services.Neo;
using Neo.SmartContract.Framework.Services.System;
using System;
using System.Numerics;

namespace RPX
{
    public class RPX : FunctionCode
    {
        
        public static Object Main(string operation, params object[] args)
        {
            if (!VerifyWithdrawal(operation)) return false;
            if(operation == "mintTokens") return MintTokens(); 
            if(operation == "totalSupply") return TotalSupply();
            if(operation == "name") return Name();
            if(operation == "symbol") return Symbol();
            if(operation == "transfer") return Transfer(args);
            if(operation == "balanceOf") return BalanceOf(args);
            if (operation == "deploy") return Deploy(args);
            if (operation == "refund") return Refund();
            if (operation == "withdrawal") return Withdrawal(args);
            if (operation == "decimals") return Decimals();
            return false;
        }
        // initialization parameters, only once
        private static bool Deploy(object[] args)
        {
            if (args.Length != 8)
            {
                return false;
            }
            byte[] name = Storage.Get(Storage.CurrentContext, "name");
            if (name.Length != 0)
            {
                return false;
            }
            BigInteger ico_start_date = (BigInteger)args[0];
            BigInteger ico_end_date = (BigInteger)args[1];
            BigInteger total_amount = (BigInteger)args[2];
            BigInteger exchange_rate = (BigInteger)args[3];
            BigInteger pre_ico_cap = (BigInteger)args[4] * 10000000;
            if(pre_ico_cap > total_amount)
            {
                return false;
            }
            string name = (string)args[5];
            string symbol = (string)args[6];
            byte[] owner = (byte[])args[7];
            Storage.Put(Storage.CurrentContext, "icoStartDate", IntToBytes(ico_start_date));
            Storage.Put(Storage.CurrentContext, "icoEndDate", IntToBytes(ico_end_date));
            Storage.Put(Storage.CurrentContext, "totalAmount", IntToBytes(total_amount));
            Storage.Put(Storage.CurrentContext, owner, IntToBytes(pre_ico_cap));
            Storage.Put(Storage.CurrentContext, "totalSypply", IntToBytes(pre_ico_cap));
            Storage.Put(Storage.CurrentContext, "exchangeRate", IntToBytes(exchange_rate));
            Storage.Put(Storage.CurrentContext, "name", name);
            Storage.Put(Storage.CurrentContext, "symbol", symbol);
            Storage.Put(Storage.CurrentContext, "decimals", IntToBytes(8));
            Storage.Put(Storage.CurrentContext, "owner", owner);
            return true;
        }
        // The function Withdrawal is only usable when contract owner want
        // to transfer neo from contract
        private static bool Withdrawal(object[] args)
        {
            if(args.Length != 1)
            {
                return false;
            }
            byte[] signature = (byte[])args[0];
            byte[] owner = Storage.Get(Storage.CurrentContext, "owner");
            return VerifySignature(owner, signature);
        }

        // 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
        private static bool MintTokens()
        {
            Transaction trans = (Transaction)ExecutionEngine.ScriptContainer;
            TransactionInput trans_input = trans.GetInputs()[0];
            Transaction prev_trans = Blockchain.GetTransaction(trans_input.PrevHash);
            byte[] sender = prev_trans.GetOutputs()[trans_input.PrevIndex].ScriptHash;
            TransactionOutput[] trans_outputs = trans.GetOutputs();
            byte[] receiver = ExecutionEngine.ExecutingScriptHash;
            long value = 0;
            foreach (TransactionOutput trans_output in trans_outputs)
            {
                if (BytesEqual(trans_output.ScriptHash, receiver))
                {
                    value += trans_output.Value;

                }
            }
            uint swap_rate = CurrentSwapRate();
            if (swap_rate == 0)
            {
                byte[] refund = Storage.Get(Storage.CurrentContext, "refund");
                byte[] sender_value = IntToBytes(value);
                byte[] new_refund = refund.Concat(sender.Concat(IntToBytes(sender_value.Length).Concat(sender_value)));
                Storage.Put(Storage.CurrentContext, "refund", new_refund);
                return false;
            }
            long token = value * swap_rate * 10000000;
            BigInteger total_token = BytesToInt(Storage.Get(Storage.CurrentContext, sender));
            Storage.Put(Storage.CurrentContext, sender, IntToBytes(token + total_token));
            byte[] totalSypply = Storage.Get(Storage.CurrentContext, "totalSypply");
            Storage.Put(Storage.CurrentContext, "totalSypply", IntToBytes(token + BytesToInt(totalSypply)));
            return true;
        }

        private static byte[] Refund()
        {
            return Storage.Get(Storage.CurrentContext, "refund");
        }

        private static BigInteger TotalSupply()
        {
            byte[] totalSupply = Storage.Get(Storage.CurrentContext, "totalSypply");
            return BytesToInt(totalSupply);
        }

        private static string Name()
        {
            byte[] name = Storage.Get(Storage.CurrentContext, "name");
            return name.AsString();
        }

        private static string Symbol()
        {
            byte[] symbol = Storage.Get(Storage.CurrentContext, "symbol");
            return symbol.AsString();
        }

        private static bool Transfer(object[] args)
        {
            if (args.Length != 3) return false;
            byte[] from = (byte[])args[0];
            if (!Runtime.CheckWitness(from)) return false;
            byte[] to = (byte[])args[1];
            BigInteger value = BytesToInt((byte[])args[2]);
            if (value < 0) return false;
            byte[] from_value = Storage.Get(Storage.CurrentContext, from);
            byte[] to_value = Storage.Get(Storage.CurrentContext, to);
            BigInteger n_from_value = BytesToInt(from_value) - value;
            if (n_from_value < 0) return false;
            BigInteger n_to_value = BytesToInt(to_value) + value;
            Storage.Put(Storage.CurrentContext, from, IntToBytes(n_from_value));
            Storage.Put(Storage.CurrentContext, to, IntToBytes(n_to_value));
            Transferred(args);
            return true;
        }

        private static void Transferred(object[] args)
        {
            Runtime.Notify(args);
        }

        private static BigInteger BalanceOf(object[] args)
        {
            if (args.Length != 1) return 0;
            byte[] address = (byte[])args[0];
            byte[] balance = Storage.Get(Storage.CurrentContext, address);
            return BytesToInt(balance);
        }

        private static BigInteger Decimals()
        {
            byte[] decimals = Storage.Get(Storage.CurrentContext, "decimals");
            return BytesToInt(decimals);
        }

        private static BigInteger BytesToInt(byte[] array)
        {
            var buffer = new BigInteger(array);
            return buffer;
        }

        private static byte[] IntToBytes(BigInteger value)
        {
            byte[] buffer = value.ToByteArray();
            return buffer;
        }

        private static bool BytesEqual(byte[] b1, byte[] b2)
        {
            if (b1.Length != b2.Length) return false;
            for (int i = 0; i < b1.Length; i++)
                if (b1[i] != b2[i])
                    return false;
            return true;
        }

        // transfer neo in smart contract can only invoke
        // the function Withdrawal
        private static bool VerifyWithdrawal(string operation)
        {
            if(operation == "withdrawal")
            {
                return true;
            }
            Transaction trans = (Transaction)ExecutionEngine.ScriptContainer;
            TransactionInput trans_input = trans.GetInputs()[0];
            Transaction prev_trans = Blockchain.GetTransaction(trans_input.PrevHash);
            TransactionOutput prev_trans_output = prev_trans.GetOutputs()[trans_input.PrevIndex];
            byte[] script_hash = ExecutionEngine.ExecutingScriptHash;
            if (BytesEqual(prev_trans_output.ScriptHash, script_hash))
            {
                return false;
            }
            return true;
        }
        // The function CurrentSwapRate() returns the current exchange rate
        // between rpx tokens and neo during the token swap period
        private static uint CurrentSwapRate()
        {
            byte[] ico_start_date = Storage.Get(Storage.CurrentContext, "icoStartDate");
            BigInteger start_date = BytesToInt(ico_start_date);
            byte[] total_supply = Storage.Get(Storage.CurrentContext, "totalSupply");
            byte[] total_amount = Storage.Get(Storage.CurrentContext, "totalAmount");
            if(BytesToInt(total_supply) > BytesToInt(total_amount))
            {
                return 0;
            }
            byte[] exchange_rate = Storage.Get(Storage.CurrentContext, "exchageRate");
            uint rate = (uint) BytesToInt(exchange_rate);
            uint height = Blockchain.GetHeight();
            uint now = Blockchain.GetHeader(height).Timestamp;
            uint time = (uint)start_date - now;
            if (time < 0)
            {
                return 0;
            }else if (time <= 86400)
            {
                return rate * 130 /100;
            }
            else if (time <= 259200)
            {
                return rate * 120 /100;
            }
            else if (time <= 604800)
            {
                return rate * 110 / 100;
            }
            else if (time <= 1209600)
            {
                return rate;
            }
            else
            {
                return 0;
            }

        }
    }
}
Clone this wiki locally