diff --git a/API/ContractAPI.cs b/API/ContractAPI.cs new file mode 100644 index 0000000..242748c --- /dev/null +++ b/API/ContractAPI.cs @@ -0,0 +1,34 @@ +using Ont.SmartContract.Framework; +using Ont.SmartContract.Framework.Services.Ont; +using Ont.SmartContract.Framework.Services.System; + +public class ContractExample : SmartContract +{ + public static bool Main(string operation, params object[] args) + { + if (operation == "Destroy") + { + return DestroyContract(); + } + if (operation == "Migrate") + { + //smart contract avm code + byte[] code = (byte[])args[0]; + return Migrate(code); + } + + return false; + } + + public static bool DestroyContract() + { + Contract.Destroy(); + return true; + } + + public static bool Migrate(byte[] code) + { + Contract.Migrate(code, true, "", "", "", "", ""); + return true; + } +} \ No newline at end of file diff --git a/API/DynamicCallOep4.cs b/API/DynamicCallOep4.cs new file mode 100644 index 0000000..b00b5a8 --- /dev/null +++ b/API/DynamicCallOep4.cs @@ -0,0 +1,40 @@ +using Ont.SmartContract.Framework; +using System; +using System.Numerics; + +namespace Contract +{ + public class Contract : SmartContract + { + public delegate object OEP4Contract(string method, object[] args); + + public static Object Main(string operation, params object[] args) + { + if (operation == "CallOep4Contract") + { + if (args.Length != 4) return false; + byte[] from = (byte[])args[0]; + byte[] to = (byte[])args[1]; + ulong value = (ulong)args[2]; + byte[] hash = (byte[])args[3]; + return CallOep4Contract(from, to, value, hash); + } + return false; + } + + public static bool CallOep4Contract(byte[] from, byte[] to, ulong value, byte[] contractHash) + { + + if (!TransferOEP4(from, to, contractHash, value)) throw new Exception(); + return true; + } + + private static bool TransferOEP4(byte[] from, byte[] to, byte[] assetID, BigInteger amount) + { + var args = new object[] { from, to, amount }; + var contract = (OEP4Contract)assetID.ToDelegate(); + if (!(bool)contract("transfer", args)) return false; + return true; + } + } +} diff --git a/API/MapExample.cs b/API/MapExample.cs new file mode 100644 index 0000000..1773e80 --- /dev/null +++ b/API/MapExample.cs @@ -0,0 +1,27 @@ +using Ont.SmartContract.Framework; +using Ont.SmartContract.Framework.Services.Ont; +using Helper = Ont.SmartContract.Framework.Helper; + +public class MapExample : SmartContract +{ + + public static void Main() + { + Map m = new Map(); + m["k1"] = 100; + m["k2"] = 200; + Runtime.Notify(m["k1"]); + Runtime.Notify(m["k2"]); + + // seriallize + byte[] b = Helper.Serialize(m); + Storage.Put(Storage.CurrentContext, "mapexample", b); + byte[] v = Storage.Get(Storage.CurrentContext, "mapexample"); + + // deserialize + Map m2 = (Map)Helper.Deserialize(v); + Runtime.Notify(m2["k1"]); + Runtime.Notify(m2["k2"]); + } + +} \ No newline at end of file diff --git a/API/RuntimeAPI.cs b/API/RuntimeAPI.cs new file mode 100644 index 0000000..229e5cd --- /dev/null +++ b/API/RuntimeAPI.cs @@ -0,0 +1,24 @@ +using Ont.SmartContract.Framework; +using Ont.SmartContract.Framework.Services.Ont; +using Ont.SmartContract.Framework.Services.System; + +public class RuntimeExample : SmartContract +{ + public static void Main() + { + // get current block time + Runtime.Notify(Runtime.Time); + + // check the caller authority, it's very useful function for check user authentication + byte[] user = { 248, 142, 51, 220, 214, 177, 110, 235, 27, 218, 59, 86, 23, 47, 140, 20, 114, 119, 159, 152 }; + Runtime.CheckWitness(user); + + // Notify the message to the blockchain,the arguments is a object array + Runtime.Notify("Hi blockchain"); + Runtime.Notify("s1", "s2", 1, 2, 3); + + // Runtime.Log() write the log message to the blockchain, the arguments can only be string + Runtime.Log("log message."); + + } +} \ No newline at end of file diff --git a/API/StorageExample.cs b/API/StorageExample.cs new file mode 100644 index 0000000..517afa4 --- /dev/null +++ b/API/StorageExample.cs @@ -0,0 +1,21 @@ +using Ont.SmartContract.Framework; +using Ont.SmartContract.Framework.Services.Ont; +using System.Numerics; + +public class StorageExample : SmartContract +{ public static void Main() + { + // get the storage context + StorageContext context = Storage.CurrentContext; + + Storage.Put(context, "key", 100); + BigInteger v = Storage.Get(context, "key").AsBigInteger(); + Runtime.Notify(v); + + Storage.Put(context, "key".AsByteArray(), "100"); + Runtime.Notify(Storage.Get(context,"key".AsByteArray()).AsString()); + + Storage.Delete(context, "key"); + Runtime.Notify(Storage.Get(context, "key".AsByteArray())); + } +} \ No newline at end of file diff --git a/API/StorageMapExample.cs b/API/StorageMapExample.cs new file mode 100644 index 0000000..dda4dd3 --- /dev/null +++ b/API/StorageMapExample.cs @@ -0,0 +1,22 @@ +using Ont.SmartContract.Framework; +using Ont.SmartContract.Framework.Services.Ont; + +namespace CGAS +{ + public class StorageExample : SmartContract + { + public static void Main(string method, object[] args) + { + StorageMap asset = Storage.CurrentContext.CreateMap(nameof(asset)); + + asset.Put("key", 100); + Runtime.Notify(asset.Get("key").AsBigInteger()); + + asset.Get("key"); + Runtime.Notify(asset.Get("key").AsBigInteger()); + + asset.Delete("key"); + Runtime.Notify(asset.Get("key").AsBigInteger()); + } + } +} diff --git a/API/StructExample.cs b/API/StructExample.cs new file mode 100644 index 0000000..5291e0b --- /dev/null +++ b/API/StructExample.cs @@ -0,0 +1,34 @@ +using Ont.SmartContract.Framework; +using Ont.SmartContract.Framework.Services.Ont; +using Helper = Ont.SmartContract.Framework.Helper; + +public class StructExmple : SmartContract +{ + + public static void Main() + { + // create struct instance + Person p = new Person(); + p.Name = "bob"; + p.Age = 20; + Runtime.Notify(p.Name); + Runtime.Notify(p.Age); + + // serialize struct instance to byte[] + byte[] b = Helper.Serialize(p); + + // deserialize byte[] to struct + Person p2 = (Person)Helper.Deserialize(b); + Runtime.Notify(p2.Name); + Runtime.Notify(p2.Age); + + // create struct array + Person[] array = new Person[] { new Person { Name = "tom", Age = 18 }, new Person { Name = "jack", Age = 20 } }; + } + + struct Person + { + public string Name; + public int Age; + } +} \ No newline at end of file diff --git a/API/ThrowException.cs b/API/ThrowException.cs new file mode 100644 index 0000000..198cd5c --- /dev/null +++ b/API/ThrowException.cs @@ -0,0 +1,59 @@ +using Ont.SmartContract.Framework; +using Ont.SmartContract.Framework.Services.Ont; +using System; +using System.Numerics; + +namespace ExceptionTest +{ + public class ExceptionTest : SmartContract + { + + public static Object Main(string operation, params object[] args) + { + if (operation == "transferMulti") + { + return TransferMulti(args); + } + return false; + } + + // smart contract throw excepiton example in multiple transfer + public static bool TransferMulti(object[] args) + { + for(int i=0;i "OEP-4 Token"; + public static string symbol() => "OEP4"; + public static readonly byte[] owner = "AGjD4Mo25kzcStyh1stp7tXkUuMopD43NT".ToScriptHash(); + public static byte Decimals() => 8; + private const ulong factor = 100000000; //decided by Decimals() + private const ulong totalAmount = 10000000000 * factor; + + public delegate void deleTransfer(byte[] from, byte[] to, BigInteger value); + [DisplayName("transfer")] + public static event deleTransfer Transferred; + + public delegate void deleApprove(byte[] onwer, byte[] spender, BigInteger value); + [DisplayName("approval")] + public static event deleApprove Approval; + + public struct State + { + public byte[] From; + public byte[] To; + public BigInteger Amount; + } + + public static Object Main(string operation, params object[] args) + { + if (operation == "init") return init(); + if (operation == "decimals") return Decimals(); + if (operation == "totalSupply") return totalSupply(); + if (operation == "name") return name(); + if (operation == "symbol") return symbol(); + if (operation == "balanceOf") + { + if (args.Length != 1) return 0; + byte[] address = (byte[])args[0]; + return balanceOf(address); + } + 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 == "transferMulti") + { + return transferMulti(args); + } + if (operation == "approve") + { + if (args.Length != 3) return false; + byte[] owner = (byte[])args[0]; + if (owner.Length != 20) + { + return false; + } + byte[] spender = (byte[])args[1]; + if (spender.Length != 20) + { + return false; + } + BigInteger value = (BigInteger)args[2]; + return approve(owner, spender, value); + } + if (operation == "allowance") + { + if (args.Length != 2) return 0; + byte[] owner = (byte[])args[0]; + byte[] spender = (byte[])args[1]; + return allowance(owner, spender); + } + if (operation == "transferFrom") + { + if (args.Length != 4) return false; + byte[] sender = (byte[])args[0]; + if (sender.Length != 20) + { + return false; + } + byte[] from = (byte[])args[1]; + if (from.Length != 20) + { + return false; + } + byte[] to = (byte[])args[2]; + if (to.Length != 20) + { + return false; + } + BigInteger amount = (BigInteger)args[3]; + return transferFrom(sender, from, to, amount); + } + return false; + } + + /// initialize contract parameter + /// initialize result, success or failure + //[DisplayName("init")] + public static bool init() + { + byte[] total_supply = Storage.Get(Storage.CurrentContext, "totalSupply"); + if (total_supply.Length != 0) return false; + + Storage.Put(Storage.CurrentContext, owner, totalAmount); + Runtime.Notify(null, owner, totalAmount); + Storage.Put(Storage.CurrentContext, "totalSupply", totalAmount); + return true; + } + + /// query the total supply of token + /// total supply of token + public static BigInteger totalSupply() + { + return Storage.Get(Storage.CurrentContext, "totalSupply").AsBigInteger(); + } + + + /// query balance of any address + /// balance of the address + /// account or contract address + public static BigInteger balanceOf(byte[] address) + { + return Storage.Get(Storage.CurrentContext, address).AsBigInteger(); + } + + /// + /// transfer amount of token from sender to receiver, + /// the address can be account or contract address which should be 20-byte + /// + /// transfer result, success or failure + /// transfer sender address + /// transfer receiver address + /// transfer amount + 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 fromValue = Storage.Get(Storage.CurrentContext, from).AsBigInteger(); + if (fromValue < value) return false; + if (fromValue == value) + Storage.Delete(Storage.CurrentContext, from); + else + Storage.Put(Storage.CurrentContext, from, fromValue - value); + + BigInteger toValue = Storage.Get(Storage.CurrentContext, to).AsBigInteger(); + Storage.Put(Storage.CurrentContext, to, toValue + value); + Runtime.Notify(from, to, value); + return true; + } + + /// transfer multiple amount of token from multiple sender to multiple receiver + /// return transfer result, if any transfer fail, all of transfers should fail. + /// state struct + /// public struct State + /// { + /// public byte[] From; // transfer sender + /// public byte[] To; // transfer receiver + /// public BigInteger Amount; //transfer amount + ///} + public static bool transferMulti(object[] args) + { + for (int i = 0; i < args.Length; i++) + { + State state = (State)args[i]; + if (!transfer(state.From, state.To, state.Amount)) throw new Exception(); + } + return true; + } + + /// + /// approve allows spender to withdraw from owner account multiple times, up to the value amount + /// the address can be account or contract address which should be 20-byte + /// + /// transfer result, success or failure + /// approve owner address + /// approve spender address + /// approve amount + public static bool approve(byte[] owner, byte[] spender, BigInteger amount) + { + if (amount < 0) return false; + if (!Runtime.CheckWitness(owner)) return false; + if (!validateAddress(spender)) return false; + if (owner == spender) return false; + BigInteger ownerBalance = balanceOf(owner); + if (ownerBalance < amount) return false; + byte[] approveKey = owner.Concat(spender); + Storage.Put(Storage.CurrentContext, approveKey, amount); + Runtime.Notify("approve", owner, spender, amount); + return true; + } + + /// + /// transferFrom allows `spender` to withdraw amount of token from `from` account to `to` account + /// the address can be account or contract address which should be 20-byte + /// + /// transferFrom result, success or failure + /// approve owner address + /// approve owner address + /// approve spender address + /// approve amount + public static bool transferFrom(byte[] spender, byte[] from, byte[] to, BigInteger amount) + { + if (amount < 0) return false; + if (!Runtime.CheckWitness(spender)) return false; + if (!validateAddress(from)) return false; + if (!validateAddress(to)) return false; + if (from == to) return true; + if (balanceOf(from) < amount) return false; + + byte[] approveKey = from.Concat(spender); + BigInteger approveValue = Storage.Get(Storage.CurrentContext, approveKey).AsBigInteger(); + if (approveValue < amount) return false; + if (approveValue == amount) + Storage.Delete(Storage.CurrentContext, approveKey); + else + Storage.Put(Storage.CurrentContext, approveKey, approveValue - amount); + + Storage.Put(Storage.CurrentContext, from, balanceOf(from) - amount); + Storage.Put(Storage.CurrentContext, from, balanceOf(to) + amount); + + return transfer(from, to, amount); + } + + /// query `spender` can withdraw the amount of token from `owner` account + /// withdraw amount of token + /// account or contract address + /// account or contract address + public static BigInteger allowance(byte[] owner, byte[] spender) + { + return Storage.Get(Storage.CurrentContext, owner.Concat(spender)).AsBigInteger(); + } + + private static bool validateAddress(byte[] address) + { + if (address.Length != 20) return false; + if (address.AsBigInteger() == 0) return false; + return true; + } + + } +} diff --git a/OEPS/OEP5.cs b/OEPS/OEP5.cs new file mode 100644 index 0000000..eaad2d0 --- /dev/null +++ b/OEPS/OEP5.cs @@ -0,0 +1,227 @@ +using Ont.SmartContract.Framework; +using Ont.SmartContract.Framework.Services.Ont; +using Ont.SmartContract.Framework.Services.System; +using System; +using System.ComponentModel; +using System.Numerics; + +namespace OEP5 +{ + public class OEP5 : SmartContract + { + //Token Settings + public static string Name() => "My Non-Fungibles"; + public static string Symbol() => "MNFT"; + public static readonly byte[] admin = "ATrzHaicmhRj15C3Vv6e6gLfLqhSD2PtTr".ToScriptHash(); + //Store Key Prefix + public static readonly byte[] owner_balance_prefix = "Balance".AsByteArray(); + public static readonly byte[] owner_of_token_prefix = "OwnerOf".AsByteArray(); + public static readonly byte[] approve_prefix = "Approve".AsByteArray(); + public static readonly byte[] token_index_prefix = "Index".AsByteArray(); + public static readonly byte[] token_cir_key = "in_circulation".AsByteArray(); + public static readonly byte[] token_property_prefix = "token_property".AsByteArray(); + public static readonly byte[] token_url_prefix = "token_url".AsByteArray(); + public delegate void deleTransfer(byte[] from, byte[] to, byte[] tokenId); + [DisplayName("transfer")] + public static event deleTransfer Transferred; + public delegate void deleApprove(byte[] onwer, byte[] spender, byte[] tokenId); + [DisplayName("approval")] + public static event deleApprove Approval; + public struct State + { + public byte[] To; + public byte[] TokenId; + } + public static Object Main(string operation, params object[] args) + { + if (operation == "name") return Name(); + if (operation == "symbol") return Symbol(); + if (operation == "balanceOf") + { + if (args.Length != 1) return 0; + byte[] address = (byte[])args[0]; + return BalanceOf(address); + } + if (operation == "ownerOf") + { + if (args.Length != 1) return false; + byte[] tokenId = (byte[])args[0]; + return ownerOf(tokenId); + } + if (operation == "transfer") + { + if (args.Length != 2) return false; + byte[] to = (byte[])args[0]; + byte[] tokenId = (byte[])args[1]; + return Transfer(to, tokenId); + } + if (operation == "transferMulti") + { + return TransferMulti(args); + } + if (operation == "approve") + { + if (args.Length != 2) return false; + byte[] to = (byte[])args[0]; + byte[] tokenId = (byte[])args[1]; + return Approve(to, tokenId); + } + if (operation == "takeOwnership") + { + if (args.Length != 2) return false; + byte[] to = (byte[])args[0]; + byte[] tokenId = (byte[])args[1]; + return TakeOwnership(to, tokenId); + } + if (operation == "mintToken") + { + if (args.Length != 4) return false; + byte[] owner = (byte[])args[0]; + byte[] tokenId = (byte[])args[1]; + byte[] property = (byte[])args[2]; + string url = (string)args[3]; + return MintToken(owner, tokenId, property, url); + } + if (operation == "totalSupply") + { + return TotalSupply(); + } + return false; + } + /// ransfers an NFTs of tokens from the from account to the to account. + /// to SHOULD be 20-byte address. If not, throw an exception. + /// + /// return transfer result, success or fail. + /// token receiver address + /// NFT token id + public static bool Transfer(byte[] to, byte[] tokenId) + { + Require(validateAddress(to), "invalid to address"); + byte[] owner = ownerOf(tokenId); + Require(Runtime.CheckWitness(owner), "invalid owner"); + StorageContext context = Storage.CurrentContext; + Storage.Put(context, owner_balance_prefix.Concat(owner), BalanceOf(to) - 1); + Storage.Put(context, owner_of_token_prefix.Concat(tokenId), to); + Storage.Put(context, owner_balance_prefix.Concat(to), BalanceOf(to) + 1); + return true; + } + /// transfer multiple amount of NFT token from multiple sender to multiple receiver + /// return transfer result, if any transfer fail, all of transfers should fail. + /// state struct + /// public struct State + /// { + /// public byte[] TokenId; // NFT token id + /// public byte[] To; // transfer receiver + ///} + public static bool TransferMulti(object[] args) + { + for (int i = 0; i < args.Length; i++) + { + State state = (State)args[i]; + if (!Transfer(state.To, state.TokenId)) throw new Exception(); + } + return true; + } + /// return the number of NFTs assigned to address + /// the owner's total NFT number + /// address SHOULD be a 20-byte address + public static BigInteger BalanceOf(byte[] address) + { + if (!validateAddress(address)) throw new Exception("Invalid address"); + return Storage.Get(Storage.CurrentContext, owner_balance_prefix.Concat(address)).AsBigInteger(); + } + /// return the address currently marked as the owner of tokenId + /// owner address + /// NFT token id + public static byte[] ownerOf(byte[] tokenId) + { + byte[] owner = Storage.Get(Storage.CurrentContext, owner_of_token_prefix.Concat(tokenId)); + if (owner == null || !validateAddress(owner)) throw new Exception(); + return owner; + } + /// + /// The approve allows to grant an NFTs toto account multiple times. + /// If this function is called again it overwrites to or tokenId + /// + /// transfer result, success or failure + /// approve receiver address + /// approved NFT token id + public static bool Approve(byte[] to, byte[] tokenId) + { + Require(validateAddress(to), "invalid to address"); + byte[] owner = ownerOf(tokenId); + Require(Runtime.CheckWitness(owner), "invalid owner"); + Storage.Put(Storage.CurrentContext, approve_prefix.Concat(tokenId), to); + Runtime.Notify("approve", owner, to, tokenId); + return true; + } + /// + /// Assigns the ownership of the Non-fungible with ID tokenId to to address. + /// to SHOULD be 20-byte addresses. + /// + /// success or failure + /// receiver address + /// NFT token id + public static bool TakeOwnership(byte[] to, byte[] tokenId) + { + Require(Runtime.CheckWitness(to), "not owner"); + byte[] owner = ownerOf(tokenId); + Require(validateAddress(owner), "invalid address"); + byte[] approveAcc = Storage.Get(Storage.CurrentContext, approve_prefix.Concat(tokenId)); + Require(approveAcc == to, "not approved"); + Storage.Delete(Storage.CurrentContext, approve_prefix.Concat(tokenId)); + Storage.Put(Storage.CurrentContext, owner_of_token_prefix.Concat(tokenId), to); + Storage.Put(Storage.CurrentContext, owner_balance_prefix.Concat(owner), BalanceOf(owner) - 1); + Storage.Put(Storage.CurrentContext, owner_balance_prefix.Concat(to), BalanceOf(to) + 1); + Runtime.Notify("take the owner ship", owner, to, tokenId); + return true; + } + /// + /// Mint Token issue new NFT token id to a owner + /// + /// success or failure + /// token receiver address + /// NFT token id + /// the NFT token property, can't be empty. + /// token url + public static bool MintToken(byte[] owner,byte[] tokenId, byte[] property, string URL) + { + Require(Runtime.CheckWitness(admin), "not admin"); + Require(validateAddress(owner), "invalid address"); + Require(property == null, "missing properties data string"); + Require(tokenId.Length <= 128, "token id too long"); + StorageContext context = Storage.CurrentContext; + if (validateAddress(Storage.Get(context, owner_of_token_prefix.Concat(tokenId)))) { + Runtime.Notify("token id already exist"); + return false; + } + BigInteger tokenNumber = Storage.Get(context, token_cir_key).AsBigInteger(); + tokenNumber += 1; + Storage.Put(context, token_cir_key, tokenNumber); + Storage.Put(context, owner_of_token_prefix.Concat(tokenId), owner); + Storage.Put(context, token_property_prefix.Concat(tokenId), property); + Storage.Put(context, token_url_prefix.Concat(tokenId), URL); + Storage.Put(Storage.CurrentContext, owner_balance_prefix.Concat(owner), BalanceOf(owner) + 1); + Runtime.Notify("mintToken", owner, tokenId); + return true; + } + public static BigInteger TotalSupply() + { + return Storage.Get(Storage.CurrentContext, token_cir_key).AsBigInteger(); + } + private static bool validateAddress(byte[] address) + { + if (address.Length != 20) return false; + if (address.AsBigInteger() == 0) return false; + return true; + } + private static void Require(bool cond, string msg) + { + if (!cond) + { + Runtime.Log(msg); + throw new Exception(); + } + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..c0d9c04 --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +## csharp smart contract +This is ontology C# smart contract template collections, you can refer to these templates when developing ontoloy smart contract. + +## Content + +These templates are divided into different directory structures according to different functions. + +- [Utils] + + the common.cs contain the most commonly used functions base on NEO VM, like + + bytes to string conversion, biginteger to bytes, and so on. + + All the most common tool templates will be placed in this directory + +- [math] + + The Math.cs and SafeMath.cs provide add, subtract, multiply, divide,mod, max, min, average functions in mathematics. + +- [API] + + This directory provide ontology smart contract api template, like Contract api, Storage api, Struct example, Map exmaple, Exception handle exmaple, and so on. + + All examples related to interfaces and data types are placed here. + +- [Crypto] + + All cryptographic related contract calls are placed here + +- [Asset] + + All cryptographic related contract calls are placed here, like ont, ong. + +- [Application] + + some contracts with realistic application scenarios will be placed here. like bond.cs, it provides offline bond contracts in the form of smart contracts. It will be useful for the investor and invest institute. + + We may also develop a smart contract for the game later. + + If the contract becomes more and more mature, we will divide it separately for a new project. + +- [CrowdSale] + + TODO + +- [OEPS] + + This directory include the [OEPS Proposal]( https://github.com/ontio/OEPs/tree/master/OEPS) smart contract template + + diff --git a/Utils/common.cs b/Utils/common.cs new file mode 100644 index 0000000..3b5db22 --- /dev/null +++ b/Utils/common.cs @@ -0,0 +1,49 @@ +using Ont.SmartContract.Framework; +using Ont.SmartContract.Framework.Services.Ont; +using Ont.SmartContract.Framework.Services.System; +using System.Numerics; + +public class Contract : SmartContract +{ + public static bool Main(string operation, params object[] args) + { + return false; + } + + public byte[] bytesConcat(byte[] a, byte[] b) + { + return a.Concat(b); + } + + public byte[] stringConcat(string a, string b) + { + return a.AsByteArray().Concat(b.AsByteArray()); + } + + public byte[] stringToBytes(string s) + { + return s.AsByteArray(); + } + + public string bytesToString(byte[] arr) + { + return arr.AsString(); + } + + public BigInteger bytestoBiginteger(byte[] arr) + { + return arr.AsBigInteger(); + } + + public byte[] bigintegerToBytes(BigInteger b) + { + return b.AsByteArray(); + } + + public static bool validateAddress(byte[] address) + { + if (address.Length != 20) return false; + if (address.AsBigInteger() == 0) return false; + return true; + } +} diff --git a/math/Math.cs b/math/Math.cs new file mode 100644 index 0000000..570444c --- /dev/null +++ b/math/Math.cs @@ -0,0 +1,24 @@ +using Ont.SmartContract.Framework; +using System; +using System.Numerics; + +namespace Math{ + + public class ArithMath + { + public static BigInteger Max(BigInteger a, BigInteger b) + { + return a >= b ? a : b; + } + + public static BigInteger Min(BigInteger a, BigInteger b) + { + return a >= b ? a : b; + } + + public static BigInteger Average(BigInteger a, BigInteger b) + { + return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); + } + } +} diff --git a/math/SafeMath.cs b/math/SafeMath.cs new file mode 100644 index 0000000..bcedd1a --- /dev/null +++ b/math/SafeMath.cs @@ -0,0 +1,52 @@ +using Ont.SmartContract.Framework; +using System; +using System.Numerics; + +namespace Math{ + + public class SafeMath + { + public static BigInteger Mul(BigInteger a, BigInteger b) + { + if (a == 0) + { + return 0; + } + + BigInteger c = a * b; + if (c / a != b) throw new Exception(); + + return c; + } + + public static BigInteger Div(BigInteger a, BigInteger b) + { + if (b <= 0) throw new Exception(); + BigInteger c = a / b; + + return c; + } + + public static BigInteger Sub(BigInteger a, BigInteger b) + { + if (b > a) throw new Exception(); + BigInteger c = a - b; + + return c; + } + + public static BigInteger Add(BigInteger a, BigInteger b) + { + BigInteger c = a + b; + if (c < a) throw new Exception(); + + return c; + } + + public static BigInteger Mod(BigInteger a, BigInteger b) + { + if (b == 0) throw new Exception(); + return a % b; + } + } +}