From 99b3ad1a9fc339179bb758dd413ba99c82f45646 Mon Sep 17 00:00:00 2001 From: Jayant Krishnamurthy Date: Wed, 2 Apr 2025 08:32:15 -0700 Subject: [PATCH 1/9] update stuff --- .../contracts/contracts/entropy/Entropy.sol | 93 +++- .../contracts/forge-test/Entropy.t.sol | 454 ++++++++++++++++-- target_chains/ethereum/contracts/package.json | 4 +- .../ethereum/contracts/remappings.txt | 1 + .../entropy_sdk/solidity/EntropyEvents.sol | 7 + .../entropy_sdk/solidity/EntropyStructs.sol | 10 +- 6 files changed, 516 insertions(+), 53 deletions(-) diff --git a/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol b/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol index ede2e39976..ba3fddbe0e 100644 --- a/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol +++ b/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol @@ -247,7 +247,7 @@ abstract contract Entropy is IEntropy, EntropyState { req.blockNumber = SafeCast.toUint64(block.number); req.useBlockhash = useBlockhash; - req.isRequestWithCallback = isRequestWithCallback; + req.status = (uint8) isRequestWithCallback; } // As a user, request a random number from `provider`. Prior to calling this method, the user should @@ -470,6 +470,11 @@ abstract contract Entropy is IEntropy, EntropyState { if (!req.isRequestWithCallback) { revert EntropyErrors.InvalidRevealCall(); } + + if (req.reentryGuard) { + revert EntropyErrors.AssertionFailure(); + } + bytes32 blockHash; bytes32 randomNumber; (randomNumber, blockHash) = revealHelper( @@ -480,26 +485,76 @@ abstract contract Entropy is IEntropy, EntropyState { address callAddress = req.requester; - emit RevealedWithCallback( - req, - userRandomNumber, - providerRevelation, - randomNumber - ); - - clearRequest(provider, sequenceNumber); - - // Check if the callAddress is a contract account. - uint len; - assembly { - len := extcodesize(callAddress) - } - if (len != 0) { - IEntropyConsumer(callAddress)._entropyCallback( - sequenceNumber, - provider, + // blockNumberOrGasLimit holds the gas limit in the callback case. + // If the gas limit is 0, then the provider hasn't configured their default limit, + // so we default to the prior entropy flow (where there is no failure state). + // Similarly, if the request has already failed, we fall back to the prior flow so that + // recovery attempts can provide more gas / directly see the revert reason. + if (!req.callbackFailed) { + req.reentryGuard = true; + bool success; + bytes memory ret; + (success, ret) = callAddress.excessivelySafeCall( + req.blockNumberOrGasLimit, + 0, + 256, + abi.encodeWithSelector( + IEntropyConsumer._entropyCallback.selector, + sequenceNumber, + provider, + randomNumber + ) + ); + req.reentryGuard = false; + + if (success) { + emit RevealedWithCallback( + req, + userRandomNumber, + providerRevelation, + randomNumber + ); + clearRequest(provider, sequenceNumber); + } else if (ret.length > 0) { + emit CallbackFailed( + provider, + req.requester, + sequenceNumber, + ret + ); + req.callbackFailed = true; + } else { + // The callback ran out of gas + // TODO: this case will go away once we add provider gas limits + revert; + } + } else { + emit RevealedWithCallback( + req, + userRandomNumber, + providerRevelation, randomNumber ); + + clearRequest(provider, sequenceNumber); + + // Check if the callAddress is a contract account. + uint len; + assembly { + len := extcodesize(callAddress) + } + if (len != 0) { + // Setting the reentry guard here isn't strictly necessary because we've cleared the request above + // (using the check-effects-interactions pattern). However, it seems like a good measure for consistency + // across the two cases. + req.reentryGuard = true; + IEntropyConsumer(callAddress)._entropyCallback( + sequenceNumber, + provider, + randomNumber + ); + req.reentryGuard = false; + } } } diff --git a/target_chains/ethereum/contracts/forge-test/Entropy.t.sol b/target_chains/ethereum/contracts/forge-test/Entropy.t.sol index d088bb0c37..13668fdff3 100644 --- a/target_chains/ethereum/contracts/forge-test/Entropy.t.sol +++ b/target_chains/ethereum/contracts/forge-test/Entropy.t.sol @@ -203,7 +203,10 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { function testBasicFlow() public { vm.roll(17); uint64 sequenceNumber = request(user2, provider1, 42, false); - assertEq(random.getRequest(provider1, sequenceNumber).blockNumber, 17); + assertEq( + random.getRequest(provider1, sequenceNumber).blockNumberOrGasLimit, + 17 + ); assertEq( random.getRequest(provider1, sequenceNumber).useBlockhash, false @@ -243,7 +246,10 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { 42, false ); - assertEq(random.getRequest(provider1, sequenceNumber).blockNumber, 20); + assertEq( + random.getRequest(provider1, sequenceNumber).blockNumberOrGasLimit, + 20 + ); assertEq( random.getRequest(provider1, sequenceNumber).useBlockhash, false @@ -405,7 +411,7 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { uint64 sequenceNumber = request(user2, provider1, 42, true); assertEq( - random.getRequest(provider1, sequenceNumber).blockNumber, + random.getRequest(provider1, sequenceNumber).blockNumberOrGasLimit, 1234 ); assertEq( @@ -801,10 +807,12 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { providerInfo.currentCommitment ) ), - blockNumber: 1234, + blockNumberOrGasLimit: 0, requester: user1, useBlockhash: false, - isRequestWithCallback: true + isRequestWithCallback: true, + callbackFailed: false, + reentryGuard: false }) ); vm.roll(1234); @@ -835,7 +843,7 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { function testRequestWithCallbackAndRevealWithCallbackByContract() public { bytes32 userRandomNumber = bytes32(uint(42)); uint fee = random.getFee(provider1); - EntropyConsumer consumer = new EntropyConsumer(address(random)); + EntropyConsumer consumer = new EntropyConsumer(address(random), false); vm.deal(user1, fee); vm.prank(user1); uint64 assignedSequenceNumber = consumer.requestEntropy{value: fee}( @@ -938,12 +946,159 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { ); } - function testRequestWithCallbackAndRevealWithCallbackFailing() public { + function testRequestWithCallbackAndRevealWithCallbackWithGasLimit() public { + uint64 defaultGasLimit = 100000; + vm.prank(provider1); + random.setDefaultGasLimit(defaultGasLimit); + + bytes32 userRandomNumber = bytes32(uint(42)); + uint fee = random.getFee(provider1); + EntropyConsumer consumer = new EntropyConsumer(address(random), false); + vm.deal(user1, fee); + vm.prank(user1); + uint64 assignedSequenceNumber = consumer.requestEntropy{value: fee}( + userRandomNumber + ); + EntropyStructs.Request memory req = random.getRequest( + provider1, + assignedSequenceNumber + ); + + // Verify the gas limit was set correctly + assertEq(req.blockNumberOrGasLimit, defaultGasLimit); + + vm.expectEmit(false, false, false, true, address(random)); + emit RevealedWithCallback( + req, + userRandomNumber, + provider1Proofs[assignedSequenceNumber], + random.combineRandomValues( + userRandomNumber, + provider1Proofs[assignedSequenceNumber], + 0 + ) + ); + random.revealWithCallback( + provider1, + assignedSequenceNumber, + userRandomNumber, + provider1Proofs[assignedSequenceNumber] + ); + + assertEq(consumer.sequence(), assignedSequenceNumber); + assertEq(consumer.provider(), provider1); + assertEq( + consumer.randomness(), + random.combineRandomValues( + userRandomNumber, + provider1Proofs[assignedSequenceNumber], + 0 + ) + ); + + EntropyStructs.Request memory reqAfterReveal = random.getRequest( + provider1, + assignedSequenceNumber + ); + assertEq(reqAfterReveal.sequenceNumber, 0); + } + + function testRequestWithCallbackAndRevealWithCallbackWithGasLimitAndFailure() + public + { + uint64 defaultGasLimit = 100000; + vm.prank(provider1); + random.setDefaultGasLimit(defaultGasLimit); + bytes32 userRandomNumber = bytes32(uint(42)); uint fee = random.getFee(provider1); - EntropyConsumerFails consumer = new EntropyConsumerFails( - address(random) + EntropyConsumer consumer = new EntropyConsumer(address(random), true); + vm.deal(user1, fee); + vm.prank(user1); + uint64 assignedSequenceNumber = consumer.requestEntropy{value: fee}( + userRandomNumber + ); + EntropyStructs.Request memory req = random.getRequest( + provider1, + assignedSequenceNumber + ); + + // Verify the gas limit was set correctly + assertEq(req.blockNumberOrGasLimit, defaultGasLimit); + + // On the first attempt, the transaction should succeed and emit CallbackFailed event. + bytes memory revertReason = abi.encodeWithSelector( + 0x08c379a0, + "Callback failed" + ); + vm.expectEmit(false, false, false, true, address(random)); + emit CallbackFailed( + provider1, + address(consumer), + assignedSequenceNumber, + revertReason + ); + random.revealWithCallback( + provider1, + assignedSequenceNumber, + userRandomNumber, + provider1Proofs[assignedSequenceNumber] + ); + + // Verify request is still active after failure + EntropyStructs.Request memory reqAfterFailure = random.getRequest( + provider1, + assignedSequenceNumber + ); + assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber); + assertTrue(reqAfterFailure.callbackFailed); + + // Second attempt should revert + vm.expectRevert(); + random.revealWithCallback( + provider1, + assignedSequenceNumber, + userRandomNumber, + provider1Proofs[assignedSequenceNumber] + ); + + // Again, request stays active after failure + reqAfterFailure = random.getRequest(provider1, assignedSequenceNumber); + assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber); + assertTrue(reqAfterFailure.callbackFailed); + + // If the callback starts succeeding, we can invoke it and it emits the usual RevealedWithCallback event. + consumer.setReverts(false); + vm.expectEmit(false, false, false, true, address(random)); + emit RevealedWithCallback( + reqAfterFailure, + userRandomNumber, + provider1Proofs[assignedSequenceNumber], + random.combineRandomValues( + userRandomNumber, + provider1Proofs[assignedSequenceNumber], + 0 + ) + ); + random.revealWithCallback( + provider1, + assignedSequenceNumber, + userRandomNumber, + provider1Proofs[assignedSequenceNumber] ); + + // Verify request is cleared after successful reveal + EntropyStructs.Request memory reqAfterReveal = random.getRequest( + provider1, + assignedSequenceNumber + ); + assertEq(reqAfterReveal.sequenceNumber, 0); + } + + function testRequestWithCallbackAndRevealWithCallbackFailing() public { + bytes32 userRandomNumber = bytes32(uint(42)); + uint fee = random.getFee(provider1); + EntropyConsumer consumer = new EntropyConsumer(address(random), true); vm.deal(address(consumer), fee); vm.startPrank(address(consumer)); uint64 assignedSequenceNumber = random.requestWithCallback{value: fee}( @@ -1148,6 +1303,234 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { vm.expectRevert(); random.setProviderFeeAsFeeManager(provider1, 1000); } + + function testSetDefaultGasLimit() public { + uint64 newGasLimit = 100000; + + vm.prank(provider1); + random.setDefaultGasLimit(newGasLimit); + + EntropyStructs.ProviderInfo memory info = random.getProviderInfo( + provider1 + ); + assertEq(info.defaultGasLimit, newGasLimit); + } + + function testSetDefaultGasLimitRevertIfNotFromProvider() public { + vm.expectRevert(EntropyErrors.NoSuchProvider.selector); + random.setDefaultGasLimit(100000); + } + + function testRequestWithCallbackUsesDefaultGasLimit() public { + uint64 defaultGasLimit = 100000; + vm.prank(provider1); + random.setDefaultGasLimit(defaultGasLimit); + + bytes32 userRandomNumber = bytes32(uint(42)); + uint fee = random.getFee(provider1); + + vm.deal(user1, fee); + vm.prank(user1); + uint64 sequenceNumber = random.requestWithCallback{value: fee}( + provider1, + userRandomNumber + ); + + EntropyStructs.Request memory req = random.getRequest( + provider1, + sequenceNumber + ); + assertEq(req.blockNumberOrGasLimit, defaultGasLimit); + } + + function testRequestWithCallbackAndCustomGasLimit() public { + uint64 defaultGasLimit = 100000; + uint64 customGasLimit = 200000; + + vm.prank(provider1); + random.setDefaultGasLimit(defaultGasLimit); + + bytes32 userRandomNumber = bytes32(uint(42)); + uint fee = random.getFeeForGas(provider1, customGasLimit); + + vm.deal(user1, fee); + vm.prank(user1); + uint64 sequenceNumber = random.requestWithCallbackAndGas{value: fee}( + provider1, + userRandomNumber, + customGasLimit + ); + + EntropyStructs.Request memory req = random.getRequest( + provider1, + sequenceNumber + ); + assertEq(req.blockNumberOrGasLimit, customGasLimit); + } + + function testRequestWithCallbackAndGasLimitFeeScaling() public { + uint64 defaultGasLimit = 100000; + uint64 doubleGasLimit = 200000; + + vm.prank(provider1); + random.setDefaultGasLimit(defaultGasLimit); + + uint baseFee = random.getFee(provider1); + assertEq(baseFee, provider1FeeInWei + pythFeeInWei); + + // Fee scales proportionally with gas limit + uint scaledFee = random.getFeeForGas(provider1, doubleGasLimit); + assertEq(scaledFee, 2 * provider1FeeInWei + pythFeeInWei); + } + + function testRequestWithCallbackAndGasLimitInsufficientFee() public { + uint64 defaultGasLimit = 100000; + uint64 doubleGasLimit = 200000; + + vm.prank(provider1); + random.setDefaultGasLimit(defaultGasLimit); + + bytes32 userRandomNumber = bytes32(uint(42)); + uint baseFee = random.getFee(provider1); // This is insufficient for double gas + + vm.deal(user1, baseFee); + vm.prank(user1); + vm.expectRevert(EntropyErrors.InsufficientFee.selector); + random.requestWithCallbackAndGas{value: baseFee}( + provider1, + userRandomNumber, + doubleGasLimit + ); + } + + function testRequestWithCallbackAndGasLimitLowerThanDefault() public { + uint64 defaultGasLimit = 100000; + uint64 lowerGasLimit = 50000; + + vm.prank(provider1); + random.setDefaultGasLimit(defaultGasLimit); + + bytes32 userRandomNumber = bytes32(uint(42)); + uint fee = random.getFeeForGas(provider1, lowerGasLimit); + + vm.deal(user1, fee); + vm.prank(user1); + uint64 sequenceNumber = random.requestWithCallbackAndGas{value: fee}( + provider1, + userRandomNumber, + lowerGasLimit + ); + + EntropyStructs.Request memory req = random.getRequest( + provider1, + sequenceNumber + ); + assertEq(req.blockNumberOrGasLimit, lowerGasLimit); + // Fee should be the same as base fee since we're using less gas than default + assertEq(fee, random.getFee(provider1)); + } + + function testRequestWithCallbackAndRevealWithCallbackWithGasLimitAndFailureWithGasUsage() + public + { + uint64 defaultGasLimit = 100000; + vm.prank(provider1); + random.setDefaultGasLimit(defaultGasLimit); + + bytes32 userRandomNumber = bytes32(uint(42)); + uint fee = random.getFee(provider1); + EntropyConsumer consumer = new EntropyConsumer(address(random), false); + // Consumer callback uses ~10% more gas than the provider's default + consumer.setTargetGasUsage((defaultGasLimit * 110) / 100); + + vm.deal(user1, fee); + vm.prank(user1); + uint64 assignedSequenceNumber = consumer.requestEntropy{value: fee}( + userRandomNumber + ); + EntropyStructs.Request memory req = random.getRequest( + provider1, + assignedSequenceNumber + ); + + // Verify the gas limit was set correctly + assertEq(req.blockNumberOrGasLimit, defaultGasLimit); + + // The transaction reverts if the provider does not provide enough gas to forward + // the gasLimit to the callback transaction. + vm.expectRevert(); + random.revealWithCallback{gas: defaultGasLimit - 10000}( + provider1, + assignedSequenceNumber, + userRandomNumber, + provider1Proofs[assignedSequenceNumber] + ); + + // If called with enough gas, the transaction should succeed, but the callback should fail because + // it uses too much gas. + vm.expectEmit(false, false, false, true, address(random)); + emit CallbackFailed( + provider1, + address(consumer), + assignedSequenceNumber, + // out-of-gas reverts have an empty bytes array as the return value. + "" + ); + random.revealWithCallback( + provider1, + assignedSequenceNumber, + userRandomNumber, + provider1Proofs[assignedSequenceNumber] + ); + + // Verify request is still active after failure + EntropyStructs.Request memory reqAfterFailure = random.getRequest( + provider1, + assignedSequenceNumber + ); + assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber); + assertTrue(reqAfterFailure.callbackFailed); + + // A subsequent attempt passing insufficient gas should also revert + vm.expectRevert(); + random.revealWithCallback{gas: defaultGasLimit - 10000}( + provider1, + assignedSequenceNumber, + userRandomNumber, + provider1Proofs[assignedSequenceNumber] + ); + + // Again, request stays active after failure + reqAfterFailure = random.getRequest(provider1, assignedSequenceNumber); + assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber); + assertTrue(reqAfterFailure.callbackFailed); + + // Calling without a gas limit should succeed + vm.expectEmit(false, false, false, true, address(random)); + emit RevealedWithCallback( + reqAfterFailure, + userRandomNumber, + provider1Proofs[assignedSequenceNumber], + random.combineRandomValues( + userRandomNumber, + provider1Proofs[assignedSequenceNumber], + 0 + ) + ); + random.revealWithCallback( + provider1, + assignedSequenceNumber, + userRandomNumber, + provider1Proofs[assignedSequenceNumber] + ); + + // Verify request is cleared after successful reveal + EntropyStructs.Request memory reqAfterReveal = random.getRequest( + provider1, + assignedSequenceNumber + ); + assertEq(reqAfterReveal.sequenceNumber, 0); + } } contract EntropyConsumer is IEntropyConsumer { @@ -1155,9 +1538,14 @@ contract EntropyConsumer is IEntropyConsumer { bytes32 public randomness; address public entropy; address public provider; + bool public reverts; + uint256 public gasUsed; + uint256 public targetGasUsage; - constructor(address _entropy) { + constructor(address _entropy, bool _reverts) { entropy = _entropy; + reverts = _reverts; + targetGasUsage = 0; // Default target } function requestEntropy( @@ -1173,31 +1561,39 @@ contract EntropyConsumer is IEntropyConsumer { return entropy; } + function setReverts(bool _reverts) public { + reverts = _reverts; + } + + function setTargetGasUsage(uint256 _targetGasUsage) public { + targetGasUsage = _targetGasUsage; + } + function entropyCallback( uint64 _sequence, address _provider, bytes32 _randomness ) internal override { - sequence = _sequence; - provider = _provider; - randomness = _randomness; - } -} - -contract EntropyConsumerFails is IEntropyConsumer { - uint64 public sequence; - bytes32 public randomness; - address public entropy; - - constructor(address _entropy) { - entropy = _entropy; - } + uint256 startGas = gasleft(); + uint256 currentGasUsed = 0; + + // Keep consuming gas until we reach our target + while (currentGasUsed < targetGasUsage) { + // Consume gas with a hash operation + bytes32 hash = keccak256( + abi.encodePacked(currentGasUsed, _randomness) + ); + currentGasUsed = startGas - gasleft(); + } - function getEntropy() internal view override returns (address) { - return entropy; - } + gasUsed = currentGasUsed; - function entropyCallback(uint64, address, bytes32) internal pure override { - revert("Callback failed"); + if (!reverts) { + sequence = _sequence; + provider = _provider; + randomness = _randomness; + } else { + revert("Callback failed"); + } } } diff --git a/target_chains/ethereum/contracts/package.json b/target_chains/ethereum/contracts/package.json index 6f6ef476c4..296bd002bc 100644 --- a/target_chains/ethereum/contracts/package.json +++ b/target_chains/ethereum/contracts/package.json @@ -1,6 +1,6 @@ { "name": "@pythnetwork/pyth-evm-contract", - "version": "1.4.4-alpha.1", + "version": "1.4.3", "description": "", "private": "true", "devDependencies": { @@ -23,7 +23,7 @@ "migrate": "truffle migrate", "receiver-submit-guardian-sets": "truffle exec scripts/receiverSubmitGuardianSetUpgrades.js", "verify": "truffle run verify $npm_config_module@$npm_config_contract_address --network $npm_config_network", - "install-forge-deps": "forge install foundry-rs/forge-std@v1.7.6 --no-git --no-commit", + "install-forge-deps": "forge install foundry-rs/forge-std@v1.7.6 nomad-xyz/ExcessivelySafeCall@81cd99c --no-git --no-commit", "coverage": "./coverage.sh", "test:format": "prettier --check .", "fix:format": "prettier --write ." diff --git a/target_chains/ethereum/contracts/remappings.txt b/target_chains/ethereum/contracts/remappings.txt index 4b2c7905c0..a6ccbf917d 100644 --- a/target_chains/ethereum/contracts/remappings.txt +++ b/target_chains/ethereum/contracts/remappings.txt @@ -3,4 +3,5 @@ @pythnetwork/=./node_modules/@pythnetwork/ ds-test/=lib/forge-std/lib/ds-test/src/ forge-std/=lib/forge-std/src/ +ExcessivelySafeCall=lib/ExcessivelySafeCall/src/ truffle/=./node_modules/truffle/ diff --git a/target_chains/ethereum/entropy_sdk/solidity/EntropyEvents.sol b/target_chains/ethereum/entropy_sdk/solidity/EntropyEvents.sol index 59b595fb13..7e7aacdddb 100644 --- a/target_chains/ethereum/entropy_sdk/solidity/EntropyEvents.sol +++ b/target_chains/ethereum/entropy_sdk/solidity/EntropyEvents.sol @@ -29,6 +29,13 @@ interface EntropyEvents { bytes32 randomNumber ); + event CallbackFailed( + address indexed provider, + address indexed requestor, + uint64 indexed sequenceNumber, + bytes errorCode + ); + event ProviderFeeUpdated(address provider, uint128 oldFee, uint128 newFee); event ProviderUriUpdated(address provider, bytes oldUri, bytes newUri); diff --git a/target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol b/target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol index 15c1d1511a..030a835fdc 100644 --- a/target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol +++ b/target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol @@ -59,8 +59,12 @@ contract EntropyStructs { address requester; // If true, incorporate the blockhash of blockNumber into the generated random value. bool useBlockhash; - // If true, the requester will be called back with the generated random value. - bool isRequestWithCallback; - // There are 2 remaining bytes of free space in this slot. + // Status flag for requests with callbacks. + // 0 -- not a request with callback + // 1 -- request with callback where the callback hasn't been invoked yet. + // 2 -- request with callback where the callback is currently in flight (this state is a reentry guard) + // 3 -- request with callback where the callback has been invoked and failed + uint8 status; + // 2 bytes of space left in this struct. } } From 717d701606671c9e0021847bb0de0e341b57c826 Mon Sep 17 00:00:00 2001 From: Jayant Krishnamurthy Date: Wed, 2 Apr 2025 09:21:50 -0700 Subject: [PATCH 2/9] failure states --- .../contracts/contracts/entropy/Entropy.sol | 33 ++++++++++--------- .../entropy_sdk/solidity/EntropyConstants.sol | 12 +++++++ .../entropy_sdk/solidity/EntropyStructs.sol | 6 +--- 3 files changed, 30 insertions(+), 21 deletions(-) create mode 100644 target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol diff --git a/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol b/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol index ba3fddbe0e..8421a6abec 100644 --- a/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol +++ b/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol @@ -3,11 +3,13 @@ pragma solidity ^0.8.0; import "@pythnetwork/entropy-sdk-solidity/EntropyStructs.sol"; +import "@pythnetwork/entropy-sdk-solidity/EntropyConstants.sol"; import "@pythnetwork/entropy-sdk-solidity/EntropyErrors.sol"; import "@pythnetwork/entropy-sdk-solidity/EntropyEvents.sol"; import "@pythnetwork/entropy-sdk-solidity/IEntropy.sol"; import "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol"; import "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import "ExcessivelySafeCall/ExcessivelySafeCall.sol"; import "./EntropyState.sol"; // Entropy implements a secure 2-party random number generation procedure. The protocol @@ -76,6 +78,8 @@ import "./EntropyState.sol"; // the user is always incentivized to reveal their random number, and that the protocol has an escape hatch for // cases where the user chooses not to reveal. abstract contract Entropy is IEntropy, EntropyState { + using ExcessivelySafeCall for address; + function _initialize( address admin, uint128 pythFeeInWei, @@ -247,7 +251,7 @@ abstract contract Entropy is IEntropy, EntropyState { req.blockNumber = SafeCast.toUint64(block.number); req.useBlockhash = useBlockhash; - req.status = (uint8) isRequestWithCallback; + req.status = isRequestWithCallback ? 1 : 0; } // As a user, request a random number from `provider`. Prior to calling this method, the user should @@ -423,7 +427,7 @@ abstract contract Entropy is IEntropy, EntropyState { sequenceNumber ); - if (req.isRequestWithCallback) { + if (req.status != EntropyConstants.STATUS_NO_CALLBACK) { revert EntropyErrors.InvalidRevealCall(); } @@ -467,14 +471,10 @@ abstract contract Entropy is IEntropy, EntropyState { sequenceNumber ); - if (!req.isRequestWithCallback) { + if (!(req.status == EntropyConstants.STATUS_CALLBACK_NOT_STARTED || req.status == EntropyConstants.STATUS_CALLBACK_FAILED)) { revert EntropyErrors.InvalidRevealCall(); } - if (req.reentryGuard) { - revert EntropyErrors.AssertionFailure(); - } - bytes32 blockHash; bytes32 randomNumber; (randomNumber, blockHash) = revealHelper( @@ -490,12 +490,12 @@ abstract contract Entropy is IEntropy, EntropyState { // so we default to the prior entropy flow (where there is no failure state). // Similarly, if the request has already failed, we fall back to the prior flow so that // recovery attempts can provide more gas / directly see the revert reason. - if (!req.callbackFailed) { - req.reentryGuard = true; + if (req.status == EntropyConstants.STATUS_CALLBACK_NOT_STARTED) { + req.status = EntropyConstants.STATUS_CALLBACK_IN_PROGRESS; bool success; bytes memory ret; (success, ret) = callAddress.excessivelySafeCall( - req.blockNumberOrGasLimit, + gasleft(), // TODO: providers need to be able to configure this in the future. 0, 256, abi.encodeWithSelector( @@ -505,7 +505,8 @@ abstract contract Entropy is IEntropy, EntropyState { randomNumber ) ); - req.reentryGuard = false; + // Reset status to not started here in case the transaction reverts. + req.status = EntropyConstants.STATUS_CALLBACK_NOT_STARTED; if (success) { emit RevealedWithCallback( @@ -522,11 +523,11 @@ abstract contract Entropy is IEntropy, EntropyState { sequenceNumber, ret ); - req.callbackFailed = true; + req.status = EntropyConstants.STATUS_CALLBACK_FAILED; } else { // The callback ran out of gas - // TODO: this case will go away once we add provider gas limits - revert; + // TODO: this case will go away once we add provider gas limits, so we're not putting in a custom error type. + require(false, "provider needs to send more gas"); } } else { emit RevealedWithCallback( @@ -547,13 +548,13 @@ abstract contract Entropy is IEntropy, EntropyState { // Setting the reentry guard here isn't strictly necessary because we've cleared the request above // (using the check-effects-interactions pattern). However, it seems like a good measure for consistency // across the two cases. - req.reentryGuard = true; + req.status = EntropyConstants.STATUS_CALLBACK_IN_PROGRESS; IEntropyConsumer(callAddress)._entropyCallback( sequenceNumber, provider, randomNumber ); - req.reentryGuard = false; + req.status = EntropyConstants.STATUS_CALLBACK_NOT_STARTED; } } } diff --git a/target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol b/target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol new file mode 100644 index 0000000000..85cf35f5d1 --- /dev/null +++ b/target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol @@ -0,0 +1,12 @@ + +library EntropyConstants { + // Status values for Request.status // + // not a request with callback + uint8 public constant STATUS_NO_CALLBACK = 0; + // A request with callback where the callback hasn't been invoked yet. + uint8 public constant STATUS_CALLBACK_NOT_STARTED = 1; + // A request with callback where the callback is currently in flight (this state is a reentry guard). + uint8 public constant STATUS_CALLBACK_IN_PROGRESS = 2; + // A request with callback where the callback has been invoked and failed. + uint8 public constant STATUS_CALLBACK_FAILED = 3; +} diff --git a/target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol b/target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol index 030a835fdc..df75b918f9 100644 --- a/target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol +++ b/target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol @@ -59,11 +59,7 @@ contract EntropyStructs { address requester; // If true, incorporate the blockhash of blockNumber into the generated random value. bool useBlockhash; - // Status flag for requests with callbacks. - // 0 -- not a request with callback - // 1 -- request with callback where the callback hasn't been invoked yet. - // 2 -- request with callback where the callback is currently in flight (this state is a reentry guard) - // 3 -- request with callback where the callback has been invoked and failed + // Status flag for requests with callbacks. See EntropyConstants for the possible values of this flag. uint8 status; // 2 bytes of space left in this struct. } From bac4cce6d7ce048377628a8e10bea341cd49c16c Mon Sep 17 00:00:00 2001 From: Jayant Krishnamurthy Date: Wed, 2 Apr 2025 09:34:42 -0700 Subject: [PATCH 3/9] add stuff --- .../contracts/contracts/entropy/Entropy.sol | 30 ++++--- .../entropy_sdk/solidity/EntropyConstants.sol | 1 - .../entropy_sdk/solidity/EntropyEvents.sol | 3 + .../solidity/abis/EntropyEvents.json | 73 ++++++++++++++--- .../entropy_sdk/solidity/abis/IEntropy.json | 79 +++++++++++++++---- 5 files changed, 145 insertions(+), 41 deletions(-) diff --git a/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol b/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol index 8421a6abec..56de5e4a54 100644 --- a/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol +++ b/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol @@ -251,7 +251,9 @@ abstract contract Entropy is IEntropy, EntropyState { req.blockNumber = SafeCast.toUint64(block.number); req.useBlockhash = useBlockhash; - req.status = isRequestWithCallback ? 1 : 0; + req.status = isRequestWithCallback + ? EntropyConstants.STATUS_CALLBACK_NOT_STARTED + : EntropyConstants.STATUS_NO_CALLBACK; } // As a user, request a random number from `provider`. Prior to calling this method, the user should @@ -471,7 +473,10 @@ abstract contract Entropy is IEntropy, EntropyState { sequenceNumber ); - if (!(req.status == EntropyConstants.STATUS_CALLBACK_NOT_STARTED || req.status == EntropyConstants.STATUS_CALLBACK_FAILED)) { + if ( + !(req.status == EntropyConstants.STATUS_CALLBACK_NOT_STARTED || + req.status == EntropyConstants.STATUS_CALLBACK_FAILED) + ) { revert EntropyErrors.InvalidRevealCall(); } @@ -485,11 +490,10 @@ abstract contract Entropy is IEntropy, EntropyState { address callAddress = req.requester; - // blockNumberOrGasLimit holds the gas limit in the callback case. - // If the gas limit is 0, then the provider hasn't configured their default limit, - // so we default to the prior entropy flow (where there is no failure state). - // Similarly, if the request has already failed, we fall back to the prior flow so that - // recovery attempts can provide more gas / directly see the revert reason. + // Requests that haven't been invoked yet will be invoked safely (catching reverts), and + // any reverts will be reported as an event. Any failing requests move to a failure state + // at which point they can be recovered. The recovery flow invokes the callback directly + // (no catching errors) which allows callers to easily see the revert reason. if (req.status == EntropyConstants.STATUS_CALLBACK_NOT_STARTED) { req.status = EntropyConstants.STATUS_CALLBACK_IN_PROGRESS; bool success; @@ -497,7 +501,7 @@ abstract contract Entropy is IEntropy, EntropyState { (success, ret) = callAddress.excessivelySafeCall( gasleft(), // TODO: providers need to be able to configure this in the future. 0, - 256, + 256, // copy at most 256 bytes of the return value into ret. abi.encodeWithSelector( IEntropyConsumer._entropyCallback.selector, sequenceNumber, @@ -517,10 +521,14 @@ abstract contract Entropy is IEntropy, EntropyState { ); clearRequest(provider, sequenceNumber); } else if (ret.length > 0) { + // Callback reverted for some reason that is *not* out-of-gas. emit CallbackFailed( provider, req.requester, sequenceNumber, + userRandomNumber, + providerRevelation, + randomNumber, ret ); req.status = EntropyConstants.STATUS_CALLBACK_FAILED; @@ -530,6 +538,7 @@ abstract contract Entropy is IEntropy, EntropyState { require(false, "provider needs to send more gas"); } } else { + // This case uses the checks-effects-interactions pattern to avoid reentry attacks emit RevealedWithCallback( req, userRandomNumber, @@ -545,16 +554,11 @@ abstract contract Entropy is IEntropy, EntropyState { len := extcodesize(callAddress) } if (len != 0) { - // Setting the reentry guard here isn't strictly necessary because we've cleared the request above - // (using the check-effects-interactions pattern). However, it seems like a good measure for consistency - // across the two cases. - req.status = EntropyConstants.STATUS_CALLBACK_IN_PROGRESS; IEntropyConsumer(callAddress)._entropyCallback( sequenceNumber, provider, randomNumber ); - req.status = EntropyConstants.STATUS_CALLBACK_NOT_STARTED; } } } diff --git a/target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol b/target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol index 85cf35f5d1..84432d43e8 100644 --- a/target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol +++ b/target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol @@ -1,4 +1,3 @@ - library EntropyConstants { // Status values for Request.status // // not a request with callback diff --git a/target_chains/ethereum/entropy_sdk/solidity/EntropyEvents.sol b/target_chains/ethereum/entropy_sdk/solidity/EntropyEvents.sol index 7e7aacdddb..6587cefe41 100644 --- a/target_chains/ethereum/entropy_sdk/solidity/EntropyEvents.sol +++ b/target_chains/ethereum/entropy_sdk/solidity/EntropyEvents.sol @@ -33,6 +33,9 @@ interface EntropyEvents { address indexed provider, address indexed requestor, uint64 indexed sequenceNumber, + bytes32 userRandomNumber, + bytes32 providerRevelation, + bytes32 randomNumber, bytes errorCode ); diff --git a/target_chains/ethereum/entropy_sdk/solidity/abis/EntropyEvents.json b/target_chains/ethereum/entropy_sdk/solidity/abis/EntropyEvents.json index b34dffcf59..fcaa57e695 100644 --- a/target_chains/ethereum/entropy_sdk/solidity/abis/EntropyEvents.json +++ b/target_chains/ethereum/entropy_sdk/solidity/abis/EntropyEvents.json @@ -1,4 +1,53 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "provider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "requestor", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint64", + "name": "sequenceNumber", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "userRandomNumber", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "providerRevelation", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "randomNumber", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "errorCode", + "type": "bytes" + } + ], + "name": "CallbackFailed", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -215,9 +264,9 @@ "type": "bool" }, { - "internalType": "bool", - "name": "isRequestWithCallback", - "type": "bool" + "internalType": "uint8", + "name": "status", + "type": "uint8" } ], "indexed": false, @@ -294,9 +343,9 @@ "type": "bool" }, { - "internalType": "bool", - "name": "isRequestWithCallback", - "type": "bool" + "internalType": "uint8", + "name": "status", + "type": "uint8" } ], "indexed": false, @@ -349,9 +398,9 @@ "type": "bool" }, { - "internalType": "bool", - "name": "isRequestWithCallback", - "type": "bool" + "internalType": "uint8", + "name": "status", + "type": "uint8" } ], "indexed": false, @@ -428,9 +477,9 @@ "type": "bool" }, { - "internalType": "bool", - "name": "isRequestWithCallback", - "type": "bool" + "internalType": "uint8", + "name": "status", + "type": "uint8" } ], "indexed": false, diff --git a/target_chains/ethereum/entropy_sdk/solidity/abis/IEntropy.json b/target_chains/ethereum/entropy_sdk/solidity/abis/IEntropy.json index 61a4a6be2e..61611db0af 100644 --- a/target_chains/ethereum/entropy_sdk/solidity/abis/IEntropy.json +++ b/target_chains/ethereum/entropy_sdk/solidity/abis/IEntropy.json @@ -1,4 +1,53 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "provider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "requestor", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint64", + "name": "sequenceNumber", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "userRandomNumber", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "providerRevelation", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "randomNumber", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "errorCode", + "type": "bytes" + } + ], + "name": "CallbackFailed", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -215,9 +264,9 @@ "type": "bool" }, { - "internalType": "bool", - "name": "isRequestWithCallback", - "type": "bool" + "internalType": "uint8", + "name": "status", + "type": "uint8" } ], "indexed": false, @@ -294,9 +343,9 @@ "type": "bool" }, { - "internalType": "bool", - "name": "isRequestWithCallback", - "type": "bool" + "internalType": "uint8", + "name": "status", + "type": "uint8" } ], "indexed": false, @@ -349,9 +398,9 @@ "type": "bool" }, { - "internalType": "bool", - "name": "isRequestWithCallback", - "type": "bool" + "internalType": "uint8", + "name": "status", + "type": "uint8" } ], "indexed": false, @@ -428,9 +477,9 @@ "type": "bool" }, { - "internalType": "bool", - "name": "isRequestWithCallback", - "type": "bool" + "internalType": "uint8", + "name": "status", + "type": "uint8" } ], "indexed": false, @@ -735,9 +784,9 @@ "type": "bool" }, { - "internalType": "bool", - "name": "isRequestWithCallback", - "type": "bool" + "internalType": "uint8", + "name": "status", + "type": "uint8" } ], "internalType": "struct EntropyStructs.Request", From 63733b331ee3c6687daaafd642ce3b8ead802df1 Mon Sep 17 00:00:00 2001 From: Jayant Krishnamurthy Date: Wed, 2 Apr 2025 09:55:19 -0700 Subject: [PATCH 4/9] package --- .../contracts/forge-test/Entropy.t.sol | 378 ++++-------------- target_chains/ethereum/contracts/package.json | 2 +- 2 files changed, 75 insertions(+), 305 deletions(-) diff --git a/target_chains/ethereum/contracts/forge-test/Entropy.t.sol b/target_chains/ethereum/contracts/forge-test/Entropy.t.sol index 13668fdff3..1b23939dd5 100644 --- a/target_chains/ethereum/contracts/forge-test/Entropy.t.sol +++ b/target_chains/ethereum/contracts/forge-test/Entropy.t.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.0; import "forge-std/Test.sol"; +import "@pythnetwork/entropy-sdk-solidity/EntropyConstants.sol"; import "@pythnetwork/entropy-sdk-solidity/EntropyStructs.sol"; import "@pythnetwork/entropy-sdk-solidity/EntropyEvents.sol"; import "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol"; @@ -203,10 +204,7 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { function testBasicFlow() public { vm.roll(17); uint64 sequenceNumber = request(user2, provider1, 42, false); - assertEq( - random.getRequest(provider1, sequenceNumber).blockNumberOrGasLimit, - 17 - ); + assertEq(random.getRequest(provider1, sequenceNumber).blockNumber, 17); assertEq( random.getRequest(provider1, sequenceNumber).useBlockhash, false @@ -246,10 +244,7 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { 42, false ); - assertEq( - random.getRequest(provider1, sequenceNumber).blockNumberOrGasLimit, - 20 - ); + assertEq(random.getRequest(provider1, sequenceNumber).blockNumber, 20); assertEq( random.getRequest(provider1, sequenceNumber).useBlockhash, false @@ -411,7 +406,7 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { uint64 sequenceNumber = request(user2, provider1, 42, true); assertEq( - random.getRequest(provider1, sequenceNumber).blockNumberOrGasLimit, + random.getRequest(provider1, sequenceNumber).blockNumber, 1234 ); assertEq( @@ -807,12 +802,10 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { providerInfo.currentCommitment ) ), - blockNumberOrGasLimit: 0, + blockNumber: 1234, requester: user1, useBlockhash: false, - isRequestWithCallback: true, - callbackFailed: false, - reentryGuard: false + status: EntropyConstants.STATUS_CALLBACK_NOT_STARTED }) ); vm.roll(1234); @@ -946,70 +939,31 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { ); } - function testRequestWithCallbackAndRevealWithCallbackWithGasLimit() public { - uint64 defaultGasLimit = 100000; - vm.prank(provider1); - random.setDefaultGasLimit(defaultGasLimit); - + // TODO: restore this test once providers have custom gas limits, which allow us to toggle between + // the old and new failure behavior. + /* + function testRequestWithCallbackAndRevealWithCallbackFailing() public { bytes32 userRandomNumber = bytes32(uint(42)); uint fee = random.getFee(provider1); - EntropyConsumer consumer = new EntropyConsumer(address(random), false); - vm.deal(user1, fee); - vm.prank(user1); - uint64 assignedSequenceNumber = consumer.requestEntropy{value: fee}( - userRandomNumber - ); - EntropyStructs.Request memory req = random.getRequest( + EntropyConsumer consumer = new EntropyConsumer(address(random), true); + vm.deal(address(consumer), fee); + vm.startPrank(address(consumer)); + uint64 assignedSequenceNumber = random.requestWithCallback{value: fee}( provider1, - assignedSequenceNumber + userRandomNumber ); - // Verify the gas limit was set correctly - assertEq(req.blockNumberOrGasLimit, defaultGasLimit); - - vm.expectEmit(false, false, false, true, address(random)); - emit RevealedWithCallback( - req, - userRandomNumber, - provider1Proofs[assignedSequenceNumber], - random.combineRandomValues( - userRandomNumber, - provider1Proofs[assignedSequenceNumber], - 0 - ) - ); + vm.expectRevert(); random.revealWithCallback( provider1, assignedSequenceNumber, userRandomNumber, provider1Proofs[assignedSequenceNumber] ); - - assertEq(consumer.sequence(), assignedSequenceNumber); - assertEq(consumer.provider(), provider1); - assertEq( - consumer.randomness(), - random.combineRandomValues( - userRandomNumber, - provider1Proofs[assignedSequenceNumber], - 0 - ) - ); - - EntropyStructs.Request memory reqAfterReveal = random.getRequest( - provider1, - assignedSequenceNumber - ); - assertEq(reqAfterReveal.sequenceNumber, 0); } + */ - function testRequestWithCallbackAndRevealWithCallbackWithGasLimitAndFailure() - public - { - uint64 defaultGasLimit = 100000; - vm.prank(provider1); - random.setDefaultGasLimit(defaultGasLimit); - + function testRequestWithRevertingCallback() public { bytes32 userRandomNumber = bytes32(uint(42)); uint fee = random.getFee(provider1); EntropyConsumer consumer = new EntropyConsumer(address(random), true); @@ -1023,9 +977,6 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { assignedSequenceNumber ); - // Verify the gas limit was set correctly - assertEq(req.blockNumberOrGasLimit, defaultGasLimit); - // On the first attempt, the transaction should succeed and emit CallbackFailed event. bytes memory revertReason = abi.encodeWithSelector( 0x08c379a0, @@ -1036,6 +987,13 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { provider1, address(consumer), assignedSequenceNumber, + userRandomNumber, + provider1Proofs[assignedSequenceNumber], + random.combineRandomValues( + userRandomNumber, + provider1Proofs[assignedSequenceNumber], + 0 + ), revertReason ); random.revealWithCallback( @@ -1051,9 +1009,11 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { assignedSequenceNumber ); assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber); - assertTrue(reqAfterFailure.callbackFailed); + assertTrue( + reqAfterFailure.status == EntropyConstants.STATUS_CALLBACK_FAILED + ); - // Second attempt should revert + // On the second attempt, the transaction should directly revert vm.expectRevert(); random.revealWithCallback( provider1, @@ -1065,7 +1025,9 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { // Again, request stays active after failure reqAfterFailure = random.getRequest(provider1, assignedSequenceNumber); assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber); - assertTrue(reqAfterFailure.callbackFailed); + assertTrue( + reqAfterFailure.status == EntropyConstants.STATUS_CALLBACK_FAILED + ); // If the callback starts succeeding, we can invoke it and it emits the usual RevealedWithCallback event. consumer.setReverts(false); @@ -1095,24 +1057,60 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { assertEq(reqAfterReveal.sequenceNumber, 0); } - function testRequestWithCallbackAndRevealWithCallbackFailing() public { + function testRequestWithCallbackUsingTooMuchGas() public { + uint64 defaultGasLimit = 100000; + bytes32 userRandomNumber = bytes32(uint(42)); uint fee = random.getFee(provider1); - EntropyConsumer consumer = new EntropyConsumer(address(random), true); - vm.deal(address(consumer), fee); - vm.startPrank(address(consumer)); - uint64 assignedSequenceNumber = random.requestWithCallback{value: fee}( - provider1, + EntropyConsumer consumer = new EntropyConsumer(address(random), false); + // Consumer callback uses ~10% more gas than the provider's default + consumer.setTargetGasUsage((defaultGasLimit * 110) / 100); + + vm.deal(user1, fee); + vm.prank(user1); + uint64 assignedSequenceNumber = consumer.requestEntropy{value: fee}( userRandomNumber ); + EntropyStructs.Request memory req = random.getRequest( + provider1, + assignedSequenceNumber + ); + // The transaction reverts if the provider does not provide enough gas to forward + // the gasLimit to the callback transaction. vm.expectRevert(); + random.revealWithCallback{gas: defaultGasLimit}( + provider1, + assignedSequenceNumber, + userRandomNumber, + provider1Proofs[assignedSequenceNumber] + ); + + // Calling without a gas limit should succeed + vm.expectEmit(false, false, false, true, address(random)); + emit RevealedWithCallback( + req, + userRandomNumber, + provider1Proofs[assignedSequenceNumber], + random.combineRandomValues( + userRandomNumber, + provider1Proofs[assignedSequenceNumber], + 0 + ) + ); random.revealWithCallback( provider1, assignedSequenceNumber, userRandomNumber, provider1Proofs[assignedSequenceNumber] ); + + // Verify request is cleared after successful reveal + EntropyStructs.Request memory reqAfterReveal = random.getRequest( + provider1, + assignedSequenceNumber + ); + assertEq(reqAfterReveal.sequenceNumber, 0); } function testLastRevealedTooOld() public { @@ -1303,234 +1301,6 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { vm.expectRevert(); random.setProviderFeeAsFeeManager(provider1, 1000); } - - function testSetDefaultGasLimit() public { - uint64 newGasLimit = 100000; - - vm.prank(provider1); - random.setDefaultGasLimit(newGasLimit); - - EntropyStructs.ProviderInfo memory info = random.getProviderInfo( - provider1 - ); - assertEq(info.defaultGasLimit, newGasLimit); - } - - function testSetDefaultGasLimitRevertIfNotFromProvider() public { - vm.expectRevert(EntropyErrors.NoSuchProvider.selector); - random.setDefaultGasLimit(100000); - } - - function testRequestWithCallbackUsesDefaultGasLimit() public { - uint64 defaultGasLimit = 100000; - vm.prank(provider1); - random.setDefaultGasLimit(defaultGasLimit); - - bytes32 userRandomNumber = bytes32(uint(42)); - uint fee = random.getFee(provider1); - - vm.deal(user1, fee); - vm.prank(user1); - uint64 sequenceNumber = random.requestWithCallback{value: fee}( - provider1, - userRandomNumber - ); - - EntropyStructs.Request memory req = random.getRequest( - provider1, - sequenceNumber - ); - assertEq(req.blockNumberOrGasLimit, defaultGasLimit); - } - - function testRequestWithCallbackAndCustomGasLimit() public { - uint64 defaultGasLimit = 100000; - uint64 customGasLimit = 200000; - - vm.prank(provider1); - random.setDefaultGasLimit(defaultGasLimit); - - bytes32 userRandomNumber = bytes32(uint(42)); - uint fee = random.getFeeForGas(provider1, customGasLimit); - - vm.deal(user1, fee); - vm.prank(user1); - uint64 sequenceNumber = random.requestWithCallbackAndGas{value: fee}( - provider1, - userRandomNumber, - customGasLimit - ); - - EntropyStructs.Request memory req = random.getRequest( - provider1, - sequenceNumber - ); - assertEq(req.blockNumberOrGasLimit, customGasLimit); - } - - function testRequestWithCallbackAndGasLimitFeeScaling() public { - uint64 defaultGasLimit = 100000; - uint64 doubleGasLimit = 200000; - - vm.prank(provider1); - random.setDefaultGasLimit(defaultGasLimit); - - uint baseFee = random.getFee(provider1); - assertEq(baseFee, provider1FeeInWei + pythFeeInWei); - - // Fee scales proportionally with gas limit - uint scaledFee = random.getFeeForGas(provider1, doubleGasLimit); - assertEq(scaledFee, 2 * provider1FeeInWei + pythFeeInWei); - } - - function testRequestWithCallbackAndGasLimitInsufficientFee() public { - uint64 defaultGasLimit = 100000; - uint64 doubleGasLimit = 200000; - - vm.prank(provider1); - random.setDefaultGasLimit(defaultGasLimit); - - bytes32 userRandomNumber = bytes32(uint(42)); - uint baseFee = random.getFee(provider1); // This is insufficient for double gas - - vm.deal(user1, baseFee); - vm.prank(user1); - vm.expectRevert(EntropyErrors.InsufficientFee.selector); - random.requestWithCallbackAndGas{value: baseFee}( - provider1, - userRandomNumber, - doubleGasLimit - ); - } - - function testRequestWithCallbackAndGasLimitLowerThanDefault() public { - uint64 defaultGasLimit = 100000; - uint64 lowerGasLimit = 50000; - - vm.prank(provider1); - random.setDefaultGasLimit(defaultGasLimit); - - bytes32 userRandomNumber = bytes32(uint(42)); - uint fee = random.getFeeForGas(provider1, lowerGasLimit); - - vm.deal(user1, fee); - vm.prank(user1); - uint64 sequenceNumber = random.requestWithCallbackAndGas{value: fee}( - provider1, - userRandomNumber, - lowerGasLimit - ); - - EntropyStructs.Request memory req = random.getRequest( - provider1, - sequenceNumber - ); - assertEq(req.blockNumberOrGasLimit, lowerGasLimit); - // Fee should be the same as base fee since we're using less gas than default - assertEq(fee, random.getFee(provider1)); - } - - function testRequestWithCallbackAndRevealWithCallbackWithGasLimitAndFailureWithGasUsage() - public - { - uint64 defaultGasLimit = 100000; - vm.prank(provider1); - random.setDefaultGasLimit(defaultGasLimit); - - bytes32 userRandomNumber = bytes32(uint(42)); - uint fee = random.getFee(provider1); - EntropyConsumer consumer = new EntropyConsumer(address(random), false); - // Consumer callback uses ~10% more gas than the provider's default - consumer.setTargetGasUsage((defaultGasLimit * 110) / 100); - - vm.deal(user1, fee); - vm.prank(user1); - uint64 assignedSequenceNumber = consumer.requestEntropy{value: fee}( - userRandomNumber - ); - EntropyStructs.Request memory req = random.getRequest( - provider1, - assignedSequenceNumber - ); - - // Verify the gas limit was set correctly - assertEq(req.blockNumberOrGasLimit, defaultGasLimit); - - // The transaction reverts if the provider does not provide enough gas to forward - // the gasLimit to the callback transaction. - vm.expectRevert(); - random.revealWithCallback{gas: defaultGasLimit - 10000}( - provider1, - assignedSequenceNumber, - userRandomNumber, - provider1Proofs[assignedSequenceNumber] - ); - - // If called with enough gas, the transaction should succeed, but the callback should fail because - // it uses too much gas. - vm.expectEmit(false, false, false, true, address(random)); - emit CallbackFailed( - provider1, - address(consumer), - assignedSequenceNumber, - // out-of-gas reverts have an empty bytes array as the return value. - "" - ); - random.revealWithCallback( - provider1, - assignedSequenceNumber, - userRandomNumber, - provider1Proofs[assignedSequenceNumber] - ); - - // Verify request is still active after failure - EntropyStructs.Request memory reqAfterFailure = random.getRequest( - provider1, - assignedSequenceNumber - ); - assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber); - assertTrue(reqAfterFailure.callbackFailed); - - // A subsequent attempt passing insufficient gas should also revert - vm.expectRevert(); - random.revealWithCallback{gas: defaultGasLimit - 10000}( - provider1, - assignedSequenceNumber, - userRandomNumber, - provider1Proofs[assignedSequenceNumber] - ); - - // Again, request stays active after failure - reqAfterFailure = random.getRequest(provider1, assignedSequenceNumber); - assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber); - assertTrue(reqAfterFailure.callbackFailed); - - // Calling without a gas limit should succeed - vm.expectEmit(false, false, false, true, address(random)); - emit RevealedWithCallback( - reqAfterFailure, - userRandomNumber, - provider1Proofs[assignedSequenceNumber], - random.combineRandomValues( - userRandomNumber, - provider1Proofs[assignedSequenceNumber], - 0 - ) - ); - random.revealWithCallback( - provider1, - assignedSequenceNumber, - userRandomNumber, - provider1Proofs[assignedSequenceNumber] - ); - - // Verify request is cleared after successful reveal - EntropyStructs.Request memory reqAfterReveal = random.getRequest( - provider1, - assignedSequenceNumber - ); - assertEq(reqAfterReveal.sequenceNumber, 0); - } } contract EntropyConsumer is IEntropyConsumer { diff --git a/target_chains/ethereum/contracts/package.json b/target_chains/ethereum/contracts/package.json index 296bd002bc..fd9800ac03 100644 --- a/target_chains/ethereum/contracts/package.json +++ b/target_chains/ethereum/contracts/package.json @@ -1,6 +1,6 @@ { "name": "@pythnetwork/pyth-evm-contract", - "version": "1.4.3", + "version": "1.4.4-alpha.2", "description": "", "private": "true", "devDependencies": { From 491a01e5935a141a1a3eda41255261c98d701102 Mon Sep 17 00:00:00 2001 From: Jayant Krishnamurthy Date: Wed, 2 Apr 2025 10:18:23 -0700 Subject: [PATCH 5/9] hm --- pnpm-lock.yaml | 495 +++++++++++++++++- .../contracts/contracts/entropy/Entropy.sol | 3 +- .../contracts/forge-test/Entropy.t.sol | 8 +- target_chains/ethereum/contracts/package.json | 3 +- .../ethereum/contracts/remappings.txt | 2 +- .../entropy_sdk/solidity/EntropyConstants.sol | 2 + 6 files changed, 492 insertions(+), 21 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ae4749e24e..ccb7364052 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -905,7 +905,7 @@ importers: version: 0.9.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(react-dom@19.0.0(react@19.0.0))(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0) '@solana/wallet-adapter-wallets': specifier: 'catalog:' - version: 0.19.33(@babel/runtime@7.26.10)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.0.0(react@19.0.0))(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2) + version: 0.19.33(@babel/runtime@7.26.10)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.0.0(react@19.0.0))(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2) '@solana/web3.js': specifier: 'catalog:' version: 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) @@ -1479,7 +1479,7 @@ importers: version: 0.9.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(react-dom@19.0.0(react@19.0.0))(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0) '@solana/wallet-adapter-wallets': specifier: 'catalog:' - version: 0.19.33(@babel/runtime@7.26.10)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.0.0(react@19.0.0))(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2) + version: 0.19.33(@babel/runtime@7.26.10)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.0.0(react@19.0.0))(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2) '@solana/web3.js': specifier: ^1.73.0 version: 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) @@ -2342,6 +2342,9 @@ importers: '@matterlabs/hardhat-zksync-solc': specifier: ^0.3.14 version: 0.3.17(encoding@0.1.13)(hardhat@2.22.19(bufferutil@4.0.7)(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2))(typescript@5.8.2)(utf-8-validate@6.0.3)) + '@nomad-xyz/excessively-safe-call': + specifier: ^0.0.1-rc.1 + version: 0.0.1-rc.1 '@nomiclabs/hardhat-etherscan': specifier: ^3.1.7 version: 3.1.8(hardhat@2.22.19(bufferutil@4.0.7)(ts-node@10.9.2(@types/node@22.13.10)(typescript@5.8.2))(typescript@5.8.2)(utf-8-validate@6.0.3)) @@ -6068,6 +6071,9 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} + '@nomad-xyz/excessively-safe-call@0.0.1-rc.1': + resolution: {integrity: sha512-Q5GVakBy8J1kWjydH6W5LNbkYY+Cw2doBiLodOfbFGujeng6zM+EtMLb/V+vkWbskbM81y2r+LG5NmxsxyElPA==} + '@nomicfoundation/edr-darwin-arm64@0.8.0': resolution: {integrity: sha512-sKTmOu/P5YYhxT0ThN2Pe3hmCE/5Ag6K/eYoiavjLWbR7HEb5ZwPu2rC3DpuUk1H+UKJqt7o4/xIgJxqw9wu6A==} engines: {node: '>= 18'} @@ -23429,7 +23435,7 @@ snapshots: near-api-js: 1.1.0(encoding@0.1.13) optionalDependencies: '@injectivelabs/networks': 1.10.12(google-protobuf@3.21.4) - '@injectivelabs/sdk-ts': 1.10.72(@types/react@19.0.11)(bufferutil@4.0.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(utf-8-validate@5.0.10) + '@injectivelabs/sdk-ts': 1.10.72(bufferutil@4.0.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(utf-8-validate@5.0.10) '@injectivelabs/utils': 1.10.12(google-protobuf@3.21.4) transitivePeerDependencies: - '@types/react' @@ -23505,7 +23511,7 @@ snapshots: near-api-js: 1.1.0(encoding@0.1.13) optionalDependencies: '@injectivelabs/networks': 1.10.12(google-protobuf@3.21.4) - '@injectivelabs/sdk-ts': 1.10.72(@types/react@19.0.11)(bufferutil@4.0.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(utf-8-validate@5.0.10) + '@injectivelabs/sdk-ts': 1.10.72(bufferutil@4.0.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(utf-8-validate@5.0.10) '@injectivelabs/utils': 1.10.12(google-protobuf@3.21.4) transitivePeerDependencies: - '@types/react' @@ -25294,6 +25300,17 @@ snapshots: '@ethersproject/properties': 5.8.0 '@ethersproject/strings': 5.8.0 + '@everstake/wallet-sdk-solana@2.0.9(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana-program/compute-budget': 0.6.1(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/stake': 0.1.0(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/system': 0.6.2(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana/web3.js': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + - ws + '@everstake/wallet-sdk-solana@2.0.9(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana-program/compute-budget': 0.6.1(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))) @@ -26195,6 +26212,55 @@ snapshots: - utf-8-validate optional: true + '@injectivelabs/sdk-ts@1.10.72(bufferutil@4.0.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(utf-8-validate@5.0.10)': + dependencies: + '@apollo/client': 3.13.4(@types/react@19.0.11)(graphql@16.10.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@cosmjs/amino': 0.30.1 + '@cosmjs/proto-signing': 0.30.1 + '@cosmjs/stargate': 0.30.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@ethersproject/bytes': 5.8.0 + '@injectivelabs/core-proto-ts': 0.0.14 + '@injectivelabs/exceptions': 1.14.41(google-protobuf@3.21.4) + '@injectivelabs/grpc-web': 0.0.1(google-protobuf@3.21.4) + '@injectivelabs/grpc-web-node-http-transport': 0.0.2(@injectivelabs/grpc-web@0.0.1(google-protobuf@3.21.4)) + '@injectivelabs/grpc-web-react-native-transport': 0.0.2(@injectivelabs/grpc-web@0.0.1(google-protobuf@3.21.4)) + '@injectivelabs/indexer-proto-ts': 1.10.8-rc.4 + '@injectivelabs/mito-proto-ts': 1.0.9 + '@injectivelabs/networks': 1.14.47 + '@injectivelabs/test-utils': 1.14.41(google-protobuf@3.21.4) + '@injectivelabs/token-metadata': 1.10.42(google-protobuf@3.21.4) + '@injectivelabs/ts-types': 1.14.41 + '@injectivelabs/utils': 1.14.47 + '@metamask/eth-sig-util': 4.0.1 + axios: 0.27.2 + bech32: 2.0.0 + bip39: 3.1.0 + cosmjs-types: 0.7.2 + eth-crypto: 2.7.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ethereumjs-util: 7.1.5 + ethers: 5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + google-protobuf: 3.21.4 + graphql: 16.10.0 + http-status-codes: 2.3.0 + js-sha3: 0.8.0 + jscrypto: 1.0.3 + keccak256: 1.0.6 + link-module-alias: 1.2.0 + rxjs: 7.8.2 + secp256k1: 4.0.4 + shx: 0.3.4 + snakecase-keys: 5.5.0 + transitivePeerDependencies: + - '@types/react' + - bufferutil + - debug + - graphql-ws + - react + - react-dom + - subscriptions-transport-ws + - utf-8-validate + optional: true + '@injectivelabs/sdk-ts@1.14.49(@types/react@19.0.11)(bufferutil@4.0.9)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(utf-8-validate@5.0.10)': dependencies: '@apollo/client': 3.13.4(@types/react@19.0.11)(graphql@16.10.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -27856,6 +27922,8 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} + '@nomad-xyz/excessively-safe-call@0.0.1-rc.1': {} + '@nomicfoundation/edr-darwin-arm64@0.8.0': {} '@nomicfoundation/edr-darwin-x64@0.8.0': {} @@ -30786,31 +30854,60 @@ snapshots: - react - react-native + '@solana-program/compute-budget@0.6.1(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + dependencies: + '@solana/web3.js': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/compute-budget@0.6.1(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/web3.js': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/compute-budget@0.7.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + dependencies: + '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/compute-budget@0.7.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/stake@0.1.0(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + dependencies: + '@solana/web3.js': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/stake@0.1.0(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/web3.js': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/system@0.6.2(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + dependencies: + '@solana/web3.js': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/system@0.6.2(@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/web3.js': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/system@0.7.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + dependencies: + '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/system@0.7.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/token-2022@0.4.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))': + dependencies: + '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/sysvars': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana-program/token-2022@0.4.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))': dependencies: '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/sysvars': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana-program/token@0.5.1(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + dependencies: + '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/token@0.5.1(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) @@ -31063,6 +31160,17 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/codecs@2.0.0-rc.1(typescript@5.8.2)': + dependencies: + '@solana/codecs-core': 2.0.0-rc.1(typescript@5.8.2) + '@solana/codecs-data-structures': 2.0.0-rc.1(typescript@5.8.2) + '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.8.2) + '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/options': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/codecs@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)': dependencies: '@solana/codecs-core': 2.1.0(typescript@5.8.2) @@ -31150,6 +31258,31 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/accounts': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/addresses': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.1.0(typescript@5.8.2) + '@solana/functional': 2.1.0(typescript@5.8.2) + '@solana/instructions': 2.1.0(typescript@5.8.2) + '@solana/keys': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/programs': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-parsed-types': 2.1.0(typescript@5.8.2) + '@solana/rpc-spec-types': 2.1.0(typescript@5.8.2) + '@solana/rpc-subscriptions': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/signers': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/sysvars': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transaction-confirmation': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/transaction-messages': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transactions': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/accounts': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) @@ -31336,6 +31469,15 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-subscriptions-channel-websocket@2.0.0(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 2.0.0(typescript@5.8.2) + '@solana/functional': 2.0.0(typescript@5.8.2) + '@solana/rpc-subscriptions-spec': 2.0.0(typescript@5.8.2) + '@solana/subscribable': 2.0.0(typescript@5.8.2) + typescript: 5.8.2 + ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@solana/rpc-subscriptions-channel-websocket@2.0.0(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 2.0.0(typescript@5.8.2) @@ -31345,6 +31487,15 @@ snapshots: typescript: 5.8.2 ws: 8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@solana/rpc-subscriptions-channel-websocket@2.1.0(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 2.1.0(typescript@5.8.2) + '@solana/functional': 2.1.0(typescript@5.8.2) + '@solana/rpc-subscriptions-spec': 2.1.0(typescript@5.8.2) + '@solana/subscribable': 2.1.0(typescript@5.8.2) + typescript: 5.8.2 + ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@solana/rpc-subscriptions-channel-websocket@2.1.0(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 2.1.0(typescript@5.8.2) @@ -31370,6 +31521,24 @@ snapshots: '@solana/subscribable': 2.1.0(typescript@5.8.2) typescript: 5.8.2 + '@solana/rpc-subscriptions@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 2.0.0(typescript@5.8.2) + '@solana/fast-stable-stringify': 2.0.0(typescript@5.8.2) + '@solana/functional': 2.0.0(typescript@5.8.2) + '@solana/promises': 2.0.0(typescript@5.8.2) + '@solana/rpc-spec-types': 2.0.0(typescript@5.8.2) + '@solana/rpc-subscriptions-api': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-subscriptions-channel-websocket': 2.0.0(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions-spec': 2.0.0(typescript@5.8.2) + '@solana/rpc-transformers': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-types': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/subscribable': 2.0.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/rpc-subscriptions@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 2.0.0(typescript@5.8.2) @@ -31388,6 +31557,24 @@ snapshots: - fastestsmallesttextencoderdecoder - ws + '@solana/rpc-subscriptions@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 2.1.0(typescript@5.8.2) + '@solana/fast-stable-stringify': 2.1.0(typescript@5.8.2) + '@solana/functional': 2.1.0(typescript@5.8.2) + '@solana/promises': 2.1.0(typescript@5.8.2) + '@solana/rpc-spec-types': 2.1.0(typescript@5.8.2) + '@solana/rpc-subscriptions-api': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-subscriptions-channel-websocket': 2.1.0(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions-spec': 2.1.0(typescript@5.8.2) + '@solana/rpc-transformers': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-types': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/subscribable': 2.1.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/rpc-subscriptions@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 2.1.0(typescript@5.8.2) @@ -31545,7 +31732,7 @@ snapshots: '@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.98.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@6.0.3))(typescript@5.8.2)': dependencies: - '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs': 2.0.0-rc.1(typescript@5.8.2) '@solana/web3.js': 1.98.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@6.0.3) transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -31569,7 +31756,7 @@ snapshots: '@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(typescript@5.8.2)': dependencies: - '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs': 2.0.0-rc.1(typescript@5.8.2) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -31680,6 +31867,23 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/transaction-confirmation@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs-strings': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.0.0(typescript@5.8.2) + '@solana/keys': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/promises': 2.0.0(typescript@5.8.2) + '@solana/rpc': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-subscriptions': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transaction-messages': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transactions': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/transaction-confirmation@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) @@ -31697,6 +31901,23 @@ snapshots: - fastestsmallesttextencoderdecoder - ws + '@solana/transaction-confirmation@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/addresses': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs-strings': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.1.0(typescript@5.8.2) + '@solana/keys': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/promises': 2.1.0(typescript@5.8.2) + '@solana/rpc': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-subscriptions': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transaction-messages': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transactions': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/transaction-confirmation@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/addresses': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) @@ -31797,7 +32018,7 @@ snapshots: '@solana/wallet-adapter-base-ui@0.1.3(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0)': dependencies: - '@solana/wallet-adapter-react': 0.15.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0)(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0) + '@solana/wallet-adapter-react': 0.15.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) react: 19.0.0 transitivePeerDependencies: @@ -31942,7 +32163,7 @@ snapshots: dependencies: '@solana/wallet-adapter-base': 0.9.24(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-base-ui': 0.1.3(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0) - '@solana/wallet-adapter-react': 0.15.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0)(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0) + '@solana/wallet-adapter-react': 0.15.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) @@ -31972,6 +32193,17 @@ snapshots: - bs58 - react-native + '@solana/wallet-adapter-react@0.15.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0)': + dependencies: + '@solana-mobile/wallet-adapter-mobile': 2.1.5(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0) + '@solana/wallet-adapter-base': 0.9.24(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-standard-wallet-adapter-react': 1.1.4(@solana/wallet-adapter-base@0.9.24(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0)(react@19.0.0) + '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) + react: 19.0.0 + transitivePeerDependencies: + - bs58 + - react-native + '@solana/wallet-adapter-safepal@0.5.19(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))': dependencies: '@solana/wallet-adapter-base': 0.9.24(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) @@ -32039,6 +32271,26 @@ snapshots: - supports-color - utf-8-validate + '@solana/wallet-adapter-trezor@0.1.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/wallet-adapter-base': 0.9.24(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) + '@trezor/connect-web': 9.5.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + buffer: 6.0.3 + transitivePeerDependencies: + - '@solana/sysvars' + - bufferutil + - encoding + - expo-constants + - expo-localization + - fastestsmallesttextencoderdecoder + - react-native + - supports-color + - tslib + - typescript + - utf-8-validate + - ws + '@solana/wallet-adapter-trezor@0.1.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/wallet-adapter-base': 0.9.24(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) @@ -32101,7 +32353,84 @@ snapshots: - utf-8-validate - zod - '@solana/wallet-adapter-wallets@0.19.33(@babel/runtime@7.26.10)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.0.0(react@19.0.0))(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)': + '@solana/wallet-adapter-wallets@0.19.33(@babel/runtime@7.26.10)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.0.0(react@19.0.0))(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)': + dependencies: + '@solana/wallet-adapter-alpha': 0.1.11(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-avana': 0.1.14(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-bitkeep': 0.3.21(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-bitpie': 0.5.19(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-clover': 0.4.20(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-coin98': 0.5.21(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-coinbase': 0.1.20(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-coinhub': 0.3.19(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-fractal': 0.1.9(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@solana/wallet-adapter-huobi': 0.1.16(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-hyperpay': 0.1.15(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-keystone': 0.1.16(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(utf-8-validate@5.0.10) + '@solana/wallet-adapter-krystal': 0.1.13(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-ledger': 0.9.26(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-mathwallet': 0.9.19(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-neko': 0.2.13(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-nightly': 0.1.17(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-nufi': 0.1.18(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-onto': 0.1.8(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-particle': 0.1.13(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0) + '@solana/wallet-adapter-phantom': 0.9.25(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-safepal': 0.5.19(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-saifu': 0.1.16(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-salmon': 0.1.15(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-sky': 0.1.16(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-solflare': 0.6.29(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-solong': 0.9.19(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-spot': 0.1.16(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-tokenary': 0.1.13(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-tokenpocket': 0.4.20(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-torus': 0.11.29(@babel/runtime@7.26.10)(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) + '@solana/wallet-adapter-trezor': 0.1.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-trust': 0.1.14(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-unsafe-burner': 0.1.8(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-walletconnect': 0.1.17(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) + '@solana/wallet-adapter-xdefi': 0.1.8(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@babel/runtime' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@sentry/types' + - '@solana/sysvars' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/kv' + - aws4fetch + - bs58 + - bufferutil + - db0 + - encoding + - expo-constants + - expo-localization + - fastestsmallesttextencoderdecoder + - ioredis + - react + - react-dom + - react-native + - supports-color + - tslib + - typescript + - uploadthing + - utf-8-validate + - ws + - zod + + '@solana/wallet-adapter-wallets@0.19.33(@babel/runtime@7.26.10)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.0.0(react@19.0.0))(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)': dependencies: '@solana/wallet-adapter-alpha': 0.1.11(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-avana': 0.1.14(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) @@ -32373,7 +32702,7 @@ snapshots: bs58: 4.0.1 buffer: 6.0.3 fast-stable-stringify: 1.0.0 - jayson: 4.1.3(bufferutil@4.0.7)(utf-8-validate@6.0.3) + jayson: 4.1.3 node-fetch: 2.7.0(encoding@0.1.13) rpc-websockets: 9.1.1 superstruct: 2.0.2 @@ -32382,6 +32711,31 @@ snapshots: - encoding - utf-8-validate + '@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/accounts': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/addresses': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.0.0(typescript@5.8.2) + '@solana/functional': 2.0.0(typescript@5.8.2) + '@solana/instructions': 2.0.0(typescript@5.8.2) + '@solana/keys': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/programs': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-parsed-types': 2.0.0(typescript@5.8.2) + '@solana/rpc-spec-types': 2.0.0(typescript@5.8.2) + '@solana/rpc-subscriptions': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/signers': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/sysvars': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transaction-confirmation': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/transaction-messages': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transactions': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/web3.js@2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/accounts': 2.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) @@ -33356,6 +33710,17 @@ snapshots: - expo-localization - react-native + '@trezor/blockchain-link-types@1.3.3(fastestsmallesttextencoderdecoder@1.0.22)(tslib@2.8.1)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@trezor/type-utils': 1.1.5 + '@trezor/utxo-lib': 2.3.3(tslib@2.8.1) + tslib: 2.8.1 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + - ws + '@trezor/blockchain-link-types@1.3.3(fastestsmallesttextencoderdecoder@1.0.22)(tslib@2.8.1)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) @@ -33378,6 +33743,35 @@ snapshots: - expo-localization - react-native + '@trezor/blockchain-link@2.4.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@everstake/wallet-sdk-solana': 2.0.9(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/token': 0.5.1(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/token-2022': 0.4.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)) + '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@trezor/blockchain-link-types': 1.3.3(fastestsmallesttextencoderdecoder@1.0.22)(tslib@2.8.1)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@trezor/blockchain-link-utils': 1.3.3(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1) + '@trezor/env-utils': 1.3.2(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1) + '@trezor/utils': 9.3.3(tslib@2.8.1) + '@trezor/utxo-lib': 2.3.3(tslib@2.8.1) + '@trezor/websocket-client': 1.1.3(bufferutil@4.0.9)(tslib@2.8.1)(utf-8-validate@5.0.10) + '@types/web': 0.0.197 + events: 3.3.0 + ripple-lib: 1.10.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) + socks-proxy-agent: 8.0.5 + tslib: 2.8.1 + transitivePeerDependencies: + - '@solana/sysvars' + - bufferutil + - expo-constants + - expo-localization + - fastestsmallesttextencoderdecoder + - react-native + - supports-color + - typescript + - utf-8-validate + - ws + '@trezor/blockchain-link@2.4.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@everstake/wallet-sdk-solana': 2.0.9(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) @@ -33426,6 +33820,25 @@ snapshots: - expo-localization - react-native + '@trezor/connect-web@9.5.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@trezor/connect': 9.5.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@trezor/connect-common': 0.3.3(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1) + '@trezor/utils': 9.3.3(tslib@2.8.1) + tslib: 2.8.1 + transitivePeerDependencies: + - '@solana/sysvars' + - bufferutil + - encoding + - expo-constants + - expo-localization + - fastestsmallesttextencoderdecoder + - react-native + - supports-color + - typescript + - utf-8-validate + - ws + '@trezor/connect-web@9.5.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@trezor/connect': 9.5.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) @@ -33445,6 +33858,50 @@ snapshots: - utf-8-validate - ws + '@trezor/connect@9.5.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@ethereumjs/common': 4.4.0 + '@ethereumjs/tx': 5.4.0 + '@fivebinaries/coin-selection': 3.0.0 + '@mobily/ts-belt': 3.13.1 + '@noble/hashes': 1.7.1 + '@scure/bip39': 1.5.4 + '@solana-program/compute-budget': 0.7.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/system': 0.7.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/token': 0.5.1(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/token-2022': 0.4.0(@solana/kit@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)) + '@solana/kit': 2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@trezor/blockchain-link': 2.4.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@trezor/blockchain-link-types': 1.3.3(fastestsmallesttextencoderdecoder@1.0.22)(tslib@2.8.1)(typescript@5.8.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@trezor/blockchain-link-utils': 1.3.3(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1) + '@trezor/connect-analytics': 1.3.2(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1) + '@trezor/connect-common': 0.3.3(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1) + '@trezor/crypto-utils': 1.1.2(tslib@2.8.1) + '@trezor/device-utils': 1.0.2 + '@trezor/protobuf': 1.3.3(tslib@2.8.1) + '@trezor/protocol': 1.2.5(tslib@2.8.1) + '@trezor/schema-utils': 1.3.2(tslib@2.8.1) + '@trezor/transport': 1.4.3(encoding@0.1.13)(tslib@2.8.1) + '@trezor/utils': 9.3.3(tslib@2.8.1) + '@trezor/utxo-lib': 2.3.3(tslib@2.8.1) + blakejs: 1.2.1 + bs58: 6.0.0 + bs58check: 4.0.0 + cross-fetch: 4.1.0(encoding@0.1.13) + tslib: 2.8.1 + transitivePeerDependencies: + - '@solana/sysvars' + - bufferutil + - encoding + - expo-constants + - expo-localization + - fastestsmallesttextencoderdecoder + - react-native + - supports-color + - typescript + - utf-8-validate + - ws + '@trezor/connect@9.5.3(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.78.1(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.0.11)(bufferutil@4.0.9)(react@19.0.0)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@ethereumjs/common': 4.4.0 @@ -42082,6 +42539,24 @@ snapshots: filelist: 1.0.4 minimatch: 3.1.2 + jayson@4.1.3: + dependencies: + '@types/connect': 3.4.38 + '@types/node': 12.20.55 + '@types/ws': 7.4.7 + JSONStream: 1.3.5 + commander: 2.20.3 + delay: 5.0.0 + es6-promisify: 5.0.0 + eyes: 0.1.8 + isomorphic-ws: 4.0.1(ws@7.5.10(bufferutil@4.0.7)(utf-8-validate@6.0.3)) + json-stringify-safe: 5.0.1 + uuid: 8.3.2 + ws: 7.5.10(bufferutil@4.0.7)(utf-8-validate@6.0.3) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + jayson@4.1.3(bufferutil@4.0.7)(utf-8-validate@6.0.3): dependencies: '@types/connect': 3.4.38 diff --git a/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol b/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol index 56de5e4a54..67e1153ed8 100644 --- a/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol +++ b/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol @@ -9,7 +9,7 @@ import "@pythnetwork/entropy-sdk-solidity/EntropyEvents.sol"; import "@pythnetwork/entropy-sdk-solidity/IEntropy.sol"; import "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol"; import "@openzeppelin/contracts/utils/math/SafeCast.sol"; -import "ExcessivelySafeCall/ExcessivelySafeCall.sol"; +import "@nomad-xyz/excessively-safe-call/src/ExcessivelySafeCall.sol"; import "./EntropyState.sol"; // Entropy implements a secure 2-party random number generation procedure. The protocol @@ -500,7 +500,6 @@ abstract contract Entropy is IEntropy, EntropyState { bytes memory ret; (success, ret) = callAddress.excessivelySafeCall( gasleft(), // TODO: providers need to be able to configure this in the future. - 0, 256, // copy at most 256 bytes of the return value into ret. abi.encodeWithSelector( IEntropyConsumer._entropyCallback.selector, diff --git a/target_chains/ethereum/contracts/forge-test/Entropy.t.sol b/target_chains/ethereum/contracts/forge-test/Entropy.t.sol index 1b23939dd5..5c1981f52d 100644 --- a/target_chains/ethereum/contracts/forge-test/Entropy.t.sol +++ b/target_chains/ethereum/contracts/forge-test/Entropy.t.sol @@ -972,10 +972,6 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { uint64 assignedSequenceNumber = consumer.requestEntropy{value: fee}( userRandomNumber ); - EntropyStructs.Request memory req = random.getRequest( - provider1, - assignedSequenceNumber - ); // On the first attempt, the transaction should succeed and emit CallbackFailed event. bytes memory revertReason = abi.encodeWithSelector( @@ -1350,9 +1346,7 @@ contract EntropyConsumer is IEntropyConsumer { // Keep consuming gas until we reach our target while (currentGasUsed < targetGasUsage) { // Consume gas with a hash operation - bytes32 hash = keccak256( - abi.encodePacked(currentGasUsed, _randomness) - ); + keccak256(abi.encodePacked(currentGasUsed, _randomness)); currentGasUsed = startGas - gasleft(); } diff --git a/target_chains/ethereum/contracts/package.json b/target_chains/ethereum/contracts/package.json index fd9800ac03..814972bb7e 100644 --- a/target_chains/ethereum/contracts/package.json +++ b/target_chains/ethereum/contracts/package.json @@ -23,7 +23,7 @@ "migrate": "truffle migrate", "receiver-submit-guardian-sets": "truffle exec scripts/receiverSubmitGuardianSetUpgrades.js", "verify": "truffle run verify $npm_config_module@$npm_config_contract_address --network $npm_config_network", - "install-forge-deps": "forge install foundry-rs/forge-std@v1.7.6 nomad-xyz/ExcessivelySafeCall@81cd99c --no-git --no-commit", + "install-forge-deps": "forge install foundry-rs/forge-std@v1.7.6 --no-git --no-commit", "coverage": "./coverage.sh", "test:format": "prettier --check .", "fix:format": "prettier --write ." @@ -39,6 +39,7 @@ "@openzeppelin/contracts": "=4.8.1", "@openzeppelin/contracts-upgradeable": "=4.8.1", "@openzeppelin/hardhat-upgrades": "^1.22.1", + "@nomad-xyz/excessively-safe-call": "^0.0.1-rc.1", "@pythnetwork/contract-manager": "workspace:*", "@pythnetwork/entropy-sdk-solidity": "workspace:*", "@pythnetwork/pyth-sdk-solidity": "workspace:*", diff --git a/target_chains/ethereum/contracts/remappings.txt b/target_chains/ethereum/contracts/remappings.txt index a6ccbf917d..88dbecf8b1 100644 --- a/target_chains/ethereum/contracts/remappings.txt +++ b/target_chains/ethereum/contracts/remappings.txt @@ -3,5 +3,5 @@ @pythnetwork/=./node_modules/@pythnetwork/ ds-test/=lib/forge-std/lib/ds-test/src/ forge-std/=lib/forge-std/src/ -ExcessivelySafeCall=lib/ExcessivelySafeCall/src/ +@nomad-xyz=./node_modules/@nomad-xyz/ truffle/=./node_modules/truffle/ diff --git a/target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol b/target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol index 84432d43e8..e80ba086b9 100644 --- a/target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol +++ b/target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: Apache 2 + library EntropyConstants { // Status values for Request.status // // not a request with callback From 24e5a55ede8486f41f2e832b08c83663c8e7b1e9 Mon Sep 17 00:00:00 2001 From: Jayant Krishnamurthy Date: Thu, 3 Apr 2025 11:27:56 -0700 Subject: [PATCH 6/9] stuff --- .../contracts/contracts/entropy/Entropy.sol | 22 +++++++++---------- .../contracts/forge-test/Entropy.t.sol | 8 +++---- .../entropy_sdk/solidity/EntropyConstants.sol | 10 ++++----- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol b/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol index 67e1153ed8..bb70ac74d2 100644 --- a/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol +++ b/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.0; import "@pythnetwork/entropy-sdk-solidity/EntropyStructs.sol"; -import "@pythnetwork/entropy-sdk-solidity/EntropyConstants.sol"; import "@pythnetwork/entropy-sdk-solidity/EntropyErrors.sol"; import "@pythnetwork/entropy-sdk-solidity/EntropyEvents.sol"; import "@pythnetwork/entropy-sdk-solidity/IEntropy.sol"; @@ -11,6 +10,7 @@ import "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol"; import "@openzeppelin/contracts/utils/math/SafeCast.sol"; import "@nomad-xyz/excessively-safe-call/src/ExcessivelySafeCall.sol"; import "./EntropyState.sol"; +import "@pythnetwork/entropy-sdk-solidity/EntropyStatusConstants.sol"; // Entropy implements a secure 2-party random number generation procedure. The protocol // is an extension of a simple commit/reveal protocol. The original version has the following steps: @@ -252,8 +252,8 @@ abstract contract Entropy is IEntropy, EntropyState { req.blockNumber = SafeCast.toUint64(block.number); req.useBlockhash = useBlockhash; req.status = isRequestWithCallback - ? EntropyConstants.STATUS_CALLBACK_NOT_STARTED - : EntropyConstants.STATUS_NO_CALLBACK; + ? EntropyStatusConstants.CALLBACK_NOT_STARTED + : EntropyStatusConstants.CALLBACK_NOT_NECESSARY; } // As a user, request a random number from `provider`. Prior to calling this method, the user should @@ -409,7 +409,7 @@ abstract contract Entropy is IEntropy, EntropyState { } // Fulfill a request for a random number. This method validates the provided userRandomness and provider's proof - // against the corresponding commitments in the in-flight request. If both values are validated, this function returns + // against the corresponding commitments in the in-flight request. If both values are validated, this method returns // the corresponding random number. // // Note that this function can only be called once per in-flight request. Calling this function deletes the stored @@ -429,7 +429,7 @@ abstract contract Entropy is IEntropy, EntropyState { sequenceNumber ); - if (req.status != EntropyConstants.STATUS_NO_CALLBACK) { + if (req.status != EntropyStatusConstants.CALLBACK_NOT_NECESSARY) { revert EntropyErrors.InvalidRevealCall(); } @@ -474,8 +474,8 @@ abstract contract Entropy is IEntropy, EntropyState { ); if ( - !(req.status == EntropyConstants.STATUS_CALLBACK_NOT_STARTED || - req.status == EntropyConstants.STATUS_CALLBACK_FAILED) + !(req.status == EntropyStatusConstants.CALLBACK_NOT_STARTED || + req.status == EntropyStatusConstants.CALLBACK_FAILED) ) { revert EntropyErrors.InvalidRevealCall(); } @@ -494,8 +494,8 @@ abstract contract Entropy is IEntropy, EntropyState { // any reverts will be reported as an event. Any failing requests move to a failure state // at which point they can be recovered. The recovery flow invokes the callback directly // (no catching errors) which allows callers to easily see the revert reason. - if (req.status == EntropyConstants.STATUS_CALLBACK_NOT_STARTED) { - req.status = EntropyConstants.STATUS_CALLBACK_IN_PROGRESS; + if (req.status == EntropyStatusConstants.CALLBACK_NOT_STARTED) { + req.status = EntropyStatusConstants.CALLBACK_IN_PROGRESS; bool success; bytes memory ret; (success, ret) = callAddress.excessivelySafeCall( @@ -509,7 +509,7 @@ abstract contract Entropy is IEntropy, EntropyState { ) ); // Reset status to not started here in case the transaction reverts. - req.status = EntropyConstants.STATUS_CALLBACK_NOT_STARTED; + req.status = EntropyStatusConstants.CALLBACK_NOT_STARTED; if (success) { emit RevealedWithCallback( @@ -530,7 +530,7 @@ abstract contract Entropy is IEntropy, EntropyState { randomNumber, ret ); - req.status = EntropyConstants.STATUS_CALLBACK_FAILED; + req.status = EntropyStatusConstants.CALLBACK_FAILED; } else { // The callback ran out of gas // TODO: this case will go away once we add provider gas limits, so we're not putting in a custom error type. diff --git a/target_chains/ethereum/contracts/forge-test/Entropy.t.sol b/target_chains/ethereum/contracts/forge-test/Entropy.t.sol index 5c1981f52d..d1fb14f264 100644 --- a/target_chains/ethereum/contracts/forge-test/Entropy.t.sol +++ b/target_chains/ethereum/contracts/forge-test/Entropy.t.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.0; import "forge-std/Test.sol"; -import "@pythnetwork/entropy-sdk-solidity/EntropyConstants.sol"; import "@pythnetwork/entropy-sdk-solidity/EntropyStructs.sol"; import "@pythnetwork/entropy-sdk-solidity/EntropyEvents.sol"; import "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol"; @@ -11,6 +10,7 @@ import "@pythnetwork/entropy-sdk-solidity/IEntropy.sol"; import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import "./utils/EntropyTestUtils.t.sol"; import "../contracts/entropy/EntropyUpgradable.sol"; +import "@pythnetwork/entropy-sdk-solidity/EntropyStatusConstants.sol"; // TODO // - fuzz test? @@ -805,7 +805,7 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { blockNumber: 1234, requester: user1, useBlockhash: false, - status: EntropyConstants.STATUS_CALLBACK_NOT_STARTED + status: EntropyStatusConstants.CALLBACK_NOT_STARTED }) ); vm.roll(1234); @@ -1006,7 +1006,7 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { ); assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber); assertTrue( - reqAfterFailure.status == EntropyConstants.STATUS_CALLBACK_FAILED + reqAfterFailure.status == EntropyStatusConstants.CALLBACK_FAILED ); // On the second attempt, the transaction should directly revert @@ -1022,7 +1022,7 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { reqAfterFailure = random.getRequest(provider1, assignedSequenceNumber); assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber); assertTrue( - reqAfterFailure.status == EntropyConstants.STATUS_CALLBACK_FAILED + reqAfterFailure.status == EntropyStatusConstants.CALLBACK_FAILED ); // If the callback starts succeeding, we can invoke it and it emits the usual RevealedWithCallback event. diff --git a/target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol b/target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol index e80ba086b9..cace177264 100644 --- a/target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol +++ b/target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: Apache 2 -library EntropyConstants { +library EntropyStatusConstants { // Status values for Request.status // // not a request with callback - uint8 public constant STATUS_NO_CALLBACK = 0; + uint8 public constant CALLBACK_NOT_NECESSARY = 0; // A request with callback where the callback hasn't been invoked yet. - uint8 public constant STATUS_CALLBACK_NOT_STARTED = 1; + uint8 public constant CALLBACK_NOT_STARTED = 1; // A request with callback where the callback is currently in flight (this state is a reentry guard). - uint8 public constant STATUS_CALLBACK_IN_PROGRESS = 2; + uint8 public constant CALLBACK_IN_PROGRESS = 2; // A request with callback where the callback has been invoked and failed. - uint8 public constant STATUS_CALLBACK_FAILED = 3; + uint8 public constant CALLBACK_FAILED = 3; } From f99040dce0dd27d4b09a89bbe93fdb77f6cc0ce2 Mon Sep 17 00:00:00 2001 From: Jayant Krishnamurthy Date: Thu, 3 Apr 2025 11:35:59 -0700 Subject: [PATCH 7/9] pnpm conf --- pnpm-lock.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 61174df6e5..9321483a36 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2351,6 +2351,9 @@ importers: '@matterlabs/hardhat-zksync-solc': specifier: ^0.3.14 version: 0.3.17(encoding@0.1.13)(hardhat@2.22.19(bufferutil@4.0.7)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2))(typescript@5.8.2)(utf-8-validate@6.0.3)) + '@nomad-xyz/excessively-safe-call': + specifier: ^0.0.1-rc.1 + version: 0.0.1-rc.1 '@nomiclabs/hardhat-etherscan': specifier: ^3.1.7 version: 3.1.8(hardhat@2.22.19(bufferutil@4.0.7)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2))(typescript@5.8.2)(utf-8-validate@6.0.3)) @@ -6085,6 +6088,9 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} + '@nomad-xyz/excessively-safe-call@0.0.1-rc.1': + resolution: {integrity: sha512-Q5GVakBy8J1kWjydH6W5LNbkYY+Cw2doBiLodOfbFGujeng6zM+EtMLb/V+vkWbskbM81y2r+LG5NmxsxyElPA==} + '@nomicfoundation/edr-darwin-arm64@0.8.0': resolution: {integrity: sha512-sKTmOu/P5YYhxT0ThN2Pe3hmCE/5Ag6K/eYoiavjLWbR7HEb5ZwPu2rC3DpuUk1H+UKJqt7o4/xIgJxqw9wu6A==} engines: {node: '>= 18'} @@ -28245,6 +28251,8 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} + '@nomad-xyz/excessively-safe-call@0.0.1-rc.1': {} + '@nomicfoundation/edr-darwin-arm64@0.8.0': {} '@nomicfoundation/edr-darwin-x64@0.8.0': {} From c7703b17fe08743e0c8b90ede9a3d63f376f3ff5 Mon Sep 17 00:00:00 2001 From: Jayant Krishnamurthy Date: Thu, 3 Apr 2025 11:40:25 -0700 Subject: [PATCH 8/9] move file --- .../solidity/{EntropyConstants.sol => EntropyStatusConstants.sol} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename target_chains/ethereum/entropy_sdk/solidity/{EntropyConstants.sol => EntropyStatusConstants.sol} (100%) diff --git a/target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol b/target_chains/ethereum/entropy_sdk/solidity/EntropyStatusConstants.sol similarity index 100% rename from target_chains/ethereum/entropy_sdk/solidity/EntropyConstants.sol rename to target_chains/ethereum/entropy_sdk/solidity/EntropyStatusConstants.sol From 4d2aaca94f550152a9fdec6f568654dc183cbca4 Mon Sep 17 00:00:00 2001 From: Jayant Krishnamurthy Date: Thu, 3 Apr 2025 11:44:06 -0700 Subject: [PATCH 9/9] refactor status flag --- .../contracts/contracts/entropy/Entropy.sol | 19 +++++++++++-------- .../contracts/forge-test/Entropy.t.sol | 8 +++++--- .../entropy_sdk/solidity/EntropyStructs.sol | 2 +- .../solidity/abis/EntropyEvents.json | 8 ++++---- .../entropy_sdk/solidity/abis/IEntropy.json | 10 +++++----- 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol b/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol index bb70ac74d2..589fa7eeee 100644 --- a/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol +++ b/target_chains/ethereum/contracts/contracts/entropy/Entropy.sol @@ -251,7 +251,7 @@ abstract contract Entropy is IEntropy, EntropyState { req.blockNumber = SafeCast.toUint64(block.number); req.useBlockhash = useBlockhash; - req.status = isRequestWithCallback + req.callbackStatus = isRequestWithCallback ? EntropyStatusConstants.CALLBACK_NOT_STARTED : EntropyStatusConstants.CALLBACK_NOT_NECESSARY; } @@ -429,7 +429,9 @@ abstract contract Entropy is IEntropy, EntropyState { sequenceNumber ); - if (req.status != EntropyStatusConstants.CALLBACK_NOT_NECESSARY) { + if ( + req.callbackStatus != EntropyStatusConstants.CALLBACK_NOT_NECESSARY + ) { revert EntropyErrors.InvalidRevealCall(); } @@ -474,8 +476,9 @@ abstract contract Entropy is IEntropy, EntropyState { ); if ( - !(req.status == EntropyStatusConstants.CALLBACK_NOT_STARTED || - req.status == EntropyStatusConstants.CALLBACK_FAILED) + !(req.callbackStatus == + EntropyStatusConstants.CALLBACK_NOT_STARTED || + req.callbackStatus == EntropyStatusConstants.CALLBACK_FAILED) ) { revert EntropyErrors.InvalidRevealCall(); } @@ -494,8 +497,8 @@ abstract contract Entropy is IEntropy, EntropyState { // any reverts will be reported as an event. Any failing requests move to a failure state // at which point they can be recovered. The recovery flow invokes the callback directly // (no catching errors) which allows callers to easily see the revert reason. - if (req.status == EntropyStatusConstants.CALLBACK_NOT_STARTED) { - req.status = EntropyStatusConstants.CALLBACK_IN_PROGRESS; + if (req.callbackStatus == EntropyStatusConstants.CALLBACK_NOT_STARTED) { + req.callbackStatus = EntropyStatusConstants.CALLBACK_IN_PROGRESS; bool success; bytes memory ret; (success, ret) = callAddress.excessivelySafeCall( @@ -509,7 +512,7 @@ abstract contract Entropy is IEntropy, EntropyState { ) ); // Reset status to not started here in case the transaction reverts. - req.status = EntropyStatusConstants.CALLBACK_NOT_STARTED; + req.callbackStatus = EntropyStatusConstants.CALLBACK_NOT_STARTED; if (success) { emit RevealedWithCallback( @@ -530,7 +533,7 @@ abstract contract Entropy is IEntropy, EntropyState { randomNumber, ret ); - req.status = EntropyStatusConstants.CALLBACK_FAILED; + req.callbackStatus = EntropyStatusConstants.CALLBACK_FAILED; } else { // The callback ran out of gas // TODO: this case will go away once we add provider gas limits, so we're not putting in a custom error type. diff --git a/target_chains/ethereum/contracts/forge-test/Entropy.t.sol b/target_chains/ethereum/contracts/forge-test/Entropy.t.sol index d1fb14f264..720fd092d0 100644 --- a/target_chains/ethereum/contracts/forge-test/Entropy.t.sol +++ b/target_chains/ethereum/contracts/forge-test/Entropy.t.sol @@ -805,7 +805,7 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { blockNumber: 1234, requester: user1, useBlockhash: false, - status: EntropyStatusConstants.CALLBACK_NOT_STARTED + callbackStatus: EntropyStatusConstants.CALLBACK_NOT_STARTED }) ); vm.roll(1234); @@ -1006,7 +1006,8 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { ); assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber); assertTrue( - reqAfterFailure.status == EntropyStatusConstants.CALLBACK_FAILED + reqAfterFailure.callbackStatus == + EntropyStatusConstants.CALLBACK_FAILED ); // On the second attempt, the transaction should directly revert @@ -1022,7 +1023,8 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents { reqAfterFailure = random.getRequest(provider1, assignedSequenceNumber); assertEq(reqAfterFailure.sequenceNumber, assignedSequenceNumber); assertTrue( - reqAfterFailure.status == EntropyStatusConstants.CALLBACK_FAILED + reqAfterFailure.callbackStatus == + EntropyStatusConstants.CALLBACK_FAILED ); // If the callback starts succeeding, we can invoke it and it emits the usual RevealedWithCallback event. diff --git a/target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol b/target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol index df75b918f9..c0092ff1c6 100644 --- a/target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol +++ b/target_chains/ethereum/entropy_sdk/solidity/EntropyStructs.sol @@ -60,7 +60,7 @@ contract EntropyStructs { // If true, incorporate the blockhash of blockNumber into the generated random value. bool useBlockhash; // Status flag for requests with callbacks. See EntropyConstants for the possible values of this flag. - uint8 status; + uint8 callbackStatus; // 2 bytes of space left in this struct. } } diff --git a/target_chains/ethereum/entropy_sdk/solidity/abis/EntropyEvents.json b/target_chains/ethereum/entropy_sdk/solidity/abis/EntropyEvents.json index fcaa57e695..164c3d4b19 100644 --- a/target_chains/ethereum/entropy_sdk/solidity/abis/EntropyEvents.json +++ b/target_chains/ethereum/entropy_sdk/solidity/abis/EntropyEvents.json @@ -265,7 +265,7 @@ }, { "internalType": "uint8", - "name": "status", + "name": "callbackStatus", "type": "uint8" } ], @@ -344,7 +344,7 @@ }, { "internalType": "uint8", - "name": "status", + "name": "callbackStatus", "type": "uint8" } ], @@ -399,7 +399,7 @@ }, { "internalType": "uint8", - "name": "status", + "name": "callbackStatus", "type": "uint8" } ], @@ -478,7 +478,7 @@ }, { "internalType": "uint8", - "name": "status", + "name": "callbackStatus", "type": "uint8" } ], diff --git a/target_chains/ethereum/entropy_sdk/solidity/abis/IEntropy.json b/target_chains/ethereum/entropy_sdk/solidity/abis/IEntropy.json index 61611db0af..1c6de9d2d3 100644 --- a/target_chains/ethereum/entropy_sdk/solidity/abis/IEntropy.json +++ b/target_chains/ethereum/entropy_sdk/solidity/abis/IEntropy.json @@ -265,7 +265,7 @@ }, { "internalType": "uint8", - "name": "status", + "name": "callbackStatus", "type": "uint8" } ], @@ -344,7 +344,7 @@ }, { "internalType": "uint8", - "name": "status", + "name": "callbackStatus", "type": "uint8" } ], @@ -399,7 +399,7 @@ }, { "internalType": "uint8", - "name": "status", + "name": "callbackStatus", "type": "uint8" } ], @@ -478,7 +478,7 @@ }, { "internalType": "uint8", - "name": "status", + "name": "callbackStatus", "type": "uint8" } ], @@ -785,7 +785,7 @@ }, { "internalType": "uint8", - "name": "status", + "name": "callbackStatus", "type": "uint8" } ],