Parcourir la source

Merge branch 'main' of github.com:pyth-network/pyth-crosschain into mike/agent-jrpc-id

Mike Rolish il y a 1 mois
Parent
commit
e6768c8c21

+ 8 - 8
Cargo.lock

@@ -5674,8 +5674,8 @@ dependencies = [
  "hyper 1.6.0",
  "hyper-util",
  "protobuf",
- "pyth-lazer-protocol 0.18.1",
- "pyth-lazer-publisher-sdk 0.16.1",
+ "pyth-lazer-protocol 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pyth-lazer-publisher-sdk 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "reqwest 0.12.23",
  "serde",
  "serde_json",
@@ -5693,7 +5693,7 @@ dependencies = [
 
 [[package]]
 name = "pyth-lazer-client"
-version = "8.4.0"
+version = "8.4.1"
 dependencies = [
  "alloy-primitives 0.8.25",
  "anyhow",
@@ -5711,7 +5711,7 @@ dependencies = [
  "hex",
  "humantime-serde",
  "libsecp256k1 0.7.2",
- "pyth-lazer-protocol 0.18.0",
+ "pyth-lazer-protocol 0.18.1",
  "reqwest 0.12.23",
  "serde",
  "serde_json",
@@ -5725,7 +5725,7 @@ dependencies = [
 
 [[package]]
 name = "pyth-lazer-protocol"
-version = "0.18.0"
+version = "0.18.1"
 dependencies = [
  "alloy-primitives 0.8.25",
  "anyhow",
@@ -5772,13 +5772,13 @@ dependencies = [
 
 [[package]]
 name = "pyth-lazer-publisher-sdk"
-version = "0.16.0"
+version = "0.16.1"
 dependencies = [
  "anyhow",
  "fs-err",
  "protobuf",
  "protobuf-codegen",
- "pyth-lazer-protocol 0.18.0",
+ "pyth-lazer-protocol 0.18.1",
  "serde_json",
 ]
 
@@ -5792,7 +5792,7 @@ dependencies = [
  "fs-err",
  "protobuf",
  "protobuf-codegen",
- "pyth-lazer-protocol 0.18.1",
+ "pyth-lazer-protocol 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json",
 ]
 

+ 1 - 1
lazer/contracts/solana/programs/pyth-lazer-solana-contract/Cargo.toml

@@ -19,7 +19,7 @@ no-log-ix-name = []
 idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
-pyth-lazer-protocol = { path = "../../../../sdk/rust/protocol", version = "0.18.0" }
+pyth-lazer-protocol = { path = "../../../../sdk/rust/protocol", version = "0.18.1" }
 
 anchor-lang = "0.31.1"
 bytemuck = { version = "1.20.0", features = ["derive"] }

+ 2 - 2
lazer/publisher_sdk/rust/Cargo.toml

@@ -1,13 +1,13 @@
 [package]
 name = "pyth-lazer-publisher-sdk"
-version = "0.16.0"
+version = "0.16.1"
 edition = "2021"
 description = "Pyth Lazer Publisher SDK types."
 license = "Apache-2.0"
 repository = "https://github.com/pyth-network/pyth-crosschain"
 
 [dependencies]
-pyth-lazer-protocol = { version = "0.18.0", path = "../../sdk/rust/protocol" }
+pyth-lazer-protocol = { version = "0.18.1", path = "../../sdk/rust/protocol" }
 anyhow = "1.0.98"
 protobuf = "3.7.2"
 serde_json = "1.0.140"

+ 2 - 2
lazer/sdk/rust/client/Cargo.toml

@@ -1,12 +1,12 @@
 [package]
 name = "pyth-lazer-client"
-version = "8.4.0"
+version = "8.4.1"
 edition = "2021"
 description = "A Rust client for Pyth Lazer"
 license = "Apache-2.0"
 
 [dependencies]
-pyth-lazer-protocol = { path = "../protocol", version = "0.18.0" }
+pyth-lazer-protocol = { path = "../protocol", version = "0.18.1" }
 tokio = { version = "1", features = ["full"] }
 tokio-tungstenite = { version = "0.20", features = ["native-tls"] }
 futures-util = "0.3"

+ 1 - 1
lazer/sdk/rust/protocol/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "pyth-lazer-protocol"
-version = "0.18.0"
+version = "0.18.1"
 edition = "2021"
 description = "Pyth Lazer SDK - protocol types."
 license = "Apache-2.0"

+ 1 - 1
lazer/sdk/rust/protocol/src/jrpc.rs

@@ -6,7 +6,7 @@ use crate::{api::Channel, price::Price};
 use serde::{Deserialize, Serialize};
 use std::time::Duration;
 
-#[derive(Serialize, Deserialize, Debug, Default, Eq, PartialEq)]
+#[derive(Serialize, Deserialize, Clone, Debug, Default, Eq, PartialEq)]
 #[serde(untagged)]
 pub enum JrpcId {
     String(String),

+ 246 - 0
target_chains/ethereum/contracts/test/MockEntropy.t.sol

@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: Apache 2
+pragma solidity ^0.8.0;
+
+import "forge-std/Test.sol";
+import "@pythnetwork/entropy-sdk-solidity/MockEntropy.sol";
+import "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol";
+import "@pythnetwork/entropy-sdk-solidity/EntropyStructsV2.sol";
+
+contract MockEntropyConsumer is IEntropyConsumer {
+    address public entropy;
+    bytes32 public lastRandomNumber;
+    uint64 public lastSequenceNumber;
+    address public lastProvider;
+    uint256 public callbackCount;
+
+    constructor(address _entropy) {
+        entropy = _entropy;
+    }
+
+    function requestRandomNumber() external payable returns (uint64) {
+        return MockEntropy(entropy).requestV2{value: msg.value}();
+    }
+
+    function requestRandomNumberWithGasLimit(
+        uint32 gasLimit
+    ) external payable returns (uint64) {
+        return MockEntropy(entropy).requestV2{value: msg.value}(gasLimit);
+    }
+
+    function requestRandomNumberFromProvider(
+        address provider,
+        uint32 gasLimit
+    ) external payable returns (uint64) {
+        return
+            MockEntropy(entropy).requestV2{value: msg.value}(
+                provider,
+                gasLimit
+            );
+    }
+
+    function getEntropy() internal view override returns (address) {
+        return entropy;
+    }
+
+    function entropyCallback(
+        uint64 sequenceNumber,
+        address provider,
+        bytes32 randomNumber
+    ) internal override {
+        lastSequenceNumber = sequenceNumber;
+        lastProvider = provider;
+        lastRandomNumber = randomNumber;
+        callbackCount += 1;
+    }
+}
+
+contract MockEntropyTest is Test {
+    MockEntropy public entropy;
+    MockEntropyConsumer public consumer;
+    address public provider;
+
+    function setUp() public {
+        provider = address(0x1234);
+        entropy = new MockEntropy(provider);
+        consumer = new MockEntropyConsumer(address(entropy));
+    }
+
+    function testBasicRequestAndReveal() public {
+        uint64 seq = consumer.requestRandomNumber();
+        assertEq(seq, 1, "Sequence number should be 1");
+
+        bytes32 randomNumber = bytes32(uint256(42));
+        entropy.mockReveal(provider, seq, randomNumber);
+
+        assertEq(
+            consumer.lastSequenceNumber(),
+            seq,
+            "Callback sequence number mismatch"
+        );
+        assertEq(
+            consumer.lastProvider(),
+            provider,
+            "Callback provider mismatch"
+        );
+        assertEq(
+            consumer.lastRandomNumber(),
+            randomNumber,
+            "Random number mismatch"
+        );
+        assertEq(consumer.callbackCount(), 1, "Callback should be called once");
+    }
+
+    function testDifferentInterleavings() public {
+        uint64 seq1 = consumer.requestRandomNumber();
+        uint64 seq2 = consumer.requestRandomNumber();
+        uint64 seq3 = consumer.requestRandomNumber();
+
+        assertEq(seq1, 1, "First sequence should be 1");
+        assertEq(seq2, 2, "Second sequence should be 2");
+        assertEq(seq3, 3, "Third sequence should be 3");
+
+        bytes32 random2 = bytes32(uint256(200));
+        bytes32 random3 = bytes32(uint256(300));
+        bytes32 random1 = bytes32(uint256(100));
+
+        entropy.mockReveal(provider, seq2, random2);
+        assertEq(
+            consumer.lastRandomNumber(),
+            random2,
+            "Should reveal seq2 first"
+        );
+        assertEq(consumer.lastSequenceNumber(), seq2, "Sequence should be 2");
+
+        entropy.mockReveal(provider, seq3, random3);
+        assertEq(
+            consumer.lastRandomNumber(),
+            random3,
+            "Should reveal seq3 second"
+        );
+        assertEq(consumer.lastSequenceNumber(), seq3, "Sequence should be 3");
+
+        entropy.mockReveal(provider, seq1, random1);
+        assertEq(
+            consumer.lastRandomNumber(),
+            random1,
+            "Should reveal seq1 last"
+        );
+        assertEq(consumer.lastSequenceNumber(), seq1, "Sequence should be 1");
+
+        assertEq(
+            consumer.callbackCount(),
+            3,
+            "All three callbacks should be called"
+        );
+    }
+
+    function testDifferentProviders() public {
+        address provider2 = address(0x5678);
+
+        uint64 seq1 = consumer.requestRandomNumberFromProvider(
+            provider,
+            100000
+        );
+        uint64 seq2 = consumer.requestRandomNumberFromProvider(
+            provider2,
+            100000
+        );
+
+        assertEq(seq1, 1, "Provider 1 first sequence should be 1");
+        assertEq(seq2, 1, "Provider 2 first sequence should be 1");
+
+        bytes32 random1 = bytes32(uint256(111));
+        bytes32 random2 = bytes32(uint256(222));
+
+        entropy.mockReveal(provider, seq1, random1);
+        assertEq(
+            consumer.lastRandomNumber(),
+            random1,
+            "First provider random number"
+        );
+
+        entropy.mockReveal(provider2, seq2, random2);
+        assertEq(
+            consumer.lastRandomNumber(),
+            random2,
+            "Second provider random number"
+        );
+    }
+
+    function testRequestWithGasLimit() public {
+        uint64 seq = consumer.requestRandomNumberWithGasLimit(200000);
+
+        assertEq(seq, 1, "Sequence should be 1");
+
+        EntropyStructsV2.Request memory req = entropy.getRequestV2(
+            provider,
+            seq
+        );
+        assertEq(req.gasLimit10k, 20, "Gas limit should be 20 (200k / 10k)");
+
+        bytes32 randomNumber = bytes32(uint256(999));
+        entropy.mockReveal(provider, seq, randomNumber);
+
+        assertEq(
+            consumer.lastRandomNumber(),
+            randomNumber,
+            "Random number should match"
+        );
+    }
+
+    function testGetProviderInfo() public {
+        EntropyStructsV2.ProviderInfo memory info = entropy.getProviderInfoV2(
+            provider
+        );
+        assertEq(info.feeInWei, 1, "Fee should be 1");
+        assertEq(
+            info.defaultGasLimit,
+            100000,
+            "Default gas limit should be 100000"
+        );
+        assertEq(info.sequenceNumber, 1, "Sequence number should start at 1");
+    }
+
+    function testGetDefaultProvider() public {
+        assertEq(
+            entropy.getDefaultProvider(),
+            provider,
+            "Default provider should match"
+        );
+    }
+
+    function testFeesReturnZero() public {
+        assertEq(entropy.getFeeV2(), 0, "getFeeV2() should return 0");
+        assertEq(
+            entropy.getFeeV2(100000),
+            0,
+            "getFeeV2(gasLimit) should return 0"
+        );
+        assertEq(
+            entropy.getFeeV2(provider, 100000),
+            0,
+            "getFeeV2(provider, gasLimit) should return 0"
+        );
+    }
+
+    function testCustomRandomNumbers() public {
+        uint64 seq = consumer.requestRandomNumber();
+
+        bytes32[] memory randomNumbers = new bytes32[](3);
+        randomNumbers[0] = bytes32(uint256(0));
+        randomNumbers[1] = bytes32(type(uint256).max);
+        randomNumbers[2] = keccak256("custom random value");
+
+        for (uint i = 0; i < randomNumbers.length; i++) {
+            if (i > 0) {
+                seq = consumer.requestRandomNumber();
+            }
+            entropy.mockReveal(provider, seq, randomNumbers[i]);
+            assertEq(
+                consumer.lastRandomNumber(),
+                randomNumbers[i],
+                "Custom random number should match"
+            );
+        }
+    }
+}

+ 171 - 0
target_chains/ethereum/entropy_sdk/solidity/MockEntropy.sol

@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: Apache 2
+pragma solidity ^0.8.0;
+
+import "./IEntropyV2.sol";
+import "./IEntropyConsumer.sol";
+import "./EntropyStructsV2.sol";
+import "./EntropyEventsV2.sol";
+
+contract MockEntropy is IEntropyV2 {
+    address public defaultProvider;
+
+    mapping(address => EntropyStructsV2.ProviderInfo) public providers;
+    mapping(address => mapping(uint64 => EntropyStructsV2.Request))
+        public requests;
+
+    constructor(address _defaultProvider) {
+        require(_defaultProvider != address(0), "Invalid default provider");
+        defaultProvider = _defaultProvider;
+
+        providers[_defaultProvider].sequenceNumber = 1;
+        providers[_defaultProvider].feeInWei = 1;
+        providers[_defaultProvider].defaultGasLimit = 100000;
+    }
+
+    function requestV2()
+        external
+        payable
+        override
+        returns (uint64 assignedSequenceNumber)
+    {
+        return _requestV2(defaultProvider, bytes32(0), 0);
+    }
+
+    function requestV2(
+        uint32 gasLimit
+    ) external payable override returns (uint64 assignedSequenceNumber) {
+        return _requestV2(defaultProvider, bytes32(0), gasLimit);
+    }
+
+    function requestV2(
+        address provider,
+        uint32 gasLimit
+    ) external payable override returns (uint64 assignedSequenceNumber) {
+        return _requestV2(provider, bytes32(0), gasLimit);
+    }
+
+    function requestV2(
+        address provider,
+        bytes32 userRandomNumber,
+        uint32 gasLimit
+    ) external payable override returns (uint64 assignedSequenceNumber) {
+        return _requestV2(provider, userRandomNumber, gasLimit);
+    }
+
+    function _requestV2(
+        address provider,
+        bytes32 userRandomNumber,
+        uint32 gasLimit
+    ) internal returns (uint64 assignedSequenceNumber) {
+        EntropyStructsV2.ProviderInfo storage providerInfo = providers[
+            provider
+        ];
+
+        if (providerInfo.sequenceNumber == 0) {
+            providerInfo.sequenceNumber = 1;
+            providerInfo.feeInWei = 1;
+            providerInfo.defaultGasLimit = 100000;
+        }
+
+        assignedSequenceNumber = providerInfo.sequenceNumber;
+        providerInfo.sequenceNumber += 1;
+
+        uint32 effectiveGasLimit = gasLimit == 0
+            ? providerInfo.defaultGasLimit
+            : gasLimit;
+
+        EntropyStructsV2.Request storage req = requests[provider][
+            assignedSequenceNumber
+        ];
+        req.provider = provider;
+        req.sequenceNumber = assignedSequenceNumber;
+        req.requester = msg.sender;
+        req.blockNumber = uint64(block.number);
+        req.useBlockhash = false;
+        req.gasLimit10k = uint16(effectiveGasLimit / 10000);
+
+        emit Requested(
+            provider,
+            msg.sender,
+            assignedSequenceNumber,
+            userRandomNumber,
+            effectiveGasLimit,
+            bytes("")
+        );
+
+        return assignedSequenceNumber;
+    }
+
+    function mockReveal(
+        address provider,
+        uint64 sequenceNumber,
+        bytes32 randomNumber
+    ) external {
+        EntropyStructsV2.Request storage req = requests[provider][
+            sequenceNumber
+        ];
+        require(req.requester != address(0), "Request not found");
+
+        address requester = req.requester;
+
+        emit Revealed(
+            provider,
+            requester,
+            sequenceNumber,
+            randomNumber,
+            bytes32(0),
+            bytes32(0),
+            false,
+            bytes(""),
+            0,
+            bytes("")
+        );
+
+        delete requests[provider][sequenceNumber];
+
+        uint256 codeSize;
+        assembly {
+            codeSize := extcodesize(requester)
+        }
+
+        if (codeSize > 0) {
+            IEntropyConsumer(requester)._entropyCallback(
+                sequenceNumber,
+                provider,
+                randomNumber
+            );
+        }
+    }
+
+    function getProviderInfoV2(
+        address provider
+    ) external view override returns (EntropyStructsV2.ProviderInfo memory) {
+        return providers[provider];
+    }
+
+    function getDefaultProvider() external view override returns (address) {
+        return defaultProvider;
+    }
+
+    function getRequestV2(
+        address provider,
+        uint64 sequenceNumber
+    ) external view override returns (EntropyStructsV2.Request memory) {
+        return requests[provider][sequenceNumber];
+    }
+
+    function getFeeV2() external pure override returns (uint128) {
+        return 0;
+    }
+
+    function getFeeV2(uint32) external pure override returns (uint128) {
+        return 0;
+    }
+
+    function getFeeV2(
+        address,
+        uint32
+    ) external pure override returns (uint128) {
+        return 0;
+    }
+}

+ 1 - 1
target_chains/ethereum/entropy_sdk/solidity/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@pythnetwork/entropy-sdk-solidity",
-  "version": "2.0.0",
+  "version": "2.1.0",
   "description": "Generate secure random numbers with Pyth Entropy",
   "type": "module",
   "repository": {