Skip to content

Commit 9e519a9

Browse files
devin-ai-integration[bot]Jayant
andauthored
feat(entropy-sdk): add MockEntropy contract for local testing (#3121)
* feat(entropy-sdk): add MockEntropy contract for local testing - Implements IEntropyV2 interface with two-step request/reveal pattern - requestV2() stores request and returns sequence number - mockReveal() allows manual callback triggering with custom random numbers - Enables testing different interleavings of requests and reveals - Includes comprehensive test suite demonstrating usage patterns - Simplifies testing by removing fee requirements and commitment validation Co-Authored-By: Jayant <[email protected]> * fix(entropy-sdk): initialize feeInWei to 1 and bump version to 2.1.0 - Set feeInWei to 1 in MockEntropy constructor and _requestV2 - Update package.json version from 2.0.0 to 2.1.0 - Update test assertion to expect feeInWei = 1 Co-Authored-By: Jayant <[email protected]> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Jayant <[email protected]>
1 parent 6fe8594 commit 9e519a9

File tree

3 files changed

+418
-1
lines changed

3 files changed

+418
-1
lines changed
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
// SPDX-License-Identifier: Apache 2
2+
pragma solidity ^0.8.0;
3+
4+
import "forge-std/Test.sol";
5+
import "@pythnetwork/entropy-sdk-solidity/MockEntropy.sol";
6+
import "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol";
7+
import "@pythnetwork/entropy-sdk-solidity/EntropyStructsV2.sol";
8+
9+
contract MockEntropyConsumer is IEntropyConsumer {
10+
address public entropy;
11+
bytes32 public lastRandomNumber;
12+
uint64 public lastSequenceNumber;
13+
address public lastProvider;
14+
uint256 public callbackCount;
15+
16+
constructor(address _entropy) {
17+
entropy = _entropy;
18+
}
19+
20+
function requestRandomNumber() external payable returns (uint64) {
21+
return MockEntropy(entropy).requestV2{value: msg.value}();
22+
}
23+
24+
function requestRandomNumberWithGasLimit(
25+
uint32 gasLimit
26+
) external payable returns (uint64) {
27+
return MockEntropy(entropy).requestV2{value: msg.value}(gasLimit);
28+
}
29+
30+
function requestRandomNumberFromProvider(
31+
address provider,
32+
uint32 gasLimit
33+
) external payable returns (uint64) {
34+
return
35+
MockEntropy(entropy).requestV2{value: msg.value}(
36+
provider,
37+
gasLimit
38+
);
39+
}
40+
41+
function getEntropy() internal view override returns (address) {
42+
return entropy;
43+
}
44+
45+
function entropyCallback(
46+
uint64 sequenceNumber,
47+
address provider,
48+
bytes32 randomNumber
49+
) internal override {
50+
lastSequenceNumber = sequenceNumber;
51+
lastProvider = provider;
52+
lastRandomNumber = randomNumber;
53+
callbackCount += 1;
54+
}
55+
}
56+
57+
contract MockEntropyTest is Test {
58+
MockEntropy public entropy;
59+
MockEntropyConsumer public consumer;
60+
address public provider;
61+
62+
function setUp() public {
63+
provider = address(0x1234);
64+
entropy = new MockEntropy(provider);
65+
consumer = new MockEntropyConsumer(address(entropy));
66+
}
67+
68+
function testBasicRequestAndReveal() public {
69+
uint64 seq = consumer.requestRandomNumber();
70+
assertEq(seq, 1, "Sequence number should be 1");
71+
72+
bytes32 randomNumber = bytes32(uint256(42));
73+
entropy.mockReveal(provider, seq, randomNumber);
74+
75+
assertEq(
76+
consumer.lastSequenceNumber(),
77+
seq,
78+
"Callback sequence number mismatch"
79+
);
80+
assertEq(
81+
consumer.lastProvider(),
82+
provider,
83+
"Callback provider mismatch"
84+
);
85+
assertEq(
86+
consumer.lastRandomNumber(),
87+
randomNumber,
88+
"Random number mismatch"
89+
);
90+
assertEq(consumer.callbackCount(), 1, "Callback should be called once");
91+
}
92+
93+
function testDifferentInterleavings() public {
94+
uint64 seq1 = consumer.requestRandomNumber();
95+
uint64 seq2 = consumer.requestRandomNumber();
96+
uint64 seq3 = consumer.requestRandomNumber();
97+
98+
assertEq(seq1, 1, "First sequence should be 1");
99+
assertEq(seq2, 2, "Second sequence should be 2");
100+
assertEq(seq3, 3, "Third sequence should be 3");
101+
102+
bytes32 random2 = bytes32(uint256(200));
103+
bytes32 random3 = bytes32(uint256(300));
104+
bytes32 random1 = bytes32(uint256(100));
105+
106+
entropy.mockReveal(provider, seq2, random2);
107+
assertEq(
108+
consumer.lastRandomNumber(),
109+
random2,
110+
"Should reveal seq2 first"
111+
);
112+
assertEq(consumer.lastSequenceNumber(), seq2, "Sequence should be 2");
113+
114+
entropy.mockReveal(provider, seq3, random3);
115+
assertEq(
116+
consumer.lastRandomNumber(),
117+
random3,
118+
"Should reveal seq3 second"
119+
);
120+
assertEq(consumer.lastSequenceNumber(), seq3, "Sequence should be 3");
121+
122+
entropy.mockReveal(provider, seq1, random1);
123+
assertEq(
124+
consumer.lastRandomNumber(),
125+
random1,
126+
"Should reveal seq1 last"
127+
);
128+
assertEq(consumer.lastSequenceNumber(), seq1, "Sequence should be 1");
129+
130+
assertEq(
131+
consumer.callbackCount(),
132+
3,
133+
"All three callbacks should be called"
134+
);
135+
}
136+
137+
function testDifferentProviders() public {
138+
address provider2 = address(0x5678);
139+
140+
uint64 seq1 = consumer.requestRandomNumberFromProvider(
141+
provider,
142+
100000
143+
);
144+
uint64 seq2 = consumer.requestRandomNumberFromProvider(
145+
provider2,
146+
100000
147+
);
148+
149+
assertEq(seq1, 1, "Provider 1 first sequence should be 1");
150+
assertEq(seq2, 1, "Provider 2 first sequence should be 1");
151+
152+
bytes32 random1 = bytes32(uint256(111));
153+
bytes32 random2 = bytes32(uint256(222));
154+
155+
entropy.mockReveal(provider, seq1, random1);
156+
assertEq(
157+
consumer.lastRandomNumber(),
158+
random1,
159+
"First provider random number"
160+
);
161+
162+
entropy.mockReveal(provider2, seq2, random2);
163+
assertEq(
164+
consumer.lastRandomNumber(),
165+
random2,
166+
"Second provider random number"
167+
);
168+
}
169+
170+
function testRequestWithGasLimit() public {
171+
uint64 seq = consumer.requestRandomNumberWithGasLimit(200000);
172+
173+
assertEq(seq, 1, "Sequence should be 1");
174+
175+
EntropyStructsV2.Request memory req = entropy.getRequestV2(
176+
provider,
177+
seq
178+
);
179+
assertEq(req.gasLimit10k, 20, "Gas limit should be 20 (200k / 10k)");
180+
181+
bytes32 randomNumber = bytes32(uint256(999));
182+
entropy.mockReveal(provider, seq, randomNumber);
183+
184+
assertEq(
185+
consumer.lastRandomNumber(),
186+
randomNumber,
187+
"Random number should match"
188+
);
189+
}
190+
191+
function testGetProviderInfo() public {
192+
EntropyStructsV2.ProviderInfo memory info = entropy.getProviderInfoV2(
193+
provider
194+
);
195+
assertEq(info.feeInWei, 1, "Fee should be 1");
196+
assertEq(
197+
info.defaultGasLimit,
198+
100000,
199+
"Default gas limit should be 100000"
200+
);
201+
assertEq(info.sequenceNumber, 1, "Sequence number should start at 1");
202+
}
203+
204+
function testGetDefaultProvider() public {
205+
assertEq(
206+
entropy.getDefaultProvider(),
207+
provider,
208+
"Default provider should match"
209+
);
210+
}
211+
212+
function testFeesReturnZero() public {
213+
assertEq(entropy.getFeeV2(), 0, "getFeeV2() should return 0");
214+
assertEq(
215+
entropy.getFeeV2(100000),
216+
0,
217+
"getFeeV2(gasLimit) should return 0"
218+
);
219+
assertEq(
220+
entropy.getFeeV2(provider, 100000),
221+
0,
222+
"getFeeV2(provider, gasLimit) should return 0"
223+
);
224+
}
225+
226+
function testCustomRandomNumbers() public {
227+
uint64 seq = consumer.requestRandomNumber();
228+
229+
bytes32[] memory randomNumbers = new bytes32[](3);
230+
randomNumbers[0] = bytes32(uint256(0));
231+
randomNumbers[1] = bytes32(type(uint256).max);
232+
randomNumbers[2] = keccak256("custom random value");
233+
234+
for (uint i = 0; i < randomNumbers.length; i++) {
235+
if (i > 0) {
236+
seq = consumer.requestRandomNumber();
237+
}
238+
entropy.mockReveal(provider, seq, randomNumbers[i]);
239+
assertEq(
240+
consumer.lastRandomNumber(),
241+
randomNumbers[i],
242+
"Custom random number should match"
243+
);
244+
}
245+
}
246+
}

0 commit comments

Comments
 (0)