Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/main/java/com/iexec/commons/poco/chain/SignerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@

package com.iexec.commons.poco.chain;

import com.iexec.commons.poco.eip712.EIP712Domain;
import com.iexec.commons.poco.eip712.EIP712Entity;
import com.iexec.commons.poco.eip712.EIP712TypedData;
import com.iexec.commons.poco.order.Order;
import com.iexec.commons.poco.security.Signature;
import com.iexec.commons.poco.utils.BytesUtils;
import com.iexec.commons.poco.utils.EthAddress;
Expand Down Expand Up @@ -111,6 +114,10 @@ public Signature signMessageHash(String messageHash) {
return SignatureUtils.signMessageHashAndGetSignature(messageHash, credentials.getEcKeyPair());
}

/**
* @deprecated use signTypedDataForDomain instead
*/
@Deprecated(forRemoval = true)
public String signEIP712Entity(EIP712Entity<?> eip712Entity) {
final String signature = eip712Entity.signMessage(credentials.getEcKeyPair());
if (StringUtils.isEmpty(signature)) {
Expand All @@ -120,6 +127,23 @@ public String signEIP712Entity(EIP712Entity<?> eip712Entity) {
return signature;
}

/**
* Hashes and signs structured type data following EIP-712
*
* @param typedData structured data implementing {@link EIP712TypedData} to hash and sign
* @param domain target EIP712Domain describing the target for which the data is hashed and signed
* @return a valid signature
* @see <a href="https://eips.ethereum.org/EIPS/eip-712">EIP-712</a>
*/
public String signTypedDataForDomain(final EIP712TypedData typedData, final EIP712Domain domain) {
return typedData.sign(credentials.getEcKeyPair(), domain);
}

public Order signOrderForDomain(final Order order, final EIP712Domain domain) {
final String sig = signTypedDataForDomain(order, domain);
return order.withSignature(sig);
}

/**
* Builds an authorization token for given {@link EIP712Entity}.
* <p>
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/iexec/commons/poco/eip712/EIP712Entity.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* @deprecated implements {@code EIP712TypedData} interface instead
*/
@Deprecated(forRemoval = true)
@Slf4j
@NoArgsConstructor
public abstract class EIP712Entity<M> implements EIP712<M> {
Expand Down
45 changes: 45 additions & 0 deletions src/main/java/com/iexec/commons/poco/eip712/EIP712TypedData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2025 IEXEC BLOCKCHAIN TECH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.iexec.commons.poco.eip712;

import com.iexec.commons.poco.utils.HashUtils;
import com.iexec.commons.poco.utils.SignatureUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.web3j.crypto.ECKeyPair;

public interface EIP712TypedData {
Logger log = LoggerFactory.getLogger(EIP712TypedData.class);

default String computeHash(final EIP712Domain domain) {
final String domainSeparator = domain.getDomainSeparator();
final String messageHash = computeMessageHash();
final String hash = HashUtils.concatenateAndHash("0x1901", domainSeparator, messageHash);
if (log.isDebugEnabled()) {
log.debug("domainSeparator {}", domainSeparator);
log.debug("messageHash {}", messageHash);
log.debug("hash {}", hash);
}
return hash;
}

String computeMessageHash();

default String sign(final ECKeyPair ecKeyPair, final EIP712Domain domain) {
return SignatureUtils.signAsString(computeHash(domain), ecKeyPair);
}
}
25 changes: 25 additions & 0 deletions src/main/java/com/iexec/commons/poco/order/AppOrder.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.iexec.commons.poco.contract.generated.IexecHubContract;
import com.iexec.commons.poco.eip712.EIP712Utils;
import com.iexec.commons.poco.utils.HashUtils;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.web3j.utils.Numeric;

import java.math.BigInteger;
import java.util.stream.Stream;

@Slf4j
@Value
@EqualsAndHashCode(callSuper = true)
@JsonDeserialize(builder = AppOrder.AppOrderBuilder.class)
Expand Down Expand Up @@ -70,6 +75,26 @@ public AppOrder withSignature(String signature) {
);
}

// region EIP-712
public String computeMessageHash() {
final String type = "AppOrder(address app,uint256 appprice,uint256 volume,bytes32 tag,address datasetrestrict,address workerpoolrestrict,address requesterrestrict,bytes32 salt)";
final String[] encodedValues = Stream.of(type, app, appprice, volume, tag, datasetrestrict, workerpoolrestrict, requesterrestrict, salt)
.map(EIP712Utils::encodeData)
.toArray(String[]::new);
if (log.isDebugEnabled()) {
log.debug("{}", type);
for (String value : encodedValues) {
log.debug("{}", value);
}
}
return HashUtils.concatenateAndHash(encodedValues);
}
// endregion

/**
* @deprecated no more used
*/
@Deprecated(forRemoval = true)
public IexecHubContract.AppOrder toHubContract() {
return new IexecHubContract.AppOrder(
this.app,
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/com/iexec/commons/poco/order/DatasetOrder.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.iexec.commons.poco.contract.generated.IexecHubContract;
import com.iexec.commons.poco.eip712.EIP712Utils;
import com.iexec.commons.poco.utils.HashUtils;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.web3j.utils.Numeric;

import java.math.BigInteger;
import java.util.stream.Stream;

@Slf4j
@Value
@EqualsAndHashCode(callSuper = true)
@JsonDeserialize(builder = DatasetOrder.DatasetOrderBuilder.class)
Expand Down Expand Up @@ -69,6 +74,26 @@ public DatasetOrder withSignature(String signature) {
);
}

// region EIP-712
public String computeMessageHash() {
final String type = "DatasetOrder(address dataset,uint256 datasetprice,uint256 volume,bytes32 tag,address apprestrict,address workerpoolrestrict,address requesterrestrict,bytes32 salt)";
final String[] encodedValues = Stream.of(type, dataset, datasetprice, volume, tag, apprestrict, workerpoolrestrict, requesterrestrict, salt)
.map(EIP712Utils::encodeData)
.toArray(String[]::new);
if (log.isDebugEnabled()) {
log.debug("{}", type);
for (String value : encodedValues) {
log.debug("{}", value);
}
}
return HashUtils.concatenateAndHash(encodedValues);
}
// endregion

/**
* @deprecated no more used
*/
@Deprecated(forRemoval = true)
public IexecHubContract.DatasetOrder toHubContract() {
return new IexecHubContract.DatasetOrder(
this.dataset,
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/com/iexec/commons/poco/order/Order.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@
package com.iexec.commons.poco.order;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.iexec.commons.poco.eip712.EIP712TypedData;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.math.BigInteger;

@Slf4j
@Getter
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class Order {
public abstract class Order implements EIP712TypedData {

protected final BigInteger volume;
protected final String tag;
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/com/iexec/commons/poco/order/RequestOrder.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.iexec.commons.poco.contract.generated.IexecHubContract;
import com.iexec.commons.poco.eip712.EIP712Utils;
import com.iexec.commons.poco.utils.HashUtils;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.web3j.utils.Numeric;

import java.math.BigInteger;
import java.util.stream.Stream;

@Slf4j
@Value
@EqualsAndHashCode(callSuper = true)
@JsonDeserialize(builder = RequestOrder.RequestOrderBuilder.class)
Expand Down Expand Up @@ -92,6 +97,26 @@ public RequestOrder withSignature(String signature) {
);
}

// region EIP-712
public String computeMessageHash() {
final String type = "RequestOrder(address app,uint256 appmaxprice,address dataset,uint256 datasetmaxprice,address workerpool,uint256 workerpoolmaxprice,address requester,uint256 volume,bytes32 tag,uint256 category,uint256 trust,address beneficiary,address callback,string params,bytes32 salt)";
final String[] encodedValues = Stream.of(type, app, appmaxprice, dataset, datasetmaxprice, workerpool, workerpoolmaxprice, requester, volume, tag, category, trust, beneficiary, callback, params, salt)
.map(EIP712Utils::encodeData)
.toArray(String[]::new);
if (log.isDebugEnabled()) {
log.debug("{}", type);
for (String value : encodedValues) {
log.debug("{}", value);
}
}
return HashUtils.concatenateAndHash(encodedValues);
}
// endregion

/**
* @deprecated no more used
*/
@Deprecated(forRemoval = true)
public IexecHubContract.RequestOrder toHubContract() {
return new IexecHubContract.RequestOrder(
this.app,
Expand Down
27 changes: 25 additions & 2 deletions src/main/java/com/iexec/commons/poco/order/WorkerpoolOrder.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,20 @@
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.iexec.commons.poco.contract.generated.IexecHubContract;
import com.iexec.commons.poco.eip712.EIP712Utils;
import com.iexec.commons.poco.utils.HashUtils;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.web3j.utils.Numeric;

import java.math.BigInteger;
import java.util.stream.Stream;

@Slf4j
@Value
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@JsonDeserialize(builder = WorkerpoolOrder.WorkerpoolOrderBuilder.class)
public class WorkerpoolOrder extends Order {

Expand Down Expand Up @@ -78,6 +81,26 @@ public WorkerpoolOrder withSignature(String signature) {
);
}

// region EIP-712
public String computeMessageHash() {
final String type = "WorkerpoolOrder(address workerpool,uint256 workerpoolprice,uint256 volume,bytes32 tag,uint256 category,uint256 trust,address apprestrict,address datasetrestrict,address requesterrestrict,bytes32 salt)";
final String[] encodedValues = Stream.of(type, workerpool, workerpoolprice, volume, tag, category, trust, apprestrict, datasetrestrict, requesterrestrict, salt)
.map(EIP712Utils::encodeData)
.toArray(String[]::new);
if (log.isDebugEnabled()) {
log.debug("{}", type);
for (String value : encodedValues) {
log.debug("{}", value);
}
}
return HashUtils.concatenateAndHash(encodedValues);
}
// endregion

/**
* @deprecated no more used
*/
@Deprecated(forRemoval = true)
public IexecHubContract.WorkerpoolOrder toHubContract() {
return new IexecHubContract.WorkerpoolOrder(
this.workerpool,
Expand Down
16 changes: 4 additions & 12 deletions src/test/java/com/iexec/commons/poco/itest/OrdersService.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@
import com.iexec.commons.poco.chain.DealParams;
import com.iexec.commons.poco.chain.SignerService;
import com.iexec.commons.poco.eip712.EIP712Domain;
import com.iexec.commons.poco.eip712.entity.EIP712AppOrder;
import com.iexec.commons.poco.eip712.entity.EIP712DatasetOrder;
import com.iexec.commons.poco.eip712.entity.EIP712RequestOrder;
import com.iexec.commons.poco.eip712.entity.EIP712WorkerpoolOrder;
import com.iexec.commons.poco.encoding.MatchOrdersDataEncoder;
import com.iexec.commons.poco.order.*;
import com.iexec.commons.poco.utils.BytesUtils;
Expand Down Expand Up @@ -64,8 +60,7 @@ public AppOrder buildSignedAppOrder(String appAddress) {
.requesterrestrict(BytesUtils.EMPTY_ADDRESS)
.salt(Hash.sha3String(RandomStringUtils.randomAlphanumeric(20)))
.build();
final String sig = signerService.signEIP712Entity(new EIP712AppOrder(domain, appOrder));
return appOrder.withSignature(sig);
return (AppOrder) signerService.signOrderForDomain(appOrder, domain);
}

public DatasetOrder buildSignedDatasetOrder(String datasetAddress) {
Expand All @@ -79,8 +74,7 @@ public DatasetOrder buildSignedDatasetOrder(String datasetAddress) {
.requesterrestrict(BytesUtils.EMPTY_ADDRESS)
.salt(Hash.sha3String(RandomStringUtils.randomAlphanumeric(20)))
.build();
final String sig = signerService.signEIP712Entity(new EIP712DatasetOrder(domain, datasetOrder));
return datasetOrder.withSignature(sig);
return (DatasetOrder) signerService.signOrderForDomain(datasetOrder, domain);
}

public WorkerpoolOrder buildSignedWorkerpoolOrder(String workerpoolAddress, BigInteger trust) {
Expand All @@ -96,8 +90,7 @@ public WorkerpoolOrder buildSignedWorkerpoolOrder(String workerpoolAddress, BigI
.requesterrestrict(BytesUtils.EMPTY_ADDRESS)
.salt(Hash.sha3String(RandomStringUtils.randomAlphanumeric(20)))
.build();
final String sig = signerService.signEIP712Entity(new EIP712WorkerpoolOrder(domain, workerpoolOrder));
return workerpoolOrder.withSignature(sig);
return (WorkerpoolOrder) signerService.signOrderForDomain(workerpoolOrder, domain);
}

public RequestOrder buildSignedRequestOrder(AppOrder appOrder, DatasetOrder datasetOrder, WorkerpoolOrder workerpoolOrder, BigInteger trust) {
Expand Down Expand Up @@ -128,8 +121,7 @@ public RequestOrder buildSignedRequestOrder(AppOrder appOrder, DatasetOrder data
.params(dealParams.toJsonString())
.salt(Hash.sha3String(RandomStringUtils.randomAlphanumeric(20)))
.build();
final String sig = signerService.signEIP712Entity(new EIP712RequestOrder(domain, requestOrder));
return requestOrder.withSignature(sig);
return (RequestOrder) signerService.signOrderForDomain(requestOrder, domain);
}

public DealOrders buildAllSignedOrders(final String appAddress, final String datasetAddress, final String workerpoolAddress, final BigInteger trust) {
Expand Down
21 changes: 21 additions & 0 deletions src/test/java/com/iexec/commons/poco/order/AppOrderTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.iexec.commons.poco.chain.SignerService;
import com.iexec.commons.poco.contract.generated.IexecHubContract;
import com.iexec.commons.poco.eip712.EIP712Domain;
import com.iexec.commons.poco.utils.BytesUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
Expand Down Expand Up @@ -81,4 +83,23 @@ void shouldCastToHubContract() {
);
}

@Test
void shouldSignAppOrder() throws Exception {
final int chainId = 133;
final SignerService signer = new SignerService(null, chainId, "whatever", "./src/test/resources/wallet.json");
final AppOrder appOrder = AppOrder.builder()
.app("0x2EbD509d777B187E8394566bA6ec093B9dd73DF1")
.appprice(BigInteger.ZERO)
.volume(BigInteger.ONE)
.tag("0x0000000000000000000000000000000000000000000000000000000000000000")
.datasetrestrict(BytesUtils.EMPTY_ADDRESS)
.workerpoolrestrict(BytesUtils.EMPTY_ADDRESS)
.requesterrestrict(BytesUtils.EMPTY_ADDRESS)
.salt("0xbe858b0eee90cf2e85297bd3df81373f6b4de20c67a3e1f5db1a9d5be8abc3c4")
.build();
final EIP712Domain domain = new EIP712Domain(chainId, "0x3eca1B216A7DF1C7689aEb259fFB83ADFB894E7f");
final AppOrder signedOrder = (AppOrder) signer.signOrderForDomain(appOrder, domain);
assertThat(signedOrder.getSign()).isEqualTo("0x82c2d8a5f59f1088eb0b9a627c367ae7dae1772c8bd98c394699ae24830611e1171026f4e28d2c60302c34a04c60c4fc2f1363e165072dca04a9f203734978671c");
}

}
Loading