Add files via upload
This commit is contained in:
93
src/ShapeShift/CancelResult.cs
Normal file
93
src/ShapeShift/CancelResult.cs
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Kalakoi.Crypto.ShapeShift
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides ability to cancel pending exchanges.
|
||||||
|
/// </summary>
|
||||||
|
public class CancelResult
|
||||||
|
{
|
||||||
|
/*url: shapeshift.io/cancelpending
|
||||||
|
method: POST
|
||||||
|
data type: JSON
|
||||||
|
data required: address = The deposit address associated with the pending transaction
|
||||||
|
|
||||||
|
Example data : {address : "1HB5XMLmzFVj8ALj6mfBsbifRoD4miY36v"}
|
||||||
|
|
||||||
|
Success Output:
|
||||||
|
|
||||||
|
{ success : " Pending Transaction cancelled " }
|
||||||
|
|
||||||
|
Error Output:
|
||||||
|
|
||||||
|
{ error : {errorMessage} }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// True if cancel was successful.
|
||||||
|
/// </summary>
|
||||||
|
public bool Success { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Message returned from cancel operation, if any.
|
||||||
|
/// </summary>
|
||||||
|
public string Message { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Error message thrown during cancel, if any.
|
||||||
|
/// </summary>
|
||||||
|
public string Error { get; private set; }
|
||||||
|
|
||||||
|
private CancelResult() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to cancel pending exchange
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Address">The deposit address associated with the pending transaction.</param>
|
||||||
|
/// <returns>Result of cancel operation.</returns>
|
||||||
|
internal static async Task<CancelResult> CancelAsync(string Address)
|
||||||
|
{
|
||||||
|
//Get URI for POST request
|
||||||
|
Uri uri = GetUri();
|
||||||
|
//Generate JSON data string
|
||||||
|
string data = CreateData(Address);
|
||||||
|
//Send POST request
|
||||||
|
string response = await RestServices.GetPostResponseAsync(uri, data).ConfigureAwait(false);
|
||||||
|
//Parse response for results
|
||||||
|
return await ParseResponseAsync(response).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri GetUri() =>
|
||||||
|
new Uri(@"https://shapeshift.io/cancelpending");
|
||||||
|
|
||||||
|
private static string CreateData(string Address) =>
|
||||||
|
"{" + string.Format("\"address\":\"{0}\"", Address) + "}";
|
||||||
|
|
||||||
|
private static async Task<CancelResult> ParseResponseAsync(string response)
|
||||||
|
{
|
||||||
|
CancelResult result = new CancelResult();
|
||||||
|
using (JsonTextReader jtr = new JsonTextReader(new StringReader(response)))
|
||||||
|
{
|
||||||
|
while (await jtr.ReadAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
if (jtr.Value == null) continue;
|
||||||
|
else if (jtr.Value.ToString() == "success")
|
||||||
|
{
|
||||||
|
result.Success = true;
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
result.Message = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "error")
|
||||||
|
{
|
||||||
|
result.Success = false;
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
result.Error = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
103
src/ShapeShift/EmailReceipt.cs
Normal file
103
src/ShapeShift/EmailReceipt.cs
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Kalakoi.Crypto.ShapeShift
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Status of Email request.
|
||||||
|
/// </summary>
|
||||||
|
public enum EmailStatuses { Success, Failure }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides ability to request a receipt for a transaction to be sent via email.
|
||||||
|
/// </summary>
|
||||||
|
public class EmailReceipt
|
||||||
|
{
|
||||||
|
/*url: shapeshift.io/mail
|
||||||
|
method: POST
|
||||||
|
data type: JSON
|
||||||
|
data required:
|
||||||
|
email = the address for receipt email to be sent to
|
||||||
|
txid = the transaction id of the transaction TO the user (ie the txid for the withdrawal NOT the deposit)
|
||||||
|
example data {"email":"mail@example.com", "txid":"123ABC"}
|
||||||
|
|
||||||
|
Success Output:
|
||||||
|
{"email":
|
||||||
|
{
|
||||||
|
"status":"success",
|
||||||
|
"message":"Email receipt sent"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Status of receipt request.
|
||||||
|
/// </summary>
|
||||||
|
public EmailStatuses Status { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Message returned by request, if any.
|
||||||
|
/// </summary>
|
||||||
|
public string Message { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Error thrown by request, if any.
|
||||||
|
/// </summary>
|
||||||
|
public string Error { get; private set; }
|
||||||
|
|
||||||
|
private EmailReceipt() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Requests a receipt for transaction to be sent via email.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Email">Email address to send receipt to.</param>
|
||||||
|
/// <param name="TxID">Transaction ID of the transaction sent to the user.</param>
|
||||||
|
/// <returns>Result of receipt request.</returns>
|
||||||
|
internal static async Task<EmailReceipt> RequestAsync(string Email, string TxID)
|
||||||
|
{
|
||||||
|
//Get URI for POST request
|
||||||
|
Uri uri = GetUri();
|
||||||
|
//Generate JSON data as string to send
|
||||||
|
string data = CreateData(Email, TxID);
|
||||||
|
//Send POST request and awaits response
|
||||||
|
string response = await RestServices.GetPostResponseAsync(uri, data).ConfigureAwait(false);
|
||||||
|
//Parse response for results
|
||||||
|
return await ParseResponseAsync(response).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri GetUri() =>
|
||||||
|
new Uri(@"https://shapeshift.io/mail");
|
||||||
|
|
||||||
|
private static string CreateData(string Email, string TxID) =>
|
||||||
|
"{" + string.Format("\"email\":\"{0}\", \"txid\":\"{1}\"", Email, TxID) + "}";
|
||||||
|
|
||||||
|
private static async Task<EmailReceipt> ParseResponseAsync(string response)
|
||||||
|
{
|
||||||
|
EmailReceipt receipt = new EmailReceipt();
|
||||||
|
using (JsonTextReader jtr = new JsonTextReader(new StringReader(response)))
|
||||||
|
{
|
||||||
|
while (await jtr.ReadAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
if (jtr.Value == null) continue;
|
||||||
|
else if (jtr.Value.ToString() == "status")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
receipt.Status = jtr.Value.ToString() == "success" ? EmailStatuses.Success : EmailStatuses.Failure;
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "message")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
receipt.Message = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "error")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
receipt.Error = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return receipt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
139
src/ShapeShift/QuoteRequest.cs
Normal file
139
src/ShapeShift/QuoteRequest.cs
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Kalakoi.Crypto.ShapeShift
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides ability to request quotes for specific pair exchanges.
|
||||||
|
/// </summary>
|
||||||
|
public class QuoteRequest
|
||||||
|
{
|
||||||
|
/*url: shapeshift.io/sendamount
|
||||||
|
method: POST
|
||||||
|
data type: JSON
|
||||||
|
|
||||||
|
Data required:
|
||||||
|
|
||||||
|
amount = the amount to be sent to the withdrawal address
|
||||||
|
pair = what coins are being exchanged in the form [input coin]_[output coin] ie ltc_btc
|
||||||
|
|
||||||
|
example data {"amount":123, "pair":"ltc_btc"}
|
||||||
|
|
||||||
|
Success Output:
|
||||||
|
|
||||||
|
{
|
||||||
|
success:
|
||||||
|
{
|
||||||
|
pair: [pair],
|
||||||
|
withdrawalAmount: [Withdrawal Amount], // Amount of the output coin you will receive
|
||||||
|
depositAmount: [Deposit Amount], // Exact amount of input coin to send in
|
||||||
|
expiration: [timestamp when this will expire],
|
||||||
|
quotedRate: [the exchange rate to be honored]
|
||||||
|
minerFee: [miner fee for this transaction]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Coin pair to exchange between.
|
||||||
|
/// </summary>
|
||||||
|
public string Pair { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Amount of coin to be received by user.
|
||||||
|
/// </summary>
|
||||||
|
public double WithdrawalAmount { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Amount of coin required to be deposited.
|
||||||
|
/// </summary>
|
||||||
|
public double DepositAmount { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Expiration timestamp of quote.
|
||||||
|
/// </summary>
|
||||||
|
public double Expiration { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Quoted rate of exchange.
|
||||||
|
/// </summary>
|
||||||
|
public double QuotedRate { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Fee to be sent to miners to fascilitate exchange.
|
||||||
|
/// </summary>
|
||||||
|
public double MinerFee { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Error thrown by request, if any.
|
||||||
|
/// </summary>
|
||||||
|
public string Error { get; private set; }
|
||||||
|
|
||||||
|
private QuoteRequest() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Requests a quote for an exchange without exchanging.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Pair">Coin pair to exchange between.</param>
|
||||||
|
/// <param name="Amount">Amount of coin to be sent to withdrawal address.</param>
|
||||||
|
/// <returns>Quote for exchange information.</returns>
|
||||||
|
internal static async Task<QuoteRequest> RequestAsync(string Pair, double Amount)
|
||||||
|
{
|
||||||
|
Uri uri = GetUri();
|
||||||
|
string data = CreateData(Pair, Amount);
|
||||||
|
string response = await RestServices.GetPostResponseAsync(uri, data).ConfigureAwait(false);
|
||||||
|
return await ParseResponseAsync(response).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri GetUri() =>
|
||||||
|
new Uri(@"https://shapeshift.io/sendamount");
|
||||||
|
|
||||||
|
private static string CreateData(string Pair, double Amount) =>
|
||||||
|
"{" + string.Format("\"amount\":\"{0}\", \"pair\":\"{1}\"", Amount.ToString(), Pair) + "}";
|
||||||
|
|
||||||
|
private static async Task<QuoteRequest> ParseResponseAsync(string response)
|
||||||
|
{
|
||||||
|
QuoteRequest request = new QuoteRequest();
|
||||||
|
using (JsonTextReader jtr = new JsonTextReader(new StringReader(response)))
|
||||||
|
{
|
||||||
|
while (await jtr.ReadAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
if (jtr.Value == null) continue;
|
||||||
|
else if (jtr.Value.ToString() == "pair")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
request.Pair = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "withdrawalAmount")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
request.WithdrawalAmount = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "depositAmount")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
request.DepositAmount = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "expiration")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
request.Expiration = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "quotedRate")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
request.QuotedRate = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "minerFee")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
request.MinerFee = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "error")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
request.Error = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
116
src/ShapeShift/RecentTx.cs
Normal file
116
src/ShapeShift/RecentTx.cs
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Kalakoi.Crypto.ShapeShift
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides access to information on recent exchanges completed by ShapeShift.
|
||||||
|
/// </summary>
|
||||||
|
public class RecentTx
|
||||||
|
{
|
||||||
|
/*url: shapeshift.io/recenttx/[max]
|
||||||
|
method: GET
|
||||||
|
|
||||||
|
[max] is an optional maximum number of transactions to return.
|
||||||
|
If [max] is not specified this will return 5 transactions.
|
||||||
|
Also, [max] must be a number between 1 and 50 (inclusive).
|
||||||
|
|
||||||
|
Success Output:
|
||||||
|
[
|
||||||
|
{
|
||||||
|
curIn : [currency input],
|
||||||
|
curOut: [currency output],
|
||||||
|
amount: [amount],
|
||||||
|
timestamp: [time stamp] //in seconds
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Currency user sent to exchange.
|
||||||
|
/// </summary>
|
||||||
|
public string CurrencyInput { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Currency user requested from exchange.
|
||||||
|
/// </summary>
|
||||||
|
public string CurrencyOutput { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Amount sent to user's withdrawal address.
|
||||||
|
/// </summary>
|
||||||
|
public double Amount { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Timestamp of exchange.
|
||||||
|
/// </summary>
|
||||||
|
public double TimeStamp { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets information on recent transactions completed by ShapeShift.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Max">Maximum number of transactions to return. Must be betweeen 1 and 50, inclusive.</param>
|
||||||
|
/// <returns>List of recent transactions.</returns>
|
||||||
|
internal static async Task<List<RecentTx>> GetRecentTransactionsAsync(int Max)
|
||||||
|
{
|
||||||
|
if (Max < 1 || Max > 50) throw new InvalidOperationException();
|
||||||
|
Uri uri = GetUri(Max);
|
||||||
|
string response = await RestServices.GetResponseAsync(uri).ConfigureAwait(false);
|
||||||
|
return await ParseResponseAsync(response).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Gets information on recent transactions completed by ShapeShift.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>List of last 5 transactions.</returns>
|
||||||
|
internal static async Task<List<RecentTx>> GetRecentTransactionsAsync() =>
|
||||||
|
await GetRecentTransactionsAsync(5).ConfigureAwait(false);
|
||||||
|
|
||||||
|
private static Uri GetUri(int max = 5) =>
|
||||||
|
new Uri(string.Format(@"https://shapeshift.io/recenttx/{0}", max.ToString()));
|
||||||
|
|
||||||
|
private static async Task<List<RecentTx>> ParseResponseAsync(string response)
|
||||||
|
{
|
||||||
|
List<RecentTx> TxList = new List<RecentTx>();
|
||||||
|
RecentTx NewTx = new RecentTx();
|
||||||
|
using (JsonTextReader jtr = new JsonTextReader(new StringReader(response)))
|
||||||
|
{
|
||||||
|
while (await jtr.ReadAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
if (jtr.TokenType.ToString() == "StartObject")
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(NewTx.CurrencyInput))
|
||||||
|
TxList.Add(NewTx);
|
||||||
|
NewTx = new RecentTx();
|
||||||
|
}
|
||||||
|
else if (jtr.Value == null) continue;
|
||||||
|
else if (jtr.Value.ToString() == "curIn")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
NewTx.CurrencyInput = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "curOut")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
NewTx.CurrencyOutput = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "amount")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
NewTx.Amount = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "timestamp")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
NewTx.TimeStamp = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(NewTx.CurrencyInput))
|
||||||
|
TxList.Add(NewTx);
|
||||||
|
|
||||||
|
return TxList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
185
src/ShapeShift/SendAmountRequest.cs
Normal file
185
src/ShapeShift/SendAmountRequest.cs
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Kalakoi.Crypto.ShapeShift
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides ability to request amount needed to be sent to complete transaction.
|
||||||
|
/// </summary>
|
||||||
|
public class SendAmountRequest
|
||||||
|
{
|
||||||
|
/*url: shapeshift.io/sendamount
|
||||||
|
method: POST
|
||||||
|
data type: JSON
|
||||||
|
|
||||||
|
Data required:
|
||||||
|
|
||||||
|
amount = the amount to be sent to the withdrawal address
|
||||||
|
withdrawal = the address for coin to be sent to
|
||||||
|
pair = what coins are being exchanged in the form [input coin]_[output coin] ie ltc_btc
|
||||||
|
returnAddress = (Optional) address to return deposit to if anything goes wrong with exchange
|
||||||
|
destTag = (Optional) Destination tag that you want appended to a Ripple payment to you
|
||||||
|
rsAddress = (Optional) For new NXT accounts to be funded, supply this on NXT payment to you
|
||||||
|
apiKey = (Optional) Your affiliate PUBLIC KEY, for volume tracking, affiliate payments, split-shifts, etc...
|
||||||
|
|
||||||
|
example data {"amount":123, "withdrawal":"123ABC", "pair":"ltc_btc", returnAddress:"BBBBBBB"}
|
||||||
|
|
||||||
|
Success Output:
|
||||||
|
|
||||||
|
{
|
||||||
|
success:
|
||||||
|
{
|
||||||
|
pair: [pair],
|
||||||
|
withdrawal: [Withdrawal Address], //-- will match address submitted in post
|
||||||
|
withdrawalAmount: [Withdrawal Amount], // Amount of the output coin you will receive
|
||||||
|
deposit: [Deposit Address (or memo field if input coin is BTS / BITUSD)],
|
||||||
|
depositAmount: [Deposit Amount], // Exact amount of input coin to send in
|
||||||
|
expiration: [timestamp when this will expire],
|
||||||
|
quotedRate: [the exchange rate to be honored]
|
||||||
|
apiPubKey: [public API attached to this shift, if one was given]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Coin pair requested for exchange.
|
||||||
|
/// </summary>
|
||||||
|
public string Pair { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Address to send exchanged coins to.
|
||||||
|
/// </summary>
|
||||||
|
public string WithdrawalAddress { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Amount of coins to be received from exchange.
|
||||||
|
/// </summary>
|
||||||
|
public double WithdrawalAmount { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Address to send coins to be exchanged.
|
||||||
|
/// </summary>
|
||||||
|
public string DepositAddress { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Amount of coins required to complete exchange.
|
||||||
|
/// </summary>
|
||||||
|
public double DepositAmount { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Exchange expiration timestamp.
|
||||||
|
/// </summary>
|
||||||
|
public double Expiration { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Quoted rate of exchange.
|
||||||
|
/// </summary>
|
||||||
|
public double QuotedRate { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Public API key attached to this exchange, if any.
|
||||||
|
/// </summary>
|
||||||
|
public string APIKey { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Error thrown by request, if any.
|
||||||
|
/// </summary>
|
||||||
|
public string Error { get; private set; }
|
||||||
|
|
||||||
|
private SendAmountRequest() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets information on pending exchange.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Amount">Amount to be sent to withdrawal address.</param>
|
||||||
|
/// <param name="Address">The withdrawal address.</param>
|
||||||
|
/// <param name="Pair">The coin pair.</param>
|
||||||
|
/// <param name="ReturnAddress">Address to return coins to if exchange fails.</param>
|
||||||
|
/// <param name="RippleTag">Destination tag that you want appended to a Ripple payment to you.</param>
|
||||||
|
/// <param name="NXTRsAddress">For new NXT accounts to be funded, supply this on NXT payment to you.</param>
|
||||||
|
/// <param name="APIKey">Your affiliate PUBLIC KEY, for volume tracking, affiliate payments, split-shifts, etc...</param>
|
||||||
|
/// <returns>Information on pending exchange.</returns>
|
||||||
|
internal static async Task<SendAmountRequest> RequestAsync(double Amount, string Address, string Pair, string ReturnAddress = "", string RippleTag = "", string NXTRsAddress = "", string APIKey = "")
|
||||||
|
{
|
||||||
|
Uri uri = GetUri();
|
||||||
|
string data = CreateData(Amount, Address, Pair, ReturnAddress, RippleTag, NXTRsAddress, APIKey);
|
||||||
|
string response = await RestServices.GetPostResponseAsync(uri, data).ConfigureAwait(false);
|
||||||
|
return await ParseResponseAsync(response).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri GetUri() =>
|
||||||
|
new Uri(@"https://shapeshift.io/sendamount");
|
||||||
|
|
||||||
|
private static string CreateData(double Amount, string Address, string Pair, string ReturnAddress, string RippleTag, string NXTRsAddress, string APIKey)
|
||||||
|
{
|
||||||
|
string dataFormat = "\"{0}\":\"{1}\"";
|
||||||
|
string data = "{";
|
||||||
|
data += string.Format(dataFormat, "amount", Amount.ToString());
|
||||||
|
data += ", " + string.Format(dataFormat, "withdrawal", Address);
|
||||||
|
data += ", " + string.Format(dataFormat, "pair", Pair);
|
||||||
|
if (!string.IsNullOrEmpty(ReturnAddress))
|
||||||
|
data += ", " + string.Format(dataFormat, "returnAddress", ReturnAddress);
|
||||||
|
if (!string.IsNullOrEmpty(RippleTag))
|
||||||
|
data += ", " + string.Format(dataFormat, "destTag", RippleTag);
|
||||||
|
if (!string.IsNullOrEmpty(NXTRsAddress))
|
||||||
|
data += ", " + string.Format(dataFormat, "rsAddress", NXTRsAddress);
|
||||||
|
if (!string.IsNullOrEmpty(APIKey))
|
||||||
|
data += ", " + string.Format(dataFormat, "apiKey", APIKey);
|
||||||
|
data += "}";
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<SendAmountRequest> ParseResponseAsync(string response)
|
||||||
|
{
|
||||||
|
SendAmountRequest request = new SendAmountRequest();
|
||||||
|
using (JsonTextReader jtr = new JsonTextReader(new StringReader(response)))
|
||||||
|
{
|
||||||
|
while (await jtr.ReadAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
if (jtr.Value == null) continue;
|
||||||
|
else if (jtr.Value.ToString() == "pair")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
request.Pair = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "withdrawal")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
request.WithdrawalAddress = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "withdrawalAmount")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
request.WithdrawalAmount = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "deposit")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
request.DepositAddress = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "depositAmount")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
request.DepositAmount = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "expiration")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
request.Expiration = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "quotedRate")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
request.QuotedRate = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "apiPubKey")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
request.APIKey = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "error")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
request.Error = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
166
src/ShapeShift/ShiftResult.cs
Normal file
166
src/ShapeShift/ShiftResult.cs
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Kalakoi.Crypto.ShapeShift
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides ability to send exchange requests to ShapeShift.
|
||||||
|
/// </summary>
|
||||||
|
public class ShiftResult
|
||||||
|
{
|
||||||
|
/*url: shapeshift.io/shift
|
||||||
|
method: POST
|
||||||
|
data type: JSON
|
||||||
|
data required:
|
||||||
|
withdrawal = the address for resulting coin to be sent to
|
||||||
|
pair = what coins are being exchanged in the form [input coin]_[output coin] ie btc_ltc
|
||||||
|
returnAddress = (Optional) address to return deposit to if anything goes wrong with exchange
|
||||||
|
destTag = (Optional) Destination tag that you want appended to a Ripple payment to you
|
||||||
|
rsAddress = (Optional) For new NXT accounts to be funded, you supply this on NXT payment to you
|
||||||
|
apiKey = (Optional) Your affiliate PUBLIC KEY, for volume tracking, affiliate payments, split-shifts, etc...
|
||||||
|
|
||||||
|
example data: {"withdrawal":"AAAAAAAAAAAAA", "pair":"btc_ltc", returnAddress:"BBBBBBBBBBB"}
|
||||||
|
|
||||||
|
Success Output:
|
||||||
|
{
|
||||||
|
deposit: [Deposit Address (or memo field if input coin is BTS / BITUSD)],
|
||||||
|
depositType: [Deposit Type (input coin symbol)],
|
||||||
|
withdrawal: [Withdrawal Address], //-- will match address submitted in post
|
||||||
|
withdrawalType: [Withdrawal Type (output coin symbol)],
|
||||||
|
public: [NXT RS-Address pubkey (if input coin is NXT)],
|
||||||
|
xrpDestTag : [xrpDestTag (if input coin is XRP)],
|
||||||
|
apiPubKey: [public API attached to this shift, if one was given]
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Address to send coins to exchange.
|
||||||
|
/// </summary>
|
||||||
|
public string DepositAddress { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Currency to exchange from.
|
||||||
|
/// </summary>
|
||||||
|
public string DepositCoin { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Address to send exchanged coins to.
|
||||||
|
/// </summary>
|
||||||
|
public string WithdrawalAddress { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Currency to exchange to.
|
||||||
|
/// </summary>
|
||||||
|
public string WithdrawalCoin { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Destination tag to be appended to Ripple payment.
|
||||||
|
/// </summary>
|
||||||
|
public string RippleTag { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// NXT RS-Address public key.
|
||||||
|
/// </summary>
|
||||||
|
public string NXTRsAddress { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Public API key attached to this exchange, if any.
|
||||||
|
/// </summary>
|
||||||
|
public string APIKey { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Error thrown by exchange request, if any.
|
||||||
|
/// </summary>
|
||||||
|
public string Error { get; private set; }
|
||||||
|
|
||||||
|
private ShiftResult() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends Shift request.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Withdrawal">Address for resulting coins to be sent to.</param>
|
||||||
|
/// <param name="Pair">Currency pair for exchange.</param>
|
||||||
|
/// <param name="Return">Address to return coins to if exchange fails.</param>
|
||||||
|
/// <param name="RippleTag">Destination tag that you want appended to a Ripple payment to you.</param>
|
||||||
|
/// <param name="NXTRsAddress">For new NXT accounts to be funded, you supply this on NXT payment to you.</param>
|
||||||
|
/// <param name="APIKey">Your affiliate PUBLIC KEY, for volume tracking, affiliate payments, split-shifts, etc...</param>
|
||||||
|
/// <returns>Result of Shift request.</returns>
|
||||||
|
internal static async Task<ShiftResult> ShiftAsync(string Withdrawal, string Pair, string Return = "", string RippleTag = "", string NXTRsAddress = "", string APIKey = "")
|
||||||
|
{
|
||||||
|
Uri uri = GetUri();
|
||||||
|
string data = CreateData(Withdrawal, Pair, Return, RippleTag, NXTRsAddress, APIKey);
|
||||||
|
string response = await RestServices.GetPostResponseAsync(uri, data).ConfigureAwait(false);
|
||||||
|
return await ParseResponseAsync(response).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri GetUri() =>
|
||||||
|
new Uri(@"https://shapeshift.io/shift");
|
||||||
|
|
||||||
|
private static string CreateData(string Withdrawal, string Pair, string Return, string RippleTag, string NXTRsAddress, string APIKey)
|
||||||
|
{
|
||||||
|
string dataFormat = "\"{0}\":\"{1}\"";
|
||||||
|
string data = "{";
|
||||||
|
data += string.Format(dataFormat, "withdrawal", Withdrawal);
|
||||||
|
data += ", " + string.Format(dataFormat, "pair", Pair);
|
||||||
|
if (!string.IsNullOrEmpty(Return))
|
||||||
|
data += ", " + string.Format(dataFormat, "returnAddress", Return);
|
||||||
|
if (!string.IsNullOrEmpty(RippleTag))
|
||||||
|
data += ", " + string.Format(dataFormat, "destTag", RippleTag);
|
||||||
|
if (!string.IsNullOrEmpty(NXTRsAddress))
|
||||||
|
data += ", " + string.Format(dataFormat, "rsAddress", NXTRsAddress);
|
||||||
|
if (!string.IsNullOrEmpty(APIKey))
|
||||||
|
data += ", " + string.Format(dataFormat, "apiKey", APIKey);
|
||||||
|
data += "}";
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<ShiftResult> ParseResponseAsync(string response)
|
||||||
|
{
|
||||||
|
ShiftResult result = new ShiftResult();
|
||||||
|
using (JsonTextReader jtr = new JsonTextReader(new StringReader(response)))
|
||||||
|
{
|
||||||
|
while (await jtr.ReadAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
if (jtr.Value == null) continue;
|
||||||
|
else if (jtr.Value.ToString() == "deposit")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
result.DepositAddress = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "depositType")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
result.DepositCoin = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "withdrawal")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
result.WithdrawalAddress = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "withdrawalType")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
result.WithdrawalCoin = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "public")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
result.NXTRsAddress = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "xrpDestTag")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
result.RippleTag = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "apiPubKey")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
result.APIKey = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "error")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
result.Error = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
127
src/ShapeShift/SupportedCoin.cs
Normal file
127
src/ShapeShift/SupportedCoin.cs
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Kalakoi.Crypto.ShapeShift
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Exchange availability status of coin.
|
||||||
|
/// </summary>
|
||||||
|
public enum CoinStatuses { Available, Unavailable }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides information on specific currencies.
|
||||||
|
/// </summary>
|
||||||
|
public class SupportedCoin
|
||||||
|
{
|
||||||
|
/*url: shapeshift.io/getcoins
|
||||||
|
method: GET
|
||||||
|
|
||||||
|
Success Output:
|
||||||
|
|
||||||
|
{
|
||||||
|
"SYMBOL1" :
|
||||||
|
{
|
||||||
|
name: ["Currency Formal Name"],
|
||||||
|
symbol: <"SYMBOL1">,
|
||||||
|
image: ["https://shapeshift.io/images/coins/coinName.png"],
|
||||||
|
status: [available / unavailable]
|
||||||
|
}
|
||||||
|
(one listing per supported currency)
|
||||||
|
}
|
||||||
|
|
||||||
|
The status can be either "available" or "unavailable". Sometimes coins become temporarily unavailable during updates or
|
||||||
|
unexpected service issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name of currency.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Ticker symbol for currency.
|
||||||
|
/// </summary>
|
||||||
|
public string Symbol { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Link to currency icon.
|
||||||
|
/// </summary>
|
||||||
|
public string ImageLink { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Currency exchange availability.
|
||||||
|
/// </summary>
|
||||||
|
public CoinStatuses Status { get; private set; }
|
||||||
|
|
||||||
|
private SupportedCoin() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides information on all currencies supported by ShapeShift.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>List of all supported currencies.</returns>
|
||||||
|
internal static async Task<List<SupportedCoin>> GetCoinsAsync()
|
||||||
|
{
|
||||||
|
Uri uri = GetUri();
|
||||||
|
string response = await RestServices.GetResponseAsync(uri).ConfigureAwait(false);
|
||||||
|
return await ParseResponseAsync(response).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides information on a specific currency supported by ShapeShift.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Symbol">Ticker symbol of currency.</param>
|
||||||
|
/// <returns>Information on specific supported currency.</returns>
|
||||||
|
internal static async Task<SupportedCoin> GetCoinAsync(string Symbol) =>
|
||||||
|
(await GetCoinsAsync().ConfigureAwait(false)).First(c => c.Symbol == Symbol);
|
||||||
|
|
||||||
|
private static Uri GetUri() => new Uri(@"https://shapeshift.io/getcoins");
|
||||||
|
|
||||||
|
private static async Task<List<SupportedCoin>> ParseResponseAsync(string response)
|
||||||
|
{
|
||||||
|
List<SupportedCoin> CoinList = new List<SupportedCoin>();
|
||||||
|
SupportedCoin ToAdd = new SupportedCoin();
|
||||||
|
using (JsonTextReader jtr = new JsonTextReader(new StringReader(response)))
|
||||||
|
{
|
||||||
|
while (await jtr.ReadAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
if (jtr.TokenType.ToString() == "StartObject")
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(ToAdd.Name))
|
||||||
|
CoinList.Add(ToAdd);
|
||||||
|
ToAdd = new SupportedCoin();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (jtr.Value != null)
|
||||||
|
{
|
||||||
|
if (jtr.Value.ToString() == "name")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
ToAdd.Name = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "symbol")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
ToAdd.Symbol = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "image")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
ToAdd.ImageLink = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "status")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
ToAdd.Status = jtr.Value.ToString() == "available" ? CoinStatuses.Available : CoinStatuses.Unavailable;
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(ToAdd.Name))
|
||||||
|
CoinList.Add(ToAdd);
|
||||||
|
|
||||||
|
return CoinList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
84
src/ShapeShift/TimeRemaining.cs
Normal file
84
src/ShapeShift/TimeRemaining.cs
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Kalakoi.Crypto.ShapeShift
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Statuses available for Time Remaining requests.
|
||||||
|
/// </summary>
|
||||||
|
public enum TimeStatuses { Pending, Expired }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides access to information on time remaining for pending deposits.
|
||||||
|
/// </summary>
|
||||||
|
public class TimeRemaining
|
||||||
|
{
|
||||||
|
/*url: shapeshift.io/timeremaining/[address]
|
||||||
|
method: GET
|
||||||
|
|
||||||
|
[address] is the deposit address to look up.
|
||||||
|
|
||||||
|
Success Output:
|
||||||
|
|
||||||
|
{
|
||||||
|
status:"pending",
|
||||||
|
seconds_remaining: 600
|
||||||
|
}
|
||||||
|
|
||||||
|
The status can be either "pending" or "expired".
|
||||||
|
If the status is expired then seconds_remaining will show 0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Status of deposit.
|
||||||
|
/// </summary>
|
||||||
|
public TimeStatuses Status { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Seconds remaining before transaction expires.
|
||||||
|
/// </summary>
|
||||||
|
public double SecondsRemaining { get; private set; }
|
||||||
|
|
||||||
|
private TimeRemaining() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets status of deposit and time remaining to complete deposit before expiration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Address">The deposit address to look up.</param>
|
||||||
|
/// <returns>Time remaining for deposit.</returns>
|
||||||
|
internal static async Task<TimeRemaining> GetTimeRemainingAsync(string Address)
|
||||||
|
{
|
||||||
|
Uri uri = GetUri(Address);
|
||||||
|
string response = await RestServices.GetResponseAsync(uri).ConfigureAwait(false);
|
||||||
|
return await ParseResponseAsync(response).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri GetUri(string Address) =>
|
||||||
|
new Uri(string.Format(@"https://shapeshift.io/timeremaining/{0}", Address));
|
||||||
|
|
||||||
|
private static async Task<TimeRemaining> ParseResponseAsync(string response)
|
||||||
|
{
|
||||||
|
TimeRemaining tr = new TimeRemaining();
|
||||||
|
using (JsonTextReader jtr = new JsonTextReader(new StringReader(response)))
|
||||||
|
{
|
||||||
|
while (await jtr.ReadAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
if (jtr.Value == null) continue;
|
||||||
|
else if (jtr.Value.ToString() == "status")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
tr.Status = jtr.Value.ToString() == "pending" ? TimeStatuses.Pending : TimeStatuses.Expired;
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "seconds_remaining")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
tr.SecondsRemaining = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
103
src/ShapeShift/TradingLimit.cs
Normal file
103
src/ShapeShift/TradingLimit.cs
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Kalakoi.Crypto.ShapeShift
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides access to trade limits for specific coin pairs.
|
||||||
|
/// </summary>
|
||||||
|
public class TradingLimit
|
||||||
|
{
|
||||||
|
/*url: shapeshift.io/limit/[pair]
|
||||||
|
method: GET
|
||||||
|
|
||||||
|
[pair] is any valid coin pair such as btc_ltc or ltc_btc
|
||||||
|
|
||||||
|
Success Output:
|
||||||
|
{
|
||||||
|
"pair" : "btc_ltc",
|
||||||
|
"limit" : "1.2345"
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Currency pair.
|
||||||
|
/// </summary>
|
||||||
|
public string Pair { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Trade limit.
|
||||||
|
/// </summary>
|
||||||
|
public double Limit { get; private set; }
|
||||||
|
|
||||||
|
private TradingLimit() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets trade limit for specified currency pair.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Pair">Currency pair to exchange.</param>
|
||||||
|
/// <returns>Trading limit information.</returns>
|
||||||
|
internal static async Task<TradingLimit> GetLimitAsync(string Pair)
|
||||||
|
{
|
||||||
|
Uri uri = GetUri(Pair);
|
||||||
|
string response = await RestServices.GetResponseAsync(uri).ConfigureAwait(false);
|
||||||
|
return await ParseResponseAsync(response).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets trade limit for specified currency pair.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Ticker1">Ticker for currency to exchange from.</param>
|
||||||
|
/// <param name="Ticker2">Ticker for currency to exchange to.</param>
|
||||||
|
/// <returns>Trading limit information.</returns>
|
||||||
|
internal static async Task<TradingLimit> GetLimitAsync(string Ticker1, string Ticker2) =>
|
||||||
|
await GetLimitAsync(string.Format("{0}_{1}", Ticker1, Ticker2)).ConfigureAwait(false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets list of all trade limits.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>List of all trade limits.</returns>
|
||||||
|
internal static async Task<List<TradingLimit>> GetAllLimitsAsync()
|
||||||
|
{
|
||||||
|
List<TradingLimit> LimitList = new List<TradingLimit>();
|
||||||
|
List<TradingPair> PairList = await TradingPair.GetAllPairsAsync().ConfigureAwait(false);
|
||||||
|
foreach (TradingPair tp in PairList)
|
||||||
|
{
|
||||||
|
TradingLimit NewLimit = await GetLimitAsync(tp.Pair).ConfigureAwait(false);
|
||||||
|
LimitList.Add(NewLimit);
|
||||||
|
}
|
||||||
|
return LimitList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri GetUri(string Pair) =>
|
||||||
|
new Uri(string.Format(@"https://shapeshift.io/limit/{0}", Pair));
|
||||||
|
|
||||||
|
private static async Task<TradingLimit> ParseResponseAsync(string response)
|
||||||
|
{
|
||||||
|
TradingLimit limit = new TradingLimit();
|
||||||
|
using (JsonTextReader jtr = new JsonTextReader(new StringReader(response)))
|
||||||
|
{
|
||||||
|
while (await jtr.ReadAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
if (jtr.Value != null)
|
||||||
|
{
|
||||||
|
if (jtr.Value.ToString() == "pair")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
limit.Pair = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "limit")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
limit.Limit = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
135
src/ShapeShift/TradingMarketInfo.cs
Normal file
135
src/ShapeShift/TradingMarketInfo.cs
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Kalakoi.Crypto.ShapeShift
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides access to exchange market info for currency pairs.
|
||||||
|
/// </summary>
|
||||||
|
public class TradingMarketInfo
|
||||||
|
{
|
||||||
|
/*url: shapeshift.io/marketinfo/[pair]
|
||||||
|
method: GET
|
||||||
|
|
||||||
|
[pair] (OPTIONAL) is any valid coin pair such as btc_ltc or ltc_btc.
|
||||||
|
The pair is not required and if not specified will return an array of all market infos.
|
||||||
|
|
||||||
|
Success Output:
|
||||||
|
{
|
||||||
|
"pair" : "btc_ltc",
|
||||||
|
"rate" : 130.12345678,
|
||||||
|
"limit" : 1.2345,
|
||||||
|
"min" : 0.02621232,
|
||||||
|
"minerFee" : 0.0001
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Currency pair.
|
||||||
|
/// </summary>
|
||||||
|
public string Pair { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Exchange rate.
|
||||||
|
/// </summary>
|
||||||
|
public double Rate { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Exchange limit.
|
||||||
|
/// </summary>
|
||||||
|
public double Limit { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Minimum exchange amount.
|
||||||
|
/// </summary>
|
||||||
|
public double Min { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Fee to be sent to miners for exchange.
|
||||||
|
/// </summary>
|
||||||
|
public double MinerFee { get; private set; }
|
||||||
|
|
||||||
|
private TradingMarketInfo() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets market info for specific currency pair.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Pair">Pair to get information for.</param>
|
||||||
|
/// <returns>Market Information.</returns>
|
||||||
|
internal static async Task<TradingMarketInfo> GetMarketInfoAsync(string Pair)
|
||||||
|
{
|
||||||
|
Uri uri = GetUri(Pair);
|
||||||
|
string response = await RestServices.GetResponseAsync(uri).ConfigureAwait(false);
|
||||||
|
return await ParseResponseAsync(response).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets market info for specific currency pair.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Ticker1">Ticker for currency to exchange from.</param>
|
||||||
|
/// <param name="Ticker2">Ticker for currency to exchange to.</param>
|
||||||
|
/// <returns>Market Information.</returns>
|
||||||
|
internal static async Task<TradingMarketInfo> GetMarketInfoAsync(string Ticker1, string Ticker2) =>
|
||||||
|
await GetMarketInfoAsync(string.Format("{0}_{1}", Ticker1, Ticker2)).ConfigureAwait(false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets market info for all currency pairs.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>List of Market Information.</returns>
|
||||||
|
internal static async Task<List<TradingMarketInfo>> GetAllMarketsAsync()
|
||||||
|
{
|
||||||
|
List<TradingMarketInfo> MarketList = new List<TradingMarketInfo>();
|
||||||
|
List<TradingPair> PairList = await TradingPair.GetAllPairsAsync().ConfigureAwait(false);
|
||||||
|
foreach (TradingPair tp in PairList)
|
||||||
|
{
|
||||||
|
TradingMarketInfo NewMarket = await GetMarketInfoAsync(tp.Pair).ConfigureAwait(false);
|
||||||
|
MarketList.Add(NewMarket);
|
||||||
|
}
|
||||||
|
return MarketList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri GetUri(string Pair) =>
|
||||||
|
new Uri(string.Format(@"https://shapeshift.io/marketinfo/{0}", Pair));
|
||||||
|
|
||||||
|
private static async Task<TradingMarketInfo> ParseResponseAsync(string response)
|
||||||
|
{
|
||||||
|
TradingMarketInfo MarketInfo = new TradingMarketInfo();
|
||||||
|
using (JsonTextReader jtr = new JsonTextReader(new StringReader(response)))
|
||||||
|
{
|
||||||
|
while (await jtr.ReadAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
if (jtr.Value != null)
|
||||||
|
{
|
||||||
|
if (jtr.Value.ToString() == "pair")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
MarketInfo.Pair = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "rate")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
MarketInfo.Rate = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "limit")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
MarketInfo.Limit = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "min")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
MarketInfo.Min = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "minerFee")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
MarketInfo.MinerFee = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MarketInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
65
src/ShapeShift/TradingPair.cs
Normal file
65
src/ShapeShift/TradingPair.cs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Kalakoi.Crypto.ShapeShift
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides access to verified currency pairs available for exchange.
|
||||||
|
/// </summary>
|
||||||
|
public class TradingPair
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The Pair string used by ShapeShift.
|
||||||
|
/// </summary>
|
||||||
|
public string Pair { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The Ticker of the currency to be converted.
|
||||||
|
/// </summary>
|
||||||
|
public string Ticker1 { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The Ticker of the currency to convert to.
|
||||||
|
/// </summary>
|
||||||
|
public string Ticker2 { get; private set; }
|
||||||
|
|
||||||
|
private TradingPair() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a list of all TradingPairs supported by ShapeShift.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A List of TradingPairs.</returns>
|
||||||
|
internal static async Task<List<TradingPair>> GetAllPairsAsync()
|
||||||
|
{
|
||||||
|
//Initialize an empty List of TradingPairs
|
||||||
|
List<TradingPair> PairList = new List<TradingPair>();
|
||||||
|
//Generate a List of all SupportedCoins
|
||||||
|
List<SupportedCoin> CoinList = await SupportedCoin.GetCoinsAsync().ConfigureAwait(false);
|
||||||
|
//Loop through all SupportedCoins
|
||||||
|
foreach (SupportedCoin Coin1 in CoinList)
|
||||||
|
{
|
||||||
|
//Check if coin is available for Shifting
|
||||||
|
if (Coin1.Status == CoinStatuses.Available)
|
||||||
|
{
|
||||||
|
//Loop through all SupportedCoins again for generating all TradingPairs
|
||||||
|
foreach (SupportedCoin Coin2 in CoinList)
|
||||||
|
{
|
||||||
|
//Check if both coins are not the same and both coins are available to Shift
|
||||||
|
if (Coin1 != Coin2 && Coin2.Status == CoinStatuses.Available)
|
||||||
|
{
|
||||||
|
//Create new TradingPair object and assign values
|
||||||
|
TradingPair NewPair = new TradingPair();
|
||||||
|
NewPair.Ticker1 = Coin1.Symbol;
|
||||||
|
NewPair.Ticker2 = Coin2.Symbol;
|
||||||
|
NewPair.Pair = string.Format("{0}_{1}", Coin1.Symbol, Coin2.Symbol);
|
||||||
|
//Add new TradingPair object to List of TradingPairs
|
||||||
|
PairList.Add(NewPair);
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
//Return complete TradingPair List
|
||||||
|
return PairList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
104
src/ShapeShift/TradingRate.cs
Normal file
104
src/ShapeShift/TradingRate.cs
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Kalakoi.Crypto.ShapeShift
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides ability to find exchange rates for coin pairs.
|
||||||
|
/// </summary>
|
||||||
|
public class TradingRate
|
||||||
|
{
|
||||||
|
/*url: shapeshift.io/rate/[pair]
|
||||||
|
method: GET
|
||||||
|
|
||||||
|
[pair] is any valid coin pair such as btc_ltc or ltc_btc
|
||||||
|
|
||||||
|
Success Output:
|
||||||
|
|
||||||
|
{
|
||||||
|
"pair" : "btc_ltc",
|
||||||
|
"rate" : "70.1234"
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Coin pair.
|
||||||
|
/// </summary>
|
||||||
|
public string Pair { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Exchange rate.
|
||||||
|
/// </summary>
|
||||||
|
public double Rate { get; private set; }
|
||||||
|
|
||||||
|
private TradingRate() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds exchange rate for specified coin pair.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Pair">Coin pair to find rate for.</param>
|
||||||
|
/// <returns>Exchange rate.</returns>
|
||||||
|
internal static async Task<TradingRate> GetRateAsync(string Pair)
|
||||||
|
{
|
||||||
|
Uri uri = GetUri(Pair);
|
||||||
|
string response = await RestServices.GetResponseAsync(uri).ConfigureAwait(false);
|
||||||
|
return await ParseResponseAsync(response).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds exchange rate for specified coin pair.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Ticker1">Ticker symbol for coin to exchange.</param>
|
||||||
|
/// <param name="Ticker2">Ticker symbol for resulting coin.</param>
|
||||||
|
/// <returns>Exchange rate.</returns>
|
||||||
|
internal static async Task<TradingRate> GetRateAsync(string Ticker1, string Ticker2) =>
|
||||||
|
await GetRateAsync(string.Format("{0}_{1}", Ticker1, Ticker2)).ConfigureAwait(false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds exchange rates for all valid coin pairs.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>List of exchange rates.</returns>
|
||||||
|
internal static async Task<List<TradingRate>> GetAllRatesAsync()
|
||||||
|
{
|
||||||
|
List<TradingRate> RateList = new List<TradingRate>();
|
||||||
|
List<TradingPair> PairList = await TradingPair.GetAllPairsAsync().ConfigureAwait(false);
|
||||||
|
foreach (TradingPair tp in PairList)
|
||||||
|
{
|
||||||
|
TradingRate NewRate = await GetRateAsync(tp.Pair).ConfigureAwait(false);
|
||||||
|
RateList.Add(NewRate);
|
||||||
|
}
|
||||||
|
return RateList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri GetUri(string Pair) =>
|
||||||
|
new Uri(string.Format(@"https://shapeshift.io/rate/{0}", Pair));
|
||||||
|
|
||||||
|
private static async Task<TradingRate> ParseResponseAsync(string response)
|
||||||
|
{
|
||||||
|
TradingRate rate = new TradingRate();
|
||||||
|
using (JsonTextReader jtr = new JsonTextReader(new StringReader(response)))
|
||||||
|
{
|
||||||
|
while (await jtr.ReadAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
if (jtr.Value != null)
|
||||||
|
{
|
||||||
|
if (jtr.Value.ToString() == "pair")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
rate.Pair = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "rate")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
rate.Rate = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
217
src/ShapeShift/Tx.cs
Normal file
217
src/ShapeShift/Tx.cs
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Kalakoi.Crypto.ShapeShift
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides ability to view previous transactions by address or API key.
|
||||||
|
/// </summary>
|
||||||
|
public class Tx
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Transaction ID of the input coin going into shapeshift.
|
||||||
|
/// </summary>
|
||||||
|
public string InputTxID { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Address that the input coin was paid to for this shift.
|
||||||
|
/// </summary>
|
||||||
|
public string InputAddress { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Currency type of the input coin.
|
||||||
|
/// </summary>
|
||||||
|
public string InputCoin { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Amount of input coin that was paid in on this shift.
|
||||||
|
/// </summary>
|
||||||
|
public double InputAmount { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Transaction ID of the output coin going out to user.
|
||||||
|
/// </summary>
|
||||||
|
public string OutputTxID { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Address that the output coin was sent to for this shift.
|
||||||
|
/// </summary>
|
||||||
|
public string OutputAddress { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Currency type of the output coin.
|
||||||
|
/// </summary>
|
||||||
|
public string OutputCoin { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Amount of output coin that was paid out on this shift.
|
||||||
|
/// </summary>
|
||||||
|
public double OutputAmount { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The effective rate the user got on this shift.
|
||||||
|
/// </summary>
|
||||||
|
public double ShiftRate { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Status of the shift.
|
||||||
|
/// </summary>
|
||||||
|
public TxStatuses Status { get; private set; }
|
||||||
|
|
||||||
|
private Tx() { }
|
||||||
|
|
||||||
|
/*url: shapeshift.io/txbyapikey/[apiKey]
|
||||||
|
method: GET
|
||||||
|
|
||||||
|
[apiKey] is the affiliate's PRIVATE api key.
|
||||||
|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
inputTXID: [Transaction ID of the input coin going into shapeshift],
|
||||||
|
inputAddress: [Address that the input coin was paid to for this shift],
|
||||||
|
inputCurrency: [Currency type of the input coin],
|
||||||
|
inputAmount: [Amount of input coin that was paid in on this shift],
|
||||||
|
outputTXID: [Transaction ID of the output coin going out to user],
|
||||||
|
outputAddress: [Address that the output coin was sent to for this shift],
|
||||||
|
outputCurrency: [Currency type of the output coin],
|
||||||
|
outputAmount: [Amount of output coin that was paid out on this shift],
|
||||||
|
shiftRate: [The effective rate the user got on this shift.],
|
||||||
|
status: [status of the shift]
|
||||||
|
}
|
||||||
|
(one listing per transaction returned)
|
||||||
|
]
|
||||||
|
|
||||||
|
The status can be "received", "complete", "returned", "failed".
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds all transactions sent using the specified API key.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="APIKey">The affiliate's PRIVATE api key.</param>
|
||||||
|
/// <returns>List of transactions.</returns>
|
||||||
|
internal static async Task<List<Tx>> GetTransactionsByAPIKeyAsync(string APIKey)
|
||||||
|
{
|
||||||
|
Uri uri = GetKeyUri(APIKey);
|
||||||
|
string response = await RestServices.GetResponseAsync(uri).ConfigureAwait(false);
|
||||||
|
return await ParseResponseAsync(response).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri GetKeyUri(string APIKey) =>
|
||||||
|
new Uri(string.Format(@"https://shapeshift.io/txbyapikey/{0}", APIKey));
|
||||||
|
|
||||||
|
/*url: shapeshift.io/txbyaddress/[address]/[apiKey]
|
||||||
|
method: GET
|
||||||
|
|
||||||
|
[address] the address that output coin was sent to for the shift
|
||||||
|
[apiKey] is the affiliate's PRIVATE api key.
|
||||||
|
|
||||||
|
Success Output:
|
||||||
|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
inputTXID: [Transaction ID of the input coin going into shapeshift],
|
||||||
|
inputAddress: [Address that the input coin was paid to for this shift],
|
||||||
|
inputCurrency: [Currency type of the input coin],
|
||||||
|
inputAmount: [Amount of input coin that was paid in on this shift],
|
||||||
|
outputTXID: [Transaction ID of the output coin going out to user],
|
||||||
|
outputAddress: [Address that the output coin was sent to for this shift],
|
||||||
|
outputCurrency: [Currency type of the output coin],
|
||||||
|
outputAmount: [Amount of output coin that was paid out on this shift],
|
||||||
|
shiftRate: [The effective rate the user got on this shift.],
|
||||||
|
status: [status of the shift]
|
||||||
|
}
|
||||||
|
(one listing per transaction returned)
|
||||||
|
]
|
||||||
|
|
||||||
|
The status can be "received", "complete", "returned", "failed".
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds all transactions sent to specified address.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Address">The address that output coin was sent to for the shift.</param>
|
||||||
|
/// <param name="APIKey">The affiliate's PRIVATE api key.</param>
|
||||||
|
/// <returns>List of transactions.</returns>
|
||||||
|
internal static async Task<List<Tx>> GetTransactionsByAddressAsync(string Address, string APIKey)
|
||||||
|
{
|
||||||
|
Uri uri = GetAddressUri(Address, APIKey);
|
||||||
|
string response = await RestServices.GetResponseAsync(uri).ConfigureAwait(false);
|
||||||
|
return await ParseResponseAsync(response).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri GetAddressUri(string Address, string APIKey) =>
|
||||||
|
new Uri(string.Format(@"https://shapeshift.io/txbyaddress/{0}/{1}", Address, APIKey));
|
||||||
|
|
||||||
|
private static async Task<List<Tx>> ParseResponseAsync(string response)
|
||||||
|
{
|
||||||
|
List<Tx> TxList = new List<Tx>();
|
||||||
|
Tx NewTx = new Tx();
|
||||||
|
using (JsonTextReader jtr = new JsonTextReader(new StringReader(response)))
|
||||||
|
{
|
||||||
|
while (await jtr.ReadAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
if (jtr.TokenType.ToString() == "StartObject")
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(NewTx.InputTxID))
|
||||||
|
TxList.Add(NewTx);
|
||||||
|
NewTx = new Tx();
|
||||||
|
}
|
||||||
|
else if (jtr.Value == null) continue;
|
||||||
|
else if (jtr.Value.ToString() == "inputTXID")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
NewTx.InputTxID = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "inputAddress")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
NewTx.InputAddress = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "inputCurrency")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
NewTx.InputCoin = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "inputAmount")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
NewTx.InputAmount = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "outputTXID")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
NewTx.OutputTxID = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "outputAddress")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
NewTx.OutputAddress = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "outputCurrency")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
NewTx.OutputCoin = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "outputAmount")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
NewTx.OutputAmount = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "shiftRate")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
NewTx.ShiftRate = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "status")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
NewTx.Status =
|
||||||
|
jtr.Value.ToString() == "received" ? TxStatuses.Received :
|
||||||
|
jtr.Value.ToString() == "complete" ? TxStatuses.Complete :
|
||||||
|
jtr.Value.ToString() == "returned" ? TxStatuses.Returned :
|
||||||
|
jtr.Value.ToString() == "failed" ? TxStatuses.Failed : TxStatuses.NoDeposits;
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(NewTx.InputTxID))
|
||||||
|
TxList.Add(NewTx);
|
||||||
|
|
||||||
|
return TxList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
175
src/ShapeShift/TxStatus.cs
Normal file
175
src/ShapeShift/TxStatus.cs
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Kalakoi.Crypto.ShapeShift
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Transaction Statuses.
|
||||||
|
/// </summary>
|
||||||
|
public enum TxStatuses { NoDeposits, Received, Returned, Complete, Failed }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides access to transaction status.
|
||||||
|
/// </summary>
|
||||||
|
public class TxStatus
|
||||||
|
{
|
||||||
|
/*url: shapeshift.io/txStat/[address]
|
||||||
|
method: GET
|
||||||
|
|
||||||
|
[address] is the deposit address to look up.
|
||||||
|
|
||||||
|
Success Output: (various depending on status)
|
||||||
|
|
||||||
|
Status: No Deposits Received
|
||||||
|
{
|
||||||
|
status:"no_deposits",
|
||||||
|
address:[address] //matches address submitted
|
||||||
|
}
|
||||||
|
|
||||||
|
Status: Received (we see a new deposit but have not finished processing it)
|
||||||
|
{
|
||||||
|
status:"received",
|
||||||
|
address:[address] //matches address submitted
|
||||||
|
}
|
||||||
|
|
||||||
|
Status: Complete
|
||||||
|
{
|
||||||
|
status : "complete",
|
||||||
|
address: [address],
|
||||||
|
withdraw: [withdrawal address],
|
||||||
|
incomingCoin: [amount deposited],
|
||||||
|
incomingType: [coin type of deposit],
|
||||||
|
outgoingCoin: [amount sent to withdrawal address],
|
||||||
|
outgoingType: [coin type of withdrawal],
|
||||||
|
transaction: [transaction id of coin sent to withdrawal address]
|
||||||
|
}
|
||||||
|
|
||||||
|
Status: Failed
|
||||||
|
{
|
||||||
|
status : "failed",
|
||||||
|
error: [Text describing failure]
|
||||||
|
}
|
||||||
|
|
||||||
|
//Note: this can still get the normal style error returned. For example if request is made without an address.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Status of exchange.
|
||||||
|
/// </summary>
|
||||||
|
public TxStatuses Status { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Deposit address coins (need to be) sent to.
|
||||||
|
/// </summary>
|
||||||
|
public string Address { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Address to send coins after exchange.
|
||||||
|
/// </summary>
|
||||||
|
public string WithdrawalAddress { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Amount to send to deposit address.
|
||||||
|
/// </summary>
|
||||||
|
public double IncomingAmount { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Currency type to send.
|
||||||
|
/// </summary>
|
||||||
|
public string IncomingCoin { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Amount (to be) received from exchange.
|
||||||
|
/// </summary>
|
||||||
|
public double OutgoingAmount { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Currency type to receive.
|
||||||
|
/// </summary>
|
||||||
|
public string OutgoingCoin { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Transaction ID of coin sent to withdrawal address.
|
||||||
|
/// </summary>
|
||||||
|
public string TxID { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Error thrown by status check, if any.
|
||||||
|
/// </summary>
|
||||||
|
public string Error { get; private set; }
|
||||||
|
|
||||||
|
private TxStatus() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets status of transaction (to be) deposited to supplied address.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Address">Deposit address.</param>
|
||||||
|
/// <returns>Transaction status.</returns>
|
||||||
|
internal static async Task<TxStatus> GetStatusAsync(string Address)
|
||||||
|
{
|
||||||
|
Uri uri = GetUri(Address);
|
||||||
|
string response = await RestServices.GetResponseAsync(uri).ConfigureAwait(false);
|
||||||
|
return await ParseResponseAsync(response).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri GetUri(string address) =>
|
||||||
|
new Uri(string.Format(@"https://shapeshift.io/txStat/{0}", address));
|
||||||
|
|
||||||
|
private static async Task<TxStatus> ParseResponseAsync(string response)
|
||||||
|
{
|
||||||
|
TxStatus status = new TxStatus();
|
||||||
|
using (JsonTextReader jtr = new JsonTextReader(new StringReader(response)))
|
||||||
|
{
|
||||||
|
while (await jtr.ReadAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
if (jtr.Value == null) continue;
|
||||||
|
else if (jtr.Value.ToString() == "status")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
status.Status =
|
||||||
|
jtr.Value.ToString() == "no_deposits" ? TxStatuses.NoDeposits :
|
||||||
|
jtr.Value.ToString() == "received" ? TxStatuses.Received :
|
||||||
|
jtr.Value.ToString() == "complete" ? TxStatuses.Complete :
|
||||||
|
jtr.Value.ToString() == "failed" ? TxStatuses.Failed : TxStatuses.Returned;
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "address")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
status.Address = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "withdraw")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
status.WithdrawalAddress = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "incomingCoin")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
status.IncomingAmount = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "incomingType")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
status.IncomingCoin = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "outgoingCoin")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
status.OutgoingAmount = Convert.ToDouble(jtr.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "outgoingType")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
status.OutgoingCoin = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "transaction")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
status.TxID = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "error")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
status.Error = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
src/ShapeShift/ValidateAddress.cs
Normal file
82
src/ShapeShift/ValidateAddress.cs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Kalakoi.Crypto.ShapeShift
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides ability to validate addresses for supported coins.
|
||||||
|
/// </summary>
|
||||||
|
public class ValidateAddress
|
||||||
|
{
|
||||||
|
/*url: shapeshift.io/validateAddress/[address]/[coinSymbol]
|
||||||
|
method: GET
|
||||||
|
|
||||||
|
[address] the address that the user wishes to validate
|
||||||
|
[coinSymbol] the currency symbol of the coin
|
||||||
|
|
||||||
|
Success Output:
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
isValid: [true / false],
|
||||||
|
error: [(if isvalid is false, there will be an error message)]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
isValid will either be true or false. If isvalid returns false, an error parameter will be present and will contain a descriptive error message.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// True if address is valid.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsValid { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Error thrown by validation check.
|
||||||
|
/// </summary>
|
||||||
|
public string Error { get; private set; }
|
||||||
|
|
||||||
|
private ValidateAddress() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Validates address belongs to specified currency.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Address">Address to check.</param>
|
||||||
|
/// <param name="Symbol">Ticker symbol for currency to check.</param>
|
||||||
|
/// <returns>Validation results.</returns>
|
||||||
|
internal static async Task<ValidateAddress> ValidateAsync(string Address, string Symbol)
|
||||||
|
{
|
||||||
|
Uri uri = GetUri(Address, Symbol);
|
||||||
|
string response = await RestServices.GetResponseAsync(uri).ConfigureAwait(false);
|
||||||
|
return await ParseResponseAsync(response).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri GetUri(string Address, string Symbol) =>
|
||||||
|
new Uri(string.Format(@"https://shapeshift.io/validateaddress/{0}/{1}", Address, Symbol));
|
||||||
|
|
||||||
|
private static async Task<ValidateAddress> ParseResponseAsync(string response)
|
||||||
|
{
|
||||||
|
ValidateAddress va = new ValidateAddress();
|
||||||
|
using (JsonTextReader jtr = new JsonTextReader(new StringReader(response)))
|
||||||
|
{
|
||||||
|
while (await jtr.ReadAsync().ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
if (jtr.Value == null) continue;
|
||||||
|
else if (jtr.Value.ToString() == "isValid")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
va.IsValid = jtr.Value.ToString() == "true";
|
||||||
|
}
|
||||||
|
else if (jtr.Value.ToString() == "error")
|
||||||
|
{
|
||||||
|
await jtr.ReadAsync().ConfigureAwait(false);
|
||||||
|
va.Error = jtr.Value.ToString();
|
||||||
|
}
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return va;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user