private static bool SetAssetSettings(byte[] assetId, byte[] settings) { if (VerifyOwner() == false || (assetId.Length != 20 && assetId.Length != 32)) { return(false); } // Byte 0 (First byte): Transfer type to use. If not set, or set to 0, it will use NEP5 'transfer' // Byte 1-8: Withdraw fee in APH satoshis. Storage.Put(Storage.CurrentContext, PREFIX_ASSET_SETTINGS.Concat(assetId), settings); Runtime.Notify("setAssetSettings", settings); return(true); }
private static bool SendNep5(byte[] toAddress, byte[] assetId, BigInteger amount) { byte[] assetSettings = Storage.Get(Storage.CurrentContext, PREFIX_ASSET_SETTINGS.Concat(assetId)); if (assetSettings.Length == 0) { Runtime.Notify("sendNep5Fail", "Invalid Asset", toAddress, assetId, amount); return(false); } if (Nep5Transfer(assetId, ExecutionEngine.ExecutingScriptHash, toAddress, "transfer", amount) == false) { return(false); } AdjustTotalUserDexBalance(assetId, 0 - amount); // Runtime.Notify("SendNEP5Token() succeeded", assetId, toAddress, amount); return(true); }
private static bool PullNep5(byte[] assetId, byte[] fromAddress, BigInteger amountToPull) { byte[] assetSettings = Storage.Get(Storage.CurrentContext, PREFIX_ASSET_SETTINGS.Concat(assetId)); if (assetSettings.Length == 0) { Runtime.Notify("pullNep5Fail", "Invalid Asset", fromAddress, assetId, amountToPull); return(false); } var transferMethod = assetSettings.Take(1) == USER_ASSET_TYPE_NEP5_EXTENSIONS ? "transferFrom" : "transfer"; if (Nep5Transfer(assetId, fromAddress, ExecutionEngine.ExecutingScriptHash, transferMethod, amountToPull) == false) { return(false); } AdjustTotalUserDexBalance(assetId, amountToPull); //Runtime.Notify("PullNEP5Token() succeeded", assetId, fromAddress, amountToPull); return(true); }
private static bool ExecuteWithdraw() { Transaction tx = (Transaction)ExecutionEngine.ScriptContainer; var attributes = tx.GetAttributes(); var step = EMPTY; var toAddress = EMPTY; var assetId = EMPTY; BigInteger amount = 0; // var step = ReadSignatureRequestType(tx); // var toAddress = ReadWithdrawToAddress(tx); // var assetId = ReadWithdrawAssetId(tx); // Use 1 loop to save gas. foreach (var attr in attributes) { if (attr.Usage == AttributeUsage_SignatureRequestType) { step = attr.Data.Take(1); } else if (attr.Usage == AttributeUsage_WithdrawAddress) { toAddress = attr.Data.Take(20); } else if (attr.Usage == AttributeUsage_WithdrawSystemAssetId) { assetId = attr.Data.Take(32); } else if (attr.Usage == AttributeUsage_WithdrawNEP5AssetId) { assetId = attr.Data.Take(20); } else if (attr.Usage == AttributeUsage_WithdrawAmount) { amount = attr.Data.Take(8).AsBigInteger(); } } object[] notifyArgs; if (step == SignatureRequestTypeWithdrawStepWithdraw) { if (assetId.Length == 20) { byte[] userAssetBalanceKey = toAddress.Concat(assetId); BigInteger balance; bool isOwnerWithdrawingAph = false; if (assetId == APH && toAddress == GetOwner()) { isOwnerWithdrawingAph = true; byte[] poolData = Storage.Get(Storage.CurrentContext, FEES_POOL_KEY); balance = poolData.Range(8, 8).AsBigInteger(); } else { balance = Storage.Get(Storage.CurrentContext, userAssetBalanceKey).AsBigInteger(); } if (balance < amount) { notifyArgs = new object[] { null, "Withdraw NEP5 insufficent balance", toAddress, balance, amount }; goto NotifyWithdrawFail; } var transferSucceeded = SendNep5(toAddress, assetId, amount); if (transferSucceeded == false) { notifyArgs = new object[] { null, "executeWithdraw NEP5 Transfer failed", toAddress, assetId, amount }; goto NotifyWithdrawFail; } balance -= amount; if (isOwnerWithdrawingAph) { SetBalanceOfForWithdrawal(assetId, toAddress, balance); } else { if (balance <= 0) { Storage.Delete(Storage.CurrentContext, userAssetBalanceKey); } else { Storage.Put(Storage.CurrentContext, userAssetBalanceKey, balance.AsByteArray()); } } } else { TransactionInput[] inputs = tx.GetInputs(); if (assetId.Length != 32) { notifyArgs = new object[] { null, "Mark assetId len != 32", toAddress }; goto NotifyWithdrawFail; } DeleteUserValue(toAddress, assetId.Concat(POSTFIX_USER_ASSET_WITHDRAWING)); // NOTE: Could verify the amount passed equals the amount from the user value, but not required since // the amount from the Runtime.Notify is not used for non-nep5 withdraws. // Delete the marked UTXOs foreach (var input in inputs) { // Note this includes inputs not from the contract; but we won't have anything in storage for them // in that case, so it won't be an issue. Storage.Delete(Storage.CurrentContext, input.PrevHash.Concat(ShortToByteArray(input.PrevIndex))); } } Runtime.Notify("withdraw", toAddress, assetId, amount); return(true); } if (step == SignatureRequestTypeWithdrawStepMark) { // ExecuteMarkStep -- INLINE to save space TransactionOutput[] outputs = tx.GetOutputs(); if (assetId.Length == 20) { // NOTE: this is probably dead code because verify step wouldn't let it get this far. notifyArgs = new object[] { null, "Can't mark NEP5", toAddress }; goto NotifyWithdrawFail; } if (assetId.Length != 32) { notifyArgs = new object[] { null, "Mark assetId len != 32", toAddress }; goto NotifyWithdrawFail; } byte[] utxoAmountKey = toAddress.Concat(assetId).Concat(POSTFIX_USER_ASSET_WITHDRAWING); var withdrawingUTXOAmountBytes = Storage.Get(Storage.CurrentContext, utxoAmountKey); if (withdrawingUTXOAmountBytes.Length > 0) { notifyArgs = new object[] { null, "Already withdrawing", toAddress, withdrawingUTXOAmountBytes }; goto NotifyWithdrawFail; } var balance = GetBalanceOfForWithdrawal(assetId, toAddress); if (balance < amount) { notifyArgs = new object[] { null, "Insufficient balance", toAddress, balance, amount }; goto NotifyWithdrawFail; } // Check if there is a withdraw fee imposed byte[] assetSettings = Storage.Get(Storage.CurrentContext, PREFIX_ASSET_SETTINGS.Concat(assetId)); if (assetSettings.Length > 8) { BigInteger aphFee = assetSettings.Range(1, 8).AsBigInteger(); if (aphFee > MAX_APH_WITHDRAW_FEE) { aphFee = MAX_APH_WITHDRAW_FEE; } if (aphFee > 0) { // Everyone other than owner has to pay withdraw fee if one applies. if (toAddress != GetOwner() && NoPullReduceBalanceOf(APH, toAddress, aphFee) == false) { notifyArgs = new object[] { null, "Insufficient APH for withdraw Fee", toAddress, aphFee }; goto NotifyWithdrawFail; } } } balance -= amount; SetBalanceOfForWithdrawal(assetId, toAddress, balance); var reserved = SetOutputReservedFor(tx, outputs, amount, toAddress); if (reserved == false) { notifyArgs = new object[] { null, "Mark Step, failed to reserve output UTXO", toAddress }; goto NotifyWithdrawFail; } // MarkForWithdraw AdjustTotalUserDexBalance(assetId, 0 - amount); // Save the balance being withdrawn for this user in storage so it can be read later Storage.Put(Storage.CurrentContext, utxoAmountKey, amount.ToByteArray()); Runtime.Notify("withdrawMark", toAddress, assetId, amount); return(true); } Runtime.Notify("withdrawFailInvalidStep", step); return(false); NotifyWithdrawFail: notifyArgs[0] = "withdrawFail"; Runtime.Notify(notifyArgs); return(false); }
private static bool SetMarket(object[] args) { string failReason; if (args.Length != 6) { // Runtime.Notify(setMarketFailStr, "requires six parameters", args.Length); return(false); } var quoteAssetId = (byte[])args[0]; var baseAssetId = (byte[])args[1]; if (quoteAssetId.Length != 32 && quoteAssetId.Length != 20 || baseAssetId.Length != 32 && baseAssetId.Length != 20) { failReason = "bad asset len"; goto SetMarketFail; } byte[] marketId = PREFIX_MARKETS.Concat(quoteAssetId).Concat(baseAssetId); Market market; if (VerifyManager() == false && VerifyOwner() == false) { byte[] existingMarket = Storage.Get(Storage.CurrentContext, marketId); if (existingMarket.Length == 0 || VerifyWhitelister() == false) { failReason = "No permission"; goto SetMarketFail; } // Only make it here if the whitelister is calling with an already existing market. // We allow programatically changing the minimumSize, buyFee, and sellFee by the whitelister. market = (Market)existingMarket.Deserialize(); market.MinimumSize = (BigInteger)args[2]; market.BuyFeePercent = (BigInteger)args[4]; market.SellFeePercent = (BigInteger)args[5]; } else { market = new Market(); market.QuoteAssetId = quoteAssetId; market.BaseAssetId = baseAssetId; market.MinimumSize = (BigInteger)args[2]; market.MinimumTickSize = (BigInteger)args[3]; market.BuyFeePercent = (BigInteger)args[4]; market.SellFeePercent = (BigInteger)args[5]; } if (market.BuyFeePercent < 0 || market.SellFeePercent < 0) { failReason = "Fee cannot be negative"; goto SetMarketFail; } // Verify base asset and quote asset have asset settings set byte[] quoteAssetSettings = Storage.Get(Storage.CurrentContext, PREFIX_ASSET_SETTINGS.Concat(market.QuoteAssetId)); byte[] baseAssetSettings = Storage.Get(Storage.CurrentContext, PREFIX_ASSET_SETTINGS.Concat(market.BaseAssetId)); if (quoteAssetSettings.Length == 0 || baseAssetSettings.Length == 0) { failReason = "Invalid Asset"; goto SetMarketFail; } byte[] marketData = market.Serialize(); Storage.Put(Storage.CurrentContext, marketId, marketData); Runtime.Notify("putMarket", marketId, marketData); Runtime.Notify("marketSet", marketId, market.QuoteAssetId, market.BaseAssetId, market.MinimumSize, market.MinimumTickSize, market.BuyFeePercent, market.SellFeePercent); return(true); SetMarketFail: Runtime.Notify("setMarketFail", failReason); return(false); }