Skip to content

Commit

Permalink
Merge pull request #4 from grvgoel81/feat/add-type-signed-message-fun…
Browse files Browse the repository at this point in the history
…ction

feat:added signTypedData signing function and eip1559 signing functio…
  • Loading branch information
metalurgical authored Sep 12, 2023
2 parents 29c43b7 + 54410c2 commit 52305b3
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 13 deletions.
26 changes: 26 additions & 0 deletions web3-android-mpc-provider/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
plugins {
id 'com.android.library'
id 'maven-publish'
}

android {
Expand Down Expand Up @@ -34,7 +35,32 @@ dependencies {
implementation 'com.github.grvgoel81:tss-client-android:0.0.8'
//Web3j
implementation 'org.web3j:core:4.9.5'

testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}

task javadoc(type: Javadoc) {
failOnError(false)
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
exclude '*R.java'
exclude {
it.file.path.contains('web3-android-mpc-provider')
}
}

afterEvaluate {
javadoc.classpath += files(android.libraryVariants.collect { variant ->
variant.javaCompileProvider.get().classpath.files
})

publishing {
publications {
release(MavenPublication) {
from components.release
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package com.web3auth.web3_android_mpc_provider;

import static org.junit.Assert.assertNotNull;

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 org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.response.EthChainId;
import org.web3j.protocol.core.methods.response.EthGasPrice;
import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
import org.web3j.protocol.http.HttpService;

import java.io.IOException;
import java.math.BigInteger;
import java.security.SignatureException;
import java.util.concurrent.ExecutionException;

@RunWith(AndroidJUnit4.class)
Expand All @@ -20,7 +25,7 @@ public class MpcProviderTests {
System.loadLibrary("dkls-native");
}

final String example1 = "{\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{{\"name\":\"wallet\",\"type\":\"address\"}]],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person\"},{\"name\":\"contents\",\"type\":\"string\"}]},\"primaryType\":\"Mail\",\"domain\":{\"name\":\"Ether Mail\",\"version\":\"1\",\"chainId\":1,\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"},\"message\":{\"from\":{\"name\":\"Account\",\"wallet\":\"0x048975d4997d7578a3419851639c10318db430b6\"},\"to\":{\"name\":\"Bob\",\"wallet\":\"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB\"},\"contents\":\"Hello, Bob!\"}}";
final String example1 = "{\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"wallet\",\"type\":\"address\"}],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person\"},{\"name\":\"contents\",\"type\":\"string\"}]},\"primaryType\":\"Mail\",\"domain\":{\"name\":\"Ether Mail\",\"version\":\"1\",\"chainId\":1,\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"},\"message\":{\"from\":{\"name\":\"Account\",\"wallet\":\"0x048975d4997d7578a3419851639c10318db430b6\"},\"to\":{\"name\":\"Bob\",\"wallet\":\"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB\"},\"contents\":\"Hello,Bob!\"}}";

final String fullAddress = "04238569d5e12caf57d34fb5b2a0679c7775b5f61fd18cd69db9cc600a651749c3ec13a9367380b7a024a67f5e663f3afd40175c3223da63f6024b05d0bd9f292e";
final String factorKey = "3b4af35bc4838471f94825f34c4f649904a258c0907d348bed653eb0c94ec6c0";
Expand Down Expand Up @@ -58,12 +63,59 @@ public void testSigningMessage() throws TSSClientError, CustomSigningError {
}

@Test
public void testSigningTransaction() throws TSSClientError, CustomSigningError, IOException, ExecutionException, InterruptedException {
public void testSignTypedData() throws TSSClientError, IOException, CustomSigningError {
EthTssAccountParams params = new EthTssAccountParams(
fullAddress, factorKey, tssNonce, tssShare, tssIndex, selected_tag, verifier, verifierId,
nodeIndexs, tssEndpoints, sigs);

EthereumTssAccount account = new EthereumTssAccount(params);

account.signTypedData(example1);
}

@Test
public void testSigningLegacyTransaction() throws TSSClientError, CustomSigningError, ExecutionException, InterruptedException, IOException {
EthTssAccountParams params = new EthTssAccountParams(
fullAddress, factorKey, tssNonce, tssShare, tssIndex, selected_tag, verifier, verifierId,
nodeIndexs, tssEndpoints, sigs);
EthereumTssAccount account = new EthereumTssAccount(params);
// setup Web3j
String url = "https://rpc.ankr.com/eth_goerli";
Web3j web3j = Web3j.build(new HttpService(url));
EthGetTransactionCount ethGetTransactionCount = web3j.ethGetTransactionCount(
account.evmAddress,
DefaultBlockParameterName.LATEST
).send();
BigInteger nonce = ethGetTransactionCount.getTransactionCount();
BigInteger gasLimit = BigInteger.valueOf(21000);
EthChainId chainIdResponse = web3j.ethChainId().sendAsync().get();
BigInteger chainId = chainIdResponse.getChainId();

String toAddress = "0xE09543f1974732F5D6ad442dDf176D9FA54a5Be0";
account.signLegacyTransaction(chainId, toAddress, 0.001, null, nonce, gasLimit);
}

@Test
public void testSigningTransaction() throws TSSClientError, CustomSigningError, SignatureException, ExecutionException, InterruptedException, IOException {
EthTssAccountParams params = new EthTssAccountParams(
fullAddress, factorKey, tssNonce, tssShare, tssIndex, selected_tag, verifier, verifierId,
nodeIndexs, tssEndpoints, sigs);
EthereumTssAccount account = new EthereumTssAccount(params);
String toAddress = "0x048975d4997D7578A3419851639c10318db430b6";
account.signTransaction(new BigInteger("5"), toAddress, 0.001, null, new BigInteger("0"), new BigInteger("21000" ), new BigInteger("21000"), new BigInteger("21000"));
// setup Web3j
String url = "https://rpc.ankr.com/eth_goerli";
Web3j web3j = Web3j.build(new HttpService(url));
EthGetTransactionCount ethGetTransactionCount = web3j.ethGetTransactionCount(
account.evmAddress,
DefaultBlockParameterName.LATEST
).send();
BigInteger nonce = ethGetTransactionCount.getTransactionCount();
BigInteger gasLimit = BigInteger.valueOf(21000);
EthChainId chainIdResponse = web3j.ethChainId().sendAsync().get();
BigInteger chainId = chainIdResponse.getChainId();
EthGasPrice gasPriceResponse = web3j.ethGasPrice().send();
BigInteger gasPrice = gasPriceResponse.getGasPrice();

String toAddress = "0xE09543f1974732F5D6ad442dDf176D9FA54a5Be0";
account.signTransaction(chainId, toAddress, 0.001, null, nonce, gasLimit, gasPrice, gasPrice);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.web3j.crypto.Keys;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.Sign;
import org.web3j.crypto.StructuredDataEncoder;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
Expand All @@ -27,6 +28,7 @@

import java.io.IOException;
import java.math.BigInteger;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -59,14 +61,58 @@ public String signMessage(String message) throws TSSClientError, CustomSigningEr
return TSSHelpers.hexSignature(signatureResult.getFirst(), signatureResult.getSecond(), v);
}

//todo: Method for signing eip712 structured data
public String signTypedData(String jsonData) throws IOException, TSSClientError, CustomSigningError {
StructuredDataEncoder dataEncoder = new StructuredDataEncoder(jsonData);
byte[] hashStructuredData = dataEncoder.hashStructuredData();
String structuredData = android.util.Base64.encodeToString(hashStructuredData, Base64.NO_WRAP);
Triple<BigInteger, BigInteger, Byte> signatureResult = sign(structuredData);
Byte v = signatureResult.getThird();
if (v < 27) {
v = (byte) (v + 27);
}
return TSSHelpers.hexSignature(signatureResult.getFirst(), signatureResult.getSecond(), v);
}

//todo Method for signing eip1559 transactions, note that v follows a formula here and is not just modified with 27

public String signTransaction(BigInteger chainID, String toAddress, Double amount, @Nullable String data, BigInteger nonce, BigInteger gasLimit, BigInteger maxPriorityFeePerGas, BigInteger maxFeePerGas) throws TSSClientError, CustomSigningError {
public String signLegacyTransaction(BigInteger chainID, String toAddress, Double amount, @Nullable String data, BigInteger nonce, BigInteger gasLimit) throws TSSClientError, CustomSigningError {
BigInteger value = Convert.toWei(Double.toString(amount), Convert.Unit.ETHER).toBigInteger();

String txData = "";
if (data != null) {
txData = data;
}

RawTransaction rawTransaction = RawTransaction.createTransaction(
chainID,
nonce,
gasLimit,
toAddress,
value,
txData
);

byte[] encodedTransaction = TransactionEncoder.encode(rawTransaction);
String encodedTransactionString = Base64.encodeToString(Hash.sha3(encodedTransaction), Base64.NO_WRAP);

Triple<BigInteger, BigInteger, Byte> signatureResult = sign(encodedTransactionString);

Byte v = signatureResult.getThird();
if (v < 27) {
v = (byte) (v + 27);
}

Sign.SignatureData signatureData = new Sign.SignatureData(v,
signatureResult.getSecond().toByteArray(),
signatureResult.getFirst().toByteArray());

byte[] signedTransaction = TransactionEncoder.encode(rawTransaction, signatureData);

return Numeric.toHexString(signedTransaction);
}

public String signTransaction(BigInteger chainID, String toAddress, Double amount, @Nullable String data, BigInteger nonce, BigInteger gasLimit, BigInteger maxPriorityFeePerGas, BigInteger maxFeePerGas) throws TSSClientError, CustomSigningError, SignatureException {
BigInteger value = Convert.toWei(Double.toString(amount), Convert.Unit.ETHER).toBigInteger();

// todo: this appears to be a bug in web3j, if data is null it throws but is marked as nullable
String txData = "";
if (data != null) {
txData = data;
Expand All @@ -88,12 +134,18 @@ public String signTransaction(BigInteger chainID, String toAddress, Double amoun

Triple<BigInteger, BigInteger, Byte> signatureResult = sign(encodedTransactionString);

Sign.SignatureData signatureData = new Sign.SignatureData((byte) (signatureResult.getThird() + 27),
Byte v = signatureResult.getThird();
if (v < 35) {
v = (byte) ((chainID.byteValue() * 2) + (v + 35));
}

Sign.SignatureData signatureData = new Sign.SignatureData(v,
signatureResult.getSecond().toByteArray(),
signatureResult.getFirst().toByteArray());
byte[] signedMsg = TransactionEncoder.encode(rawTransaction, signatureData);

return Numeric.toHexString(signedMsg);
byte[] signedTransaction = TransactionEncoder.encode(rawTransaction, signatureData);

return Numeric.toHexString(signedTransaction);
}

public void sendTransaction(Web3j web3j, String signedTx) throws IOException, CustomSigningError {
Expand Down Expand Up @@ -176,6 +228,7 @@ private Pair<TSSClient, Map<String, String>> bootstrapTssClient(EthTssAccountPar
return new Pair<>(client, coeffs);
}


private EndpointsData generateEndpoints(int parties, int clientIndex, List<String> tssEndpoints) {
List<String> endpoints = new ArrayList<>();
List<String> tssWSEndpoints = new ArrayList<>();
Expand Down

0 comments on commit 52305b3

Please sign in to comment.