diff --git a/Swap/flamingo-contract-swap/FlamingoSwapFactory/FlamingoSwapFactoryContract.cs b/Swap/flamingo-contract-swap/FlamingoSwapFactory/FlamingoSwapFactoryContract.cs index dfb5203..95b9352 100644 --- a/Swap/flamingo-contract-swap/FlamingoSwapFactory/FlamingoSwapFactoryContract.cs +++ b/Swap/flamingo-contract-swap/FlamingoSwapFactory/FlamingoSwapFactoryContract.cs @@ -220,6 +220,7 @@ private static bool SetFeeTo(byte[] feeTo) return true; } + /// /// 获取pair diff --git a/Swap/flamingo-contract-swap/FlamingoSwapPair/FlamingoSwapPairContract.Admin.cs b/Swap/flamingo-contract-swap/FlamingoSwapPair/FlamingoSwapPairContract.Admin.cs index ee98b01..baec45c 100644 --- a/Swap/flamingo-contract-swap/FlamingoSwapPair/FlamingoSwapPairContract.Admin.cs +++ b/Swap/flamingo-contract-swap/FlamingoSwapPair/FlamingoSwapPairContract.Admin.cs @@ -17,12 +17,14 @@ partial class FlamingoSwapPairContract static readonly byte[] superAdmin = "AZaCs7GwthGy9fku2nFXtbrdKBRmrUQoFP".ToScriptHash(); - ///// - ///// Factory地址 - ///// - //static readonly byte[] FactoryContract = "32904da4441d544d05074774ade7c891d912f61a".HexToBytes(); + /// + /// WhiteList 合约地址 + /// + static readonly byte[] WhiteListContract = "3008f596f4fbdcaf712d6fc0ad2e9a522cc061cf".HexToBytes(); + const string AdminKey = nameof(superAdmin); + private const string WhiteListContractKey = nameof(WhiteListContract); /// @@ -49,6 +51,39 @@ public static bool SetAdmin(byte[] admin) } + /// + /// 获取WhiteListContract地址 + /// + /// + public static byte[] GetWhiteListContract() + { + var whiteList = Storage.Get(WhiteListContractKey); + return whiteList.Length == 20 ? whiteList : WhiteListContract; + } + + /// + /// 设置WhiteListContract地址 + /// + /// + /// + public static bool SetWhiteListContract(byte[] whiteList) + { + Assert(whiteList.Length == 20, "WhiteList contract Invalid"); + Assert(Runtime.CheckWitness(GetAdmin()), "Forbidden"); + Storage.Put(WhiteListContractKey, whiteList); + return true; + } + + /// + /// 检查是否为router合约 + /// + /// + /// + private static bool CheckIsRouter(byte[] callScript) + { + var whiteList = GetWhiteListContract(); + return ((Func)whiteList.ToDelegate())("checkRouter", new object[] { callScript }); + } #endregion diff --git a/Swap/flamingo-contract-swap/FlamingoSwapPair/FlamingoSwapPairContract.Nep5.cs b/Swap/flamingo-contract-swap/FlamingoSwapPair/FlamingoSwapPairContract.Nep5.cs index ce90787..870ebef 100644 --- a/Swap/flamingo-contract-swap/FlamingoSwapPair/FlamingoSwapPairContract.Nep5.cs +++ b/Swap/flamingo-contract-swap/FlamingoSwapPair/FlamingoSwapPairContract.Nep5.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Neo.SmartContract.Framework; using Neo.SmartContract.Framework.Services.Neo; +using Neo.SmartContract.Framework.Services.System; namespace FlamingoSwapPair { @@ -70,6 +71,12 @@ private static bool Transfer(byte[] from, byte[] to, BigInteger amount, byte[] c Assert(from.Length == 20 && to.Length == 20, "The parameters from and to SHOULD be 20-byte addresses."); Assert(amount >= 0, "The parameter amount MUST be greater than 0."); + var me = ExecutionEngine.ExecutingScriptHash; + if (to == me) + { + Assert(CheckIsRouter(callscript), "Only support transfer to me by Router"); + } + if (!Runtime.CheckWitness(from) && from.AsBigInteger() != callscript.AsBigInteger()) return false; StorageMap asset = Storage.CurrentContext.CreateMap(BalanceMapKey); diff --git a/Swap/flamingo-contract-swap/FlamingoSwapPair/FlamingoSwapPairContract.cs b/Swap/flamingo-contract-swap/FlamingoSwapPair/FlamingoSwapPairContract.cs index 43f417b..d2392bf 100644 --- a/Swap/flamingo-contract-swap/FlamingoSwapPair/FlamingoSwapPairContract.cs +++ b/Swap/flamingo-contract-swap/FlamingoSwapPair/FlamingoSwapPairContract.cs @@ -10,8 +10,6 @@ namespace FlamingoSwapPair partial class FlamingoSwapPairContract : SmartContract { - - /// /// https://uniswap.org/docs/v2/protocol-overview/smart-contracts/#minimum-liquidity /// @@ -124,6 +122,12 @@ public static object Main(string method, object[] args) if (method == "setAdmin") return SetAdmin((byte[])args[0]); + if (method == "getWhiteListContract") return GetWhiteListContract(); + + if (method == "setWhiteListContract") return SetWhiteListContract((byte[])args[0]); + + if (method == "checkIsRouter") return CheckIsRouter((byte[])args[0]); + if (method == "upgrade") { Assert(args.Length == 9, "upgrade: args.Length != 9."); @@ -144,8 +148,6 @@ public static object Main(string method, object[] args) } - - #region Swap /// @@ -157,6 +159,8 @@ public static object Main(string method, object[] args) /// public static bool Swap(byte[] msgSender, BigInteger amount0Out, BigInteger amount1Out, byte[] toAddress) { + Assert(CheckIsRouter(msgSender), "Only Router Can Swap"); + var me = ExecutionEngine.ExecutingScriptHash; //转出量必需一个为0一个为正数 @@ -218,6 +222,7 @@ public static bool Swap(byte[] msgSender, BigInteger amount0Out, BigInteger amou /// public static object Burn(byte[] msgSender, byte[] toAddress) { + Assert(CheckIsRouter(msgSender),"Only Router Can Burn"); var me = ExecutionEngine.ExecutingScriptHash; var r = ReservePair; @@ -259,13 +264,14 @@ public static object Burn(byte[] msgSender, byte[] toAddress) /// /// 铸造代币,此方法应该由router在AddLiquidity时调用 - /// todo:禁止外部直接调用 /// /// /// /// 返回本次铸币量 public static BigInteger Mint(byte[] msgSender, byte[] toAddress) { + Assert(CheckIsRouter(msgSender), "Only Router Can Mint"); + var me = ExecutionEngine.ExecutingScriptHash; var r = ReservePair; diff --git a/Swap/flamingo-contract-swap/FlamingoSwapPairWhiteList/FlamingoSwapPairWhiteList.Admin.cs b/Swap/flamingo-contract-swap/FlamingoSwapPairWhiteList/FlamingoSwapPairWhiteList.Admin.cs new file mode 100644 index 0000000..73dc479 --- /dev/null +++ b/Swap/flamingo-contract-swap/FlamingoSwapPairWhiteList/FlamingoSwapPairWhiteList.Admin.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Services.Neo; + +namespace FlamingoSwapPairWhiteList +{ + partial class FlamingoSwapPairWhiteList + { + #region Admin + + static readonly byte[] superAdmin = "AZaCs7GwthGy9fku2nFXtbrdKBRmrUQoFP".ToScriptHash(); + const string AdminKey = nameof(superAdmin); + + + /// + /// 获取合约管理员 + /// + /// + public static byte[] GetAdmin() + { + var admin = Storage.Get(AdminKey); + return admin.Length == 20 ? admin : superAdmin; + } + + /// + /// 设置合约管理员 + /// + /// + /// + public static bool SetAdmin(byte[] admin) + { + Assert(admin.Length == 20, "NewAdmin Invalid"); + Assert(Runtime.CheckWitness(GetAdmin()), "Forbidden"); + Storage.Put(AdminKey, admin); + return true; + } + + + + #endregion + + } +} diff --git a/Swap/flamingo-contract-swap/FlamingoSwapPairWhiteList/FlamingoSwapPairWhiteList.Helper.cs b/Swap/flamingo-contract-swap/FlamingoSwapPairWhiteList/FlamingoSwapPairWhiteList.Helper.cs new file mode 100644 index 0000000..2f24e49 --- /dev/null +++ b/Swap/flamingo-contract-swap/FlamingoSwapPairWhiteList/FlamingoSwapPairWhiteList.Helper.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Services.Neo; + +namespace FlamingoSwapPairWhiteList +{ + partial class FlamingoSwapPairWhiteList + { + /// + /// 断言 + /// + /// + /// + private static void Assert(bool condition, string message) + { + if (!condition) + { + Runtime.Notify("Fault:" + message); + throw new Exception(message); + } + } + + ///// + ///// 断言,节约gas + ///// + ///// + ///// + //[OpCode(OpCode.THROWIFNOT)] + //[OpCode(OpCode.DROP)] + //private static extern void Assert(bool condition, string message); + + + [OpCode(OpCode.APPEND)] + private static extern void Append(T[] array, T newItem); + } +} diff --git a/Swap/flamingo-contract-swap/FlamingoSwapPairWhiteList/FlamingoSwapPairWhiteList.cs b/Swap/flamingo-contract-swap/FlamingoSwapPairWhiteList/FlamingoSwapPairWhiteList.cs new file mode 100644 index 0000000..21d29a0 --- /dev/null +++ b/Swap/flamingo-contract-swap/FlamingoSwapPairWhiteList/FlamingoSwapPairWhiteList.cs @@ -0,0 +1,128 @@ +using System; +using System.ComponentModel; +using System.Numerics; +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Services.Neo; +using Neo.SmartContract.Framework.Services.System; + +namespace FlamingoSwapPairWhiteList +{ + partial class FlamingoSwapPairWhiteList : SmartContract + { + + /// + /// 允许向LP合约转入LP token的白名单地址 + /// + private const string WhiteList = "WhiteList"; + + + #region 通知 + + /// + /// params: routerHash + /// + [DisplayName("addRouter")] + public static event Action onAddRouter; + + /// + /// params: routerHash + /// + [DisplayName("removeRouter")] + public static event Action onRemoveRouter; + + + #endregion + + public static object Main(string method, object[] args) + { + if (Runtime.Trigger == TriggerType.Verification) + { + return Runtime.CheckWitness(GetAdmin()); + } + else if (Runtime.Trigger == TriggerType.Application) + { + //合约调用时,等价以太坊的msg.sender + //直接调用时,此处为 tx.Script.ToScriptHash(); + //var msgSender = ExecutionEngine.CallingScriptHash; + if (method == "checkRouter") return CheckRouterWhiteList((byte[])args[0]); + if (method == "addRouter") return AddRouterWhiteList((byte[])args[0]); + if (method == "removeRouter") return RemoveRouterWhiteList((byte[])args[0]); + if (method == "getAllRouter") return GetAllRouterWhiteList(); + if (method == "getAdmin") return GetAdmin(); + if (method == "setAdmin") return SetAdmin((byte[])args[0]); + } + return false; + } + + + + /// + /// 增加router白名单,加过白名单的router才能完成burn + /// + /// Nep5 tokenA + /// + public static bool AddRouterWhiteList(byte[] router) + { + Assert(Runtime.CheckWitness(GetAdmin()), "Forbidden"); + Assert(router.Length == 20, "Invalid Router Address"); + var key = WhiteList.AsByteArray().Concat(router); + Storage.Put(key, 1); + onAddRouter(router); + return true; + } + + + /// + /// 移除router白名单,加过白名单的router才能完成burn + /// + /// Nep5 tokenA + /// + public static bool RemoveRouterWhiteList(byte[] router) + { + Assert(Runtime.CheckWitness(GetAdmin()), "Forbidden"); + Assert(router.Length == 20, "Invalid Router Address"); + var key = WhiteList.AsByteArray().Concat(router); + Storage.Delete(key); + onRemoveRouter(router); + return true; + } + + + /// + /// 检查router白名单 + /// + /// Nep5 tokenA + /// + public static bool CheckRouterWhiteList(byte[] router) + { + if (router.Length != 20) + { + return false; + } + var key = WhiteList.AsByteArray().Concat(router); + var value = Storage.Get(key).AsBigInteger(); + return value > 0; + } + + + /// + /// 查询router白名单 + /// + /// + public static byte[][] GetAllRouterWhiteList() + { + var iterator = Storage.Find(WhiteList); + var result = new byte[0][]; + while (iterator.Next()) + { + if (iterator.Value.AsBigInteger() > 0) + { + var router = iterator.Key.AsByteArray().Last(20); + Append(result, router); + } + } + return result; + } + + } +} diff --git a/Swap/flamingo-contract-swap/FlamingoSwapPairWhiteList/FlamingoSwapPairWhiteList.csproj b/Swap/flamingo-contract-swap/FlamingoSwapPairWhiteList/FlamingoSwapPairWhiteList.csproj new file mode 100644 index 0000000..7a39f4a --- /dev/null +++ b/Swap/flamingo-contract-swap/FlamingoSwapPairWhiteList/FlamingoSwapPairWhiteList.csproj @@ -0,0 +1,15 @@ + + + + netcoreapp2.1 + true + + + + + + + + + + diff --git a/Swap/flamingo-contract-swap/flamingo-contract-swap.sln b/Swap/flamingo-contract-swap/flamingo-contract-swap.sln index 557aa94..ab2f3b3 100644 --- a/Swap/flamingo-contract-swap/flamingo-contract-swap.sln +++ b/Swap/flamingo-contract-swap/flamingo-contract-swap.sln @@ -9,7 +9,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FlamingoSwapFactory", "Flam EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FlamingoSwapPair", "FlamingoSwapPair\FlamingoSwapPair.csproj", "{B3C9F843-1172-4A3C-A36B-681AF68907F8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FlamingoSwapRouter", "FlamingoSwapRouter\FlamingoSwapRouter.csproj", "{6B1E966F-2F8F-4B8F-9613-BC64EAE32783}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FlamingoSwapRouter", "FlamingoSwapRouter\FlamingoSwapRouter.csproj", "{6B1E966F-2F8F-4B8F-9613-BC64EAE32783}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FlamingoSwapPairWhiteList", "FlamingoSwapPairWhiteList\FlamingoSwapPairWhiteList.csproj", "{F1EAFA3A-A911-4433-8C66-1C54CF7964B6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -33,6 +35,10 @@ Global {6B1E966F-2F8F-4B8F-9613-BC64EAE32783}.Debug|Any CPU.Build.0 = Debug|Any CPU {6B1E966F-2F8F-4B8F-9613-BC64EAE32783}.Release|Any CPU.ActiveCfg = Release|Any CPU {6B1E966F-2F8F-4B8F-9613-BC64EAE32783}.Release|Any CPU.Build.0 = Release|Any CPU + {F1EAFA3A-A911-4433-8C66-1C54CF7964B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F1EAFA3A-A911-4433-8C66-1C54CF7964B6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F1EAFA3A-A911-4433-8C66-1C54CF7964B6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F1EAFA3A-A911-4433-8C66-1C54CF7964B6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE