Merge pull request #33 from agarzon/add-potcoin

Add potcoin
This commit is contained in:
GENERAL BYTES 2017-09-05 12:16:18 +02:00 committed by GitHub
commit 057c246cfd
13 changed files with 594 additions and 0 deletions

View File

@ -32,6 +32,7 @@ public interface ICurrencies {
public static final String ICG = "ICG";
public static final String NBT = "NBT";
public static final String NXT = "NXT";
public static final String POT = "POT";
public static final String START = "START";
public static final String TKN = "TKN";
public static final String WDC = "WDC";

View File

@ -0,0 +1,35 @@
package com.generalbytes.batm.server.extensions.extra.potcoin;
import com.generalbytes.batm.server.coinutil.AddressFormatException;
import com.generalbytes.batm.server.coinutil.Base58;
import com.generalbytes.batm.server.extensions.ExtensionsUtil;
import com.generalbytes.batm.server.extensions.ICryptoAddressValidator;
public class PotcoinAddressValidator implements ICryptoAddressValidator {
@Override
public boolean isAddressValid(String address) {
if (address.startsWith("P")) {
try {
Base58.decodeToBigInteger(address);
Base58.decodeChecked(address);
} catch (AddressFormatException e) {
e.printStackTrace();
return false;
}
return true;
}else{
return false;
}
}
@Override
public boolean isPaperWalletSupported() {
return false;
}
@Override
public boolean mustBeBase58Address() {
return true;
}
}

View File

@ -0,0 +1,107 @@
package com.generalbytes.batm.server.extensions.extra.potcoin;
import com.generalbytes.batm.server.extensions.*;
import com.generalbytes.batm.server.extensions.extra.potcoin.sources.FixPriceRateSource;
import com.generalbytes.batm.server.extensions.extra.potcoin.sources.coinmarketcap.CoinmarketcapRateSource;
import com.generalbytes.batm.server.extensions.extra.potcoin.wallets.potwallet.Potwallet;
import com.generalbytes.batm.server.extensions.watchlist.IWatchList;
import java.math.BigDecimal;
import java.util.*;
public class PotcoinExtension implements IExtension{
@Override
public String getName() {
return "BATM Potcoin extension";
}
@Override
public IExchange createExchange(String exchangeLogin) {
return null;
}
@Override
public IWallet createWallet(String walletLogin) {
if (walletLogin !=null && !walletLogin.trim().isEmpty()) {
StringTokenizer st = new StringTokenizer(walletLogin,":");
String walletType = st.nextToken();
if ("potwallet".equalsIgnoreCase(walletType)) {
String publicKey = st.nextToken();
String privateKey = st.nextToken();
String walletId = st.nextToken();
if (publicKey != null && privateKey != null && walletId != null) {
return new Potwallet(publicKey,privateKey,walletId);
}
}
}
return null;
}
@Override
public ICryptoAddressValidator createAddressValidator(String cryptoCurrency) {
if (ICurrencies.POT.equalsIgnoreCase(cryptoCurrency)) {
return new PotcoinAddressValidator();
}
return null;
}
@Override
public IPaperWalletGenerator createPaperWalletGenerator(String cryptoCurrency) {
return null;
}
@Override
public IPaymentProcessor createPaymentProcessor(String paymentProcessorLogin) {
return null; //no payment processors available
}
@Override
public IRateSource createRateSource(String sourceLogin) {
if (sourceLogin != null && !sourceLogin.trim().isEmpty()) {
StringTokenizer st = new StringTokenizer(sourceLogin,":");
String rsType = st.nextToken();
if ("potfix".equalsIgnoreCase(rsType)) {
BigDecimal rate = BigDecimal.ZERO;
if (st.hasMoreTokens()) {
try {
rate = new BigDecimal(st.nextToken());
} catch (Throwable e) {
}
}
String preferedFiatCurrency = ICurrencies.CAD;
if (st.hasMoreTokens()) {
preferedFiatCurrency = st.nextToken().toUpperCase();
}
return new FixPriceRateSource(rate,preferedFiatCurrency);
} else if ("coinmarketcap".equalsIgnoreCase(rsType)) {
String preferredFiatCurrency = ICurrencies.CAD;
if (st.hasMoreTokens()) {
preferredFiatCurrency = st.nextToken();
}
return new CoinmarketcapRateSource(preferredFiatCurrency);
}
}
return null;
}
@Override
public Set<String> getSupportedCryptoCurrencies() {
Set<String> result = new HashSet<String>();
result.add(ICurrencies.POT);
return result;
}
@Override
public Set<String> getSupportedWatchListsNames() {
return null;
}
@Override
public IWatchList getWatchList(String name) {
return null;
}
}

View File

@ -0,0 +1,53 @@
package com.generalbytes.batm.server.extensions.extra.potcoin.sources;
import com.generalbytes.batm.server.extensions.ICurrencies;
import com.generalbytes.batm.server.extensions.IRateSource;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Set;
public class FixPriceRateSource implements IRateSource {
private BigDecimal rate = BigDecimal.ZERO;
private String preferedFiatCurrency = ICurrencies.CAD;
public FixPriceRateSource(BigDecimal rate,String preferedFiatCurrency) {
this.rate = rate;
if (ICurrencies.CAD.equalsIgnoreCase(preferedFiatCurrency)) {
this.preferedFiatCurrency = ICurrencies.CAD;
}
if (ICurrencies.USD.equalsIgnoreCase(preferedFiatCurrency)) {
this.preferedFiatCurrency = ICurrencies.USD;
}
}
@Override
public Set<String> getCryptoCurrencies() {
Set<String> result = new HashSet<String>();
result.add(ICurrencies.POT);
return result;
}
@Override
public BigDecimal getExchangeRateLast(String cryptoCurrency, String fiatCurrency) {
if (ICurrencies.POT.equalsIgnoreCase(cryptoCurrency)) {
return rate;
}
return null;
}
@Override
public Set<String> getFiatCurrencies() {
Set<String> result = new HashSet<String>();
result.add(ICurrencies.USD);
result.add(ICurrencies.CAD);
return result;
}
@Override
public String getPreferredFiatCurrency() {
return preferedFiatCurrency;
}
}

View File

@ -0,0 +1,100 @@
package com.generalbytes.batm.server.extensions.extra.potcoin.sources.coinmarketcap;
import com.generalbytes.batm.server.extensions.ICurrencies;
import com.generalbytes.batm.server.extensions.IRateSource;
import si.mazi.rescu.RestProxyFactory;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Set;
public class CoinmarketcapRateSource implements IRateSource {
private String preferedFiatCurrency = ICurrencies.USD;
private ICoinmarketcapRateAPI api;
/**
* Constructor
*/
public CoinmarketcapRateSource(String preferedFiatCurrency) {
if (ICurrencies.USD.equalsIgnoreCase(preferedFiatCurrency)) {
this.preferedFiatCurrency = ICurrencies.USD;
}
if (ICurrencies.CAD.equalsIgnoreCase(preferedFiatCurrency)) {
this.preferedFiatCurrency = ICurrencies.CAD;
}
if (ICurrencies.EUR.equalsIgnoreCase(preferedFiatCurrency)) {
this.preferedFiatCurrency = ICurrencies.EUR;
}
api = RestProxyFactory.createProxy(ICoinmarketcapRateAPI.class, "https://api.coinmarketcap.com");
}
/**
* This method returns list of supported crypto currencies
* @return
*/
@Override
public Set<String> getCryptoCurrencies() {
Set<String> result = new HashSet<String>();
result.add(ICurrencies.POT);
//result.add(ICurrencies.BTC);
return result;
}
/**
* Returns current price of cryptocurrency in specified fiat currency
* @param cryptoCurrency
* @param fiatCurrency
* @return
*/
@Override
public BigDecimal getExchangeRateLast(String cryptoCurrency, String fiatCurrency) {
// coinmarketcap uses coin name instead coin symbol
if (ICurrencies.BTC.equalsIgnoreCase(cryptoCurrency)) {
cryptoCurrency = "bitcoin";
} else if (ICurrencies.POT.equalsIgnoreCase(cryptoCurrency)) {
cryptoCurrency = "potcoin";
}
CoinmarketcapResponse[] response = api.getRequest(cryptoCurrency, fiatCurrency);
if (response != null) {
if (ICurrencies.USD.equalsIgnoreCase(fiatCurrency)) {
BigDecimal rate = response[0].getPrice_usd();
return rate;
} else if (ICurrencies.CAD.equalsIgnoreCase(fiatCurrency)) {
BigDecimal rate = response[0].getPrice_cad();
return rate;
} else if (ICurrencies.EUR.equalsIgnoreCase(fiatCurrency)) {
BigDecimal rate = response[0].getPrice_eur();
return rate;
} else {
return null;
}
}
return null;
}
/**
* This method returns list of supported fiat currencies
* @return
*/
@Override
public Set<String> getFiatCurrencies() {
Set<String> result = new HashSet<String>();
result.add(ICurrencies.USD);
result.add(ICurrencies.CAD);
result.add(ICurrencies.EUR);
return result;
}
/**
* Returns fiat currency that is used for actual purchases of cryptocurrency by server
* @return
*/
@Override
public String getPreferredFiatCurrency() {
return preferedFiatCurrency;
}
}

View File

@ -0,0 +1,34 @@
package com.generalbytes.batm.server.extensions.extra.potcoin.sources.coinmarketcap;
import java.math.BigDecimal;
public class CoinmarketcapResponse {
private BigDecimal price_usd;
private BigDecimal price_cad;
private BigDecimal price_eur;
public BigDecimal getPrice_usd() {
return price_usd;
}
public void setPrice_usd(BigDecimal price_usd) {
this.price_usd = price_usd;
}
public BigDecimal getPrice_cad() {
return price_cad;
}
public void setPrice_cad(BigDecimal price_cad) {
this.price_cad = price_cad;
}
public BigDecimal getPrice_eur() {
return price_eur;
}
public void setPrice_eur(BigDecimal price_eur) {
this.price_eur = price_eur;
}
}

View File

@ -0,0 +1,15 @@
package com.generalbytes.batm.server.extensions.extra.potcoin.sources.coinmarketcap;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/v1")
@Produces(MediaType.APPLICATION_JSON)
public interface ICoinmarketcapRateAPI {
@GET
@Path("/ticker/{cryptocurrency}/?convert={fiatcurrency}")
CoinmarketcapResponse[] getRequest(@PathParam("cryptocurrency") String cryptoCurrency, @PathParam("fiatcurrency") String fiatCurrency);
}

View File

@ -0,0 +1,169 @@
package com.generalbytes.batm.server.extensions.extra.potcoin.wallets.potwallet;
import com.generalbytes.batm.server.extensions.ICurrencies;
import com.generalbytes.batm.server.extensions.IWallet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import si.mazi.rescu.HttpStatusIOException;
import si.mazi.rescu.RestProxyFactory;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Set;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
public class Potwallet implements IWallet {
private static final Logger log = LoggerFactory.getLogger("batm.master.Potwallet");
private String nonce;
private String accessHash;
private String publicKey;
private String privateKey;
private String walletId;
private PotwalletAPI api;
public Potwallet(String publicKey, String privateKey, String walletId) {
this.nonce = generateRandomString(8);
this.publicKey = publicKey;
this.privateKey = privateKey;
this.walletId = walletId;
api = RestProxyFactory.createProxy(PotwalletAPI.class, "https://api.potwallet.com");
}
@Override
public String getPreferredCryptoCurrency() {
return ICurrencies.POT;
}
@Override
public Set<String> getCryptoCurrencies() {
Set<String> result = new HashSet<String>();
result.add(ICurrencies.POT);
return result;
}
@Override
public String getCryptoAddress(String cryptoCurrency) {
if (!getCryptoCurrencies().contains(cryptoCurrency)) {
log.error("Cryptocurrency " + cryptoCurrency + " not supported.");
return null;
}
if (walletId != null) {
return walletId;
}
try {
accessHash = generateHash(privateKey, "https://api.potwallet.com/v1/address", nonce);
PotwalletResponse response = api.getAddress(publicKey, accessHash, nonce);
if (response != null && response.getMessage() != null && response.getSuccess()) {
return new String(response.getMessage());
}
} catch (HttpStatusIOException e) {
log.error(e.getHttpBody());
} catch (IOException e) {
log.error("", e);
}
return null;
}
@Override
public BigDecimal getCryptoBalance(String cryptoCurrency) {
if (!getCryptoCurrencies().contains(cryptoCurrency)) {
log.error("Cryptocurrency " + cryptoCurrency + " not supported.");
return null;
}
try {
accessHash = generateHash(privateKey, "https://api.potwallet.com/v1/balance", nonce);
PotwalletResponse response = api.getCryptoBalance(publicKey, accessHash, nonce);
if (response != null && response.getMessage() != null && response.getSuccess()) {
log.debug("Transaction " + response.getMessage() + " sent.");
return new BigDecimal(response.getMessage());
}
} catch (HttpStatusIOException e) {
log.error(e.getHttpBody());
} catch (IOException e) {
log.error("", e);
}
return null;
}
@Override
public String sendCoins(String destinationAddress, BigDecimal amount, String cryptoCurrency, String description) {
if (!getCryptoCurrencies().contains(cryptoCurrency)) {
log.error("Cryptocurrency " + cryptoCurrency + " not supported.");
return null;
}
try{
accessHash = generateHash(privateKey, "https://api.potwallet.com/v1/send", nonce);
PotwalletResponse response = api.sendPots(publicKey, accessHash, nonce, new PotwalletSendRequest(destinationAddress, amount.stripTrailingZeros()));
if (response != null && response.getMessage() != null && response.getSuccess()) {
return new String(response.getMessage());
}
} catch (HttpStatusIOException e) {
log.error(e.getHttpBody());
} catch (IOException e) {
log.error("", e);
}
return null;
}
private static String generateRandomString(int length)
{
String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random rng = new Random();
char[] text = new char[length];
for (int i = 0; i < length; i++)
{
text[i] = characters.charAt(rng.nextInt(characters.length()));
}
return new String(text);
}
private static String generateHash(String privateHash, String endPoint, String nonce )
{
String digest = null;
try
{
String content = endPoint + nonce;
SecretKeySpec key = new SecretKeySpec((privateHash).getBytes("UTF-8"), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(key);
byte[] bytes = mac.doFinal(content.getBytes("ASCII"));
StringBuffer hash = new StringBuffer();
for (int i=0; i<bytes.length; i++) {
String hex = Integer.toHexString(0xFF & bytes[i]);
if (hex.length() == 1) {
hash.append('0');
}
hash.append(hex);
}
digest = hash.toString();
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
catch(InvalidKeyException e){
e.printStackTrace();
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return digest ;
}
}

View File

@ -0,0 +1,21 @@
package com.generalbytes.batm.server.extensions.extra.potcoin.wallets.potwallet;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.math.BigDecimal;
@Path("/v1")
@Produces(MediaType.APPLICATION_JSON)
public interface PotwalletAPI {
@GET
@Path("/balance")
PotwalletResponse getCryptoBalance(@HeaderParam("Access-Public") String publicKey, @HeaderParam("Access-Hash") String accessHash, @HeaderParam("Access-Nonce") String nonce) throws IOException;
@GET
@Path("/address")
PotwalletResponse getAddress(@HeaderParam("Access-Public") String publicKey, @HeaderParam("Access-Hash") String accessHash, @HeaderParam("Access-Nonce") String nonce) throws IOException;
@POST
@Path("/send")
@Consumes(MediaType.APPLICATION_JSON)
PotwalletResponse sendPots(@HeaderParam("Access-Public") String publicKey, @HeaderParam("Access-Hash") String accessHash, @HeaderParam("Access-Nonce") String nonce, PotwalletSendRequest request) throws IOException;
}

View File

@ -0,0 +1,24 @@
package com.generalbytes.batm.server.extensions.extra.potcoin.wallets.potwallet;
import java.math.BigDecimal;
public class PotwalletResponse {
private Boolean success;
private String message;
public Boolean getSuccess() {
return success;
}
public void setSuccess(Boolean success) {
this.success = success;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@ -0,0 +1,18 @@
package com.generalbytes.batm.server.extensions.extra.potcoin.wallets.potwallet;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.math.BigDecimal;
public class PotwalletSendRequest {
@JsonProperty("address")
String address;
@JsonProperty("amount")
BigDecimal amount;
public PotwalletSendRequest(String address, BigDecimal amount) {
this.address = address;
this.amount = amount;
}
}

View File

@ -289,6 +289,23 @@
</ratesource>
<cryptologo cryptocurrency="NXT" file="nxt.png"/>
</extension>
<extension class="com.generalbytes.batm.server.extensions.extra.potcoin.PotcoinExtension" >
<wallet prefix="potwallet" name="PotCoin">
<param name="publicKey" />
<param name="privateKey" />
<param name="walletId" />
<cryptocurrency>POT</cryptocurrency>
</wallet>
<ratesource prefix="potfix" name ="Fix Price" >
<param name="price" />
<cryptocurrency>POT</cryptocurrency>
</ratesource>
<ratesource prefix="coinmarketcap" name ="coinmarketcap.com" >
<param name="fiatcurrency" />
<cryptocurrency>POT</cryptocurrency>
</ratesource>
<cryptologo cryptocurrency="POT" file="pot.png"/>
</extension>
<extension class="com.generalbytes.batm.server.extensions.extra.dexacoin.DexCoinSupport">
<ratesource prefix="dex_fix" name ="Fix Price" >
<param name="price" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB