Updated on 2026-08-14

This commit is contained in:
Tangem 2019-07-24 14:13:44 +00:00
commit 9524fabb84
76 changed files with 4700 additions and 63 deletions

View file

@ -24,7 +24,8 @@ public enum Blockchain {
Matic("MATIC", "MTX", 1.0, R.drawable.tangem2, "Matic"),
MaticTestNet("MATIC/test", "MTX", 1.0, R.drawable.tangem2, "Matic Testnet"),
Stellar("XLM", "XLM", 1000000.0, R.drawable.ic_logo_stellar, "Stellar"),
StellarTestNet("XLM/test", "XLM", 1000000.0, R.drawable.ic_logo_stellar, "Stellar Testnet");
StellarTestNet("XLM/test", "XLM", 1000000.0, R.drawable.ic_logo_stellar, "Stellar Testnet"),
Eos("EOS", "EOS", 10000.0, R.drawable.tangem2, "EOS");
Blockchain(String ID, String currency, double multiplier, int imageResource, String officialName) {
mID = ID;

View file

@ -0,0 +1,48 @@
package com.tangem.data.network;
import android.util.Log;
import com.tangem.wallet.eos.EosApiPush;
import com.tangem.wallet.eos.EosPushTransactionRequest;
import io.jafka.jeos.EosApi;
import io.jafka.jeos.EosApiFactory;
import io.jafka.jeos.core.request.chain.transaction.PushTransactionRequest;
import io.jafka.jeos.core.response.chain.account.Account;
import io.jafka.jeos.core.response.chain.transaction.PushedTransaction;
import io.jafka.jeos.impl.EosApiServiceGenerator;
import io.jafka.jeos.impl.EosChainApiService;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
public class ServerApiEos {
private static String TAG = ServerApiBinance.class.getSimpleName();
public static void getBalance(String wallet, Observer<Account> accountObserver) {
Log.i(TAG, "new getBalance request");
EosApi eosApi = EosApiFactory.create("https://api.eosdetroit.io:443"); //TODO: add random server request
Observable<Account> accountObservable = Observable.just(new Account())
.map(account -> eosApi.getAccount(wallet))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
accountObservable.subscribe(accountObserver);
}
public static void sendTransaction(EosPushTransactionRequest req, Observer<PushedTransaction> sendObserver) {
Log.i(TAG, "new getBalance request");
// EosApi eosApi = EosApiFactory.create("https://api.eosdetroit.io:443"); //TODO: add random server request
EosApiPush eosApiPush = EosApiServiceGenerator.createService(EosApiPush.class, "https://api.eosdetroit.io:443"); //TODO: add random server request
Observable<PushedTransaction> sendObservable = Observable.just(new PushedTransaction())
.map(pushedTransaction -> EosApiServiceGenerator.executeSync(eosApiPush.pushTransaction(req)))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
sendObservable.subscribe(sendObserver);
}
}

View file

@ -5,22 +5,22 @@ import android.util.Log;
import com.tangem.wallet.ECDSASignatureETH;
import com.tangem.card_common.util.Util;
import org.spongycastle.asn1.ASN1EncodableVector;
import org.spongycastle.asn1.ASN1Integer;
import org.spongycastle.asn1.DERSequence;
import org.spongycastle.asn1.sec.SECNamedCurves;
import org.spongycastle.asn1.x9.X9ECParameters;
import org.spongycastle.asn1.x9.X9IntegerConverter;
import org.spongycastle.crypto.params.ECDomainParameters;
import org.spongycastle.crypto.params.ECPrivateKeyParameters;
import org.spongycastle.crypto.params.ECPublicKeyParameters;
import org.spongycastle.crypto.signers.ECDSASigner;
import org.spongycastle.jce.ECNamedCurveTable;
import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
import org.spongycastle.jce.spec.ECPublicKeySpec;
import org.spongycastle.math.ec.ECAlgorithms;
import org.spongycastle.math.ec.ECCurve;
import org.spongycastle.math.ec.ECPoint;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.sec.SECNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.asn1.x9.X9IntegerConverter;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.signers.ECDSASigner;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECAlgorithms;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

View file

@ -87,46 +87,46 @@ public class DerEncodingUtil {
return bos.toByteArray();
}
public static byte[] DerEncoding(byte[] sign)
{
byte[] r = sign;
byte[] s = new byte[32];
for(int i =0; i < 32; ++i)
{
s[i] = sign[i+32];
}
byte[] newR = PackInteger(r);
byte[] newS = PackInteger(s);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write((byte)(newR.length+newS.length+2));
baos.write((byte)newR.length);
baos.write(newR, 0, newR.length);
baos.write((byte)newS.length);
baos.write(newS, 0, newS.length);
return baos.toByteArray();
}
public static byte[] DerEncodingBI(BigInteger[] sign)
{
byte[] r = sign[0].toByteArray();
byte[] s = sign[1].toByteArray();
byte[] newR = PackInteger(r);
byte[] newS = PackInteger(s);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write((byte)(newR.length+newS.length+2));
baos.write((byte)newR.length);
baos.write(newR, 0, newR.length);
baos.write((byte)newS.length);
baos.write(newS, 0, newS.length);
return baos.toByteArray();
}
// public static byte[] DerEncoding(byte[] sign)
// {
// byte[] r = sign;
// byte[] s = new byte[32];
// for(int i =0; i < 32; ++i)
// {
// s[i] = sign[i+32];
// }
//
// byte[] newR = PackInteger(r);
// byte[] newS = PackInteger(s);
//
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
// baos.write((byte)(newR.length+newS.length+2));
// baos.write((byte)newR.length);
// baos.write(newR, 0, newR.length);
// baos.write((byte)newS.length);
// baos.write(newS, 0, newS.length);
//
// return baos.toByteArray();
// }
//
// public static byte[] DerEncodingBI(BigInteger[] sign)
// {
// byte[] r = sign[0].toByteArray();
// byte[] s = sign[1].toByteArray();
//
// byte[] newR = PackInteger(r);
// byte[] newS = PackInteger(s);
//
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
//
// baos.write((byte)(newR.length+newS.length+2));
//
// baos.write((byte)newR.length);
// baos.write(newR, 0, newR.length);
//
// baos.write((byte)newS.length);
// baos.write(newS, 0, newS.length);
//
// return baos.toByteArray();
// }
}

View file

@ -165,6 +165,11 @@ public abstract class CoinEngine {
public boolean isZero() {
return compareTo(BigDecimal.ZERO) == 0;
}
@Override
public Amount setScale(int newScale) {
return new Amount(super.setScale(newScale), currency);
}
}
protected TangemContext ctx;

View file

@ -7,6 +7,7 @@ import com.tangem.wallet.eth.EthEngine
import com.tangem.wallet.token.TokenEngine
import com.tangem.wallet.bch.BtcCashEngine
import com.tangem.data.Blockchain
import com.tangem.wallet.eos.EosEngine
import com.tangem.wallet.binance.BinanceEngine
import com.tangem.wallet.cardano.CardanoData
import com.tangem.wallet.cardano.CardanoEngine
@ -45,6 +46,7 @@ object CoinEngineFactory {
Blockchain.Binance, Blockchain.BinanceTestNet -> BinanceEngine()
Blockchain.Matic, Blockchain.MaticTestNet -> MaticTokenEngine()
Blockchain.StellarTestNet, Blockchain.Stellar -> XlmEngine()
Blockchain.Eos -> EosEngine()
else -> null
}
}
@ -78,6 +80,8 @@ object CoinEngineFactory {
MaticTokenEngine(context)
else if (Blockchain.Stellar == context.blockchain || Blockchain.StellarTestNet == context.blockchain)
XlmEngine(context)
else if (Blockchain.Eos == context.blockchain)
EosEngine(context)
else
return null
} catch (e: Exception) {

View file

@ -0,0 +1,13 @@
package com.tangem.wallet.eos;
import com.tangem.wallet.eos.EosPushTransactionRequest;
import io.jafka.jeos.core.response.chain.transaction.PushedTransaction;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.POST;
public interface EosApiPush {
@POST("/v1/chain/push_transaction")
Call<PushedTransaction> pushTransaction(@Body EosPushTransactionRequest eosPushTransactionRequest);
}

View file

@ -0,0 +1,53 @@
package com.tangem.wallet.eos;
import android.os.Bundle;
import android.util.Log;
import com.tangem.wallet.CoinData;
import com.tangem.wallet.CoinEngine;
public class EosData extends CoinData {
private CoinEngine.Amount balance = null;
@Override
public void clearInfo() {
super.clearInfo();
balance = null;
}
public CoinEngine.Amount getBalance() {
return balance;
}
public void setBalance(CoinEngine.Amount value) {
balance = value;
}
@Override
public void loadFromBundle(Bundle B) {
super.loadFromBundle(B);
if (B.containsKey("BalanceCurrency") && B.containsKey("BalanceDecimal")) {
String currency = B.getString("BalanceCurrency");
balance = new CoinEngine.Amount(B.getString("BalanceDecimal"), currency);
} else {
balance = null;
}
}
@Override
public void saveToBundle(Bundle B) {
super.saveToBundle(B);
try {
if (balance != null) {
B.putString("BalanceCurrency", balance.getCurrency());
B.putString("BalanceDecimal", balance.toValueString());
}
} catch (Exception e) {
Log.e("Can't save to bundle ", e.getMessage());
}
}
}

View file

@ -0,0 +1,630 @@
package com.tangem.wallet.eos;
import android.net.Uri;
import android.text.InputFilter;
import android.util.Log;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.primitives.Bytes;
import com.google.gson.Gson;
import com.tangem.Constant;
import com.tangem.card_common.data.TangemCard;
import com.tangem.card_common.reader.CardProtocol;
import com.tangem.card_common.tasks.SignTask;
import com.tangem.card_common.util.Util;
import com.tangem.data.Blockchain;
import com.tangem.data.network.ServerApiEos;
import com.tangem.util.CryptoUtil;
import com.tangem.util.DecimalDigitsInputFilter;
import com.tangem.util.DerEncodingUtil;
import com.tangem.wallet.BTCUtils;
import com.tangem.wallet.BalanceValidator;
import com.tangem.wallet.BuildConfig;
import com.tangem.wallet.CoinData;
import com.tangem.wallet.CoinEngine;
import com.tangem.wallet.R;
import com.tangem.wallet.TangemContext;
import com.tangem.wallet.eos.utilities.EOSFormatter;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.StringUtils;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.core.Utils;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import io.jafka.jeos.EosApi;
import io.jafka.jeos.EosApiFactory;
import io.jafka.jeos.LocalApi;
import io.jafka.jeos.convert.Packer;
import io.jafka.jeos.core.common.SignArg;
import io.jafka.jeos.core.common.transaction.TransactionAction;
import io.jafka.jeos.core.common.transaction.TransactionAuthorization;
import io.jafka.jeos.core.request.chain.json2bin.TransferArg;
import io.jafka.jeos.core.response.chain.account.Account;
import io.jafka.jeos.core.response.chain.transaction.PushedTransaction;
import io.jafka.jeos.util.Base58;
import io.jafka.jeos.util.Raw;
import io.jafka.jeos.util.ecc.Ripemd160;
import io.reactivex.Observer;
import io.reactivex.observers.DefaultObserver;
public class EosEngine extends CoinEngine {
private static final String TAG = EosEngine.class.getSimpleName();
public EosData coinData = null;
private final int signRetries = 10;
public EosEngine(TangemContext ctx) throws Exception {
super(ctx);
if (ctx.getCoinData() == null) {
coinData = new EosData();
ctx.setCoinData(coinData);
} else if (ctx.getCoinData() instanceof EosData) {
coinData = (EosData) ctx.getCoinData();
} else {
throw new Exception("Invalid type of Blockchain data for " + this.getClass().getSimpleName());
}
}
public EosEngine() {
super();
}
private static int getDecimals() {
return 4;
}
@Override
public boolean awaitingConfirmation() {
return false;
}
@Override
public Amount getBalance() {
if (!hasBalanceInfo()) {
return null;
}
return coinData.getBalance();
}
@Override
public String getBalanceHTML() {
Amount balance = getBalance();
if (balance != null) {
return balance.toDescriptionString(getDecimals());
} else {
return "";
}
}
@Override
public String getBalanceCurrency() {
return Blockchain.Eos.getCurrency();
}
@Override
public String getOfflineBalanceHTML() {
InternalAmount offlineInternalAmount = convertToInternalAmount(ctx.getCard().getOfflineBalance());
Amount offlineAmount = convertToAmount(offlineInternalAmount);
return offlineAmount.toDescriptionString(getDecimals());
}
@Override
public boolean isBalanceNotZero() {
if (coinData == null) return false;
if (coinData.getBalance() == null) return false;
return coinData.getBalance().notZero();
}
@Override
public String getFeeCurrency() {
return Blockchain.Eos.getCurrency();
}
public boolean isNeedCheckNode() {
return false;
}
@Override
public CoinData createCoinData() {
return new EosData();
}
@Override
public String getUnspentInputsDescription() {
return "";
}
public void defineWallet() throws CardProtocol.TangemException {
try {
String wallet = calculateAddress(ctx.getCard().getWalletPublicKeyRar());
ctx.getCoinData().setWallet(wallet);
} catch (Exception e) {
ctx.getCoinData().setWallet("ERROR");
throw new CardProtocol.TangemException("Can't define wallet address");
}
}
// BigDecimal convertToEth(String value) {
// BigInteger m = new BigInteger(value, 10);
// BigDecimal n = new BigDecimal(m);
// BigDecimal d = n.divide(new BigDecimal("1000000000000000000"));
// d = d.setScale(8, RoundingMode.DOWN);
// return d;
// }
@Override
public boolean validateAddress(String address) {
if (address.length() != 12) {
return false;
}
if (!address.toLowerCase().equals(address)) {
return false;
}
if (StringUtils.containsAny(address, "06789")) {
return false;
}
return true;
}
@Override
public String getBalanceEquivalent() {
Amount balance = getBalance();
if (balance == null) return "";
return balance.toEquivalentString(coinData.getRate());
}
@Override
public Amount convertToAmount(InternalAmount internalAmount) {
return new Amount(internalAmount, getBalanceCurrency());
}
@Override
public Amount convertToAmount(String strAmount, String currency) {
return new Amount(strAmount, currency);
}
@Override
public InternalAmount convertToInternalAmount(Amount amount) {
return new InternalAmount(amount, getBalanceCurrency());
}
@Override
public InternalAmount convertToInternalAmount(byte[] bytes) {
//throw new Exception("Not implemented");
return null;
}
@Override
public byte[] convertToByteArray(InternalAmount amount) throws Exception {
throw new Exception("Not implemented");
}
@Override
public boolean hasBalanceInfo() {
return coinData.getBalance() != null;
}
@Override
public Uri getShareWalletUri() { //TODO: check
return Uri.parse(ctx.getCoinData().getWallet());
}
@Override
public Uri getWalletExplorerUri() {
return Uri.parse("https://bloks.io/account/" + ctx.getCoinData().getWallet());
}
@Override
public boolean isExtractPossible() {
if (!hasBalanceInfo()) {
ctx.setMessage(R.string.cannot_obtain_data_from_blockchain);
} else if (!isBalanceNotZero()) {
ctx.setMessage(R.string.wallet_empty);
} else if (awaitingConfirmation()) {
ctx.setMessage(R.string.please_wait_while_previous);
} else {
return true;
}
return false;
}
@Override
public InputFilter[] getAmountInputFilters() {
return new InputFilter[]{new DecimalDigitsInputFilter(getDecimals())};
}
@Override
public boolean checkNewTransactionAmount(Amount amount) {
if (BuildConfig.FLAVOR == Constant.FLAVOR_TANGEM_CARDANO) {
return true;
}
Amount balance = getBalance();
if (balance == null || amount.compareTo(balance) > 0) {
return false;
}
return true;
}
@Override
public boolean checkNewTransactionAmountAndFee(Amount amount, Amount fee, Boolean isFeeIncluded) {
try {
BigDecimal cardBalance = getBalance();
if (isFeeIncluded && (amount.compareTo(cardBalance) > 0 || amount.compareTo(fee) < 0))
return false;
if (!isFeeIncluded && amount.add(fee).compareTo(cardBalance) > 0)
return false;
} catch (NumberFormatException e) {
e.printStackTrace();
}
return true;
}
@Override //TODO: check
public boolean validateBalance(BalanceValidator balanceValidator) {
if (getBalance() == null) {
balanceValidator.setScore(0);
balanceValidator.setFirstLine("Unknown balance");
balanceValidator.setSecondLine("Balance cannot be verified. Swipe down to refresh.");
return false;
}
if (coinData.isBalanceReceived()) {
balanceValidator.setScore(100);
balanceValidator.setFirstLine("Verified balance");
balanceValidator.setSecondLine("Balance confirmed in blockchain");
if (getBalance().isZero()) {
balanceValidator.setFirstLine("Empty wallet");
balanceValidator.setSecondLine("");
}
}
if ((ctx.getCard().getOfflineBalance() != null) && !coinData.isBalanceReceived() && (ctx.getCard().getRemainingSignatures() == ctx.getCard().getMaxSignatures()) && getBalance().notZero()) {
balanceValidator.setScore(80);
balanceValidator.setFirstLine("Verified offline balance");
balanceValidator.setSecondLine("Restore internet connection to obtain trusted balance from blockchain");
}
return true;
}
@Override
public String evaluateFeeEquivalent(String fee) {
try {
Amount feeValue = new Amount(fee, ctx.getBlockchain().getCurrency());
return feeValue.toEquivalentString(coinData.getRate());
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
@Override
public String calculateAddress(byte[] pkCompressed) {
String cid = Util.bytesToHex(ctx.getCard().getCID()).toLowerCase();
String address = cid.substring(0, 4) + cid.substring(8, 16);
address = address.replace("0", "o").replace("6", "b").replace("7,", "t").replace("8", "s").replace("9", "g");
return address;
// String cid = Util.bytesToHex(ctx.getCard().getCID());
// String address = "testem" + cid.substring(2, 4) + cid.substring(11, 15);
// address = address.replace("0", "o").replace("6", "b").replace("7,", "t").replace("8", "s").replace("9", "g");
// return address;
// byte[] csum = Ripemd160.from(pkCompressed).bytes();
// csum = Raw.copy(csum, 0, 4);
// byte[] addy = Raw.concat(pkCompressed, csum);
// StringBuffer bf = new StringBuffer("EOS");
// bf.append(Base58.encode(addy));
// return bf.toString() + " " + address;
}
public String calculateEosPubKey(byte[] pkCompressed) {
byte[] csum = Ripemd160.from(pkCompressed).bytes();
csum = Raw.copy(csum, 0, 4);
byte[] addy = Raw.concat(pkCompressed, csum);
StringBuffer bf = new StringBuffer("EOS");
bf.append(Base58.encode(addy));
return bf.toString();
}
// reference - https://gist.github.com/adyliu/492503b94d0306371298f24e15481da4
@Override
public SignTask.TransactionToSign constructTransaction(Amount amountValue, Amount feeValue, boolean IncFee, String targetAddress) throws JsonProcessingException {
// get the current state of blockchain
EosApi eosApi = EosApiFactory.create("https://api.eosdetroit.io:443");
SignArg arg = eosApi.getSignArg(120);
System.out.println(eosApi.getObjectMapper().writeValueAsString(arg));
// --- prepare transaction for sign as in LocalApiImpl
String quantity = amountValue.setScale(4).toString();
String memo = "";
// pack transfer data
TransferArg transferArg = new TransferArg(coinData.getWallet(), targetAddress, quantity, memo);
String transferData = Packer.packTransfer(transferArg);
//
// create the authorization
List<TransactionAuthorization> authorizations = Arrays.asList(new TransactionAuthorization(coinData.getWallet(), "active"));
// build the all actions
List<TransactionAction> actions = Arrays.asList(//
new TransactionAction("eosio.token", "transfer", authorizations, transferData)//
);
long expMillis = System.currentTimeMillis() + (arg.getExpiredSecond() * 1000);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.5", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));
String stringTime = format.format(new Date(expMillis));
// build the packed transaction
EosPackedTransaction packedTransaction = new EosPackedTransaction();
packedTransaction.setExpiration(stringTime);
packedTransaction.setRefBlockNum(arg.getLastIrreversibleBlockNum());
packedTransaction.setRefBlockPrefix(arg.getRefBlockPrefix());
packedTransaction.setMaxNetUsageWords(0);
packedTransaction.setMaxCpuUsageMs(0);
packedTransaction.setDelaySec(0);
packedTransaction.setActions(actions);
Raw raw = EosPacker.packPackedTransaction(arg.getChainId(), packedTransaction);
raw.pack(ByteBuffer.allocate(33).array()); //black magic
Sha256Hash hashForSign = Sha256Hash.of(raw.bytes());
return new SignTask.TransactionToSign() {
@Override
public boolean isSigningMethodSupported(TangemCard.SigningMethod signingMethod) {
return signingMethod == TangemCard.SigningMethod.Sign_Hash;
}
@Override
public byte[][] getHashesToSign() throws NoSuchAlgorithmException {
byte[][] hashesForSign = new byte[signRetries][];
for (int i = 0; i < signRetries; i++) {
hashesForSign[i] = hashForSign.getBytes();
}
return hashesForSign;
}
@Override
public byte[] getRawDataToSign() throws Exception {
throw new Exception("Signing of raw transaction not supported for " + this.getClass().getSimpleName());
}
@Override
public String getHashAlgToSign() throws Exception {
throw new Exception("Signing of raw transaction not supported for " + this.getClass().getSimpleName());
}
@Override
public byte[] getIssuerTransactionSignature(byte[] dataToSignByIssuer) throws Exception {
throw new Exception("Transaction validation by issuer not supported in this version");
}
@Override
public byte[] onSignCompleted(byte[] signFromCard) throws Exception {
BigInteger r = null, s = null;
for (int i = 0; i < signRetries; ++i) {
r = new BigInteger(1, Arrays.copyOfRange(signFromCard, i * 64, 32 + i * 64));
if (r.toByteArray().length == 33) {
Log.e(TAG, "33 bytes R: " + Util.bytesToHex(r.toByteArray()));
} else {
s = new BigInteger(1, Arrays.copyOfRange(signFromCard, 32 + i * 64, 64 + i * 64));
s = CryptoUtil.toCanonicalised(s);
break;
}
}
if (s == null) {
throw new Exception("All signatures not canonical");
}
boolean f = ECKey.verify(Util.calculateSHA256(raw.bytes()), new ECKey.ECDSASignature(r, s), ctx.getCard().getWalletPublicKey());
if (!f) {
Log.e(this.getClass().getSimpleName() + "-CHECK", "sign Failed.");
}
ECKey.ECDSASignature ecdsaSig = new ECKey.ECDSASignature(r, s);
int v = BruteRecoveryID(ecdsaSig, hashForSign, ctx.getCard().getWalletPublicKeyRar());
v += 4; // compressed
v += 27; // compact // 24 or 27 :( forcing odd-y 2nd key candidate)
byte[] rbytes = Utils.bigIntegerToBytes(r, 32);
byte[] sbytes = Utils.bigIntegerToBytes(s, 32);
//TODO: not every signature works for EOS, if r.toByteArray length is 33, even if first 0x00 byte is cut,
//TODO: signature would be counted non canonical because first bit is not zero. Need to check it on card or there will be multiple security delays
// if (r.toByteArray().length == 33) {
// Log.e(TAG, "33 bytes R: " + Util.bytesToHex(rbytes));
// throw new Exception("33 byte R");
// }
byte[] pub_buf = new byte[65];
pub_buf[0] = (byte) v;
System.arraycopy(rbytes, 0, pub_buf, 1, rbytes.length);
System.arraycopy(sbytes, 0, pub_buf, rbytes.length + 1, sbytes.length);
byte[] checksum = Ripemd160.from(Raw.concat(pub_buf, "K1".getBytes())).bytes();
byte[] signatureBytes = Raw.concat(pub_buf, Raw.copy(checksum, 0, 4));
Log.e(TAG, "Signature hex " + Util.byteArrayToHexString(signatureBytes));
String signatureString = "SIG_K1_" + Base58.encode(signatureBytes);
Log.e(TAG, "1st sig" + signatureString);
// byte[] sigDer = DerEncodingUtil.DerEncoding(newR, s);
// String eosPubKey = calculateEosPubKey(ctx.getCard().getWalletPublicKeyRar());
// String pemPubKey = EOSFormatter.convertEOSPublicKeyToPEMFormat(eosPubKey);
// String convertedSignature = EOSFormatter.convertDERSignatureToEOSFormat(sigDer, raw.bytes(), pemPubKey);
// Log.e(TAG, "2nd sig" + convertedSignature);
// String convertedBase = convertedSignature.substring(7);
// byte[] convertedBytes = Base58.decode(convertedBase);
EosPushTransactionRequest req = new EosPushTransactionRequest();
req.setTransaction(packedTransaction);
req.setSignatures(Arrays.asList(signatureString));
//serialize
String reqString = new Gson().toJson(req);
byte[] txForSend = SerializationUtils.serialize(reqString);
notifyOnNeedSendTransaction(txForSend);
return txForSend;
}
};
}
private int BruteRecoveryID(ECKey.ECDSASignature sig, Sha256Hash messageHash, byte[] thisKey) {
Log.e("EOS_KZ", BTCUtils.toHex(thisKey));
int recId = -1;
for (int i = 0; i < 4; i++) {
ECKey k = ECKey.recoverFromSignature(i, sig, messageHash, true);
if (k == null)
continue;
byte[] recK = k.getPubKey();
Log.e("EOS_k " + i, BTCUtils.toHex(recK));
if (Arrays.equals(recK, thisKey)) {
recId = i;
break;
}
}
return recId;
}
@Override
public void requestBalanceAndUnspentTransactions(BlockchainRequestsCallbacks blockchainRequestsCallbacks) {
Observer<Account> accountObserver = new DefaultObserver<Account>() {
@Override
public void onNext(Account account) {
if (account.getCoreLiquidBalance() != null) {
String[] balanceStrings = account.getCoreLiquidBalance().split(" ");
coinData.setBalanceReceived(true);
coinData.setBalance(new Amount(balanceStrings[0], balanceStrings[1]));
} else {
coinData.setBalanceReceived(true);
coinData.setBalance(new Amount(0L, getBalanceCurrency()));
}
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "requestBalanceAndUnspentTransactions error" + e.getMessage());
ctx.setError(e.getMessage());
blockchainRequestsCallbacks.onComplete(false);
}
@Override
public void onComplete() {
blockchainRequestsCallbacks.onComplete(true);
}
};
ServerApiEos.getBalance(coinData.getWallet(), accountObserver);
}
@Override
public void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) {
// no fee in EOS
coinData.minFee = coinData.normalFee = coinData.maxFee = new Amount(0L, "EOS");
blockchainRequestsCallbacks.onComplete(true);
}
@Override
public void requestSendTransaction(BlockchainRequestsCallbacks blockchainRequestsCallbacks, byte[] txForSend) throws IOException, ClassNotFoundException {
// deserialize
String reqString = SerializationUtils.deserialize(txForSend);
EosPushTransactionRequest req = new Gson().fromJson(reqString, EosPushTransactionRequest.class);
Observer<PushedTransaction> sendObserver = new DefaultObserver<PushedTransaction>() {
@Override
public void onNext(PushedTransaction pushedTransaction) {
if (pushedTransaction.getProcessed().getReceipt().getStatus().equals("executed")) {
ctx.setError(null);
} else {
ctx.setError("Error sending transaction. Transaction rejected");
try {
LocalApi localApi = EosApiFactory.createLocalApi();
Log.e(TAG, localApi.getObjectMapper().writeValueAsString(pushedTransaction));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "requestSendTransaction error" + e.getMessage());
ctx.setError(e.getMessage());
LocalApi localApi = EosApiFactory.createLocalApi();
try {
Log.e(TAG, localApi.getObjectMapper().writeValueAsString(req));
} catch (JsonProcessingException e1) {
e1.printStackTrace();
}
blockchainRequestsCallbacks.onComplete(false);
}
@Override
public void onComplete() {
if (!ctx.hasError()) {
blockchainRequestsCallbacks.onComplete(true);
} else {
blockchainRequestsCallbacks.onComplete(false);
}
}
};
ServerApiEos.sendTransaction(req, sendObserver);
}
public int pendingTransactionTimeoutInSeconds() {
return 10;
}
@Override
public boolean needMultipleLinesForBalance() {
return true;
}
@Override
public boolean allowSelectFeeLevel() {
return false;
}
@Override
public boolean allowSelectFeeInclusion() {
return false;
}
}

View file

@ -0,0 +1,25 @@
package com.tangem.wallet.eos
import com.fasterxml.jackson.annotation.JsonInclude
import io.jafka.jeos.core.common.transaction.TransactionAction
import java.util.*
@JsonInclude(JsonInclude.Include.NON_NULL)
data class EosPackedTransaction(
var expiration: String? = null,//"2018-08-30T02:30:49"
var refBlockNum: Long? = null,
var refBlockPrefix: Long? = null,
var maxNetUsageWords: Int? = null,
var maxCpuUsageMs: Int? = null,
var delaySec: Int? = null,
var contextFreeActions: ArrayList<TransactionAction> = ArrayList<TransactionAction>(),
var actions: List<TransactionAction> = ArrayList<TransactionAction>(),
var transactionExtensions: ArrayList<String> = ArrayList<String>(),
//private List<String> signatures;
var contextFreeData: ArrayList<String> = ArrayList<String>(),
//
var region: String? = null
)

View file

@ -0,0 +1,71 @@
package com.tangem.wallet.eos;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import io.jafka.jeos.convert.Packer;
import io.jafka.jeos.core.common.transaction.TransactionAction;
import io.jafka.jeos.core.common.transaction.TransactionAuthorization;
import io.jafka.jeos.util.Raw;
import io.jafka.jeos.util.ecc.Hex;
public class EosPacker extends Packer {
public static Raw packPackedTransaction(String chainId, EosPackedTransaction t) {
Raw raw = new Raw();
//chain
raw.pack(Hex.toBytes(chainId));
//expiration
try {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.5", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = format.parse(t.getExpiration());
raw.packUint32(date.getTime() / 1000);
} catch (ParseException e) {
e.printStackTrace();
}
//ref_block_num
raw.packUint16(t.getRefBlockNum().intValue());
//ref_block_prefix
raw.packUint32(t.getRefBlockPrefix());
//max_net_usage_words
raw.packVarint32(t.getMaxNetUsageWords());
//max_cpu_usage_ms
raw.packUint8(t.getMaxCpuUsageMs());//TODO: what the type?
//delay_sec
raw.packVarint32(t.getDelaySec());
//context_free_actions
raw.packVarint32(t.getContextFreeActions().size());
//TODO: getContextFreeActions
//actions
raw.packVarint32(t.getActions().size());
for (TransactionAction a : t.getActions()) {
//action.account
raw.packName(a.getAccount())//
.packName(a.getName())//
.packVarint32(a.getAuthorization().size())//
;
//action.authorization
for (TransactionAuthorization au : a.getAuthorization()) {
raw.packName(au.getActor())//
.packName(au.getPermission());
}
//action.data
byte[] dat = Hex.toBytes(a.getData());
raw.packVarint32(dat.length);
raw.pack(dat);
}
//transaction_extensions
//raw.packVarint32(t.getTransactionExtensions().size());
//TODO: getTransactionExtensions
//context_free_data
//raw.packVarint32(t.getContextFreeActions().size());
return raw;
}
}

View file

@ -0,0 +1,7 @@
package com.tangem.wallet.eos
data class EosPushTransactionRequest(
var compression: String = "none",
var transaction: EosPackedTransaction? = null,
var signatures: List<String>? = null
)

View file

@ -0,0 +1,39 @@
package com.tangem.wallet.eos.enums;
/**
* Enum of supported algorithms which are employed in eosio-java library
*/
public enum AlgorithmEmployed {
/**
* Supported SECP256r1 (prime256v1) algorithm curve
*/
SECP256R1("secp256r1"),
/**
* Supported SECP256k1 algorithm curve
*/
SECP256K1("secp256k1"),
/**
* Supported prime256v1 algorithm curve
*/
PRIME256V1("prime256v1");
private String str;
/**
* Initialize AlgorithmEmployed enum object with a String value
* @param str - input String value of enums in AlgorithmEmployed
*/
AlgorithmEmployed(String str) {
this.str = str;
}
/**
* Gets string value of AlgorithmEmployed's enum
* @return string value of AlgorithmEmployed's enum
*/
public String getString() {
return str;
}
}

View file

@ -0,0 +1,69 @@
package com.tangem.wallet.eos.error;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to process anything inside the
* Eosio-java library
*/
public class EosioError extends Exception {
/**
* Create an EosioError with a null message and original exception.
*/
public EosioError() {
super();
}
/**
* Construct an EosioError with the given message.
*
* @param message - Message text for the exception.
*/
public EosioError(@NotNull String message) {
super(message);
}
/**
* Construct an EosioError with the given message and original exception.
*
* @param message - Message text for the exception.
* @param exception - Original root exception for the error.
*/
public EosioError(@NotNull String message, @NotNull Exception exception) {
super(message, exception);
}
/**
* Construct an EosioError with the given original exception.
*
* @param exception - Original root exception for the error.
*/
public EosioError(@NotNull Exception exception) {
super(exception);
}
/**
* Construct a JSON formatted string describing the error code and reason.
*
* @return A JSON formatted string
*/
@NotNull
public String asJsonString() {
JsonObject errInfo = new JsonObject();
errInfo.addProperty("errorCode", this.getClass().getSimpleName());
errInfo.addProperty("reason", this.getLocalizedMessage());
JsonObject err = new JsonObject();
err.addProperty("errorType", "EosioError");
err.add("errorInfo", errInfo);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String jsonString = gson.toJson(err);
return jsonString;
}
}

View file

@ -0,0 +1,314 @@
package com.tangem.wallet.eos.error;
import java.util.List;
@SuppressWarnings("ALL")
public class ErrorConstants {
private ErrorConstants(){
}
//EOSFormatter() Errors
/**
* The private key provided is not in the EOS format.
*/
public static final String INVALID_EOS_PRIVATE_KEY = "The EOS private key provided is invalid!";
/**
* The public key provided is not in the EOS format.
*/
public static final String INVALID_EOS_PUBLIC_KEY = "The EOS public key provided is invalid!";
/**
* An error occurred while Base58 decoding the EOS key.
*/
public static final String BASE58_DECODING_ERROR = "An error occurred while Base58 decoding the EOS key!";
/**
* The key provided for Base58 decoding was empty.
*/
public static final String BASE58_EMPTY_KEY = "Input key to decode can't be empty!";
/**
* Input key, checksum or key type were empty and are needed for validation.
*/
public static final String BASE58_EMPTY_CHECKSUM_OR_KEY = "Input key, checksum and key type to validate can't be empty!";
/**
* Input key, checksum or key type were empty and are needed for validation.
*/
public static final String BASE58_EMPTY_CHECKSUM_OR_KEY_OR_KEY_TYPE = "Input key, checksum and key type to validate can't be empty!";
/**
* Input key has invalid checksum.
*/
public static final String BASE58_INVALID_CHECKSUM = "Input key has invalid checksum!";
/**
* Error converting DER encoded key to PEM format.
*/
public static final String DER_TO_PEM_CONVERSION = "Error converting DER encoded key to PEM format!";
/**
* The algorithm used to generate the object is unsupported.
*/
public static final String UNSUPPORTED_ALGORITHM = "Unsupported algorithm!";
/**
* The private key is not in PEM format.
*/
public static final String INVALID_PEM_PRIVATE_KEY = "This is not a PEM formatted private key!";
/**
* The private key is not in DER format.
*/
public static final String INVALID_DER_PRIVATE_KEY = "DER format of private key is incorrect!";
/**
* Checksum generation failed.
*/
public static final String CHECKSUM_GENERATION_ERROR = "Could not generate checksum!";
/**
* The object could not be Base58 encoded.
*/
public static final String BASE58_ENCODING_ERROR = "Unable to Base58 encode object!";
/**
* The public key could not be decompressed.
*/
public static final String PUBLIC_KEY_DECOMPRESSION_ERROR = "Problem decompressing public key!";
/**
* The public key could not be compressed.
*/
public static final String PUBLIC_KEY_COMPRESSION_ERROR = "Problem compressing public key!";
/**
* The public key provided for decoding was empty.
*/
public static final String PUBLIC_KEY_IS_EMPTY = "Input key to decode can't be empty!";
/**
* Chain id or serialized transaction parameter was empty.
*/
public static final String EMPTY_INPUT_PREPARE_SERIALIZIED_TRANS_FOR_SIGNING = "Chain id and serialized transaction can't be empty!";
/**
* The signable transaction parameter was empty.
*/
public static final String EMPTY_INPUT_EXTRACT_SERIALIZIED_TRANS_FROM_SIGNABLE = "Signable transaction can't be empty!";
/**
* The length of the signable transaction was incorrect and the serialized transaction could not
* be extracted.
*/
public static final String INVALID_INPUT_SIGNABLE_TRANS_LENGTH_EXTRACT_SERIALIZIED_TRANS_FROM_SIGNABLE = "Length of the signable transaction must be larger than %s";
/**
* The signable transaction was improperly formatted.
*/
public static final String INVALID_INPUT_SIGNABLE_TRANS_EXTRACT_SERIALIZIED_TRANS_FROM_SIGNABLE = "Signable transaction has to have this structure: chainId (64 characters) + serialized transaction + 32 bytes of 0!";
/**
* Unable to extract the serialized transaction from the signable transaction.
*/
public static final String EXTRACT_SERIALIZIED_TRANS_FROM_SIGNABLE_ERROR = "Something went wrong when trying to extract serialized transaction from signable transaction.";
/**
* Signature formatting failed.
*/
public static final String SIGNATURE_FORMATTING_ERROR = "An error occured formating the signature!";
/**
* A public key could not be recovered from the signature.
*/
public static final String COULD_NOT_RECOVER_PUBLIC_KEY_FROM_SIG = "Could not recover public key from Signature.";
/**
* The signature provided failed the canonical check.
*/
public static final String NON_CANONICAL_SIGNATURE = "Input signature is not canonical.";
/**
* The public key could not be extracted from the provided private key. The private key is most
* likely invalid.
*/
public static final String PUBLIC_KEY_COULD_NOT_BE_EXTRACTED_FROM_PRIVATE_KEY = "This is not a private key!";
// ABIProviderImpl Errors
public static final String NO_RESPONSE_RETRIEVING_ABI = "No response retrieving ABI.";
public static final String MISSING_ABI_FROM_RESPONSE = "Missing ABI from GetRawAbiResponse.";
public static final String CALCULATED_HASH_NOT_EQUAL_RETURNED = "Calculated ABI hash does not match returned hash.";
public static final String REQUESTED_ACCCOUNT_NOT_EQUAL_RETURNED = "Requested account name does not match returned account name.";
public static final String NO_ABI_FOUND = "No ABI found for requested account name.";
public static final String ERROR_RETRIEVING_ABI = "Error retrieving ABI from the chain.";
//PEMProcessor Errors
/**
* The object provided is not in the PEM format.
*/
public static final String ERROR_READING_PEM_OBJECT = "Error reading PEM object!";
/**
* The PEM object could not be parsed.
*/
public static final String ERROR_PARSING_PEM_OBJECT = "Error parsing PEM object!";
/**
* There was no key data in the PEM object.
*/
public static final String KEY_DATA_NOT_FOUND = "Key data not found in PEM object!";
/**
* PEM object could not be read.
*/
public static final String INVALID_PEM_OBJECT = "Cannot read PEM object!";
//TransactionProcessor Errors
/**
* Error message get thrown if actions list is empty during processes of {@link TransactionProcessor}.
*/
public static final String TRANSACTION_PROCESSOR_ACTIONS_EMPTY_ERROR_MSG = "Action list can't be empty!";
/**
* Error message get thrown if {@link IRPCProvider#getInfo()} thrown exception during processes of {@link TransactionProcessor}
*/
public static final String TRANSACTION_PROCESSOR_RPC_GET_INFO = "Error happened on calling GetInfo RPC.";
/**
* Error message get thrown if {@link IRPCProvider#getBlock(GetBlockRequest)} thrown exception during process of {@link TransactionProcessor#prepare(List)}
*/
public static final String TRANSACTION_PROCESSOR_PREPARE_RPC_GET_BLOCK = "Error happened on calling GetBlock RPC.";
/**
* Error message get thrown if chain id from {@link GetInfoResponse#getChainId()} does not match with the input chain id
*/
public static final String TRANSACTION_PROCESSOR_PREPARE_CHAINID_NOT_MATCH = "Provided chain id %s does not match chain id %s";
/**
* Error message get thrown if chain id from {@link GetInfoResponse#getChainId()} is empty.
*/
public static final String TRANSACTION_PROCESSOR_PREPARE_CHAINID_RPC_EMPTY = "Chain id from back end is empty!";
/**
* Error message get thrown if parsing head block time from {@link GetInfoResponse#getHeadBlockTime()} get error
*/
public static final String TRANSACTION_PROCESSOR_HEAD_BLOCK_TIME_PARSE_ERROR = "Failed to parse head block time";
/**
* Error message get thrown if making clone version of transaction is failed.
*/
public static final String TRANSACTION_PROCESSOR_PREPARE_CLONE_ERROR = "Error happened on cloning transaction.";
/**
* Error message get thrown if making clone version of transaction is failed by {@link ClassNotFoundException}
*/
public static final String TRANSACTION_PROCESSOR_PREPARE_CLONE_CLASS_NOT_FOUND = "Transaction class was not found";
/**
* Error message get thrown if the current transaction inside {@link TransactionProcessor} has not been initialized or empty.
*/
public static final String TRANSACTION_PROCESSOR_TRANSACTION_HAS_TO_BE_INITIALIZED = "Transaction must be initialized before this method could be called! call prepare for initialize Transaction";
/**
* Error message get thrown if {@link IABIProvider#getAbi(String, EOSIOName)} get error.
*/
public static final String TRANSACTION_PROCESSOR_GET_ABI_ERROR = "Error happened on getting abi for contract [%s]";
/**
* Error message get thrown if Action's serialization process execute successfully but its result is empty.
*/
public static final String TRANSACTION_PROCESSOR_SERIALIZE_ACTION_WORKED_BUT_EMPTY_RESULT = "Serialization of action worked fine but got back empty result!";
/**
* Error message get thrown if Transaction's serialization process execute successfully but its result is empty.
*/
public static final String TRANSACTION_PROCESSOR_SERIALIZE_TRANSACTION_WORKED_BUT_EMPTY_RESULT = "Serialization of transaction worked fine but got back empty result!";
/**
* Error message get thrown if Action's serialization process get error by calling {@link ISerializationProvider#serialize(AbiEosSerializationObject)}
*/
public static final String TRANSACTION_PROCESSOR_SERIALIZE_ACTION_ERROR = "Error happened on serializing action [%s]";
/**
* Error message get thrown if Transaction's serialization process get error by calling {@link ISerializationProvider#serializeTransaction(String)}
*/
public static final String TRANSACTION_PROCESSOR_SERIALIZE_TRANSACTION_ERROR = "Error happened on serializing transaction";
/**
* Error message get thrown if {@link ISignatureProvider#getAvailableKeys()} returns error.
*/
public static final String TRANSACTION_PROCESSOR_GET_AVAILABLE_KEY_ERROR = "Error happened on getAvailableKeys from SignatureProvider!";
/**
* Error message get thrown if {@link ISignatureProvider#getAvailableKeys()} returns no key.
*/
public static final String TRANSACTION_PROCESSOR_GET_AVAILABLE_KEY_EMPTY = "Signature provider return no available key";
/**
* Error message get thrown if {@link IRPCProvider#getRequiredKeys(GetRequiredKeysRequest)} get error.
*/
public static final String TRANSACTION_PROCESSOR_RPC_GET_REQUIRED_KEYS = "Error happened on calling getRequiredKeys RPC call.";
/**
* Error message get thrown if {@link IRPCProvider#getRequiredKeys(GetRequiredKeysRequest)} returns no key.
*/
public static final String GET_REQUIRED_KEY_RPC_EMPTY_RESULT = "GetRequiredKeys RPC returned no required keys";
/**
* Error message get thrown if {@link ISignatureProvider#signTransaction(EosioTransactionSignatureRequest)} returns error
*/
public static final String TRANSACTION_PROCESSOR_SIGN_TRANSACTION_ERROR = "Error happened on calling sign transaction of Signature provider";
/**
* Error message get thrown if {@link ISignatureProvider#signTransaction(EosioTransactionSignatureRequest)} return empty serialized transaction.
*/
public static final String TRANSACTION_PROCESSOR_SIGN_TRANSACTION_TRANS_EMPTY_ERROR = "Serialized transaction come back empty from Signature Provider";
/**
* Error message get thrown if {@link ISignatureProvider#signTransaction(EosioTransactionSignatureRequest)} return no signature.
*/
public static final String TRANSACTION_PROCESSOR_SIGN_TRANSACTION_SIGN_EMPTY_ERROR = "Signatures come back empty from Signature Provider";
/**
* Error message get thrown if {@link EosioTransactionSignatureResponse} which return from {@link ISignatureProvider#signTransaction(EosioTransactionSignatureRequest)} has modified serialized transaction but {@link TransactionProcessor#isTransactionModificationAllowed()} is false
*/
public static final String TRANSACTION_IS_NOT_ALLOWED_TOBE_MODIFIED = "The transaction is not allowed to be modified but was modified by signature provider!";
/**
* Error message get thrown if {@link ISerializationProvider#deserializeTransaction} returns error during deserialize modified serialized transaction inside {@link EosioTransactionSignatureResponse} which return from {@link ISignatureProvider#signTransaction(EosioTransactionSignatureRequest)}
*/
public static final String TRANSACTION_PROCESSOR_GET_SIGN_DESERIALIZE_TRANS_ERROR = "Error happened on calling deserializeTransaction to refresh transaction object with new values";
/**
* Error message get thrown if {@link IRPCProvider#pushTransaction(PushTransactionRequest)} returns error.
*/
public static final String TRANSACTION_PROCESSOR_RPC_PUSH_TRANSACTION = "Error happened on calling pushTransaction RPC call";
/**
* Error message get thrown if {@link TransactionProcessor#serialize()}
*/
public static final String TRANSACTION_PROCESSOR_SERIALIZE_ERROR = "Error happened on calling serializeTransaction";
/**
* Error message get thrown if error happens during creating signature process of {@link TransactionProcessor#sign()}
*/
public static final String TRANSACTION_PROCESSOR_SIGN_CREATE_SIGN_REQUEST_ERROR = "Error happened on creating signature request for Signature Provider to sign!";
/**
* Error message get thrown if error happens during pushing transaction to backend
*/
public static final String TRANSACTION_PROCESSOR_BROADCAST_TRANS_ERROR = "Error happened on pushing transaction to chain!";
/**
* Error message get thrown if required keys from {@link GetRequiredKeysResponse} is not subset of keys from {@link ISignatureProvider#getAvailableKeys()}
*/
public static final String TRANSACTION_PROCESSOR_REQUIRED_KEY_NOT_SUBSET = "Required keys from back end are not available in available keys from Signature Provider.";
/**
* Error message get thrown if serialized transaction is empty or has not been populated during process of {@link TransactionProcessor#broadcast()}
*/
public static final String TRANSACTION_PROCESSOR_BROADCAST_SERIALIZED_TRANSACTION_EMPTY = "Serialized Transaction is empty or has not been populated. Make sure to call prepare then sign before calling broadcast";
/**
* Error message get thrown if serialized transaction is empty or has not been populated during process of {@link TransactionProcessor#signAndBroadcast()} ()}
*/
public static final String TRANSACTION_PROCESSOR_SIGN_BROADCAST_SERIALIZED_TRANSACTION_EMPTY = "Serialized Transaction is empty or has not been populated. Make sure to call prepare then sign before calling sign and broadcast";
/**
* Error message get thrown if {@link ISignatureProvider#signTransaction(EosioTransactionSignatureRequest)} return error during process of {@link TransactionProcessor#sign()}
*/
public static final String TRANSACTION_PROCESSOR_SIGN_SIGNATURE_RESPONSE_ERROR = "Error happened on the response of getSignature.";
/**
* Error message get thrown if {@link ISerializationProvider#deserializeTransaction} returns empty result during deserialize modified serialized transaction inside {@link EosioTransactionSignatureResponse} which return from {@link ISignatureProvider#signTransaction(EosioTransactionSignatureRequest)}
*/
public static final String TRANSACTION_PROCESSOR_GET_SIGN_DESERIALIZE_TRANS_EMPTY_ERROR = "Deserialized transaction is null or empty";
/**
* Error message get thrown if {@link TransactionProcessor#getSignatures()} is empty during process of {@link TransactionProcessor#broadcast()}
*/
public static final String TRANSACTION_PROCESSOR_BROADCAST_SIGN_EMPTY = "Can't call broadcast because Signature is empty. Make sure of calling sign before calling broadcast.";
/**
* Error message get thrown if {@link TransactionProcessor#getSignatures()} is empty during process of {@link TransactionProcessor#signAndBroadcast()} ()}
*/
public static final String TRANSACTION_PROCESSOR_SIGN_BROADCAST_SIGN_EMPTY = "Can't call sign and broadcast because Signature is empty. Make sure of calling sign before calling sign and broadcast.";
}

View file

@ -0,0 +1,28 @@
package com.tangem.wallet.eos.error.abiProvider;
import com.tangem.wallet.eos.error.EosioError;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call any method in an
* AbiProvider implementation.
*/
public class AbiProviderError extends EosioError {
public AbiProviderError() {
}
public AbiProviderError(@NotNull String message) {
super(message);
}
public AbiProviderError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public AbiProviderError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.wallet.eos.error.abiProvider;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call the GetAbi or GetAbis methods
* of IABIProvider {@link one.block.eosiojava.interfaces.IABIProvider}.
*/
public class GetAbiError extends AbiProviderError {
public GetAbiError() {
}
public GetAbiError(@NotNull String message) {
super(message);
}
public GetAbiError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public GetAbiError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,6 @@
/**
* Provides the classes necessary for describe meaningful exceptions that occur during an ABI Provider implementation like:
* {@link one.block.eosiojava.error.abiProvider.GetAbiError}
*/
package com.tangem.wallet.eos.error.abiProvider;

View file

@ -0,0 +1,8 @@
/**
* Provides the classes/constants necessary to describe meaningful exceptions that occur in all processes
* of eosio-java like:
* {@link one.block.eosiojava.session.TransactionProcessor} transaction processing flow,
* {@link one.block.eosiojava.utilities.EOSFormatter} utilities and other processes.
*/
package com.tangem.wallet.eos.error;

View file

@ -0,0 +1,25 @@
package com.tangem.wallet.eos.error.rpcProvider;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to use the RPC call, getBlock().
*/
public class GetBlockRpcError extends RpcProviderError {
public GetBlockRpcError() {
}
public GetBlockRpcError(@NotNull String message) {
super(message);
}
public GetBlockRpcError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public GetBlockRpcError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,25 @@
package com.tangem.wallet.eos.error.rpcProvider;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to use the RPC call, getInfo().
*/
public class GetInfoRpcError extends RpcProviderError {
public GetInfoRpcError() {
}
public GetInfoRpcError(@NotNull String message) {
super(message);
}
public GetInfoRpcError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public GetInfoRpcError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,27 @@
package com.tangem.wallet.eos.error.rpcProvider;
import com.tangem.wallet.eos.error.EosioError;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to use the RPC call, getRawAbi().
*/
public class GetRawAbiRpcError extends EosioError {
public GetRawAbiRpcError() {
}
public GetRawAbiRpcError(@NotNull String message) {
super(message);
}
public GetRawAbiRpcError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public GetRawAbiRpcError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.wallet.eos.error.rpcProvider;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to use the RPC call,
* getRequiredKeys().
*/
public class GetRequiredKeysRpcError extends RpcProviderError {
public GetRequiredKeysRpcError() {
}
public GetRequiredKeysRpcError(@NotNull String message) {
super(message);
}
public GetRequiredKeysRpcError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public GetRequiredKeysRpcError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.wallet.eos.error.rpcProvider;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to use the RPC call,
* pushTransaction().
*/
public class PushTransactionRpcError extends RpcProviderError {
public PushTransactionRpcError() {
}
public PushTransactionRpcError(@NotNull String message) {
super(message);
}
public PushTransactionRpcError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public PushTransactionRpcError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,29 @@
package com.tangem.wallet.eos.error.rpcProvider;
import com.tangem.wallet.eos.error.EosioError;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to use any RPC call.
* <br>
* Any exception class which is used in an RPC Provider should extend this Error class.
*/
public class RpcProviderError extends EosioError {
public RpcProviderError() {
}
public RpcProviderError(@NotNull String message) {
super(message);
}
public RpcProviderError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public RpcProviderError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,6 @@
/**
* Provides the classes necessary for describe meaningful exceptions that occur during an PRC Provider implementation like:
* {@link one.block.eosiojava.error.rpcProvider.GetInfoRpcError}
*/
package com.tangem.wallet.eos.error.rpcProvider;

View file

@ -0,0 +1,26 @@
package com.tangem.wallet.eos.error.serializationProvider;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call deserializeAbi() of
* Serialization Provider
*/
public class DeserializeAbiError extends SerializationProviderError {
public DeserializeAbiError() {
}
public DeserializeAbiError(@NotNull String message) {
super(message);
}
public DeserializeAbiError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public DeserializeAbiError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.wallet.eos.error.serializationProvider;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call deserialize() of
* Serialization Provider
*/
public class DeserializeError extends SerializationProviderError {
public DeserializeError() {
}
public DeserializeError(@NotNull String message) {
super(message);
}
public DeserializeError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public DeserializeError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.wallet.eos.error.serializationProvider;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call deserializeTransaction()
* of Serialization Provider
*/
public class DeserializeTransactionError extends SerializationProviderError {
public DeserializeTransactionError() {
}
public DeserializeTransactionError(@NotNull String message) {
super(message);
}
public DeserializeTransactionError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public DeserializeTransactionError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,29 @@
package com.tangem.wallet.eos.error.serializationProvider;
import com.tangem.wallet.eos.error.EosioError;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call any method of Serialization Provider.
* <br>
* Any exception class which is used for Serialization Provider should extend this Error class.
*/
public class SerializationProviderError extends EosioError {
public SerializationProviderError() {
}
public SerializationProviderError(@NotNull String message) {
super(message);
}
public SerializationProviderError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public SerializationProviderError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.wallet.eos.error.serializationProvider;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call serializeAbi()
* of Serialization Provider
*/
public class SerializeAbiError extends SerializationProviderError {
public SerializeAbiError() {
}
public SerializeAbiError(@NotNull String message) {
super(message);
}
public SerializeAbiError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public SerializeAbiError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.wallet.eos.error.serializationProvider;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call serialize()
* of Serialization Provider
*/
public class SerializeError extends SerializationProviderError {
public SerializeError() {
}
public SerializeError(@NotNull String message) {
super(message);
}
public SerializeError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public SerializeError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.wallet.eos.error.serializationProvider;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call serializeTransaction() of
* Serialization Provider
*/
public class SerializeTransactionError extends SerializationProviderError {
public SerializeTransactionError() {
}
public SerializeTransactionError(@NotNull String message) {
super(message);
}
public SerializeTransactionError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public SerializeTransactionError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,6 @@
/**
* Provides the classes necessary to describe meaningful exceptions that occur during a Serialization Provider implementation like:
* {@link one.block.eosiojava.error.serializationProvider.SerializeTransactionError}
*/
package com.tangem.wallet.eos.error.serializationProvider;

View file

@ -0,0 +1,25 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error would be thrown from TransactionProcessor#BroadCast if signatures is empty
*/
public class TransactionBroadCastEmptySignatureError extends TransactionBroadCastError {
public TransactionBroadCastEmptySignatureError() {
}
public TransactionBroadCastEmptySignatureError(@NotNull String message) {
super(message);
}
public TransactionBroadCastEmptySignatureError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionBroadCastEmptySignatureError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,25 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call broadCast() of TransactionProcessor
*/
public class TransactionBroadCastError extends TransactionProcessorError {
public TransactionBroadCastError() {
}
public TransactionBroadCastError(@NotNull String message) {
super(message);
}
public TransactionBroadCastError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionBroadCastError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call getAbi() inside
* createSignature() of TransactionProcessor
*/
public class TransactionCreateSignatureRequestAbiError extends TransactionCreateSignatureRequestError {
public TransactionCreateSignatureRequestAbiError() {
}
public TransactionCreateSignatureRequestAbiError(@NotNull String message) {
super(message);
}
public TransactionCreateSignatureRequestAbiError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionCreateSignatureRequestAbiError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,28 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call getAvailableKeys()
* inside createSignatureRequest() of TransactionProcessor.
* <br>
* Gets thrown when the result of GetAvailableKeys() is empty.
*/
public class TransactionCreateSignatureRequestEmptyAvailableKeyError extends TransactionCreateSignatureRequestError {
public TransactionCreateSignatureRequestEmptyAvailableKeyError() {
}
public TransactionCreateSignatureRequestEmptyAvailableKeyError(@NotNull String message) {
super(message);
}
public TransactionCreateSignatureRequestEmptyAvailableKeyError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionCreateSignatureRequestEmptyAvailableKeyError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call any method related to the
* signing process inside getSignature() of TransactionProcessor.
*/
public class TransactionCreateSignatureRequestError extends TransactionProcessorError {
public TransactionCreateSignatureRequestError() {
}
public TransactionCreateSignatureRequestError(@NotNull String message) {
super(message);
}
public TransactionCreateSignatureRequestError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionCreateSignatureRequestError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call getAvailableKeys()
* inside createSignatureRequest() of TransactionProcessor
*/
public class TransactionCreateSignatureRequestKeyError extends TransactionCreateSignatureRequestError {
public TransactionCreateSignatureRequestKeyError() {
}
public TransactionCreateSignatureRequestKeyError(@NotNull String message) {
super(message);
}
public TransactionCreateSignatureRequestKeyError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionCreateSignatureRequestKeyError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,28 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call getRequiredKeys()
* inside createSignatureRequest() of TransactionProcessor.
* <br>
* Gets thrown if GetRequiredKeys() returns an empty list.
*/
public class TransactionCreateSignatureRequestRequiredKeysEmptyError extends TransactionCreateSignatureRequestError {
public TransactionCreateSignatureRequestRequiredKeysEmptyError() {
}
public TransactionCreateSignatureRequestRequiredKeysEmptyError(@NotNull String message) {
super(message);
}
public TransactionCreateSignatureRequestRequiredKeysEmptyError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionCreateSignatureRequestRequiredKeysEmptyError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call getRequiredKeys() inside
* createSignatureRequest() of TransactionProcessor
*/
public class TransactionCreateSignatureRequestRequiredKeysError extends TransactionCreateSignatureRequestError {
public TransactionCreateSignatureRequestRequiredKeysError() {
}
public TransactionCreateSignatureRequestRequiredKeysError(@NotNull String message) {
super(message);
}
public TransactionCreateSignatureRequestRequiredKeysError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionCreateSignatureRequestRequiredKeysError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call any RPC call inside
* createSignatureRequest() of TransactionProcessor
*/
public class TransactionCreateSignatureRequestRpcError extends TransactionCreateSignatureRequestError {
public TransactionCreateSignatureRequestRpcError() {
}
public TransactionCreateSignatureRequestRpcError(@NotNull String message) {
super(message);
}
public TransactionCreateSignatureRequestRpcError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionCreateSignatureRequestRpcError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call Serialization method
* inside createSignatureRequest() of TransactionProcessor
*/
public class TransactionCreateSignatureRequestSerializationError extends TransactionCreateSignatureRequestError {
public TransactionCreateSignatureRequestSerializationError() {
}
public TransactionCreateSignatureRequestSerializationError(@NotNull String message) {
super(message);
}
public TransactionCreateSignatureRequestSerializationError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionCreateSignatureRequestSerializationError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call any deserialization
* method inside createSignatureRequest() of TransactionProcessor
*/
public class TransactionGetSignatureDeserializationError extends TransactionGetSignatureError {
public TransactionGetSignatureDeserializationError() {
}
public TransactionGetSignatureDeserializationError(@NotNull String message) {
super(message);
}
public TransactionGetSignatureDeserializationError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionGetSignatureDeserializationError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,25 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call getSignature() of TransactionProcessor
*/
public class TransactionGetSignatureError extends TransactionProcessorError {
public TransactionGetSignatureError() {
}
public TransactionGetSignatureError(@NotNull String message) {
super(message);
}
public TransactionGetSignatureError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionGetSignatureError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,27 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call getSignature() inside TransactionProcessor.
* <br>
* Gets thrown when Signature provider modifies a transaction but TransactionProcessor is not set to allow that.
*/
public class TransactionGetSignatureNotAllowModifyTransactionError extends TransactionGetSignatureError {
public TransactionGetSignatureNotAllowModifyTransactionError() {
}
public TransactionGetSignatureNotAllowModifyTransactionError(@NotNull String message) {
super(message);
}
public TransactionGetSignatureNotAllowModifyTransactionError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionGetSignatureNotAllowModifyTransactionError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,25 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call getSignature() of TransactionProcessor
*/
public class TransactionGetSignatureSigningError extends TransactionGetSignatureError {
public TransactionGetSignatureSigningError() {
}
public TransactionGetSignatureSigningError(@NotNull String message) {
super(message);
}
public TransactionGetSignatureSigningError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionGetSignatureSigningError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,25 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call prepare() of TransactionProcessor
*/
public class TransactionPrepareError extends TransactionProcessorError {
public TransactionPrepareError() {
}
public TransactionPrepareError(@NotNull String message) {
super(message);
}
public TransactionPrepareError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionPrepareError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,27 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call prepare() inside TransactionProcessor.
* <br>
* Gets thrown if input for Prepare() is invalid.
*/
public class TransactionPrepareInputError extends TransactionPrepareError {
public TransactionPrepareInputError() {
}
public TransactionPrepareInputError(@NotNull String message) {
super(message);
}
public TransactionPrepareInputError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionPrepareInputError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting make any RPC calls inside
* prepare() of TransactionProcessor
*/
public class TransactionPrepareRpcError extends TransactionPrepareError {
public TransactionPrepareRpcError() {
}
public TransactionPrepareRpcError(@NotNull String message) {
super(message);
}
public TransactionPrepareRpcError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionPrepareRpcError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,25 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to initialize TransactionProcessor
*/
public class TransactionProcessorConstructorInputError extends TransactionProcessorError {
public TransactionProcessorConstructorInputError() {
}
public TransactionProcessorConstructorInputError(@NotNull String message) {
super(message);
}
public TransactionProcessorConstructorInputError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionProcessorConstructorInputError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,27 @@
package com.tangem.wallet.eos.error.session;
import com.tangem.wallet.eos.error.EosioError;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call any method of TransactionProcessor
*/
public class TransactionProcessorError extends EosioError {
public TransactionProcessorError() {
}
public TransactionProcessorError(@NotNull String message) {
super(message);
}
public TransactionProcessorError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionProcessorError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,25 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call pushTransaction() of TransactionProcessor
*/
public class TransactionPushTransactionError extends TransactionProcessorError {
public TransactionPushTransactionError() {
}
public TransactionPushTransactionError(@NotNull String message) {
super(message);
}
public TransactionPushTransactionError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionPushTransactionError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,25 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call serialize() of TransactionProcessor
*/
public class TransactionSerializeError extends TransactionProcessorError {
public TransactionSerializeError() {
}
public TransactionSerializeError(@NotNull String message) {
super(message);
}
public TransactionSerializeError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionSerializeError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,25 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call signAndBroadCast() of TransactionProcessor
*/
public class TransactionSignAndBroadCastError extends TransactionProcessorError {
public TransactionSignAndBroadCastError() {
}
public TransactionSignAndBroadCastError(@NotNull String message) {
super(message);
}
public TransactionSignAndBroadCastError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionSignAndBroadCastError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,25 @@
package com.tangem.wallet.eos.error.session;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call sign() of TransactionProcessor
*/
public class TransactionSignError extends TransactionProcessorError {
public TransactionSignError() {
}
public TransactionSignError(@NotNull String message) {
super(message);
}
public TransactionSignError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public TransactionSignError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,7 @@
/**
* Provides the classes necessary to describe meaningful exceptions that occur during {@link
* one.block.eosiojava.session.TransactionProcessor} and {@link one.block.eosiojava.session.TransactionSession}
* implementations like: {@link one.block.eosiojava.error.session.TransactionGetSignatureError}
*/
package com.tangem.wallet.eos.error.session;

View file

@ -0,0 +1,25 @@
package com.tangem.wallet.eos.error.signatureProvider;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call getAvailableKeys() of SignatureProvider
*/
public class GetAvailableKeysError extends SignatureProviderError {
public GetAvailableKeysError() {
}
public GetAvailableKeysError(@NotNull String message) {
super(message);
}
public GetAvailableKeysError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public GetAvailableKeysError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,25 @@
package com.tangem.wallet.eos.error.signatureProvider;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call signTransaction() of SignatureProvider
*/
public class SignTransactionError extends SignatureProviderError {
public SignTransactionError() {
}
public SignTransactionError(@NotNull String message) {
super(message);
}
public SignTransactionError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public SignTransactionError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,27 @@
package com.tangem.wallet.eos.error.signatureProvider;
import com.tangem.wallet.eos.error.EosioError;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call any method of SignatureProvider
*/
public class SignatureProviderError extends EosioError {
public SignatureProviderError() {
}
public SignatureProviderError(@NotNull String message) {
super(message);
}
public SignatureProviderError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public SignatureProviderError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,6 @@
/**
* Provides the classes necessary to describe meaningful exceptions that occur during a signature
* provider implementation like {@link one.block.eosiojava.error.signatureProvider.SignTransactionError}
*/
package com.tangem.wallet.eos.error.signatureProvider;

View file

@ -0,0 +1,27 @@
package com.tangem.wallet.eos.error.utilities;
import com.tangem.wallet.eos.error.EosioError;
import org.jetbrains.annotations.NotNull;
/**
* Error is thrown for exceptions that occur during Base58
* encoding or decoding operations.
*/
public class Base58ManipulationError extends EosioError {
public Base58ManipulationError() {
}
public Base58ManipulationError(@NotNull String message) {
super(message);
}
public Base58ManipulationError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public Base58ManipulationError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,28 @@
package com.tangem.wallet.eos.error.utilities;
import com.tangem.wallet.eos.error.EosioError;
import org.jetbrains.annotations.NotNull;
/**
* Error is thrown for exceptions involving conversions of keys
* or signatures from DER encoded format to PEM.
*/
public class DerToPemConversionError extends EosioError {
public DerToPemConversionError() {
}
public DerToPemConversionError(@NotNull String message) {
super(message);
}
public DerToPemConversionError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public DerToPemConversionError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,29 @@
package com.tangem.wallet.eos.error.utilities;
import com.tangem.wallet.eos.error.EosioError;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to call any method of EOSFormatter
*/
public class EOSFormatterError extends EosioError {
public EOSFormatterError() {
}
public EOSFormatterError(@NotNull String message) {
super(message);
}
public EOSFormatterError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public EOSFormatterError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2017-2019 block.one all rights reserved.
*/
package com.tangem.wallet.eos.error.utilities;
import org.jetbrains.annotations.NotNull;
/**
* Error class is used when there is an exception while attempting to convert a
* signature to EOS format and the signature is not canonical.
* <br>
* * This exception only happens with signatures signed by a key generated by the SECP256K1
* algorithm.
* <br>
* * The signature must be recreated and tested to pass this exception.
*/
public class EosFormatterSignatureIsNotCanonicalError extends EOSFormatterError {
public EosFormatterSignatureIsNotCanonicalError() {
}
public EosFormatterSignatureIsNotCanonicalError(@NotNull String message) {
super(message);
}
public EosFormatterSignatureIsNotCanonicalError(@NotNull String message, @NotNull Exception exception) {
super(message, exception);
}
public EosFormatterSignatureIsNotCanonicalError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2017-2019 block.one all rights reserved.
*/
package com.tangem.wallet.eos.error.utilities;
import org.jetbrains.annotations.NotNull;
/**
* Error thrown when exception occurs during signature manipulations. Specifically, this
* error indicates that a failure occurred while verifying whether the value of S was low.
*/
public class LowSVerificationError extends EOSFormatterError {
public LowSVerificationError() {
}
public LowSVerificationError(@NotNull String message) {
super(message);
}
public LowSVerificationError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public LowSVerificationError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2017-2019 block.one all rights reserved.
*/
package com.tangem.wallet.eos.error.utilities;
import com.tangem.wallet.eos.error.EosioError;
import org.jetbrains.annotations.NotNull;
/**
* Error that originates from the {@link one.block.eosiojava.utilities.PEMProcessor} class.
*/
public class PEMProcessorError extends EosioError {
public PEMProcessorError() {
}
public PEMProcessorError(@NotNull String message) {
super(message);
}
public PEMProcessorError(@NotNull String message,
@NotNull Exception exception) {
super(message, exception);
}
public PEMProcessorError(@NotNull Exception exception) {
super(exception);
}
}

View file

@ -0,0 +1,6 @@
/**
* Provides the classes necessary to describe meaningful exceptions that occur while using
* eosio-java utilities. like {@link one.block.eosiojava.error.utilities.PEMProcessorError}
*/
package com.tangem.wallet.eos.error.utilities;

View file

@ -0,0 +1,78 @@
/*
* Copyright (c) 2017-2019 block.one all rights reserved.
*/
package com.tangem.wallet.eos.utilities;
import com.google.common.base.CharMatcher;
import com.google.common.base.Strings;
import org.bitcoinj.core.Sha256Hash;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.encoders.Hex;
import org.jetbrains.annotations.NotNull;
/**
* This class provides methods for transforming and formatting byte data to and from different
* formats in use on the blockchain.
*/
public class ByteFormatter {
private static final int BASE64_PADDING = 4;
private static final char BASE64_PADDING_CHAR = '=';
@NotNull
private byte[] context;
public ByteFormatter(@NotNull byte[] context) {
this.context = context;
}
/**
* Create and initialize a ByteFormatter from a Base64 encoded string. The Base64 string
* will have its padding checked and adjusted if necessary.
*
* @param base64String - Base64 encoded string.
* @return - Initialized ByteFormatter
*/
public static ByteFormatter createFromBase64(@NotNull String base64String) {
// Base64 encoded strings must be an even multiple of 4 if they are handled with padding.
// The strings that we get back from the blockchain in the JSON do not follow this
// strictly so we have to adjust the string if necessary before decoding. The padding
// character is '='. So we remove all existing padding characters and then pad the
// string to the nearest multiple of 4.
String trimmed = CharMatcher.is(BASE64_PADDING_CHAR).removeFrom(base64String);
String padded = Strings.padEnd(trimmed,
(trimmed.length() + BASE64_PADDING - 1) / BASE64_PADDING * BASE64_PADDING,
BASE64_PADDING_CHAR);
return new ByteFormatter(Base64.decode(padded));
}
/**
* Create and initialize a ByteFormatter from a hex encoded string.
*
* @param hexString - Hex encoded string.
* @return - Initialized ByteFormatter
*/
public static ByteFormatter createFromHex(@NotNull String hexString) {
byte[] data = Hex.decode(hexString);
return new ByteFormatter(data);
}
/**
* Convert the current ByteFormatter contents to a Hex encoded string and return it.
* @return - Hex encoded string representation of the current formatter context.
*/
public String toHex() {
return Hex.toHexString(this.context);
}
/**
* Calculate the sha256 hash of the current ByteFormatter context and return it as a new
* ByteFormatter.
*
* @return - New ByteFormatter containing the sha256 hash of the current one.
*/
public ByteFormatter sha256() {
return new ByteFormatter(Sha256Hash.hash(this.context));
}
}

View file

@ -0,0 +1,76 @@
package com.tangem.wallet.eos.utilities;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
/**
* This class provides utility methods to handle the formatting of dates and times to supported patterns.
*/
public class DateFormatter {
/**
* Blockchain pattern for SimpleDateFormat
*/
public static final String BACKEND_DATE_PATTERN = "yyyy-MM-dd'T'kk:mm:ss.SSS";
/**
* Blockchain pattern for SimpleDateFormat. It includes timezone.
*/
public static final String BACKEND_DATE_PATTERN_WITH_TIMEZONE = "yyyy-MM-dd'T'kk:mm:ss.SSS zzz";
/**
* Blockchain timezone/time standard for SimpleDateFormat
*/
public static final String BACKEND_DATE_TIME_ZONE = "UTC";
private DateFormatter() {}
/**
* Converting backend time to millisecond.
* <p>
* Backend time pattern "yyyy-MM-dd'T'HH:mm:ss.sss" in GMT.
* @param backendTime input backend time.
* @return Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by parsed input backend time.
* @throws ParseException thrown if the input does not match with any supported datetime pattern.
*/
public static long convertBackendTimeToMilli(String backendTime) throws ParseException {
String[] datePatterns = new String[]{
BACKEND_DATE_PATTERN, BACKEND_DATE_PATTERN_WITH_TIMEZONE
};
for (String datePattern : datePatterns) {
try {
SimpleDateFormat sdf = new SimpleDateFormat(datePattern);
sdf.setTimeZone(TimeZone.getTimeZone(BACKEND_DATE_TIME_ZONE));
Date parsedDate = sdf.parse(backendTime);
return parsedDate.getTime();
} catch (ParseException ex) {
// Keep going even if exception is thrown for trying different date pattern
} catch (IllegalArgumentException ex) {
// Keep going even if exception is thrown for trying different date pattern
}
}
throw new ParseException("Unable to parse input backend time with supported date patterns!", 0);
}
/**
* Convert milliseconds to time string format used on blockchain.
* <p>
* Backend time pattern "yyyy-MM-dd'T'HH:mm:ss.sss" in GMT
* @param timeInMilliSeconds input number of milliseconds
* @return String format of input number of milliseconds
*/
public static String convertMilliSecondToBackendTimeString(long timeInMilliSeconds) {
SimpleDateFormat sdf = new SimpleDateFormat(BACKEND_DATE_PATTERN);
sdf.setTimeZone(TimeZone.getTimeZone(BACKEND_DATE_TIME_ZONE));
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(timeInMilliSeconds);
return sdf.format(calendar.getTime());
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,318 @@
/*
* Copyright (c) 2017-2019 block.one all rights reserved.
*/
package com.tangem.wallet.eos.utilities;
import com.tangem.wallet.eos.enums.AlgorithmEmployed;
import com.tangem.wallet.eos.error.ErrorConstants;
import com.tangem.wallet.eos.error.utilities.Base58ManipulationError;
import com.tangem.wallet.eos.error.utilities.EOSFormatterError;
import com.tangem.wallet.eos.error.utilities.PEMProcessorError;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DLSequence;
import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.ec.CustomNamedCurves;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.FixedPointCombMultiplier;
import org.bouncycastle.math.ec.FixedPointUtil;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.jetbrains.annotations.NotNull;
import java.io.CharArrayReader;
import java.io.IOException;
import java.io.Reader;
import java.math.BigInteger;
/**
* This is a wrapper class for PEMObjects that throws a {@link PEMProcessorError} if an invalid
* PEMObject is passed into the constructor. Once initialized the PEMProcessor can be used to
* return the type, DER format, or algorithm used to create the PEMObject.
*/
public class PEMProcessor {
/**
* PEM private key type on header
*/
private static final String PRIVATE_KEY_TYPE = "EC PRIVATE KEY";
/**
* Private key start index on ASN.1 sequence
*/
private static final int PRIVATE_KEY_START_INDEX = 2;
//region CURVE Constants
/**
* Constant name of secp256r1 curves
*/
private static final String SECP256_R1 = "secp256r1";
/**
* Constant name of secp256k1 curves
*/
private static final String SECP256_K1 = "secp256k1";
/**
* EC parameters holder of secp256r1 key type
*/
private static final X9ECParameters CURVE_PARAMS_R1 = CustomNamedCurves.getByName(SECP256_R1);
/**
* EC parameters holder of secp256k1 key type
*/
private static final X9ECParameters CURVE_PARAMS_K1 = CustomNamedCurves.getByName(SECP256_K1);
/**
* EC holder of secp256r1 key type
*/
private static final ECDomainParameters CURVE_R1;
/**
* EC holder of secp256k1 key type
*/
private static final ECDomainParameters CURVE_K1;
/**
* Signum to convert a negative value to a positive Big Integer
*/
private static final int BIG_INTEGER_POSITIVE = 1;
static {
// secp256r1
FixedPointUtil.precompute(CURVE_PARAMS_R1.getG());
CURVE_R1 = new ECDomainParameters(
CURVE_PARAMS_R1.getCurve(),
CURVE_PARAMS_R1.getG(),
CURVE_PARAMS_R1.getN(),
CURVE_PARAMS_R1.getH());
// secp256k1
CURVE_K1 = new ECDomainParameters(
CURVE_PARAMS_K1.getCurve(),
CURVE_PARAMS_K1.getG(),
CURVE_PARAMS_K1.getN(),
CURVE_PARAMS_K1.getH());
}
//endregion
private PemObject pemObject;
private String pemObjectString;
/**
* Initialize PEMProcessor with PEM content in String format.
*
* @param pemObject - input PEM content in String format.
* @throws PEMProcessorError When failing to read pem data from the input.
*/
public PEMProcessor(String pemObject) throws PEMProcessorError {
this.pemObjectString = pemObject;
try (Reader reader = new CharArrayReader(this.pemObjectString.toCharArray());
PemReader pemReader = new PemReader(reader)) {
this.pemObject = pemReader.readPemObject();
if (this.pemObject == null) {
throw new PEMProcessorError(ErrorConstants.INVALID_PEM_OBJECT);
}
} catch (Exception e) {
throw new PEMProcessorError(ErrorConstants.ERROR_PARSING_PEM_OBJECT, e);
}
}
/**
* Gets the PEM Object key type (i.e. PRIVATE KEY, PUBLIC KEY).
*
* @return key type as string
*/
@NotNull
public String getType() {
return pemObject.getType();
}
/**
* Gets the DER encoded format of the key from its PEM format.
*
* @return DER format of key as string
*/
@NotNull
public String getDERFormat() {
return Hex.toHexString(pemObject.getContent());
}
/**
* Gets the algorithm used to generate the key from its PEM format.
*
* @return The algorithm used to generate the key.
* @throws PEMProcessorError if the algorithm fetch leads to an exception.
*/
@NotNull
public AlgorithmEmployed getAlgorithm() throws PEMProcessorError {
Object pemObjectParsed = parsePEMObject();
String oid;
if (pemObjectParsed instanceof SubjectPublicKeyInfo) {
oid = ((SubjectPublicKeyInfo) pemObjectParsed).getAlgorithm().getParameters()
.toString();
} else if (pemObjectParsed instanceof PEMKeyPair) {
oid = ((PEMKeyPair) pemObjectParsed).getPrivateKeyInfo().getPrivateKeyAlgorithm()
.getParameters().toString();
} else {
throw new PEMProcessorError(ErrorConstants.DER_TO_PEM_CONVERSION);
}
if (SECObjectIdentifiers.secp256r1.getId().equals(oid)) {
return AlgorithmEmployed.SECP256R1;
} else if (SECObjectIdentifiers.secp256k1.getId().equals(oid)) {
return AlgorithmEmployed.SECP256K1;
} else {
throw new PEMProcessorError(ErrorConstants.UNSUPPORTED_ALGORITHM + oid);
}
}
/**
* Gets the key as a byte array from its PEM format.
*
* @return key as byte[]
* @throws PEMProcessorError when key data is unobtainable.
*/
@NotNull
public byte[] getKeyData() throws PEMProcessorError {
Object pemObjectParsed = parsePEMObject();
if (pemObjectParsed instanceof SubjectPublicKeyInfo) {
return ((SubjectPublicKeyInfo) pemObjectParsed).getPublicKeyData().getBytes();
} else if (pemObjectParsed instanceof PEMKeyPair) {
DLSequence sequence;
try (ASN1InputStream asn1InputStream = new ASN1InputStream(
Hex.decode(this.getDERFormat()))) {
sequence = (DLSequence) asn1InputStream.readObject();
} catch (IOException e) {
throw new PEMProcessorError(e);
}
for (Object obj : sequence) {
if (obj instanceof DEROctetString) {
byte[] key = new byte[0];
try {
key = ((DEROctetString) obj).getEncoded();
} catch (IOException e) {
throw new PEMProcessorError(e);
}
return Arrays.copyOfRange(key, PRIVATE_KEY_START_INDEX, key.length);
}
}
throw new PEMProcessorError(ErrorConstants.KEY_DATA_NOT_FOUND);
} else {
throw new PEMProcessorError(ErrorConstants.DER_TO_PEM_CONVERSION);
}
}
/**
* Extract EOS public key
*
* @param isLegacy - Set to true if the legacy format of the key is desired. This uses "EOS"
* to prefix the key data and only applies to keys generated with the secp256k1 algorithm. The
* new format prefixes the key data with "PUB_K1_".
* @return EOS format public key of the current private key
* @throws PEMProcessorError when the public key extraction fails.
*/
public String extractEOSPublicKeyFromPrivateKey(boolean isLegacy) throws PEMProcessorError {
if (!this.getType().equals(PRIVATE_KEY_TYPE)) {
throw new PEMProcessorError(ErrorConstants.PUBLIC_KEY_COULD_NOT_BE_EXTRACTED_FROM_PRIVATE_KEY);
}
AlgorithmEmployed keyCurve = this.getAlgorithm();
BigInteger privateKeyBI = new BigInteger(BIG_INTEGER_POSITIVE, this.getKeyData());
BigInteger n;
ECPoint g;
switch (keyCurve) {
case SECP256R1:
n = CURVE_R1.getN();
g = CURVE_R1.getG();
break;
default:
n = CURVE_K1.getN();
g = CURVE_K1.getG();
break;
}
if (privateKeyBI.bitLength() > n.bitLength()) {
privateKeyBI = privateKeyBI.mod(n);
}
byte[] publicKeyByteArray = new FixedPointCombMultiplier().multiply(g, privateKeyBI).getEncoded(true);
try {
return EOSFormatter.encodePublicKey(publicKeyByteArray, keyCurve, isLegacy);
} catch (Base58ManipulationError e) {
throw new PEMProcessorError(e);
}
}
/**
* Extract PEM public key
*
* @param isLegacy Whether to return the legacy format of the key. This uses "EOS"
* to prefix the key data and only applies to keys generated with the secp256k1 algorithm. The
* new format prefixes the key data with "PUB_K1_".
* @return EOS format public key of the current private key
* @throws PEMProcessorError when public key extraction fails.
*/
public String extractPEMPublicKeyFromPrivateKey(boolean isLegacy) throws PEMProcessorError {
try {
return EOSFormatter.convertEOSPublicKeyToPEMFormat(extractEOSPublicKeyFromPrivateKey(isLegacy));
} catch (EOSFormatterError e) {
throw new PEMProcessorError(e);
}
}
/**
* Gets EC Curve's domain parameter by curve type
*
* @param curve - type
* @return ECDomainParameters of input curve
* @throws PEMProcessorError would be throw if input curve is not supported.
*/
public static ECDomainParameters getCurveDomainParameters(AlgorithmEmployed curve) throws PEMProcessorError {
switch (curve) {
case SECP256R1:
case PRIME256V1:
return CURVE_R1;
case SECP256K1:
return CURVE_K1;
default:
throw new PEMProcessorError(ErrorConstants.UNSUPPORTED_ALGORITHM);
}
}
/**
* Parses PEM object.
*
* @return Parsed PEM object as Object.
* @throws PEMProcessorError when PEM parsing fails.
*/
@NotNull
private Object parsePEMObject() throws PEMProcessorError {
try (Reader reader = new CharArrayReader(this.pemObjectString.toCharArray());
PEMParser pemParser = new PEMParser(reader)) {
return pemParser.readObject();
} catch (IOException e) {
throw new PEMProcessorError(ErrorConstants.ERROR_READING_PEM_OBJECT, e);
}
}
}

View file

@ -0,0 +1,48 @@
package com.tangem.wallet.eos.utilities;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* This class provides generic utility methods
*/
public class Utils {
private Utils() {}
/**
* Clone an object
*
* @param object input object
* @param <T> - Class of the object
* @return the cloned object.
* @throws IOException Any exception thrown by the underlying OutputStream.
* @throws ClassNotFoundException Class of a serialized object cannot be found.
*/
public static <T extends Serializable> T clone(T object) throws IOException, ClassNotFoundException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(object); // Could clone only the Transaction (i.e. this.transaction)
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
return (T) objectInputStream.readObject();
}
/**
* Getting a GSON object with a date time pattern
* @param datePattern - input date time pattern
* @return Configured GSON object with input.
*/
public static Gson getGson(String datePattern) {
return new GsonBuilder()
.setDateFormat(datePattern)
.disableHtmlEscaping()
.create();
}
}