Skip to content

Commit ed89528

Browse files
authored
feat: apply EIP-712 new implementation to Challenge class (#154)
1 parent 9e91aa1 commit ed89528

File tree

3 files changed

+110
-9
lines changed

3 files changed

+110
-9
lines changed

release-please-config.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
3+
"always-update": true,
34
"draft-pull-request": true,
45
"include-component-in-tag": false,
56
"include-v-in-tag": true,
Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022-2023 IEXEC BLOCKCHAIN TECH
2+
* Copyright 2022-2025 IEXEC BLOCKCHAIN TECH
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,18 +16,43 @@
1616

1717
package com.iexec.commons.poco.eip712.entity;
1818

19-
import lombok.AllArgsConstructor;
19+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
20+
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
21+
import com.iexec.commons.poco.eip712.EIP712TypedData;
22+
import com.iexec.commons.poco.eip712.EIP712Utils;
23+
import com.iexec.commons.poco.utils.HashUtils;
2024
import lombok.Builder;
21-
import lombok.Data;
22-
import lombok.NoArgsConstructor;
25+
import lombok.Value;
26+
import lombok.extern.slf4j.Slf4j;
27+
28+
import java.util.stream.Stream;
2329

2430
/**
2531
* Represents the Challenge type in an EIP-712 compliant challenge.
2632
*/
27-
@Data
33+
@Slf4j
34+
@Value
2835
@Builder
29-
@AllArgsConstructor
30-
@NoArgsConstructor
31-
public class Challenge {
32-
private String challenge;
36+
@JsonDeserialize(builder = Challenge.ChallengeBuilder.class)
37+
public class Challenge implements EIP712TypedData {
38+
private static final String EIP712_TYPE = "Challenge(string challenge)";
39+
40+
String challenge;
41+
42+
public String computeMessageHash() {
43+
final String[] encodedValues = Stream.of(EIP712_TYPE, challenge)
44+
.map(EIP712Utils::encodeData)
45+
.toArray(String[]::new);
46+
if (log.isDebugEnabled()) {
47+
log.debug("{}", EIP712_TYPE);
48+
for (String value : encodedValues) {
49+
log.debug("{}", value);
50+
}
51+
}
52+
return HashUtils.concatenateAndHash(encodedValues);
53+
}
54+
55+
@JsonPOJOBuilder(withPrefix = "")
56+
public static class ChallengeBuilder {
57+
}
3358
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright 2025 IEXEC BLOCKCHAIN TECH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.iexec.commons.poco.eip712.entity;
18+
19+
import com.fasterxml.jackson.core.JsonProcessingException;
20+
import com.fasterxml.jackson.databind.ObjectMapper;
21+
import com.iexec.commons.poco.eip712.EIP712Domain;
22+
import com.iexec.commons.poco.utils.HashUtils;
23+
import org.apache.commons.lang3.RandomStringUtils;
24+
import org.junit.jupiter.api.Test;
25+
import org.web3j.crypto.Hash;
26+
import org.web3j.utils.Numeric;
27+
28+
import java.math.BigInteger;
29+
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
32+
class ChallengeTests {
33+
34+
private static final ObjectMapper mapper = new ObjectMapper();
35+
36+
@Test
37+
void shouldSerializeAndDeserialize() throws JsonProcessingException {
38+
final String payload = RandomStringUtils.randomAlphanumeric(20);
39+
final Challenge challenge = Challenge.builder()
40+
.challenge(payload)
41+
.build();
42+
String jsonString = mapper.writeValueAsString(challenge);
43+
assertThat(jsonString).isEqualTo("{\"challenge\":\"" + payload + "\"}");
44+
final Challenge parsedChallenge = mapper.readValue(jsonString, Challenge.class);
45+
assertThat(parsedChallenge).usingRecursiveComparison().isEqualTo(challenge);
46+
assertThat(challenge).hasToString("Challenge(challenge=" + payload + ")");
47+
}
48+
49+
@Test
50+
void shouldComputeHashForChallenge() {
51+
final Challenge challenge = Challenge.builder()
52+
.challenge("challenge")
53+
.build();
54+
final EIP712Domain domain = new EIP712Domain("COMMON", "1", 15L, null);
55+
final String domainType = "EIP712Domain(string name,string version,uint256 chainId)";
56+
final String domainSeparator = HashUtils.concatenateAndHash(
57+
Numeric.toHexString(Hash.sha3(domainType.getBytes())),
58+
Numeric.toHexString(Hash.sha3(domain.getName().getBytes())),
59+
Numeric.toHexString(Hash.sha3(domain.getVersion().getBytes())),
60+
Numeric.toHexString(Numeric.toBytesPadded(BigInteger.valueOf(domain.getChainId()), 32)));
61+
final String messageType = "Challenge(string challenge)";
62+
final String messageHash = HashUtils.concatenateAndHash(
63+
Numeric.toHexString(Hash.sha3(messageType.getBytes())),
64+
Numeric.toHexString(Hash.sha3("challenge".getBytes())));
65+
assertThat(challenge.computeMessageHash()).isEqualTo(messageHash);
66+
final String hash = HashUtils.concatenateAndHash(
67+
"0x1901",
68+
domainSeparator,
69+
messageHash);
70+
assertThat(challenge.computeHash(domain))
71+
.isEqualTo(hash)
72+
.isEqualTo("0xea5ec041da81859f2c04a4876d5999ed8e66ad221b5b8699ca91f6814693a80e");
73+
}
74+
75+
}

0 commit comments

Comments
 (0)