@@ -8,6 +8,7 @@ import "@pythnetwork/entropy-sdk-solidity/EntropyEvents.sol";
88import  "@pythnetwork/entropy-sdk-solidity/IEntropy.sol " ;
99import  "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol " ;
1010import  "@openzeppelin/contracts/utils/math/SafeCast.sol " ;
11+ import  "ExcessivelySafeCall/ExcessivelySafeCall.sol " ;
1112import  "./EntropyState.sol " ;
1213
1314// Entropy implements a secure 2-party random number generation procedure. The protocol 
@@ -76,6 +77,8 @@ import "./EntropyState.sol";
7677// the user is always incentivized to reveal their random number, and that the protocol has an escape hatch for 
7778// cases where the user chooses not to reveal. 
7879abstract  contract  Entropy  is  IEntropy , EntropyState  {
80+     using ExcessivelySafeCall   for  address ;
81+ 
7982    function _initialize  (
8083        address  admin ,
8184        uint128  pythFeeInWei ,
@@ -203,7 +206,8 @@ abstract contract Entropy is IEntropy, EntropyState {
203206        address  provider ,
204207        bytes32  userCommitment ,
205208        bool  useBlockhash ,
206-         bool  isRequestWithCallback 
209+         bool  isRequestWithCallback ,
210+         uint64  callbackGasLimit 
207211    ) internal  returns  (EntropyStructs.Request storage  req ) {
208212        EntropyStructs.ProviderInfo storage  providerInfo =  _state.providers[
209213            provider
@@ -220,7 +224,10 @@ abstract contract Entropy is IEntropy, EntropyState {
220224        // Check that fees were paid and increment the pyth / provider balances. 
221225        uint128  requiredFee =  getFee (provider);
222226        if  (msg .value  <  requiredFee) revert  EntropyErrors.InsufficientFee ();
223-         providerInfo.accruedFeesInWei +=  providerInfo.feeInWei;
227+         providerInfo.accruedFeesInWei +=  getProviderFee (
228+             provider,
229+             callbackGasLimit
230+         );
224231        _state.accruedPythFeesInWei +=  (SafeCast.toUint128 (msg .value ) - 
225232            providerInfo.feeInWei);
226233
@@ -245,9 +252,21 @@ abstract contract Entropy is IEntropy, EntropyState {
245252        );
246253        req.requester =  msg .sender ;
247254
248-         req.blockNumber =  SafeCast.toUint64 (block .number );
249-         req.useBlockhash =  useBlockhash;
250-         req.isRequestWithCallback =  isRequestWithCallback;
255+         if  (useBlockhash &&  isRequestWithCallback) {
256+             revert  EntropyErrors.AssertionFailure ();
257+         } else  if  (isRequestWithCallback) {
258+             req.isRequestWithCallback =  isRequestWithCallback;
259+             if  (callbackGasLimit ==  0 ) {
260+                 req.blockNumber =  providerInfo.defaultGasLimit;
261+             } else  {
262+                 req.blockNumber =  callbackGasLimit;
263+             }
264+             req.useBlockhash =  false ;
265+         } else  {
266+             req.isRequestWithCallback =  false ;
267+             req.blockNumber =  SafeCast.toUint64 (block .number );
268+             req.useBlockhash =  useBlockhash;
269+         }
251270    }
252271
253272    // As a user, request a random number from `provider`. Prior to calling this method, the user should 
@@ -269,7 +288,8 @@ abstract contract Entropy is IEntropy, EntropyState {
269288            provider,
270289            userCommitment,
271290            useBlockHash,
272-             false 
291+             false ,
292+             0 
273293        );
274294        assignedSequenceNumber =  req.sequenceNumber;
275295        emit  Requested (req);
@@ -294,7 +314,35 @@ abstract contract Entropy is IEntropy, EntropyState {
294314            // If we remove the blockHash from this, the provider would have no choice but to provide its committed 
295315            // random number. Hence, useBlockHash is set to false. 
296316            false ,
297-             true 
317+             true ,
318+             0 
319+         );
320+ 
321+         emit  RequestedWithCallback (
322+             provider,
323+             req.requester,
324+             req.sequenceNumber,
325+             userRandomNumber,
326+             req
327+         );
328+ 
329+         return  req.sequenceNumber;
330+     }
331+ 
332+     function requestWithCallbackAndGas  (
333+         address  provider ,
334+         bytes32  userRandomNumber ,
335+         uint64  gasLimit 
336+     ) public  payable  override  returns  (uint64 ) {
337+         EntropyStructs.Request storage  req =  requestHelper (
338+             provider,
339+             constructUserCommitment (userRandomNumber),
340+             // If useBlockHash is set to true, it allows a scenario in which the provider and miner can collude. 
341+             // If we remove the blockHash from this, the provider would have no choice but to provide its committed 
342+             // random number. Hence, useBlockHash is set to false. 
343+             false ,
344+             true ,
345+             gasLimit
298346        );
299347
300348        emit  RequestedWithCallback (
@@ -489,26 +537,21 @@ abstract contract Entropy is IEntropy, EntropyState {
489537
490538        address  callAddress =  req.requester;
491539
492-         // Check if the callAddress is a contract account. 
493-         // TODO: this can probably be deleted. 
494-         uint  len;
495-         assembly  {
496-             len :=  extcodesize (callAddress)
497-         }
540+         if  (req.blockNumber !=  0  &&  ! req.callbackAttempted) {
541+             // TODO: need to validate that we have enough gas left to forward (?) 
542+             // Or at least that we forwarded enough gas before marking the callback as failed 
543+             /* 
544+             if (gasleft() < req.blockNumber) { 
498545
499-         bool  success;
500-         bytes  memory  ret;
501-         if  (len !=  0 ) {
502-             uint64  gas;
503-             if  (req.blockNumber !=  0 ) {
504-                 gas =  req.blockNumber;
505-             } else  {
506-                 gas =  gasLeft ();
507546            } 
547+             */ 
508548
509549            req.reentryGuard =  true ;
510-             (success, ret) ==  callAddress.excessivelySafeCall (
511-                 gas,
550+             bool  success;
551+             bytes  memory  ret;
552+             (success, ret) =  callAddress.excessivelySafeCall (
553+                 req.blockNumber,
554+                 0 ,
512555                32 ,
513556                abi.encodeWithSelector (
514557                    IEntropyConsumer._entropyCallback.selector ,
@@ -518,31 +561,52 @@ abstract contract Entropy is IEntropy, EntropyState {
518561                )
519562            );
520563            req.reentryGuard =  false ;
521-         }    
522564
523-         if  (success) {
565+             if  (success) {
566+                 emit  RevealedWithCallback (
567+                     req,
568+                     userRandomNumber,
569+                     providerRevelation,
570+                     randomNumber
571+                 );
572+                 clearRequest (provider, sequenceNumber);
573+             } else  {
574+                 bytes32  errorReason;
575+                 assembly  {
576+                     errorReason :=  mload (add (ret, 32 ))
577+                 }
578+ 
579+                 emit  CallbackFailed (
580+                     provider,
581+                     req.requester,
582+                     sequenceNumber,
583+                     errorReason
584+                 );
585+                 req.callbackAttempted =  true ;
586+             }
587+         } else  {
524588            emit  RevealedWithCallback (
525589                req,
526590                userRandomNumber,
527591                providerRevelation,
528592                randomNumber
529593            );
530594            clearRequest (provider, sequenceNumber);
531-         } else  {
532-             bytes32  errorReason;
595+ 
596+             // Check if the callAddress is a contract account. 
597+             uint  len;
533598            assembly  {
534-                 errorReason  :=  mload ( add (ret,  32 )); 
599+                 len  :=  extcodesize (callAddress) 
535600            }
536601
537-             emit   CallbackFailed ( 
538-                 provider, 
539-                 req.requester ,
540-                 sequenceNumber ,
541-                 errorReason 
542-             ) 
543-             req.callbackAttempted  =   true ; 
602+             if  (len  !=   0 ) { 
603+                 IEntropyConsumer (callAddress). _entropyCallback ( 
604+                     sequenceNumber ,
605+                     provider ,
606+                     randomNumber 
607+                 ); 
608+             } 
544609        }
545- 
546610    }
547611
548612    function getProviderInfo  (
@@ -570,7 +634,30 @@ abstract contract Entropy is IEntropy, EntropyState {
570634    function getFee  (
571635        address  provider 
572636    ) public  view  override  returns  (uint128  feeAmount ) {
573-         return  _state.providers[provider].feeInWei +  _state.pythFeeInWei;
637+         return  getFeeForGas (provider, 0 );
638+     }
639+ 
640+     function getFeeForGas  (
641+         address  provider ,
642+         uint64  gasLimit 
643+     ) public  view  override  returns  (uint128  feeAmount ) {
644+         return  getProviderFee (provider, gasLimit) +  _state.pythFeeInWei;
645+     }
646+ 
647+     function getProviderFee  (
648+         address  providerAddr ,
649+         uint64  gasLimit 
650+     ) internal  view  returns  (uint128  feeAmount ) {
651+         EntropyStructs.ProviderInfo memory  provider =  _state.providers[
652+             providerAddr
653+         ];
654+         if  (gasLimit >  provider.defaultGasLimit) {
655+             uint128  additionalFee =  ((gasLimit -  provider.defaultGasLimit) * 
656+                 provider.feeInWei) /  provider.defaultGasLimit;
657+             return  provider.feeInWei +  additionalFee;
658+         } else  {
659+             return  provider.feeInWei;
660+         }
574661    }
575662
576663    function getPythFee  () public  view  returns  (uint128  feeAmount ) {
@@ -678,11 +765,7 @@ abstract contract Entropy is IEntropy, EntropyState {
678765
679766        uint64  oldGasLimit =  provider.defaultGasLimit;
680767        provider.defaultGasLimit =  gasLimit;
681-         emit  ProviderDefaultGasLimitUpdated (
682-             msg .sender ,
683-             oldGasLimit,
684-             gasLimit
685-         );
768+         emit  ProviderDefaultGasLimitUpdated (msg .sender , oldGasLimit, gasLimit);
686769    }
687770
688771    function constructUserCommitment  (
0 commit comments