forked from neo-project/neo
-
Notifications
You must be signed in to change notification settings - Fork 1
RPX_ICO
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[] deploy_flag = Storage.Get(Storage.CurrentContext, "deployFlag");
if (deploy_flag.Length != 0)
{
return false;
}
Storage.Put(Storage.CurrentContext, "deployFlag", "1");
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] * exchange_rate * 150 / 100;
if(pre_ico_cap > total_amount)
{
return false;
}
string name = (string)args[5];
string symbol = (string)args[6];
BigInteger decimals = (BigInteger)args[7];
byte[] owner = (byte[])args[8];
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(decimals));
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;
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)
{
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) && operation != "withdrawal")
{
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;
}
}
}
}