/// <summary> Sell bit asset. </summary> /// /// <remarks> Paul, 16/02/2015. </remarks> /// /// <param name="l"> The BitsharesLedgerEntry to process. </param> /// <param name="s2d"> The 2D. </param> /// <param name="trxId"> Identifier for the trx. </param> protected virtual void SellBitAsset(BitsharesLedgerEntry l, SenderToDepositRow s2d, string trxId) { decimal oldBid = m_market.bid; try { if (m_market.price_discovery) { // // adjust prices based on order // decimal informed = m_asset.GetAmountFromLarimers(l.amount.amount) / m_market.bid_max; m_market.bid = m_prices.GetBidForSell(informed); } string btcAddress = s2d.receiving_address; SendBitcoinsToDepositor(btcAddress, trxId, l.amount.amount, m_asset, s2d.deposit_address, MetaOrderType.sell, m_currency.uia); if (m_market.price_discovery) { // update database with new prices m_isDirty = true; } } catch (Exception e) { // also lets now ignore this transaction so we don't keep failing RefundBitsharesDeposit(l.from_account, l.amount.amount, trxId, e.Message, m_asset, s2d.deposit_address, MetaOrderType.sell); // restore this m_market.bid = oldBid; } }
/// <summary> Handles the bitshares deposit described by kvp. </summary> /// /// <remarks> Paul, 05/02/2015. </remarks> /// /// <param name="kvp"> The kvp. </param> public override void HandleBitsharesDeposit(KeyValuePair <string, BitsharesLedgerEntry> kvp) { // get the btc address BitsharesLedgerEntry l = kvp.Value; string trxId = kvp.Key; SenderToDepositRow s2d = BitsharesTransactionToBitcoinAddress(l); SellBitAsset(l, s2d, trxId); }
/// <summary> Refund bitcoin deposit. </summary> /// /// <remarks> Paul, 15/01/2015. </remarks> /// /// <param name="t"> The TransactionSinceBlock to process. </param> protected void RefundBitcoinDeposit(TransactionSinceBlock t, string notes, SenderToDepositRow s2d, MetaOrderType orderType) { m_daemon.MarkTransactionAsRefundedStart(t.TxId, s2d.deposit_address, m_market.symbol_pair, orderType); // get public key out of transaction string firstPubKey = GetAllPubkeysFromBitcoinTransaction(t.TxId).First(); PublicKey pk = new PublicKey(firstPubKey, m_daemon.m_AddressByteType); // refund deposit string sentTxid = m_bitcoin.SendToAddress(pk.AddressBase58, t.Amount); // mark as such m_daemon.MarkTransactionAsRefundedEnd(t.TxId, sentTxid, MetaOrderStatus.refunded, t.Amount, notes); }
/// <summary> Gets bitshares account from bitcoin deposit. </summary> /// /// <remarks> Paul, 05/02/2015. </remarks> /// /// <param name="t"> The TransactionSinceBlock to process. </param> /// /// <returns> The bitshares account from bitcoin deposit. </returns> protected SenderToDepositRow GetBitsharesAccountFromBitcoinDeposit(TransactionSinceBlock t) { // look up the deposit address in our map of sender->deposit SenderToDepositRow senderToDeposit = m_daemon.m_Database.GetSenderDepositIgnoreReferral(t.Address, m_market.symbol_pair); if (senderToDeposit != null) { return(senderToDeposit); } else { return(null); } }
string SubmitValidBitsharesAccount(string market) { string content = SubmitAddress(kBitsharesAccount, MetaOrderType.buy, market); MarketRow m = GetMarket(market); SenderToDepositRow s2d = m_database.Query <SenderToDepositRow>("SELECT * FROM sender_to_deposit WHERE receiving_address=@r AND symbol_pair=@m;", kBitsharesAccount, m.symbol_pair).FirstOrDefault(); string reality = JsonSerializer.SerializeToString <SubmitAddressResponse>(new SubmitAddressResponse { deposit_address = s2d.deposit_address }); content.Should().Be.EqualTo(reality); return(content); }
/// <summary> Handles the bitcoin deposit described by t. </summary> /// /// <remarks> Paul, 05/02/2015. </remarks> /// /// <param name="t"> The TransactionSinceBlock to process. </param> public override void HandleBitcoinDeposit(TransactionSinceBlock t) { SenderToDepositRow s2d = GetBitsharesAccountFromBitcoinDeposit(t); if (t.Confirmations >= DaemonBase.kBitcoinConfirms) { BuyBitAsset(t, s2d); } else { // mark this transaction as pending if it doesn't already exist if (m_daemon.m_Database.GetTransaction(t.TxId) == null) { m_daemon.m_Database.MarkDespositAsCreditedStart(t.TxId, s2d.deposit_address, m_market.symbol_pair, MetaOrderType.buy, MetaOrderStatus.pending); } } }
/// <summary> Sends a bit assets to depositor. </summary> /// /// <remarks> Paul, 05/02/2015. </remarks> /// /// <exception cref="RefundBitcoinException"> Thrown when a Refund Bitcoin error condition /// occurs. </exception> /// /// <param name="t"> The TransactionSinceBlock to process. </param> /// <param name="asset"> The asset. </param> /// /// <returns> A BitsharesTransactionResponse. </returns> protected BitsharesTransactionResponse SendBitAssetsToDepositor(TransactionSinceBlock t, BitsharesAsset asset, SenderToDepositRow s2d, MetaOrderType orderType) { // make sure failures after this point do not result in repeated sending m_daemon.MarkDespositAsCreditedStart(t.TxId, s2d.deposit_address, m_market.symbol_pair, orderType, MetaOrderStatus.processing, TransactionPolicy.REPLACE); if (t.Amount > m_market.ask_max) { throw new RefundBitcoinException("Over " + Numeric.SerialisedDecimal(m_market.ask_max) + " " + asset.symbol + "!"); } string bitsharesAccount = s2d.receiving_address; decimal bitAssetAmountNoFee; if (m_flipped) { // they're sending us BTC, not bitAssets because the market is flipped, this is // equivelent to the opposite order type, so we have to use bid here bitAssetAmountNoFee = t.Amount * m_market.bid; } else { bitAssetAmountNoFee = t.Amount / m_market.ask; } // when buying, the fee is charged in bitAssets, // the amount recorded in the transaction is the amount of bitAssets purchased sans fee bitAssetAmountNoFee = asset.Truncate(bitAssetAmountNoFee); decimal fee = (m_market.ask_fee_percent / 100) * bitAssetAmountNoFee; decimal amountAsset = bitAssetAmountNoFee - fee; amountAsset = asset.Truncate(amountAsset); BitsharesTransactionResponse bitsharesTrx = SendBitAssets(amountAsset, asset, bitsharesAccount, "mX: " + orderType + " " + asset.symbol); m_daemon.MarkDespositAsCreditedEnd(t.TxId, bitsharesTrx.record_id, MetaOrderStatus.completed, bitAssetAmountNoFee, m_market.ask, fee); return(bitsharesTrx); }
/// <summary> Bitshares transaction to bitcoin address. </summary> /// /// <remarks> Paul, 05/02/2015. </remarks> /// /// <exception cref="RefundBitsharesException"> Thrown when a Refund Bitshares error condition /// occurs. </exception> /// /// <param name="l"> The BitsharesLedgerEntry to process. </param> /// /// <returns> A string. </returns> protected SenderToDepositRow BitsharesTransactionToBitcoinAddress(BitsharesLedgerEntry l) { // look up the BTS address this transaction was sent to // look that address up in our map of sender->deposit address // pull the market uid out of the memo string symbolPair; uint referralUser; MemoExtract(l.memo, out symbolPair, out referralUser); SenderToDepositRow senderToDeposit = m_daemon.GetSenderDepositFromDeposit(l.memo, symbolPair, referralUser); if (senderToDeposit != null) { return(senderToDeposit); } else { throw new RefundBitsharesException("Missing/bad memo!"); } }
/// <summary> Buy bit asset. </summary> /// /// <remarks> Paul, 16/02/2015. </remarks> /// /// <param name="t"> The TransactionSinceBlock to process. </param> /// <param name="s2d"> The 2D. </param> protected virtual void BuyBitAsset(TransactionSinceBlock t, SenderToDepositRow s2d) { decimal oldAsk = m_market.ask; try { if (m_market.price_discovery) { // // adjust prices based on order // decimal informed = t.Amount / m_market.ask_max; m_market.ask = m_prices.GetAskForBuy(informed); } SendBitAssetsToDepositor(t, m_asset, s2d, MetaOrderType.buy); if (m_market.price_discovery) { // update database with new prices m_isDirty = true; } } catch (Exception e) { // lets hear about what went wrong m_daemon.LogGeneralException(e.ToString()); // also lets now ignore this transaction so we don't keep failing RefundBitcoinDeposit(t, e.Message, s2d, MetaOrderType.buy); // restore this m_market.ask = oldAsk; } }
/// <summary> Executes the submit address action. </summary> /// /// <remarks> Paul, 05/02/2015. </remarks> /// /// <exception cref="ApiExceptionMessage"> Thrown when an API exception message error /// condition occurs. </exception> /// <exception cref="UnexpectedCaseException"> Thrown when an Unexpected Case error condition /// occurs. </exception> /// /// <param name="receivingAddress"> The receiving address. </param> /// <param name="orderType"> Type of the order. </param> /// /// <returns> A SubmitAddressResponse. </returns> public override SubmitAddressResponse OnSubmitAddress(string receivingAddress, MetaOrderType orderType, uint referralUser) { SubmitAddressResponse response; if (orderType == MetaOrderType.buy) { string accountName = receivingAddress; bool isPublicKey = BitsharesPubKey.IsValidPublicKey(accountName); // check for theoretical validity if (!isPublicKey && !BitsharesWallet.IsValidAccountName(accountName)) { throw new ApiExceptionInvalidAccount(accountName); } // try and retrieve a previous entry SenderToDepositRow senderToDeposit = m_daemon.GetSenderDepositFromReceiver(accountName, m_market.symbol_pair, referralUser); if (senderToDeposit == null) { // no dice, create a new entry // check for actual validity string rcA; if (!isPublicKey) { BitsharesAccount account = m_bitshares.GetAccount(accountName); if (account == null) { throw new ApiExceptionInvalidAccount(accountName); } rcA = account.name; } else { rcA = accountName; } // generate a new bitcoin address and tie it to this account string depositAdress = m_bitcoin.GetNewAddress(); senderToDeposit = m_daemon.InsertSenderToDeposit(rcA, depositAdress, m_market.symbol_pair, referralUser); } response = new SubmitAddressResponse { deposit_address = senderToDeposit.deposit_address, receiving_address = senderToDeposit.receiving_address }; } else if (orderType == MetaOrderType.sell) { string bitcoinAddress = receivingAddress; // validate bitcoin address byte[] check = Util.Base58CheckToByteArray(bitcoinAddress); if (check == null) { throw new ApiExceptionInvalidAddress(bitcoinAddress); } // try and retrieve a previous entry SenderToDepositRow senderToDeposit = m_daemon.GetSenderDepositFromReceiver(bitcoinAddress, m_market.symbol_pair, referralUser); if (senderToDeposit == null) { // generate a memo field to use instead senderToDeposit = m_daemon.InsertSenderToDeposit(bitcoinAddress, MarketBase.CreateMemo(bitcoinAddress, m_market.symbol_pair, referralUser), m_market.symbol_pair, referralUser); } response = new SubmitAddressResponse { deposit_address = m_bitsharesAccount, receiving_address = senderToDeposit.receiving_address, memo = senderToDeposit.deposit_address }; } else { throw new UnexpectedCaseException(); } return(response); }