diff --git a/eea/src/main/java/org/web3j/protocol/eea/crypto/PrivateTransactionEncoder.java b/eea/src/main/java/org/web3j/protocol/eea/crypto/PrivateTransactionEncoder.java index ddbefcce17..8085ec11fc 100644 --- a/eea/src/main/java/org/web3j/protocol/eea/crypto/PrivateTransactionEncoder.java +++ b/eea/src/main/java/org/web3j/protocol/eea/crypto/PrivateTransactionEncoder.java @@ -77,19 +77,6 @@ public static List asRlpValues( final RawPrivateTransaction privateTransaction, final Sign.SignatureData signatureData) { - final List result = - new ArrayList<>(TransactionEncoder.asRlpValues(privateTransaction, signatureData)); - - result.add(privateTransaction.getPrivateFrom().asRlp()); - - privateTransaction - .getPrivateFor() - .ifPresent(privateFor -> result.add(Base64String.unwrapListToRlp(privateFor))); - - privateTransaction.getPrivacyGroupId().map(Base64String::asRlp).ifPresent(result::add); - - result.add(RlpString.create(privateTransaction.getRestriction().getRestriction())); - - return result; + return privateTransaction.asRlpValues(signatureData); } } diff --git a/eea/src/main/java/org/web3j/protocol/eea/crypto/RawPrivateTransaction.java b/eea/src/main/java/org/web3j/protocol/eea/crypto/RawPrivateTransaction.java index aaa5b32df0..2b127725ec 100644 --- a/eea/src/main/java/org/web3j/protocol/eea/crypto/RawPrivateTransaction.java +++ b/eea/src/main/java/org/web3j/protocol/eea/crypto/RawPrivateTransaction.java @@ -13,14 +13,21 @@ package org.web3j.protocol.eea.crypto; import java.math.BigInteger; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import org.web3j.crypto.RawTransaction; +import org.web3j.crypto.Sign; +import org.web3j.crypto.TransactionEncoder; import org.web3j.crypto.transaction.type.ITransaction; import org.web3j.crypto.transaction.type.LegacyTransaction; import org.web3j.crypto.transaction.type.Transaction1559; +import org.web3j.rlp.RlpString; +import org.web3j.rlp.RlpType; import org.web3j.utils.Base64String; +import org.web3j.utils.Bytes; +import org.web3j.utils.Numeric; import org.web3j.utils.Restriction; /** @@ -90,6 +97,50 @@ private RawPrivateTransaction( this(rawTransaction.getTransaction(), privateFrom, privateFor, privacyGroupId, restriction); } + public List asRlpValues( + final Sign.SignatureData signatureData) { + + List result = new ArrayList<>(); + + result.add(RlpString.create(getNonce())); + + result.add(RlpString.create(getGasPrice())); + result.add(RlpString.create(getGasLimit())); + + // an empty to address (contract creation) should not be encoded as a numeric 0 value + String to = getTo(); + if (to != null && to.length() > 0) { + // addresses that start with zeros should be encoded with the zeros included, not + // as numeric values + result.add(RlpString.create(Numeric.hexStringToByteArray(to))); + } else { + result.add(RlpString.create("")); + } + + result.add(RlpString.create(getValue())); + + // value field will already be hex encoded, so we need to convert into binary first + byte[] data = Numeric.hexStringToByteArray(getData()); + result.add(RlpString.create(data)); + + if (signatureData != null) { + result.add(RlpString.create(Bytes.trimLeadingZeroes(signatureData.getV()))); + result.add(RlpString.create(Bytes.trimLeadingZeroes(signatureData.getR()))); + result.add(RlpString.create(Bytes.trimLeadingZeroes(signatureData.getS()))); + } + + result.add(getPrivateFrom().asRlp()); + + getPrivateFor() + .ifPresent(privateFor -> result.add(Base64String.unwrapListToRlp(privateFor))); + + getPrivacyGroupId().map(Base64String::asRlp).ifPresent(result::add); + + result.add(RlpString.create(getRestriction().getRestriction())); + + return result; + } + public static RawPrivateTransaction createContractTransaction( final BigInteger nonce, final BigInteger gasPrice, diff --git a/eea/src/main/java/org/web3j/protocol/eea/crypto/RawPrivateTransaction1559.java b/eea/src/main/java/org/web3j/protocol/eea/crypto/RawPrivateTransaction1559.java new file mode 100644 index 0000000000..f19adbbd6a --- /dev/null +++ b/eea/src/main/java/org/web3j/protocol/eea/crypto/RawPrivateTransaction1559.java @@ -0,0 +1,140 @@ +package org.web3j.protocol.eea.crypto; + +import org.web3j.crypto.RawTransaction; +import org.web3j.crypto.Sign; +import org.web3j.crypto.transaction.type.ITransaction; +import org.web3j.rlp.RlpList; +import org.web3j.rlp.RlpString; +import org.web3j.rlp.RlpType; +import org.web3j.utils.Base64String; +import org.web3j.utils.Bytes; +import org.web3j.utils.Numeric; +import org.web3j.utils.Restriction; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +public class RawPrivateTransaction1559 extends RawPrivateTransaction{ + + private long chainId; + private BigInteger maxPriorityFeePerGas; + private BigInteger maxFeePerGas; + + + protected RawPrivateTransaction1559(long chainId, + BigInteger nonce, + BigInteger gasLimit, + String to, + String data, + BigInteger maxPriorityFeePerGas, + BigInteger maxFeePerGas, + Base64String privateFrom, + List privateFor, + Base64String privacyGroupId, + Restriction restriction) { + super(nonce, null, gasLimit, to, data, privateFrom, privateFor, privacyGroupId, restriction); + this.chainId = chainId; + this.maxPriorityFeePerGas = maxPriorityFeePerGas; + this.maxFeePerGas = maxFeePerGas; + } + + protected RawPrivateTransaction1559( + long chainId, + BigInteger nonce, + BigInteger gasLimit, + String to, + String data, + BigInteger maxPriorityFeePerGas, + BigInteger maxFeePerGas, + Base64String privateFrom, + Base64String privacyGroupId, + Restriction restriction) { + this(chainId, nonce, gasLimit, to, data, maxPriorityFeePerGas, maxFeePerGas, privateFrom, null, privacyGroupId, restriction); + } + + protected RawPrivateTransaction1559( + long chainId, + BigInteger nonce, + BigInteger gasLimit, + String to, + String data, + BigInteger maxPriorityFeePerGas, + BigInteger maxFeePerGas, + Base64String privateFrom, + List privateFor, + Restriction restriction) { + this(chainId, nonce, gasLimit, to, data, maxPriorityFeePerGas, maxFeePerGas, privateFrom, privateFor, null, restriction); + } + + @Override + public List asRlpValues( + final Sign.SignatureData signatureData) { + + List result = new ArrayList<>(); + + result.add(RlpString.create(getChainId())); + + result.add(RlpString.create(getNonce())); + + // add maxPriorityFeePerGas and maxFeePerGas if this is an EIP-1559 transaction + result.add(RlpString.create(getMaxPriorityFeePerGas())); + result.add(RlpString.create(getMaxFeePerGas())); + + result.add(RlpString.create(getGasLimit())); + + // an empty to address (contract creation) should not be encoded as a numeric 0 value + String to = getTo(); + if (to != null && to.length() > 0) { + // addresses that start with zeros should be encoded with the zeros included, not + // as numeric values + result.add(RlpString.create(Numeric.hexStringToByteArray(to))); + } else { + result.add(RlpString.create("")); + } + + result.add(RlpString.create(getValue())); + + // value field will already be hex encoded, so we need to convert into binary first + byte[] data = Numeric.hexStringToByteArray(getData()); + result.add(RlpString.create(data)); + + // access list + result.add(new RlpList()); + + if (signatureData != null) { + result.add(RlpString.create(Sign.getRecId(signatureData, getChainId()))); + result.add(RlpString.create(Bytes.trimLeadingZeroes(signatureData.getR()))); + result.add(RlpString.create(Bytes.trimLeadingZeroes(signatureData.getS()))); + } + + result.add(getPrivateFrom().asRlp()); + + getPrivateFor() + .ifPresent(privateFor -> result.add(Base64String.unwrapListToRlp(privateFor))); + + getPrivacyGroupId().map(Base64String::asRlp).ifPresent(result::add); + + result.add(RlpString.create(getRestriction().getRestriction())); + + return result; + } + + + @Override + public BigInteger getGasPrice() { + throw new UnsupportedOperationException("not available for 1559 transaction"); + } + + public long getChainId() { + return chainId; + } + + public BigInteger getMaxPriorityFeePerGas() { + return maxPriorityFeePerGas; + } + + public BigInteger getMaxFeePerGas() { + return maxFeePerGas; + } +}