Skip to content

Commit d8c2d25

Browse files
authored
feat(entropy): More ergonomic v2 interface (#2632)
* rename method signature * comments * docs
1 parent 80d3bf3 commit d8c2d25

File tree

5 files changed

+273
-52
lines changed

5 files changed

+273
-52
lines changed

target_chains/ethereum/contracts/contracts/entropy/Entropy.sol

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ abstract contract Entropy is IEntropy, EntropyState {
243243
providerInfo.sequenceNumber += 1;
244244

245245
// Check that fees were paid and increment the pyth / provider balances.
246-
uint128 requiredFee = getFeeForGas(provider, callbackGasLimit);
246+
uint128 requiredFee = getFeeV2(provider, callbackGasLimit);
247247
if (msg.value < requiredFee) revert EntropyErrors.InsufficientFee();
248248
uint128 providerFee = getProviderFee(provider, callbackGasLimit);
249249
providerInfo.accruedFeesInWei += providerFee;
@@ -295,6 +295,32 @@ abstract contract Entropy is IEntropy, EntropyState {
295295
}
296296
}
297297

298+
function requestV2()
299+
external
300+
payable
301+
override
302+
returns (uint64 assignedSequenceNumber)
303+
{
304+
assignedSequenceNumber = requestV2(getDefaultProvider(), random(), 0);
305+
}
306+
307+
function requestV2(
308+
uint32 gasLimit
309+
) external payable override returns (uint64 assignedSequenceNumber) {
310+
assignedSequenceNumber = requestV2(
311+
getDefaultProvider(),
312+
random(),
313+
gasLimit
314+
);
315+
}
316+
317+
function requestV2(
318+
address provider,
319+
uint32 gasLimit
320+
) external payable override returns (uint64 assignedSequenceNumber) {
321+
assignedSequenceNumber = requestV2(provider, random(), gasLimit);
322+
}
323+
298324
// As a user, request a random number from `provider`. Prior to calling this method, the user should
299325
// generate a random number x and keep it secret. The user should then compute hash(x) and pass that
300326
// as the userCommitment argument. (You may call the constructUserCommitment method to compute the hash.)
@@ -334,14 +360,14 @@ abstract contract Entropy is IEntropy, EntropyState {
334360
bytes32 userRandomNumber
335361
) public payable override returns (uint64) {
336362
return
337-
requestWithCallbackAndGasLimit(
363+
requestV2(
338364
provider,
339365
userRandomNumber,
340366
0 // Passing 0 will assign the request the provider's default gas limit
341367
);
342368
}
343369

344-
function requestWithCallbackAndGasLimit(
370+
function requestV2(
345371
address provider,
346372
bytes32 userRandomNumber,
347373
uint32 gasLimit
@@ -720,10 +746,20 @@ abstract contract Entropy is IEntropy, EntropyState {
720746
function getFee(
721747
address provider
722748
) public view override returns (uint128 feeAmount) {
723-
return getFeeForGas(provider, 0);
749+
return getFeeV2(provider, 0);
750+
}
751+
752+
function getFeeV2() external view override returns (uint128 feeAmount) {
753+
return getFeeV2(getDefaultProvider(), 0);
754+
}
755+
756+
function getFeeV2(
757+
uint32 gasLimit
758+
) external view override returns (uint128 feeAmount) {
759+
return getFeeV2(getDefaultProvider(), gasLimit);
724760
}
725761

726-
function getFeeForGas(
762+
function getFeeV2(
727763
address provider,
728764
uint32 gasLimit
729765
) public view override returns (uint128 feeAmount) {
@@ -1041,4 +1077,16 @@ abstract contract Entropy is IEntropy, EntropyState {
10411077
// a randomness request with sequence number 0.
10421078
return req.sequenceNumber != 0;
10431079
}
1080+
1081+
function random() internal returns (bytes32) {
1082+
_state.seed = keccak256(
1083+
abi.encodePacked(
1084+
block.timestamp,
1085+
block.difficulty,
1086+
msg.sender,
1087+
_state.seed
1088+
)
1089+
);
1090+
return _state.seed;
1091+
}
10441092
}

target_chains/ethereum/contracts/contracts/entropy/EntropyState.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ contract EntropyInternalStructs {
3737
// proposedAdmin is the new admin's account address proposed by either the owner or the current admin.
3838
// If there is no pending transfer request, this value will hold `address(0)`.
3939
address proposedAdmin;
40+
// Seed for in-contract PRNG. This seed is used to generate user random numbers in some callback flows.
41+
bytes32 seed;
4042
}
4143
}
4244

target_chains/ethereum/contracts/forge-test/Entropy.t.sol

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,9 +1695,9 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents, EntropyEventsV2 {
16951695
// Test larger than max value reverts with expected error
16961696
uint32 exceedsGasLimit = uint32(type(uint16).max) * 10000 + 1;
16971697
vm.expectRevert(EntropyErrors.MaxGasLimitExceeded.selector);
1698-
random.getFeeForGas(provider1, exceedsGasLimit);
1698+
random.getFeeV2(provider1, exceedsGasLimit);
16991699
vm.expectRevert(EntropyErrors.MaxGasLimitExceeded.selector);
1700-
random.requestWithCallbackAndGasLimit{value: 10000000000000}(
1700+
random.requestV2{value: 10000000000000}(
17011701
provider1,
17021702
bytes32(uint(42)),
17031703
exceedsGasLimit
@@ -1722,18 +1722,14 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents, EntropyEventsV2 {
17221722
) internal {
17231723
// Create a request with callback
17241724
bytes32 userRandomNumber = bytes32(uint(42));
1725-
uint fee = random.getFeeForGas(provider1, gasLimit);
1725+
uint fee = random.getFeeV2(provider1, gasLimit);
17261726
assertEq(fee - random.getPythFee(), expectedProviderFee);
17271727

17281728
// Passing 1 wei less than the expected fee causes a revert.
17291729
vm.deal(user1, fee);
17301730
vm.prank(user1);
17311731
vm.expectRevert(EntropyErrors.InsufficientFee.selector);
1732-
random.requestWithCallbackAndGasLimit{value: fee - 1}(
1733-
provider1,
1734-
userRandomNumber,
1735-
gasLimit
1736-
);
1732+
random.requestV2{value: fee - 1}(provider1, userRandomNumber, gasLimit);
17371733

17381734
EntropyStructsV2.ProviderInfo memory providerInfo = random
17391735
.getProviderInfoV2(provider1);
@@ -1749,9 +1745,11 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents, EntropyEventsV2 {
17491745
bytes("")
17501746
);
17511747
vm.prank(user1);
1752-
uint64 sequenceNumber = random.requestWithCallbackAndGasLimit{
1753-
value: fee
1754-
}(provider1, userRandomNumber, gasLimit);
1748+
uint64 sequenceNumber = random.requestV2{value: fee}(
1749+
provider1,
1750+
userRandomNumber,
1751+
gasLimit
1752+
);
17551753

17561754
assertEq(
17571755
random.getProviderInfoV2(provider1).accruedFeesInWei -
@@ -1796,7 +1794,7 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents, EntropyEventsV2 {
17961794
) internal {
17971795
// Create a request with callback
17981796
bytes32 userRandomNumber = bytes32(uint(42));
1799-
uint fee = random.getFeeForGas(provider1, gasLimit);
1797+
uint fee = random.getFeeV2(provider1, gasLimit);
18001798

18011799
vm.deal(user1, fee);
18021800
vm.prank(user1);
@@ -1981,19 +1979,23 @@ contract EntropyConsumer is IEntropyConsumer {
19811979
bytes32 randomNumber
19821980
) public payable returns (uint64 sequenceNumber) {
19831981
address _provider = IEntropy(entropy).getDefaultProvider();
1984-
sequenceNumber = IEntropy(entropy).requestWithCallback{
1985-
value: msg.value
1986-
}(_provider, randomNumber);
1982+
sequenceNumber = IEntropy(entropy).requestV2{value: msg.value}(
1983+
_provider,
1984+
randomNumber,
1985+
0
1986+
);
19871987
}
19881988

19891989
function requestEntropyWithGasLimit(
19901990
bytes32 randomNumber,
19911991
uint32 gasLimit
19921992
) public payable returns (uint64 sequenceNumber) {
19931993
address _provider = IEntropy(entropy).getDefaultProvider();
1994-
sequenceNumber = IEntropy(entropy).requestWithCallbackAndGasLimit{
1995-
value: msg.value
1996-
}(_provider, randomNumber, gasLimit);
1994+
sequenceNumber = IEntropy(entropy).requestV2{value: msg.value}(
1995+
_provider,
1996+
randomNumber,
1997+
gasLimit
1998+
);
19971999
}
19982000

19992001
function getEntropy() internal view override returns (address) {

target_chains/ethereum/entropy_sdk/solidity/IEntropy.sol

Lines changed: 104 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,96 @@ interface IEntropy is EntropyEvents, EntropyEventsV2 {
2929
// balance of fees in the contract).
3030
function withdrawAsFeeManager(address provider, uint128 amount) external;
3131

32+
/// @notice Request a random number using the default provider with default gas limit
33+
/// @return assignedSequenceNumber A unique identifier for this request
34+
/// @dev The address calling this function should be a contract that inherits from the IEntropyConsumer interface.
35+
/// The `entropyCallback` method on that interface will receive a callback with the returned sequence number and
36+
/// the generated random number.
37+
///
38+
/// `entropyCallback` will be run with the `gasLimit` provided to this function.
39+
/// The `gasLimit` will be rounded up to a multiple of 10k (e.g., 19000 -> 20000), and furthermore is lower bounded
40+
/// by the provider's configured default limit.
41+
///
42+
/// This method will revert unless the caller provides a sufficient fee (at least `getFeeV2()`) as msg.value.
43+
/// Note that the fee can change over time. Callers of this method should explicitly compute `getFeeV2()`
44+
/// prior to each invocation (as opposed to hardcoding a value). Further note that excess value is *not* refunded to the caller.
45+
///
46+
/// Note that this method uses an in-contract PRNG to generate the user's portion of the random number.
47+
/// Users must trust this PRNG in order to prove the result is random. If you wish to avoid this trust assumption,
48+
/// call a variant of `requestV2` that accepts a `userRandomNumber` parameter.
49+
function requestV2()
50+
external
51+
payable
52+
returns (uint64 assignedSequenceNumber);
53+
54+
/// @notice Request a random number using the default provider with specified gas limit
55+
/// @param gasLimit The gas limit for the callback function.
56+
/// @return assignedSequenceNumber A unique identifier for this request
57+
/// @dev The address calling this function should be a contract that inherits from the IEntropyConsumer interface.
58+
/// The `entropyCallback` method on that interface will receive a callback with the returned sequence number and
59+
/// the generated random number.
60+
///
61+
/// `entropyCallback` will be run with the `gasLimit` provided to this function.
62+
/// The `gasLimit` will be rounded up to a multiple of 10k (e.g., 19000 -> 20000), and furthermore is lower bounded
63+
/// by the provider's configured default limit.
64+
///
65+
/// This method will revert unless the caller provides a sufficient fee (at least `getFeeV2(gasLimit)`) as msg.value.
66+
/// Note that the fee can change over time. Callers of this method should explicitly compute `getFeeV2(gasLimit)`
67+
/// prior to each invocation (as opposed to hardcoding a value). Further note that excess value is *not* refunded to the caller.
68+
///
69+
/// Note that this method uses an in-contract PRNG to generate the user's portion of the random number.
70+
/// Users must trust this PRNG in order to prove the result is random. If you wish to avoid this trust assumption,
71+
/// call a variant of `requestV2` that accepts a `userRandomNumber` parameter.
72+
function requestV2(
73+
uint32 gasLimit
74+
) external payable returns (uint64 assignedSequenceNumber);
75+
76+
/// @notice Request a random number from a specific provider with specified gas limit
77+
/// @param provider The address of the provider to request from
78+
/// @param gasLimit The gas limit for the callback function
79+
/// @return assignedSequenceNumber A unique identifier for this request
80+
/// @dev The address calling this function should be a contract that inherits from the IEntropyConsumer interface.
81+
/// The `entropyCallback` method on that interface will receive a callback with the returned sequence number and
82+
/// the generated random number.
83+
///
84+
/// `entropyCallback` will be run with the `gasLimit` provided to this function.
85+
/// The `gasLimit` will be rounded up to a multiple of 10k (e.g., 19000 -> 20000), and furthermore is lower bounded
86+
/// by the provider's configured default limit.
87+
///
88+
/// This method will revert unless the caller provides a sufficient fee (at least `getFeeV2(provider, gasLimit)`) as msg.value.
89+
/// Note that provider fees can change over time. Callers of this method should explicitly compute `getFeeV2(provider, gasLimit)`
90+
/// prior to each invocation (as opposed to hardcoding a value). Further note that excess value is *not* refunded to the caller.
91+
///
92+
/// Note that this method uses an in-contract PRNG to generate the user's portion of the random number.
93+
/// Users must trust this PRNG in order to prove the result is random. If you wish to avoid this trust assumption,
94+
/// call a variant of `requestV2` that accepts a `userRandomNumber` parameter.
95+
function requestV2(
96+
address provider,
97+
uint32 gasLimit
98+
) external payable returns (uint64 assignedSequenceNumber);
99+
100+
/// @notice Request a random number from a specific provider with a user-provided random number and gas limit
101+
/// @param provider The address of the provider to request from
102+
/// @param userRandomNumber A random number provided by the user for additional entropy
103+
/// @param gasLimit The gas limit for the callback function
104+
/// @return assignedSequenceNumber A unique identifier for this request
105+
/// @dev The address calling this function should be a contract that inherits from the IEntropyConsumer interface.
106+
/// The `entropyCallback` method on that interface will receive a callback with the returned sequence number and
107+
/// the generated random number.
108+
///
109+
/// `entropyCallback` will be run with the `gasLimit` provided to this function.
110+
/// The `gasLimit` will be rounded up to a multiple of 10k (e.g., 19000 -> 20000), and furthermore is lower bounded
111+
/// by the provider's configured default limit.
112+
///
113+
/// This method will revert unless the caller provides a sufficient fee (at least `getFeeV2(provider, gasLimit)`) as msg.value.
114+
/// Note that provider fees can change over time. Callers of this method should explicitly compute `getFeeV2(provider, gasLimit)`
115+
/// prior to each invocation (as opposed to hardcoding a value). Further note that excess value is *not* refunded to the caller.
116+
function requestV2(
117+
address provider,
118+
bytes32 userRandomNumber,
119+
uint32 gasLimit
120+
) external payable returns (uint64 assignedSequenceNumber);
121+
32122
// As a user, request a random number from `provider`. Prior to calling this method, the user should
33123
// generate a random number x and keep it secret. The user should then compute hash(x) and pass that
34124
// as the userCommitment argument. (You may call the constructUserCommitment method to compute the hash.)
@@ -60,26 +150,6 @@ interface IEntropy is EntropyEvents, EntropyEventsV2 {
60150
bytes32 userRandomNumber
61151
) external payable returns (uint64 assignedSequenceNumber);
62152

63-
// Request a random number from `provider`, getting a callback with the result.
64-
// The caller must specify a provider to fulfill the request -- `getDefaultProvider()` is a sane default --
65-
// and a `userRandomNumber` to combine into the result. The method returns a sequence number which callers
66-
// should save to correlate the request with the callback.
67-
//
68-
// The address calling this function should be a contract that inherits from the IEntropyConsumer interface.
69-
// The `entropyCallback` method on that interface will receive a callback with the returned sequence number and
70-
// the generated random number. `entropyCallback` will be run with the `gasLimit` provided to this function.
71-
// The `gasLimit` will be rounded up to a multiple of 10k (e.g., 19000 -> 20000), and furthermore is lower bounded
72-
// by the provider's configured default limit.
73-
//
74-
// This method will revert unless the caller provides a sufficient fee (at least `getFeeForGas(provider, gasLimit)`) as msg.value.
75-
// Note that provider fees can change over time. Thus, callers of this method should explictly compute `getFeeForGas(provider, gasLimit)`
76-
// prior to each invocation (as opposed to hardcoding a value). Further note that excess value is *not* refunded to the caller.
77-
function requestWithCallbackAndGasLimit(
78-
address provider,
79-
bytes32 userRandomNumber,
80-
uint32 gasLimit
81-
) external payable returns (uint64 assignedSequenceNumber);
82-
83153
// Fulfill a request for a random number. This method validates the provided userRandomness and provider's proof
84154
// against the corresponding commitments in the in-flight request. If both values are validated, this function returns
85155
// the corresponding random number.
@@ -132,11 +202,22 @@ interface IEntropy is EntropyEvents, EntropyEventsV2 {
132202
) external view returns (EntropyStructsV2.Request memory req);
133203

134204
// Get the fee charged by provider for a request with the default gasLimit (`request` or `requestWithCallback`).
135-
// If you are calling `requestWithCallbackAndGasLimit`, please use `getFeeForGas`.
205+
// If you are calling any of the `requestV2` methods, please use `getFeeV2`.
136206
function getFee(address provider) external view returns (uint128 feeAmount);
137207

138-
// Get the fee charged by `provider` for a request with a specific `gasLimit` (`requestWithCallbackAndGasLimit`).
139-
function getFeeForGas(
208+
// Get the fee charged by the default provider for the default gas limit.
209+
// Use this function to determine the fee to pass to `requestV2`.
210+
function getFeeV2() external view returns (uint128 feeAmount);
211+
212+
// Get the fee charged by the default provider for the specified gas limit.
213+
// Use this function to determine the fee to pass to `requestV2`.
214+
function getFeeV2(
215+
uint32 gasLimit
216+
) external view returns (uint128 feeAmount);
217+
218+
// Get the fee charged by `provider` for a request with a specific `gasLimit`.
219+
// Use this function to determine the fee to pass to `requestV2`.
220+
function getFeeV2(
140221
address provider,
141222
uint32 gasLimit
142223
) external view returns (uint128 feeAmount);

0 commit comments

Comments
 (0)