diff --git a/.gitignore b/.gitignore
index aa724b7..10cfdbf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,12 +1,7 @@
*.iml
.gradle
/local.properties
-/.idea/caches
-/.idea/libraries
-/.idea/modules.xml
-/.idea/workspace.xml
-/.idea/navEditor.xml
-/.idea/assetWizardSettings.xml
+/.idea
.DS_Store
/build
/captures
diff --git a/.idea/androidTestResultsUserPreferences.xml b/.idea/androidTestResultsUserPreferences.xml
index 9b2dee9..2a20205 100644
--- a/.idea/androidTestResultsUserPreferences.xml
+++ b/.idea/androidTestResultsUserPreferences.xml
@@ -10,6 +10,7 @@
@@ -37,6 +38,7 @@
+
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index fb7f4a8..fcb19bf 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index bdd9278..a248a5b 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/web3-android-mpc-provider/src/androidTest/java/com/web3auth/web3_android_mpc_provider/MpcProviderTests.java b/web3-android-mpc-provider/src/androidTest/java/com/web3auth/web3_android_mpc_provider/MpcProviderTests.java
index bc78758..5e551f3 100644
--- a/web3-android-mpc-provider/src/androidTest/java/com/web3auth/web3_android_mpc_provider/MpcProviderTests.java
+++ b/web3-android-mpc-provider/src/androidTest/java/com/web3auth/web3_android_mpc_provider/MpcProviderTests.java
@@ -4,10 +4,14 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.web3auth.tss_client_android.client.TSSClientError;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.IOException;
import java.math.BigInteger;
+import java.util.concurrent.ExecutionException;
@RunWith(AndroidJUnit4.class)
public class MpcProviderTests {
@@ -42,7 +46,7 @@ public class MpcProviderTests {
BigInteger[] nodeIndexs = {new BigInteger("1"), new BigInteger("2"), new BigInteger("3")};
@Test
- public void testSigningMessage() {
+ public void testSigningMessage() throws TSSClientError, CustomSigningError {
EthTssAccountParams params = new EthTssAccountParams(
fullAddress, factorKey, tssNonce, tssShare, tssIndex, selected_tag, verifier, verifierId,
nodeIndexs, tssEndpoints, sigs);
@@ -55,19 +59,13 @@ public void testSigningMessage() {
}
@Test
- public void testSigningTransaction() {
+ public void testSigningTransaction() throws TSSClientError, CustomSigningError, IOException, ExecutionException, InterruptedException {
EthTssAccountParams params = new EthTssAccountParams(
fullAddress, factorKey, tssNonce, tssShare, tssIndex, selected_tag, verifier, verifierId,
nodeIndexs, tssEndpoints, sigs);
-
EthereumTssAccount account = new EthereumTssAccount(params);
-
- String fromAddress = Utils.generateAddressFromPubKey(params.getPublicKey());
- System.out.println("fromAddress: " + fromAddress);
- String toAddress = "0x048975d4997D7578A3419851639c10318db430b6"; //Utils.generateAddressFromPubKey(params.getPublicKey());
- String transactionHash = account.signAndSendTransaction("https://rpc.ankr.com/eth_goerli", 0.001,
- fromAddress, toAddress);
- System.out.println("Transaction Hash: " + transactionHash);
+ String toAddress = "0x048975d4997D7578A3419851639c10318db430b6";
+ String transactionHash = account.signAndSendTransaction("https://rpc.ankr.com/eth_goerli", 0.001, toAddress);
assertNotNull(transactionHash);
}
diff --git a/web3-android-mpc-provider/src/main/java/com/web3auth/web3_android_mpc_provider/EthTssAccountParams.java b/web3-android-mpc-provider/src/main/java/com/web3auth/web3_android_mpc_provider/EthTssAccountParams.java
index 56234a5..fef6a02 100644
--- a/web3-android-mpc-provider/src/main/java/com/web3auth/web3_android_mpc_provider/EthTssAccountParams.java
+++ b/web3-android-mpc-provider/src/main/java/com/web3auth/web3_android_mpc_provider/EthTssAccountParams.java
@@ -3,17 +3,17 @@
import java.math.BigInteger;
public final class EthTssAccountParams {
- private String publicKey;
- private String factorKey;
- private int tssNonce;
- private String tssShare;
- private String tssIndex;
- private String selectedTag;
- private String verifier;
- private String verifierID;
- private BigInteger[] nodeIndexes;
- private String[] tssEndpoints;
- private String[] authSigs;
+ final String publicKey;
+ final String factorKey;
+ final int tssNonce;
+ final String tssShare;
+ final String tssIndex;
+ final String selectedTag;
+ final String verifier;
+ final String verifierID;
+ final BigInteger[] nodeIndexes;
+ final String[] tssEndpoints;
+ final String[] authSigs;
public EthTssAccountParams(String publicKey, String factorKey, int tssNonce, String tssShare, String tssIndex, String selectedTag, String verifier, String verifierID, BigInteger[] nodeIndexes, String[] tssEndpoints, String[] authSigs) {
this.publicKey = publicKey;
@@ -28,49 +28,5 @@ public EthTssAccountParams(String publicKey, String factorKey, int tssNonce, Str
this.tssEndpoints = tssEndpoints;
this.authSigs = authSigs;
}
-
- public String getPublicKey() {
- return publicKey;
- }
-
- public String getFactorKey() {
- return factorKey;
- }
-
- public int getTssNonce() {
- return tssNonce;
- }
-
- public String getTssShare() {
- return tssShare;
- }
-
- public String getTssIndex() {
- return tssIndex;
- }
-
- public String getSelectedTag() {
- return selectedTag;
- }
-
- public String getVerifier() {
- return verifier;
- }
-
- public String getVerifierID() {
- return verifierID;
- }
-
- public BigInteger[] getNodeIndexes() {
- return nodeIndexes;
- }
-
- public String[] getTssEndpoints() {
- return tssEndpoints;
- }
-
- public String[] getAuthSigs() {
- return authSigs;
- }
}
diff --git a/web3-android-mpc-provider/src/main/java/com/web3auth/web3_android_mpc_provider/EthereumSignerError.java b/web3-android-mpc-provider/src/main/java/com/web3auth/web3_android_mpc_provider/EthereumSignerError.java
index 33664dc..2b5a4b3 100644
--- a/web3-android-mpc-provider/src/main/java/com/web3auth/web3_android_mpc_provider/EthereumSignerError.java
+++ b/web3-android-mpc-provider/src/main/java/com/web3auth/web3_android_mpc_provider/EthereumSignerError.java
@@ -1,7 +1,7 @@
package com.web3auth.web3_android_mpc_provider;
public class EthereumSignerError extends Error {
- private ErrorType errorType;
+ private final ErrorType errorType;
public EthereumSignerError(ErrorType errorType) {
this.errorType = errorType;
@@ -11,7 +11,7 @@ public String getErrorDescription() {
switch (errorType) {
case EMPTY_RAW_TRANSACTION:
return "emptyRawTransaction";
- case INSUFFICIENT_Funds:
+ case INSUFFICIENT_FUNDS:
return "insufficientFunds";
case UNKNOWN_ERROR:
return "unknownError";
@@ -22,7 +22,7 @@ public String getErrorDescription() {
public enum ErrorType {
EMPTY_RAW_TRANSACTION,
- INSUFFICIENT_Funds,
+ INSUFFICIENT_FUNDS,
UNKNOWN_ERROR
}
}
diff --git a/web3-android-mpc-provider/src/main/java/com/web3auth/web3_android_mpc_provider/EthereumTssAccount.java b/web3-android-mpc-provider/src/main/java/com/web3auth/web3_android_mpc_provider/EthereumTssAccount.java
index fc2df29..0d64645 100644
--- a/web3-android-mpc-provider/src/main/java/com/web3auth/web3_android_mpc_provider/EthereumTssAccount.java
+++ b/web3-android-mpc-provider/src/main/java/com/web3auth/web3_android_mpc_provider/EthereumTssAccount.java
@@ -1,6 +1,5 @@
package com.web3auth.web3_android_mpc_provider;
-import static com.web3auth.web3_android_mpc_provider.Utils.generateEndpoints;
import static org.web3j.utils.Numeric.hexStringToByteArray;
import android.util.Base64;
@@ -15,6 +14,7 @@
import com.web3auth.tss_client_android.dkls.Precompute;
import org.web3j.crypto.Hash;
+import org.web3j.crypto.Keys;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.Sign;
import org.web3j.crypto.TransactionEncoder;
@@ -34,6 +34,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ExecutionException;
public class EthereumTssAccount {
@@ -42,176 +43,119 @@ public class EthereumTssAccount {
public EthereumTssAccount(EthTssAccountParams params) {
ethAccountParams = params;
- evmAddress = Utils.generateAddressFromPubKey(params.getPublicKey());
+ evmAddress = Keys.toChecksumAddress(Keys.getAddress(params.publicKey));
}
- public String signMessage(String message) {
- String signature = null;
- TSSClient client;
- Map coeffs;
- Pair> clientCoeffsPair;
- try {
- clientCoeffsPair = bootstrapTssClient(ethAccountParams);
- client = clientCoeffsPair.first;
- coeffs = clientCoeffsPair.second;
-
- boolean connected = client.checkConnected();
- if (!connected) {
- throw new CustomSigningError("Unable to establish connection to TSS server");
- }
-
- Precompute precompute;
- try {
- precompute = client.precompute(coeffs, Arrays.asList(ethAccountParams.getAuthSigs()));
- } catch (Exception e) {
- e.printStackTrace();
- throw new EthereumSignerError(EthereumSignerError.ErrorType.UNKNOWN_ERROR);
- }
-
- boolean ready = client.isReady();
- if (!ready) {
- throw new EthereumSignerError(EthereumSignerError.ErrorType.UNKNOWN_ERROR);
- }
-
- String signingMessage = TSSHelpers.hashMessage(message);
-
- Triple signatureResult;
- try {
- signatureResult = client.sign(signingMessage, true, "", precompute, Arrays.asList(ethAccountParams.getAuthSigs()));
- } catch (TSSClientError e) {
- throw new RuntimeException(e);
- }
-
- try {
- client.cleanup(ethAccountParams.getAuthSigs());
- } catch (TSSClientError e) {
- throw new RuntimeException(e);
- }
-
- boolean verified = TSSHelpers.verifySignature(signingMessage, signatureResult.getFirst(),
- signatureResult.getSecond(), signatureResult.getThird(), Utils.convertToBytes(ethAccountParams.getPublicKey()));
-
- if (!verified) {
- throw new EthereumSignerError(EthereumSignerError.ErrorType.UNKNOWN_ERROR);
- }
+ public String signMessage(String message) throws TSSClientError, CustomSigningError {
+ String hash = TSSHelpers.hashMessage(message);
+ Triple signatureResult = sign(hash);
+ Byte v = signatureResult.getThird();
+ if (v < 27) {
+ v = (byte) (v + 27);
+ }
+ return TSSHelpers.hexSignature(signatureResult.getFirst(), signatureResult.getSecond(), v);
+ }
- signature = TSSHelpers.hexSignature(signatureResult.getFirst(), signatureResult.getSecond(), signatureResult.getThird());
- } catch (Exception e) {
- throw new RuntimeException(e);
+ public String signAndSendTransaction(String url, Double amount, String toAddress) throws TSSClientError, CustomSigningError, IOException, ExecutionException, InterruptedException {
+ //setup Web3j
+ Web3j web3j = Web3j.build(new HttpService(url));
+ EthGetTransactionCount ethGetTransactionCount = web3j.ethGetTransactionCount(
+ evmAddress,
+ DefaultBlockParameterName.LATEST
+ ).send();
+ BigInteger nonce = ethGetTransactionCount.getTransactionCount();
+ BigInteger value = Convert.toWei(Double.toString(amount), Convert.Unit.ETHER).toBigInteger();
+ BigInteger gasLimit = BigInteger.valueOf(21000);
+ EthGasPrice gasPriceResponse = web3j.ethGasPrice().send();
+ BigInteger gasPrice = gasPriceResponse.getGasPrice();
+ EthChainId chainIdResponse = web3j.ethChainId().sendAsync().get();
+ BigInteger chainId = chainIdResponse.getChainId();
+
+ RawTransaction rawTransaction = RawTransaction.createTransaction(
+ chainId.longValue(),
+ nonce,
+ gasLimit,
+ toAddress,
+ value,
+ "",
+ gasPrice,
+ gasPrice
+ );
+
+ byte[] encodedTransaction = TransactionEncoder.encode(rawTransaction);
+ String encodedTransactionString = Base64.encodeToString(Hash.sha3(encodedTransaction), Base64.NO_WRAP);
+
+ Triple signatureResult = sign(encodedTransactionString);
+
+ Sign.SignatureData signatureData = new Sign.SignatureData((byte) (signatureResult.getThird() + 27),
+ signatureResult.getSecond().toByteArray(),
+ signatureResult.getFirst().toByteArray());
+ byte[] signedMsg = TransactionEncoder.encode(rawTransaction, signatureData);
+
+ String finalSig = Numeric.toHexString(signedMsg);
+
+ EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(finalSig).send();
+
+ if (ethSendTransaction.getError() != null) {
+ throw new CustomSigningError(ethSendTransaction.getError().getMessage());
+ } else {
+ return ethSendTransaction.getTransactionHash();
}
- return signature;
}
- public String signAndSendTransaction(String url, Double amount, String fromAddress, String toAddress) {
- String transactionHash;
+ private Triple sign(String hash) throws TSSClientError, CustomSigningError {
TSSClient client;
Map coeffs;
Pair> clientCoeffsPair;
- try {
- //setup Web3j
- Web3j web3j = Web3j.build(new HttpService(url));
- EthGetTransactionCount ethGetTransactionCount = web3j.ethGetTransactionCount(
- fromAddress,
- DefaultBlockParameterName.LATEST
- ).send();
- BigInteger nonce = ethGetTransactionCount.getTransactionCount();
- BigInteger value = Convert.toWei(Double.toString(amount), Convert.Unit.ETHER).toBigInteger();
- BigInteger gasLimit = BigInteger.valueOf(21000);
- EthGasPrice gasPriceResponse = web3j.ethGasPrice().send();
- BigInteger gasPrice = gasPriceResponse.getGasPrice();
- EthChainId chainIdResponse = web3j.ethChainId().sendAsync().get();
- BigInteger chainId = chainIdResponse.getChainId();
-
- RawTransaction rawTransaction = RawTransaction.createTransaction(
- chainId.longValue(),
- nonce,
- gasLimit,
- toAddress,
- value,
- "",
- gasPrice,
- gasPrice
- );
-
- clientCoeffsPair = bootstrapTssClient(ethAccountParams);
- client = clientCoeffsPair.first;
- coeffs = clientCoeffsPair.second;
-
- boolean connected = client.checkConnected();
- if (!connected) {
- throw new CustomSigningError("Unable to establish connection to TSS server");
- }
- Precompute precompute;
- try {
- precompute = client.precompute(coeffs, Arrays.asList(ethAccountParams.getAuthSigs()));
- } catch (Exception e) {
- e.printStackTrace();
- throw new EthereumSignerError(EthereumSignerError.ErrorType.UNKNOWN_ERROR);
- }
+ clientCoeffsPair = bootstrapTssClient(ethAccountParams);
+ client = clientCoeffsPair.first;
+ coeffs = clientCoeffsPair.second;
- boolean ready = client.isReady();
- if (!ready) {
- throw new EthereumSignerError(EthereumSignerError.ErrorType.UNKNOWN_ERROR);
- }
+ boolean connected = client.checkConnected();
+ if (!connected) {
+ throw new CustomSigningError("Unable to establish connection to TSS server");
+ }
- byte[] encodedTransaction = TransactionEncoder.encode(rawTransaction);
- String encodedTransactionString = Base64.encodeToString(Hash.sha3(encodedTransaction), Base64.NO_WRAP);
+ Precompute precompute;
+ precompute = client.precompute(coeffs, Arrays.asList(ethAccountParams.authSigs));
+ boolean ready = client.isReady();
+ if (!ready) {
+ throw new EthereumSignerError(EthereumSignerError.ErrorType.UNKNOWN_ERROR);
+ }
- Triple signatureResult;
- try {
- signatureResult = client.sign(encodedTransactionString, true, "", precompute, Arrays.asList(ethAccountParams.getAuthSigs()));
- } catch (TSSClientError e) {
- throw new RuntimeException(e);
- }
+ Triple signatureResult;
+ signatureResult = client.sign(hash, true, null, precompute, Arrays.asList(ethAccountParams.authSigs));
- try {
- client.cleanup(ethAccountParams.getAuthSigs());
- } catch (TSSClientError e) {
- throw new RuntimeException(e);
- }
+ client.cleanup(ethAccountParams.authSigs);
- try {
- Sign.SignatureData signatureData = new Sign.SignatureData((byte) (signatureResult.getThird() + 27),
- signatureResult.getSecond().toByteArray(),
- signatureResult.getFirst().toByteArray());
- byte[] signedMsg = TransactionEncoder.encode(rawTransaction, signatureData);
-
- String finalSig = Numeric.toHexString(signedMsg);
-
- EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(finalSig).send();
- if (ethSendTransaction.getError() != null) {
- transactionHash = ethSendTransaction.getError().getMessage();
- } else {
- transactionHash = ethSendTransaction.getTransactionHash();
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- } catch (Exception e) {
- throw new RuntimeException(e);
+ boolean verified = TSSHelpers.verifySignature(hash, signatureResult.getFirst(),
+ signatureResult.getSecond(), signatureResult.getThird(), Utils.convertToBytes(ethAccountParams.publicKey));
+
+ if (!verified) {
+ throw new EthereumSignerError(EthereumSignerError.ErrorType.UNKNOWN_ERROR);
}
- return transactionHash;
- }
+ return signatureResult;
+ }
private Pair> bootstrapTssClient(EthTssAccountParams params) throws CustomSigningError, TSSClientError {
- if (params.getPublicKey().length() < 128 || params.getPublicKey().length() > 130) {
+ if (params.publicKey.length() < 128 || params.publicKey.length() > 130) {
throw new CustomSigningError("Public Key should be in uncompressed format");
}
BigInteger randomKey = new BigInteger(1, Secp256k1.GenerateECKey());
BigInteger random = randomKey.add(BigInteger.valueOf(System.currentTimeMillis() / 1000));
- String sessionNonce = TSSHelpers.base64ToBase64url(TSSHelpers.hashMessage(random.toByteArray().toString()));
- String session = TSSHelpers.assembleFullSession(params.getVerifier(), params.getVerifierID(),
- params.getSelectedTag(), String.valueOf(params.getTssNonce()), sessionNonce);
+ String sessionNonce = TSSHelpers.base64ToBase64url(TSSHelpers.hashMessage(Arrays.toString(random.toByteArray())));
+ String session = TSSHelpers.assembleFullSession(params.verifier, params.verifierID,
+ params.selectedTag, String.valueOf(params.tssNonce), sessionNonce);
- BigInteger userTssIndex = new BigInteger(params.getTssIndex(), 16);
+ BigInteger userTssIndex = new BigInteger(params.tssIndex, 16);
int parties = 4;
int clientIndex = parties - 1;
- EndpointsData endpointsData = generateEndpoints(parties, clientIndex, Arrays.asList(params.getTssEndpoints()));
+ EndpointsData endpointsData = generateEndpoints(parties, clientIndex, Arrays.asList(params.tssEndpoints));
List endpoints = endpointsData.getEndpoints();
List socketUrls = endpointsData.getTssWSEndpoints();
List partyIndexes = endpointsData.getPartyIndexes();
@@ -222,14 +166,32 @@ private Pair> bootstrapTssClient(EthTssAccountPar
Map coeffs = TSSHelpers.getServerCoefficients(nodeInd.toArray(new BigInteger[0]), userTssIndex);
- BigInteger shareUnsigned = new BigInteger(params.getTssShare(), 16);
- BigInteger share = shareUnsigned;
+ BigInteger share = new BigInteger(params.tssShare, 16);
BigInteger denormalizeShare = TSSHelpers.denormalizeShare(nodeInd.toArray(new BigInteger[0]), userTssIndex, share);
TSSClient client = new TSSClient(session, clientIndex, partyIndexes.stream().mapToInt(Integer::intValue).toArray(),
endpoints.toArray(new String[0]), socketUrls.toArray(new String[0]), TSSHelpers.base64Share(denormalizeShare),
- TSSHelpers.base64PublicKey(hexStringToByteArray(params.getPublicKey())));
+ TSSHelpers.base64PublicKey(hexStringToByteArray(params.publicKey)));
return new Pair<>(client, coeffs);
}
+
+ private EndpointsData generateEndpoints(int parties, int clientIndex, List tssEndpoints) {
+ List endpoints = new ArrayList<>();
+ List tssWSEndpoints = new ArrayList<>();
+ List partyIndexes = new ArrayList<>();
+
+ for (int i = 0; i < parties; ++i) {
+ partyIndexes.add(i);
+ if (i == clientIndex) {
+ endpoints.add(null);
+ tssWSEndpoints.add(null);
+ } else {
+ endpoints.add(tssEndpoints.get(i));
+ tssWSEndpoints.add(tssEndpoints.get(i).replace("/tss", ""));
+ }
+ }
+
+ return new EndpointsData(endpoints, tssWSEndpoints, partyIndexes);
+ }
}
diff --git a/web3-android-mpc-provider/src/main/java/com/web3auth/web3_android_mpc_provider/Utils.java b/web3-android-mpc-provider/src/main/java/com/web3auth/web3_android_mpc_provider/Utils.java
index 381518f..9f8163c 100644
--- a/web3-android-mpc-provider/src/main/java/com/web3auth/web3_android_mpc_provider/Utils.java
+++ b/web3-android-mpc-provider/src/main/java/com/web3auth/web3_android_mpc_provider/Utils.java
@@ -1,37 +1,6 @@
package com.web3auth.web3_android_mpc_provider;
-import com.web3auth.tss_client_android.client.EndpointsData;
-
-import org.web3j.crypto.Keys;
-
-import java.util.ArrayList;
-import java.util.List;
-
public class Utils {
-
- public static String generateAddressFromPubKey(String pubKey) {
- return Keys.toChecksumAddress(Keys.getAddress(pubKey));
- }
-
- public static String stringToHex(String str) {
- char[] chars = str.toCharArray();
- StringBuffer strBuffer = new StringBuffer();
- for (int i = 0; i < chars.length; i++) {
- strBuffer.append(Integer.toHexString((int) chars[i]));
- }
- return strBuffer.toString();
- }
-
- public static String padLeft(String inputString, Character padChar, int length) {
- if (inputString.length() >= length) return inputString;
- StringBuilder sb = new StringBuilder();
- while (sb.length() < length - inputString.length()) {
- sb.append(padChar);
- }
- sb.append(inputString);
- return sb.toString();
- }
-
public static byte[] convertToBytes(String s) {
String tmp;
byte[] b = new byte[s.length() / 2];
@@ -42,23 +11,4 @@ public static byte[] convertToBytes(String s) {
}
return b;
}
-
- public static EndpointsData generateEndpoints(int parties, int clientIndex, List tssEndpoints) {
- List endpoints = new ArrayList();
- List tssWSEndpoints = new ArrayList();
- List partyIndexes = new ArrayList();
-
- for (int i = 0; i < parties; ++i) {
- partyIndexes.add(i);
- if (i == clientIndex) {
- endpoints.add(null);
- tssWSEndpoints.add(null);
- } else {
- endpoints.add(tssEndpoints.get(i));
- tssWSEndpoints.add(tssEndpoints.get(i).replace("/tss", ""));
- }
- }
-
- return new EndpointsData(endpoints, tssWSEndpoints, partyIndexes);
- }
}