Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Orderbookv2 #34

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions Swap/flamingo-contract-swap/FlamingoSwapOrderBook/Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Neo;
using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Attributes;
using System.Numerics;

namespace FlamingoSwapOrderBook
{
public static class Extensions
{
/// <summary>
/// uint160 转为正整数,用于合约地址排序,其它场景勿用
/// </summary>
/// <param name="val">合约地址</param>
/// <returns></returns>
[OpCode(OpCode.PUSHDATA1, "0100")]
[OpCode(OpCode.CAT)]
[OpCode(OpCode.CONVERT, "21")]
public static extern BigInteger ToUInteger(this UInt160 val);

/// <summary>
/// Is Valid and not Zero address
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
public static bool IsAddress(this UInt160 address)
{
return address.IsValid && !address.IsZero;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Neo3.Compiler.CSharp.Dev" Version="3.1.0" />
<PackageReference Include="Neo.SmartContract.Framework" Version="3.1.0" />
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="$(neon3) $(ProjectDir)" />
</Target>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
using Neo;
using Neo.SmartContract;
using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Attributes;
using Neo.SmartContract.Framework.Native;
using Neo.SmartContract.Framework.Services;

namespace FlamingoSwapOrderBook
{
public partial class FlamingoSwapOrderBookContract
{
#region Admin

#warning Update the admin address if necessary
[InitialValue("NdDvLrbtqeCVQkaLstAwh3md8SYYwqWRaE", ContractParameterType.Hash160)]
static readonly UInt160 superAdmin = default;

[InitialValue("0xc0695bdb8a87a40aff33c73ff6349ccc05fa9f01", ContractParameterType.Hash160)]
static readonly UInt160 Factory = default;

[InitialValue("0xd6abe115ecb75e1fa0b42f5e85934ce8c1ae2893", ContractParameterType.Hash160)]
static readonly UInt160 bNEO = default;

static readonly uint ORDER_PER_PAGE = 1 << 8;

private const string AdminKey = nameof(superAdmin);
private const string GASAdminKey = nameof(GASAdminKey);
private const string FundAddresskey = nameof(FundAddresskey);

private static readonly byte[] OrderCounterKey = new byte[] { 0x00 };
private static readonly byte[] PageCounterKey = new byte[] { 0x01 };
private static readonly byte[] BookMapPrefix = new byte[] { 0x02 };
private static readonly byte[] PageMapPrefix = new byte[] { 0x03 };
private static readonly byte[] OrderIndexPrefix = new byte[] { 0x04 };
private static readonly byte[] MakerIndexPrefix = new byte[] { 0x05 };
private static readonly byte[] OrderMapPrefix = new byte[] { 0x06 };

// When this contract address is included in the transaction signature,
// this method will be triggered as a VerificationTrigger to verify that the signature is correct.
// For example, this method needs to be called when withdrawing token from the contract.
[Safe]
public static bool Verify() => Runtime.CheckWitness(GetAdmin());

[Safe]
public static UInt160 GetAdmin()
{
var admin = Storage.Get(Storage.CurrentReadOnlyContext, AdminKey);
return admin?.Length == 20 ? (UInt160)admin : superAdmin;
}

public static bool SetAdmin(UInt160 admin)
{
Assert(Verify(), "No Authorization");
Assert(admin.IsAddress(), "Invalid Address");
Storage.Put(Storage.CurrentContext, AdminKey, admin);
return true;
}

public static void ClaimGASFrombNEO(UInt160 receiveAddress)
{
Assert(Runtime.CheckWitness(GetGASAdmin()), "Forbidden");
var me = Runtime.ExecutingScriptHash;
var beforeBalance = GAS.BalanceOf(me);
Assert((bool)Contract.Call(bNEO, "transfer", CallFlags.All, Runtime.ExecutingScriptHash, bNEO, 0, null), "claim fail");
var afterBalance = GAS.BalanceOf(me);

GAS.Transfer(me, receiveAddress, afterBalance - beforeBalance);
}

[Safe]
public static UInt160 GetGASAdmin()
{
var address = Storage.Get(Storage.CurrentReadOnlyContext, GASAdminKey);
return address?.Length == 20 ? (UInt160)address : null;
}

public static bool SetGASAdmin(UInt160 GASAdmin)
{
Assert(GASAdmin.IsAddress(), "Invalid Address");
Assert(Verify(), "No Authorization");
Storage.Put(Storage.CurrentContext, GASAdminKey, GASAdmin);
return true;
}
#endregion

#region FundFee

[Safe]
public static UInt160 GetFundAddress()
{
var address = Storage.Get(Storage.CurrentReadOnlyContext, FundAddresskey);
return address?.Length == 20 ? (UInt160)address : null;
}

public static bool SetFundAddress(UInt160 address)
{
Assert(address.IsAddress(), "Invalid Address");
Assert(Verify(), "No Authorization");
Storage.Put(Storage.CurrentContext, FundAddresskey, address);
return true;
}
#endregion

#region Upgrade

public static void Update(ByteString nefFile, string manifest)
{
Assert(Verify(), "No Authorization");
ContractManagement.Update(nefFile, manifest, null);
}
#endregion
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Neo;
using Neo.SmartContract.Framework;
using System.ComponentModel;
using System.Numerics;

namespace FlamingoSwapOrderBook
{
public partial class FlamingoSwapOrderBookContract
{
/// <summary>
/// When orderbook status changed
/// </summary>
[DisplayName("BookStatusChanged")]
public static event BookStatusChangedEvent onBookStatusChanged;
public delegate void BookStatusChangedEvent(UInt160 baseToken, UInt160 quoteToken, BigInteger quoteScale, BigInteger minOrderAmount, BigInteger maxOrderAmount, bool isPaused);

/// <summary>
/// When order status changed
/// </summary>
[DisplayName("OrderStatusChanged")]
public static event OrderStatusChangedEvent onOrderStatusChanged;
public delegate void OrderStatusChangedEvent(UInt160 baseToken, UInt160 quoteToken, ByteString id, bool isBuy, UInt160 maker, BigInteger price, BigInteger leftAmount);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
using Neo;
using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Attributes;
using Neo.SmartContract.Framework.Services;
using System;
using System.Numerics;

namespace FlamingoSwapOrderBook
{
public partial class FlamingoSwapOrderBookContract
{

[OpCode(OpCode.APPEND)]
private static extern void Append<T>(T[] array, T newItem);

/// <summary>
/// 断言
/// </summary>
/// <param name="condition"></param>
/// <param name="message"></param>
private static void Assert(bool condition, string message)
{
if (!condition)
{
throw new Exception(message);
}
}

/// <summary>
/// 断言
/// </summary>
/// <param name="condition"></param>
/// <param name="message"></param>
/// <param name="data"></param>
private static void Assert(bool condition, string message, params object[] data)
{
if (!condition)
{
throw new Exception(message);
}
}

/// <summary>
/// 查询token缩写
/// </summary>
/// <param name="condition"></param>
/// <param name="message"></param>
/// <param name="data"></param>
public static string GetTokenSymbol(UInt160 token)
{
Assert(token.IsValid, "Invalid Address");
return (string)Contract.Call(token, "symbol", CallFlags.ReadOnly, new object[] {});
}

/// <summary>
/// 安全查询交易对,查不到立即中断合约执行
/// </summary>
/// <param name="tokenA"></param>
/// <param name="tokenB"></param>
/// <returns></returns>
public static UInt160 GetExchangePairWithAssert(UInt160 tokenA, UInt160 tokenB)
{
Assert(tokenA.IsValid && tokenB.IsValid, "Invalid A or B Address");
var pairContract = (byte[])Contract.Call(Factory, "getExchangePair", CallFlags.ReadOnly, new object[] { tokenA, tokenB });
Assert(pairContract != null && pairContract.Length == 20, "PairContract Not Found", tokenA, tokenB);
return (UInt160)pairContract;
}

/// <summary>
/// 查询TokenA,TokenB交易对合约的里的持有量并按A、B顺序返回
/// </summary>
/// <param name="pairContract"></param>
/// <param name="tokenA"></param>
/// <param name="tokenB"></param>
/// <returns></returns>
public static BigInteger[] GetReserves(UInt160 pairContract, UInt160 tokenA, UInt160 tokenB)
{
var reserveData = (ReservesData)Contract.Call(pairContract, "getReserves", CallFlags.ReadOnly, new object[] { });
return tokenA.ToUInteger() < tokenB.ToUInteger() ? new BigInteger[] { reserveData.Reserve0, reserveData.Reserve1 } : new BigInteger[] { reserveData.Reserve1, reserveData.Reserve0 };
}

/// <summary>
/// 查询交易对合约是否抽取fundfee
/// </summary>
/// <param name="pairContract"></param>
/// <returns></returns>
public static bool HasFundAddress(UInt160 pairContract)
{
return (byte[])Contract.Call(pairContract, "getFundAddress", CallFlags.ReadOnly, new object[] { }) != null;
}

/// <summary>
/// 向资金池转发兑出请求
/// </summary>
/// <param name="pairContract"></param>
/// <param name="amount0Out"></param>
/// <param name="amount1Out"></param>
/// <param name="toAddress"></param>
private static void SwapOut(UInt160 pairContract, BigInteger amount0Out, BigInteger amount1Out, UInt160 toAddress)
{
Contract.Call(pairContract, "swap", CallFlags.All, new object[] { amount0Out, amount1Out, toAddress, null });
}

/// <summary>
/// Transfer NEP-5 tokens from user
/// </summary>
/// <param name="token"></param>
/// <param name="from"></param>
/// <param name="to"></param>
/// <param name="amount"></param>
/// <param name="data"></param>
/// <returns></returns>
private static void SafeTransfer(UInt160 token, UInt160 from, UInt160 to, BigInteger amount, byte[] data = null)
{
try
{
var result = (bool)Contract.Call(token, "transfer", CallFlags.All, new object[] { from, to, amount, data });
Assert(result, "Transfer Fail in OrderBook", token);
}
catch (Exception)
{
Assert(false, "Transfer Error in OrderBook", token);
}
}

/// <summary>
/// Transfer NEP-5 tokens from contract
/// </summary>
/// <param name="token"></param>
/// <param name="from"></param>
/// <param name="to"></param>
/// <param name="amount"></param>
/// <param name="data"></param>
/// <returns></returns>
private static void RequestTransfer(UInt160 token, UInt160 from, UInt160 to, BigInteger amount, byte[] data = null)
{
try
{
var balanceBefore = (BigInteger)Contract.Call(token, "balanceOf", CallFlags.ReadOnly, new object[] { to });
var result = (bool)Contract.Call(from, "approvedTransfer", CallFlags.All, new object[] { token, to, amount, data });
var balanceAfter = (BigInteger)Contract.Call(token, "balanceOf", CallFlags.ReadOnly, new object[] { to });
Assert(result, "Transfer Not Approved in OrderBook", token);
Assert(balanceAfter == balanceBefore + amount, "Unexpected Transfer in OrderBook", token);
}
catch (Exception)
{
Assert(false, "Transfer Error in OrderBook", token);
}
}
}
}
Loading