Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- PythUpgradable
- Optimization enabled
- true
- Compiler version
- v0.8.4+commit.c7e474f2
- Optimization runs
- 10000
- EVM Version
- default
- Verified at
- 2022-12-22T04:10:08.284522Z
Contract source code
/** *Submitted for verification at cronoscan.com on 2022-12-07 */ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. * * @notice This is the **unsafe** version of BytesLib which removed all the checks (out of bound, ...) * to be more gas efficient. */ library UnsafeBytesLib { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore( 0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. ) ) } return tempBytes; } function concatStorage( bytes storage _preBytes, bytes memory _postBytes ) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div( and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2 ) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add( add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)) ) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add( add( add(_bytes, lengthmod), mul(0x20, iszero(lengthmod)) ), _start ) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress( bytes memory _bytes, uint256 _start ) internal pure returns (address) { address tempAddress; assembly { tempAddress := div( mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000 ) } return tempAddress; } function toUint8( bytes memory _bytes, uint256 _start ) internal pure returns (uint8) { uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16( bytes memory _bytes, uint256 _start ) internal pure returns (uint16) { uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32( bytes memory _bytes, uint256 _start ) internal pure returns (uint32) { uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64( bytes memory _bytes, uint256 _start ) internal pure returns (uint64) { uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96( bytes memory _bytes, uint256 _start ) internal pure returns (uint96) { uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128( bytes memory _bytes, uint256 _start ) internal pure returns (uint128) { uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256( bytes memory _bytes, uint256 _start ) internal pure returns (uint256) { uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32( bytes memory _bytes, uint256 _start ) internal pure returns (bytes32) { bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div( and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2 ) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for { } eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } } contract PythStructs { // A price with a degree of uncertainty, represented as a price +- a confidence interval. // // The confidence interval roughly corresponds to the standard error of a normal distribution. // Both the price and confidence are stored in a fixed-point numeric representation, // `x * (10^expo)`, where `expo` is the exponent. // // Please refer to the documentation at https://docs.pyth.network/consumers/best-practices for how // to how this price safely. struct Price { // Price int64 price; // Confidence interval around the price uint64 conf; // Price exponent int32 expo; // Unix timestamp describing when the price was published uint publishTime; } // PriceFeed represents a current aggregate price from pyth publisher feeds. struct PriceFeed { // The price ID. bytes32 id; // Latest available price Price price; // Latest available exponentially-weighted moving average price Price emaPrice; } } /// @title IPythEvents contains the events that Pyth contract emits. /// @dev This interface can be used for listening to the updates for off-chain and testing purposes. interface IPythEvents { /// @dev Emitted when the price feed with `id` has received a fresh update. /// @param id The Pyth Price Feed ID. /// @param publishTime Publish time of the given price update. /// @param price Price of the given price update. /// @param conf Confidence interval of the given price update. event PriceFeedUpdate( bytes32 indexed id, uint64 publishTime, int64 price, uint64 conf ); /// @dev Emitted when a batch price update is processed successfully. /// @param chainId ID of the source chain that the batch price update comes from. /// @param sequenceNumber Sequence number of the batch price update. event BatchPriceFeedUpdate(uint16 chainId, uint64 sequenceNumber); } /// @title Consume prices from the Pyth Network (https://pyth.network/). /// @dev Please refer to the guidance at https://docs.pyth.network/consumers/best-practices for how to consume prices safely. /// @author Pyth Data Association interface IPyth is IPythEvents { /// @notice Returns the period (in seconds) that a price feed is considered valid since its publish time function getValidTimePeriod() external view returns (uint validTimePeriod); /// @notice Returns the price and confidence interval. /// @dev Reverts if the price has not been updated within the last `getValidTimePeriod()` seconds. /// @param id The Pyth Price Feed ID of which to fetch the price and confidence interval. /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely. function getPrice( bytes32 id ) external view returns (PythStructs.Price memory price); /// @notice Returns the exponentially-weighted moving average price and confidence interval. /// @dev Reverts if the EMA price is not available. /// @param id The Pyth Price Feed ID of which to fetch the EMA price and confidence interval. /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely. function getEmaPrice( bytes32 id ) external view returns (PythStructs.Price memory price); /// @notice Returns the price of a price feed without any sanity checks. /// @dev This function returns the most recent price update in this contract without any recency checks. /// This function is unsafe as the returned price update may be arbitrarily far in the past. /// /// Users of this function should check the `publishTime` in the price to ensure that the returned price is /// sufficiently recent for their application. If you are considering using this function, it may be /// safer / easier to use either `getPrice` or `getPriceNoOlderThan`. /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely. function getPriceUnsafe( bytes32 id ) external view returns (PythStructs.Price memory price); /// @notice Returns the price that is no older than `age` seconds of the current time. /// @dev This function is a sanity-checked version of `getPriceUnsafe` which is useful in /// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently /// recently. /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely. function getPriceNoOlderThan( bytes32 id, uint age ) external view returns (PythStructs.Price memory price); /// @notice Returns the exponentially-weighted moving average price of a price feed without any sanity checks. /// @dev This function returns the same price as `getEmaPrice` in the case where the price is available. /// However, if the price is not recent this function returns the latest available price. /// /// The returned price can be from arbitrarily far in the past; this function makes no guarantees that /// the returned price is recent or useful for any particular application. /// /// Users of this function should check the `publishTime` in the price to ensure that the returned price is /// sufficiently recent for their application. If you are considering using this function, it may be /// safer / easier to use either `getEmaPrice` or `getEmaPriceNoOlderThan`. /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely. function getEmaPriceUnsafe( bytes32 id ) external view returns (PythStructs.Price memory price); /// @notice Returns the exponentially-weighted moving average price that is no older than `age` seconds /// of the current time. /// @dev This function is a sanity-checked version of `getEmaPriceUnsafe` which is useful in /// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently /// recently. /// @return price - please read the documentation of PythStructs.Price to understand how to use this safely. function getEmaPriceNoOlderThan( bytes32 id, uint age ) external view returns (PythStructs.Price memory price); /// @notice Update price feeds with given update messages. /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling /// `getUpdateFee` with the length of the `updateData` array. /// Prices will be updated if they are more recent than the current stored prices. /// The call will succeed even if the update is not the most recent. /// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid. /// @param updateData Array of price update data. function updatePriceFeeds(bytes[] calldata updateData) external payable; /// @notice Wrapper around updatePriceFeeds that rejects fast if a price update is not necessary. A price update is /// necessary if the current on-chain publishTime is older than the given publishTime. It relies solely on the /// given `publishTimes` for the price feeds and does not read the actual price update publish time within `updateData`. /// /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling /// `getUpdateFee` with the length of the `updateData` array. /// /// `priceIds` and `publishTimes` are two arrays with the same size that correspond to senders known publishTime /// of each priceId when calling this method. If all of price feeds within `priceIds` have updated and have /// a newer or equal publish time than the given publish time, it will reject the transaction to save gas. /// Otherwise, it calls updatePriceFeeds method to update the prices. /// /// @dev Reverts if update is not needed or the transferred fee is not sufficient or the updateData is invalid. /// @param updateData Array of price update data. /// @param priceIds Array of price ids. /// @param publishTimes Array of publishTimes. `publishTimes[i]` corresponds to known `publishTime` of `priceIds[i]` function updatePriceFeedsIfNecessary( bytes[] calldata updateData, bytes32[] calldata priceIds, uint64[] calldata publishTimes ) external payable; /// @notice Returns the required fee to update an array of price updates. /// @param updateData Array of price update data. /// @return feeAmount The required fee in Wei. function getUpdateFee( bytes[] calldata updateData ) external view returns (uint feeAmount); /// @notice Parse `updateData` and return price feeds of the given `priceIds` if they are all published /// within `minPublishTime` and `maxPublishTime`. /// /// You can use this method if you want to use a Pyth price at a fixed time and not the most recent price; /// otherwise, please consider using `updatePriceFeeds`. This method does not store the price updates on-chain. /// /// This method requires the caller to pay a fee in wei; the required fee can be computed by calling /// `getUpdateFee` with the length of the `updateData` array. /// /// /// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid or there is /// no update for any of the given `priceIds` within the given time range. /// @param updateData Array of price update data. /// @param priceIds Array of price ids. /// @param minPublishTime minimum acceptable publishTime for the given `priceIds`. /// @param maxPublishTime maximum acceptable publishTime for the given `priceIds`. /// @return priceFeeds Array of the price feeds corresponding to the given `priceIds` (with the same order). function parsePriceFeedUpdates( bytes[] calldata updateData, bytes32[] calldata priceIds, uint64 minPublishTime, uint64 maxPublishTime ) external payable returns (PythStructs.PriceFeed[] memory priceFeeds); } library PythErrors { // Function arguments are invalid (e.g., the arguments lengths mismatch) error InvalidArgument(); // Update data is coming from an invalid data source. error InvalidUpdateDataSource(); // Update data is invalid (e.g., deserialization error) error InvalidUpdateData(); // Insufficient fee is paid to the method. error InsufficientFee(); // There is no fresh update, whereas expected fresh updates. error NoFreshUpdate(); // There is no price feed found within the given range or it does not exists. error PriceFeedNotFoundWithinRange(); // Price feed not found or it is not pushed on-chain yet. error PriceFeedNotFound(); // Requested price is stale. error StalePrice(); // Given message is not a valid Wormhole VAA. error InvalidWormholeVaa(); // Governance message is invalid (e.g., deserialization error). error InvalidGovernanceMessage(); // Governance message is not for this contract. error InvalidGovernanceTarget(); // Governance message is coming from an invalid data source. error InvalidGovernanceDataSource(); // Governance message is old. error OldGovernanceMessage(); } abstract contract AbstractPyth is IPyth { /// @notice Returns the price feed with given id. /// @dev Reverts if the price does not exist. /// @param id The Pyth Price Feed ID of which to fetch the PriceFeed. function queryPriceFeed( bytes32 id ) public view virtual returns (PythStructs.PriceFeed memory priceFeed); /// @notice Returns true if a price feed with the given id exists. /// @param id The Pyth Price Feed ID of which to check its existence. function priceFeedExists( bytes32 id ) public view virtual returns (bool exists); function getValidTimePeriod() public view virtual override returns (uint validTimePeriod); function getPrice( bytes32 id ) external view virtual override returns (PythStructs.Price memory price) { return getPriceNoOlderThan(id, getValidTimePeriod()); } function getEmaPrice( bytes32 id ) external view virtual override returns (PythStructs.Price memory price) { return getEmaPriceNoOlderThan(id, getValidTimePeriod()); } function getPriceUnsafe( bytes32 id ) public view virtual override returns (PythStructs.Price memory price) { PythStructs.PriceFeed memory priceFeed = queryPriceFeed(id); return priceFeed.price; } function getPriceNoOlderThan( bytes32 id, uint age ) public view virtual override returns (PythStructs.Price memory price) { price = getPriceUnsafe(id); if (diff(block.timestamp, price.publishTime) > age) revert PythErrors.StalePrice(); return price; } function getEmaPriceUnsafe( bytes32 id ) public view virtual override returns (PythStructs.Price memory price) { PythStructs.PriceFeed memory priceFeed = queryPriceFeed(id); return priceFeed.emaPrice; } function getEmaPriceNoOlderThan( bytes32 id, uint age ) public view virtual override returns (PythStructs.Price memory price) { price = getEmaPriceUnsafe(id); if (diff(block.timestamp, price.publishTime) > age) revert PythErrors.StalePrice(); return price; } function diff(uint x, uint y) internal pure returns (uint) { if (x > y) { return x - y; } else { return y - x; } } // Access modifier is overridden to public to be able to call it locally. function updatePriceFeeds( bytes[] calldata updateData ) public payable virtual override; function updatePriceFeedsIfNecessary( bytes[] calldata updateData, bytes32[] calldata priceIds, uint64[] calldata publishTimes ) external payable virtual override { if (priceIds.length != publishTimes.length) revert PythErrors.InvalidArgument(); for (uint i = 0; i < priceIds.length; i++) { if ( !priceFeedExists(priceIds[i]) || queryPriceFeed(priceIds[i]).price.publishTime < publishTimes[i] ) { updatePriceFeeds(updateData); return; } } revert PythErrors.NoFreshUpdate(); } function parsePriceFeedUpdates( bytes[] calldata updateData, bytes32[] calldata priceIds, uint64 minPublishTime, uint64 maxPublishTime ) external payable virtual override returns (PythStructs.PriceFeed[] memory priceFeeds); } // contracts/Structs.sol interface Structs { struct Provider { uint16 chainId; uint16 governanceChainId; bytes32 governanceContract; } struct GuardianSet { address[] keys; uint32 expirationTime; } struct Signature { bytes32 r; bytes32 s; uint8 v; uint8 guardianIndex; } struct VM { uint8 version; uint32 timestamp; uint32 nonce; uint16 emitterChainId; bytes32 emitterAddress; uint64 sequence; uint8 consistencyLevel; bytes payload; uint32 guardianSetIndex; Signature[] signatures; bytes32 hash; } } // contracts/Messages.sol interface IWormhole is Structs { event LogMessagePublished( address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel ); function publishMessage( uint32 nonce, bytes memory payload, uint8 consistencyLevel ) external payable returns (uint64 sequence); function parseAndVerifyVM( bytes calldata encodedVM ) external view returns (Structs.VM memory vm, bool valid, string memory reason); function verifyVM( Structs.VM memory vm ) external view returns (bool valid, string memory reason); function verifySignatures( bytes32 hash, Structs.Signature[] memory signatures, Structs.GuardianSet memory guardianSet ) external pure returns (bool valid, string memory reason); function parseVM( bytes memory encodedVM ) external pure returns (Structs.VM memory vm); function getGuardianSet( uint32 index ) external view returns (Structs.GuardianSet memory); function getCurrentGuardianSetIndex() external view returns (uint32); function getGuardianSetExpiry() external view returns (uint32); function governanceActionIsConsumed( bytes32 hash ) external view returns (bool); function isInitialized(address impl) external view returns (bool); function chainId() external view returns (uint16); function governanceChainId() external view returns (uint16); function governanceContract() external view returns (bytes32); function messageFee() external view returns (uint256); } /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ library BytesLib { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore( 0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. ) ) } return tempBytes; } function concatStorage( bytes storage _preBytes, bytes memory _postBytes ) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div( and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2 ) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add( add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)) ) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add( add( add(_bytes, lengthmod), mul(0x20, iszero(lengthmod)) ), _start ) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress( bytes memory _bytes, uint256 _start ) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div( mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000 ) } return tempAddress; } function toUint8( bytes memory _bytes, uint256 _start ) internal pure returns (uint8) { require(_bytes.length >= _start + 1, "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16( bytes memory _bytes, uint256 _start ) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32( bytes memory _bytes, uint256 _start ) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64( bytes memory _bytes, uint256 _start ) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96( bytes memory _bytes, uint256 _start ) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128( bytes memory _bytes, uint256 _start ) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256( bytes memory _bytes, uint256 _start ) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32( bytes memory _bytes, uint256 _start ) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div( and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2 ) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for { } eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } } // contracts/Structs.sol contract PythInternalStructs { using BytesLib for bytes; struct PriceInfo { // slot 1 uint64 publishTime; int32 expo; int64 price; uint64 conf; // slot 2 int64 emaPrice; uint64 emaConf; } struct DataSource { uint16 chainId; bytes32 emitterAddress; } } // contracts/PythDeprecatedStructs.sol // This contract contains self contained structs of all our deprecated structs. // When deprecating the structs, make sure that there be no dependency to // the sdk as the sdk might change. // // By storing these structs, we keep deprecated fields definitions correctly. Then, // in the future, we can use them to cleanup their storage and redeem some gas back. contract PythDeprecatedStructs { // Structs related to the _deprecatedLatestPriceInfoV1 enum DeprecatedPriceStatusV1 { UNKNOWN, TRADING, HALTED, AUCTION } struct DeprecatedPriceFeedV1 { // The price ID. bytes32 id; // Product account key. bytes32 productId; // The current price. int64 price; // Confidence interval around the price. uint64 conf; // Price exponent. int32 expo; // Status of price. DeprecatedPriceStatusV1 status; // Maximum number of allowed publishers that can contribute to a price. uint32 maxNumPublishers; // Number of publishers that made up current aggregate. uint32 numPublishers; // Exponentially moving average price. int64 emaPrice; // Exponentially moving average confidence interval. uint64 emaConf; // Unix timestamp describing when the price was published uint64 publishTime; // Price of previous price with TRADING status int64 prevPrice; // Confidence interval of previous price with TRADING status uint64 prevConf; // Unix timestamp describing when the previous price with TRADING status was published uint64 prevPublishTime; } struct DeprecatedPriceInfoV1 { uint256 attestationTime; uint256 arrivalTime; uint256 arrivalBlock; DeprecatedPriceFeedV1 priceFeed; } // Structs related to the _deprecatedLatestPriceInfoV2 struct DeprecatedPriceV2 { // Price int64 price; // Confidence interval around the price uint64 conf; // Price exponent int32 expo; // Unix timestamp describing when the price was published uint publishTime; } // PriceFeed represents a current aggregate price from pyth publisher feeds. struct DeprecatedPriceFeedV2 { // The price ID. bytes32 id; // Latest available price DeprecatedPriceV2 price; // Latest available exponentially-weighted moving average price DeprecatedPriceV2 emaPrice; } struct DeprecatedPriceInfoV2 { uint256 attestationTime; uint256 arrivalTime; uint256 arrivalBlock; DeprecatedPriceFeedV2 priceFeed; } } // contracts/State.sol contract PythStorage { struct State { address wormhole; uint16 _deprecatedPyth2WormholeChainId; // Replaced by validDataSources/isValidDataSource bytes32 _deprecatedPyth2WormholeEmitter; // Ditto // After a backward-incompatible change in PriceFeed this mapping got deprecated. mapping(bytes32 => PythDeprecatedStructs.DeprecatedPriceInfoV1) _deprecatedLatestPriceInfoV1; // For tracking all active emitter/chain ID pairs PythInternalStructs.DataSource[] validDataSources; // (chainId, emitterAddress) => isValid; takes advantage of // constant-time mapping lookup for VM verification mapping(bytes32 => bool) isValidDataSource; uint singleUpdateFeeInWei; /// Maximum acceptable time period before price is considered to be stale. /// This includes attestation delay, block time, and potential clock drift /// between the source/target chains. uint validTimePeriodSeconds; // Governance data source. VAA messages from this source can change this contract // state. e.g., upgrade the contract, change the valid data sources, and more. PythInternalStructs.DataSource governanceDataSource; // Sequence number of the last executed governance message. Any governance message // with a lower or equal sequence number will be discarded. This prevents double-execution, // and also makes sure that messages are executed in the right order. uint64 lastExecutedGovernanceSequence; // After a backward-incompatible change in PriceFeed this mapping got deprecated. mapping(bytes32 => PythDeprecatedStructs.DeprecatedPriceInfoV2) _deprecatedLatestPriceInfoV2; // Index of the governance data source, increased each time the governance data source // changes. uint32 governanceDataSourceIndex; // Mapping of cached price information // priceId => PriceInfo mapping(bytes32 => PythInternalStructs.PriceInfo) latestPriceInfo; } } contract PythState { PythStorage.State _state; } // contracts/Getters.sol contract PythGetters is PythState { function wormhole() public view returns (IWormhole) { return IWormhole(_state.wormhole); } function latestPriceInfo( bytes32 priceId ) internal view returns (PythInternalStructs.PriceInfo memory info) { return _state.latestPriceInfo[priceId]; } function latestPriceInfoPublishTime( bytes32 priceId ) public view returns (uint64) { return _state.latestPriceInfo[priceId].publishTime; } function hashDataSource( PythInternalStructs.DataSource memory ds ) public pure returns (bytes32) { return keccak256(abi.encodePacked(ds.chainId, ds.emitterAddress)); } function isValidDataSource( uint16 dataSourceChainId, bytes32 dataSourceEmitterAddress ) public view returns (bool) { return _state.isValidDataSource[ keccak256( abi.encodePacked( dataSourceChainId, dataSourceEmitterAddress ) ) ]; } function isValidGovernanceDataSource( uint16 governanceChainId, bytes32 governanceEmitterAddress ) public view returns (bool) { return _state.governanceDataSource.chainId == governanceChainId && _state.governanceDataSource.emitterAddress == governanceEmitterAddress; } function chainId() public view returns (uint16) { return wormhole().chainId(); } function lastExecutedGovernanceSequence() public view returns (uint64) { return _state.lastExecutedGovernanceSequence; } function validDataSources() public view returns (PythInternalStructs.DataSource[] memory) { return _state.validDataSources; } function governanceDataSource() public view returns (PythInternalStructs.DataSource memory) { return _state.governanceDataSource; } function singleUpdateFeeInWei() public view returns (uint) { return _state.singleUpdateFeeInWei; } function validTimePeriodSeconds() public view returns (uint) { return _state.validTimePeriodSeconds; } function governanceDataSourceIndex() public view returns (uint32) { return _state.governanceDataSourceIndex; } } // contracts/Setters.sol contract PythSetters is PythState { function setWormhole(address wh) internal { _state.wormhole = payable(wh); } function setLatestPriceInfo( bytes32 priceId, PythInternalStructs.PriceInfo memory info ) internal { _state.latestPriceInfo[priceId] = info; } function setSingleUpdateFeeInWei(uint fee) internal { _state.singleUpdateFeeInWei = fee; } function setValidTimePeriodSeconds(uint validTimePeriodSeconds) internal { _state.validTimePeriodSeconds = validTimePeriodSeconds; } function setGovernanceDataSource( PythInternalStructs.DataSource memory newDataSource ) internal { _state.governanceDataSource = newDataSource; } function setLastExecutedGovernanceSequence(uint64 sequence) internal { _state.lastExecutedGovernanceSequence = sequence; } function setGovernanceDataSourceIndex(uint32 newIndex) internal { _state.governanceDataSourceIndex = newIndex; } } // contracts/Bridge.sol abstract contract Pyth is PythGetters, PythSetters, AbstractPyth { function _initialize( address wormhole, uint16[] calldata dataSourceEmitterChainIds, bytes32[] calldata dataSourceEmitterAddresses, uint16 governanceEmitterChainId, bytes32 governanceEmitterAddress, uint64 governanceInitialSequence, uint validTimePeriodSeconds, uint singleUpdateFeeInWei ) internal { setWormhole(wormhole); if ( dataSourceEmitterChainIds.length != dataSourceEmitterAddresses.length ) revert PythErrors.InvalidArgument(); for (uint i = 0; i < dataSourceEmitterChainIds.length; i++) { PythInternalStructs.DataSource memory ds = PythInternalStructs .DataSource( dataSourceEmitterChainIds[i], dataSourceEmitterAddresses[i] ); if (PythGetters.isValidDataSource(ds.chainId, ds.emitterAddress)) revert PythErrors.InvalidArgument(); _state.isValidDataSource[hashDataSource(ds)] = true; _state.validDataSources.push(ds); } { PythInternalStructs.DataSource memory ds = PythInternalStructs .DataSource(governanceEmitterChainId, governanceEmitterAddress); PythSetters.setGovernanceDataSource(ds); PythSetters.setLastExecutedGovernanceSequence( governanceInitialSequence ); } PythSetters.setValidTimePeriodSeconds(validTimePeriodSeconds); PythSetters.setSingleUpdateFeeInWei(singleUpdateFeeInWei); } function updatePriceBatchFromVm(bytes calldata encodedVm) private { parseAndProcessBatchPriceAttestation( parseAndVerifyBatchAttestationVM(encodedVm) ); } function updatePriceFeeds( bytes[] calldata updateData ) public payable override { uint requiredFee = getUpdateFee(updateData); if (msg.value < requiredFee) revert PythErrors.InsufficientFee(); for (uint i = 0; i < updateData.length; ) { updatePriceBatchFromVm(updateData[i]); unchecked { i++; } } } /// This method is deprecated, please use the `getUpdateFee(bytes[])` instead. function getUpdateFee( uint updateDataSize ) public view returns (uint feeAmount) { return singleUpdateFeeInWei() * updateDataSize; } function getUpdateFee( bytes[] calldata updateData ) public view override returns (uint feeAmount) { return singleUpdateFeeInWei() * updateData.length; } function verifyPythVM( IWormhole.VM memory vm ) private view returns (bool valid) { return isValidDataSource(vm.emitterChainId, vm.emitterAddress); } function parseAndProcessBatchPriceAttestation( IWormhole.VM memory vm ) internal { // Most of the math operations below are simple additions. // In the places that there is more complex operation there is // a comment explaining why it is safe. Also, byteslib // operations have proper require. unchecked { bytes memory encoded = vm.payload; ( uint index, uint nAttestations, uint attestationSize ) = parseBatchAttestationHeader(encoded); // Deserialize each attestation for (uint j = 0; j < nAttestations; j++) { ( PythInternalStructs.PriceInfo memory info, bytes32 priceId ) = parseSingleAttestationFromBatch( encoded, index, attestationSize ); // Respect specified attestation size for forward-compat index += attestationSize; // Store the attestation uint64 latestPublishTime = latestPriceInfoPublishTime(priceId); if (info.publishTime > latestPublishTime) { setLatestPriceInfo(priceId, info); emit PriceFeedUpdate( priceId, info.publishTime, info.price, info.conf ); } } emit BatchPriceFeedUpdate(vm.emitterChainId, vm.sequence); } } function parseSingleAttestationFromBatch( bytes memory encoded, uint index, uint attestationSize ) internal pure returns (PythInternalStructs.PriceInfo memory info, bytes32 priceId) { unchecked { // NOTE: We don't advance the global index immediately. // attestationIndex is an attestation-local offset used // for readability and easier debugging. uint attestationIndex = 0; // Unused bytes32 product id attestationIndex += 32; priceId = UnsafeBytesLib.toBytes32( encoded, index + attestationIndex ); attestationIndex += 32; info.price = int64( UnsafeBytesLib.toUint64(encoded, index + attestationIndex) ); attestationIndex += 8; info.conf = UnsafeBytesLib.toUint64( encoded, index + attestationIndex ); attestationIndex += 8; info.expo = int32( UnsafeBytesLib.toUint32(encoded, index + attestationIndex) ); attestationIndex += 4; info.emaPrice = int64( UnsafeBytesLib.toUint64(encoded, index + attestationIndex) ); attestationIndex += 8; info.emaConf = UnsafeBytesLib.toUint64( encoded, index + attestationIndex ); attestationIndex += 8; { // Status is an enum (encoded as uint8) with the following values: // 0 = UNKNOWN: The price feed is not currently updating for an unknown reason. // 1 = TRADING: The price feed is updating as expected. // 2 = HALTED: The price feed is not currently updating because trading in the product has been halted. // 3 = AUCTION: The price feed is not currently updating because an auction is setting the price. uint8 status = UnsafeBytesLib.toUint8( encoded, index + attestationIndex ); attestationIndex += 1; // Unused uint32 numPublishers attestationIndex += 4; // Unused uint32 numPublishers attestationIndex += 4; // Unused uint64 attestationTime attestationIndex += 8; info.publishTime = UnsafeBytesLib.toUint64( encoded, index + attestationIndex ); attestationIndex += 8; if (status == 1) { // status == TRADING attestationIndex += 24; } else { // If status is not trading then the latest available price is // the previous price info that are passed here. // Previous publish time info.publishTime = UnsafeBytesLib.toUint64( encoded, index + attestationIndex ); attestationIndex += 8; // Previous price info.price = int64( UnsafeBytesLib.toUint64( encoded, index + attestationIndex ) ); attestationIndex += 8; // Previous confidence info.conf = UnsafeBytesLib.toUint64( encoded, index + attestationIndex ); attestationIndex += 8; } } if (attestationIndex > attestationSize) revert PythErrors.InvalidUpdateData(); } } // This is an overwrite of the same method in AbstractPyth.sol // to be more gas efficient. function updatePriceFeedsIfNecessary( bytes[] calldata updateData, bytes32[] calldata priceIds, uint64[] calldata publishTimes ) external payable override { if (priceIds.length != publishTimes.length) revert PythErrors.InvalidArgument(); for (uint i = 0; i < priceIds.length; ) { // If the price does not exist, then the publish time is zero and // this condition will work fine. if (latestPriceInfoPublishTime(priceIds[i]) < publishTimes[i]) { updatePriceFeeds(updateData); return; } unchecked { i++; } } revert PythErrors.NoFreshUpdate(); } // This is an overwrite of the same method in AbstractPyth.sol // to be more gas efficient. It cannot move to PythGetters as it // is overwriting the interface. Even indirect calling of a similar // method from PythGetter has some gas overhead. function getPriceUnsafe( bytes32 id ) public view override returns (PythStructs.Price memory price) { PythInternalStructs.PriceInfo storage info = _state.latestPriceInfo[id]; price.publishTime = info.publishTime; price.expo = info.expo; price.price = info.price; price.conf = info.conf; if (price.publishTime == 0) revert PythErrors.PriceFeedNotFound(); } // This is an overwrite of the same method in AbstractPyth.sol // to be more gas efficient. It cannot move to PythGetters as it // is overwriting the interface. Even indirect calling of a similar // method from PythGetter has some gas overhead. function getEmaPriceUnsafe( bytes32 id ) public view override returns (PythStructs.Price memory price) { PythInternalStructs.PriceInfo storage info = _state.latestPriceInfo[id]; price.publishTime = info.publishTime; price.expo = info.expo; price.price = info.emaPrice; price.conf = info.emaConf; if (price.publishTime == 0) revert PythErrors.PriceFeedNotFound(); } function parseBatchAttestationHeader( bytes memory encoded ) internal pure returns (uint index, uint nAttestations, uint attestationSize) { unchecked { index = 0; // Check header { uint32 magic = UnsafeBytesLib.toUint32(encoded, index); index += 4; if (magic != 0x50325748) revert PythErrors.InvalidUpdateData(); uint16 versionMajor = UnsafeBytesLib.toUint16(encoded, index); index += 2; if (versionMajor != 3) revert PythErrors.InvalidUpdateData(); // This value is only used as the check below which currently // never reverts // uint16 versionMinor = UnsafeBytesLib.toUint16(encoded, index); index += 2; // This check is always false as versionMinor is 0, so it is commented. // in the future that the minor version increases this will have effect. // if(versionMinor < 0) revert InvalidUpdateData(); uint16 hdrSize = UnsafeBytesLib.toUint16(encoded, index); index += 2; // NOTE(2022-04-19): Currently, only payloadId comes after // hdrSize. Future extra header fields must be read using a // separate offset to respect hdrSize, i.e.: // // uint hdrIndex = 0; // bpa.header.payloadId = UnsafeBytesLib.toUint8(encoded, index + hdrIndex); // hdrIndex += 1; // // bpa.header.someNewField = UnsafeBytesLib.toUint32(encoded, index + hdrIndex); // hdrIndex += 4; // // // Skip remaining unknown header bytes // index += bpa.header.hdrSize; uint8 payloadId = UnsafeBytesLib.toUint8(encoded, index); // Skip remaining unknown header bytes index += hdrSize; // Payload ID of 2 required for batch headerBa if (payloadId != 2) revert PythErrors.InvalidUpdateData(); } // Parse the number of attestations nAttestations = UnsafeBytesLib.toUint16(encoded, index); index += 2; // Parse the attestation size attestationSize = UnsafeBytesLib.toUint16(encoded, index); index += 2; // Given the message is valid the arithmetic below should not overflow, and // even if it overflows then the require would fail. if (encoded.length != (index + (attestationSize * nAttestations))) revert PythErrors.InvalidUpdateData(); } } function parseAndVerifyBatchAttestationVM( bytes calldata encodedVm ) internal view returns (IWormhole.VM memory vm) { { bool valid; (vm, valid, ) = wormhole().parseAndVerifyVM(encodedVm); if (!valid) revert PythErrors.InvalidWormholeVaa(); } if (!verifyPythVM(vm)) revert PythErrors.InvalidUpdateDataSource(); } function parsePriceFeedUpdates( bytes[] calldata updateData, bytes32[] calldata priceIds, uint64 minPublishTime, uint64 maxPublishTime ) external payable override returns (PythStructs.PriceFeed[] memory priceFeeds) { unchecked { { uint requiredFee = getUpdateFee(updateData); if (msg.value < requiredFee) revert PythErrors.InsufficientFee(); } priceFeeds = new PythStructs.PriceFeed[](priceIds.length); for (uint i = 0; i < updateData.length; i++) { bytes memory encoded; { IWormhole.VM memory vm = parseAndVerifyBatchAttestationVM( updateData[i] ); encoded = vm.payload; } ( uint index, uint nAttestations, uint attestationSize ) = parseBatchAttestationHeader(encoded); // Deserialize each attestation for (uint j = 0; j < nAttestations; j++) { // NOTE: We don't advance the global index immediately. // attestationIndex is an attestation-local offset used // for readability and easier debugging. uint attestationIndex = 0; // Unused bytes32 product id attestationIndex += 32; bytes32 priceId = UnsafeBytesLib.toBytes32( encoded, index + attestationIndex ); // Check whether the caller requested for this data. uint k = 0; for (; k < priceIds.length; k++) { if (priceIds[k] == priceId) { break; } } // If priceFeed[k].id != 0 then it means that there was a valid // update for priceIds[k] and we don't need to process this one. if (k == priceIds.length || priceFeeds[k].id != 0) { index += attestationSize; continue; } ( PythInternalStructs.PriceInfo memory info, ) = parseSingleAttestationFromBatch( encoded, index, attestationSize ); priceFeeds[k].id = priceId; priceFeeds[k].price.price = info.price; priceFeeds[k].price.conf = info.conf; priceFeeds[k].price.expo = info.expo; priceFeeds[k].price.publishTime = uint(info.publishTime); priceFeeds[k].emaPrice.price = info.emaPrice; priceFeeds[k].emaPrice.conf = info.emaConf; priceFeeds[k].emaPrice.expo = info.expo; priceFeeds[k].emaPrice.publishTime = uint(info.publishTime); // Check the publish time of the price is within the given range // if it is not, then set the id to 0 to indicate that this price id // still does not have a valid price feed. This will allow other updates // for this price id to be processed. if ( priceFeeds[k].price.publishTime < minPublishTime || priceFeeds[k].price.publishTime > maxPublishTime ) { priceFeeds[k].id = 0; } index += attestationSize; } } for (uint k = 0; k < priceIds.length; k++) { if (priceFeeds[k].id == 0) { revert PythErrors.PriceFeedNotFoundWithinRange(); } } } } function queryPriceFeed( bytes32 id ) public view override returns (PythStructs.PriceFeed memory priceFeed) { // Look up the latest price info for the given ID PythInternalStructs.PriceInfo memory info = latestPriceInfo(id); if (info.publishTime == 0) revert PythErrors.PriceFeedNotFound(); priceFeed.id = id; priceFeed.price.price = info.price; priceFeed.price.conf = info.conf; priceFeed.price.expo = info.expo; priceFeed.price.publishTime = uint(info.publishTime); priceFeed.emaPrice.price = info.emaPrice; priceFeed.emaPrice.conf = info.emaConf; priceFeed.emaPrice.expo = info.expo; priceFeed.emaPrice.publishTime = uint(info.publishTime); } function priceFeedExists(bytes32 id) public view override returns (bool) { return (latestPriceInfoPublishTime(id) != 0); } function getValidTimePeriod() public view override returns (uint) { return validTimePeriodSeconds(); } function version() public pure returns (string memory) { return "1.2.0"; } } // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol) /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() initializer {} * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { // If the contract is initializing we ignore whether _initialized is set in order to support multiple // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the // contract may have been reentered. require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} modifier, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } function _isConstructor() private view returns (bool) { return !AddressUpgradeable.isContract(address(this)); } } // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822ProxiableUpgradeable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); } // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeaconUpgradeable { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); } // OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol) /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlotUpgradeable { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly { r.slot := slot } } } // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol) /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967UpgradeUpgradeable is Initializable { function __ERC1967Upgrade_init() internal onlyInitializing { } function __ERC1967Upgrade_init_unchained() internal onlyInitializing { } // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { _functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS( address newImplementation, bytes memory data, bool forceCall ) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Emitted when the beacon is upgraded. */ event BeaconUpgraded(address indexed beacon); /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data); } } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) { require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed"); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; } // OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/UUPSUpgradeable.sol) /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. * * _Available since v4.1._ */ abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable { function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment address private immutable __self = address(this); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { require(address(this) != __self, "Function must be called through delegatecall"); require(_getImplementation() == __self, "Function must be called through active proxy"); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall"); _; } /** * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate that the this implementation remains valid after an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual override notDelegated returns (bytes32) { return _IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeTo(address newImplementation) external virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data, true); } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeTo} and {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal override onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; } // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; } // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; } // contracts/GovernanceStructs.sol /** * @dev `PythGovernanceInstructions` defines a set of structs and parsing functions * for Pyth governance instructions. */ contract PythGovernanceInstructions { using BytesLib for bytes; // Magic is `PTGM` encoded as a 4 byte data: Pyth Governance Message uint32 constant MAGIC = 0x5054474d; enum GovernanceModule { Executor, // 0 Target // 1 } GovernanceModule constant MODULE = GovernanceModule.Target; enum GovernanceAction { UpgradeContract, // 0 AuthorizeGovernanceDataSourceTransfer, // 1 SetDataSources, // 2 SetFee, // 3 SetValidPeriod, // 4 RequestGovernanceDataSourceTransfer // 5 } struct GovernanceInstruction { GovernanceModule module; GovernanceAction action; uint16 targetChainId; bytes payload; } struct UpgradeContractPayload { address newImplementation; } struct AuthorizeGovernanceDataSourceTransferPayload { // Transfer governance control over this contract to another data source. // The claimVaa field is a VAA created by the new data source; using a VAA prevents mistakes // in the handoff by ensuring that the new data source can send VAAs (i.e., is not an invalid address). bytes claimVaa; } struct RequestGovernanceDataSourceTransferPayload { // Governance data source index is used to prevent replay attacks // So a claimVaa cannot be used twice. uint32 governanceDataSourceIndex; } struct SetDataSourcesPayload { PythInternalStructs.DataSource[] dataSources; } struct SetFeePayload { uint newFee; } struct SetValidPeriodPayload { uint newValidPeriod; } /// @dev Parse a GovernanceInstruction function parseGovernanceInstruction( bytes memory encodedInstruction ) public pure returns (GovernanceInstruction memory gi) { uint index = 0; uint32 magic = encodedInstruction.toUint32(index); if (magic != MAGIC) revert PythErrors.InvalidGovernanceMessage(); index += 4; uint8 modNumber = encodedInstruction.toUint8(index); gi.module = GovernanceModule(modNumber); index += 1; if (gi.module != MODULE) revert PythErrors.InvalidGovernanceTarget(); uint8 actionNumber = encodedInstruction.toUint8(index); gi.action = GovernanceAction(actionNumber); index += 1; gi.targetChainId = encodedInstruction.toUint16(index); index += 2; // As solidity performs math operations in a checked mode // if the length of the encoded instruction be smaller than index // it will revert. So we don't need any extra check. gi.payload = encodedInstruction.slice( index, encodedInstruction.length - index ); } /// @dev Parse a UpgradeContractPayload (action 1) with minimal validation function parseUpgradeContractPayload( bytes memory encodedPayload ) public pure returns (UpgradeContractPayload memory uc) { uint index = 0; uc.newImplementation = address(encodedPayload.toAddress(index)); index += 20; if (encodedPayload.length != index) revert PythErrors.InvalidGovernanceMessage(); } /// @dev Parse a AuthorizeGovernanceDataSourceTransferPayload (action 2) with minimal validation function parseAuthorizeGovernanceDataSourceTransferPayload( bytes memory encodedPayload ) public pure returns (AuthorizeGovernanceDataSourceTransferPayload memory sgds) { sgds.claimVaa = encodedPayload; } /// @dev Parse a AuthorizeGovernanceDataSourceTransferPayload (action 2) with minimal validation function parseRequestGovernanceDataSourceTransferPayload( bytes memory encodedPayload ) public pure returns (RequestGovernanceDataSourceTransferPayload memory sgdsClaim) { uint index = 0; sgdsClaim.governanceDataSourceIndex = encodedPayload.toUint32(index); index += 4; if (encodedPayload.length != index) revert PythErrors.InvalidGovernanceMessage(); } /// @dev Parse a SetDataSourcesPayload (action 3) with minimal validation function parseSetDataSourcesPayload( bytes memory encodedPayload ) public pure returns (SetDataSourcesPayload memory sds) { uint index = 0; uint8 dataSourcesLength = encodedPayload.toUint8(index); index += 1; sds.dataSources = new PythInternalStructs.DataSource[]( dataSourcesLength ); for (uint i = 0; i < dataSourcesLength; i++) { sds.dataSources[i].chainId = encodedPayload.toUint16(index); index += 2; sds.dataSources[i].emitterAddress = encodedPayload.toBytes32(index); index += 32; } if (encodedPayload.length != index) revert PythErrors.InvalidGovernanceMessage(); } /// @dev Parse a SetFeePayload (action 4) with minimal validation function parseSetFeePayload( bytes memory encodedPayload ) public pure returns (SetFeePayload memory sf) { uint index = 0; uint64 val = encodedPayload.toUint64(index); index += 8; uint64 expo = encodedPayload.toUint64(index); index += 8; sf.newFee = uint256(val) * uint256(10) ** uint256(expo); if (encodedPayload.length != index) revert PythErrors.InvalidGovernanceMessage(); } /// @dev Parse a SetValidPeriodPayload (action 5) with minimal validation function parseSetValidPeriodPayload( bytes memory encodedPayload ) public pure returns (SetValidPeriodPayload memory svp) { uint index = 0; svp.newValidPeriod = uint256(encodedPayload.toUint64(index)); index += 8; if (encodedPayload.length != index) revert PythErrors.InvalidGovernanceMessage(); } } // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); } // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); } // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol) /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly { r.slot := slot } } } // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol) /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967Upgrade { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { Address.functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS( address newImplementation, bytes memory data, bool forceCall ) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Emitted when the beacon is upgraded. */ event BeaconUpgraded(address indexed beacon); /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } } } // contracts/Governance.sol /** * @dev `Governance` defines a means to enacting changes to the Pyth contract. */ abstract contract PythGovernance is PythGetters, PythSetters, PythGovernanceInstructions { event ContractUpgraded( address oldImplementation, address newImplementation ); event GovernanceDataSourceSet( PythInternalStructs.DataSource oldDataSource, PythInternalStructs.DataSource newDataSource, uint64 initialSequence ); event DataSourcesSet( PythInternalStructs.DataSource[] oldDataSources, PythInternalStructs.DataSource[] newDataSources ); event FeeSet(uint oldFee, uint newFee); event ValidPeriodSet(uint oldValidPeriod, uint newValidPeriod); function verifyGovernanceVM( bytes memory encodedVM ) internal returns (IWormhole.VM memory parsedVM) { (IWormhole.VM memory vm, bool valid, ) = wormhole().parseAndVerifyVM( encodedVM ); if (!valid) revert PythErrors.InvalidWormholeVaa(); if (!isValidGovernanceDataSource(vm.emitterChainId, vm.emitterAddress)) revert PythErrors.InvalidGovernanceDataSource(); if (vm.sequence <= lastExecutedGovernanceSequence()) revert PythErrors.OldGovernanceMessage(); setLastExecutedGovernanceSequence(vm.sequence); return vm; } function executeGovernanceInstruction(bytes calldata encodedVM) public { IWormhole.VM memory vm = verifyGovernanceVM(encodedVM); GovernanceInstruction memory gi = parseGovernanceInstruction( vm.payload ); if (gi.targetChainId != chainId() && gi.targetChainId != 0) revert PythErrors.InvalidGovernanceTarget(); if (gi.action == GovernanceAction.UpgradeContract) { if (gi.targetChainId == 0) revert PythErrors.InvalidGovernanceTarget(); upgradeContract(parseUpgradeContractPayload(gi.payload)); } else if ( gi.action == GovernanceAction.AuthorizeGovernanceDataSourceTransfer ) { AuthorizeGovernanceDataSourceTransfer( parseAuthorizeGovernanceDataSourceTransferPayload(gi.payload) ); } else if (gi.action == GovernanceAction.SetDataSources) { setDataSources(parseSetDataSourcesPayload(gi.payload)); } else if (gi.action == GovernanceAction.SetFee) { setFee(parseSetFeePayload(gi.payload)); } else if (gi.action == GovernanceAction.SetValidPeriod) { setValidPeriod(parseSetValidPeriodPayload(gi.payload)); } else if ( gi.action == GovernanceAction.RequestGovernanceDataSourceTransfer ) { // RequestGovernanceDataSourceTransfer can be only part of AuthorizeGovernanceDataSourceTransfer message revert PythErrors.InvalidGovernanceMessage(); } else { revert PythErrors.InvalidGovernanceMessage(); } } function upgradeContract(UpgradeContractPayload memory payload) internal { // This method on this contract does not have enough access to execute this, it should be executed on the // upgradable contract. upgradeUpgradableContract(payload); } function upgradeUpgradableContract( UpgradeContractPayload memory payload ) internal virtual; // Transfer the governance data source to a new value with sanity checks // to ensure the new governance data source can manage the contract. function AuthorizeGovernanceDataSourceTransfer( AuthorizeGovernanceDataSourceTransferPayload memory payload ) internal { PythInternalStructs.DataSource memory oldGovernanceDatSource = governanceDataSource(); // Make sure the claimVaa is a valid VAA with RequestGovernanceDataSourceTransfer governance message // If it's valid then its emitter can take over the governance from the current emitter. // The VAA is checked here to ensure that the new governance data source is valid and can send message // through wormhole. (IWormhole.VM memory vm, bool valid, ) = wormhole().parseAndVerifyVM( payload.claimVaa ); if (!valid) revert PythErrors.InvalidWormholeVaa(); GovernanceInstruction memory gi = parseGovernanceInstruction( vm.payload ); if (gi.targetChainId != chainId() && gi.targetChainId != 0) revert PythErrors.InvalidGovernanceTarget(); if (gi.action != GovernanceAction.RequestGovernanceDataSourceTransfer) revert PythErrors.InvalidGovernanceMessage(); RequestGovernanceDataSourceTransferPayload memory claimPayload = parseRequestGovernanceDataSourceTransferPayload( gi.payload ); // Governance data source index is used to prevent replay attacks, so a claimVaa cannot be used twice. if ( governanceDataSourceIndex() >= claimPayload.governanceDataSourceIndex ) revert PythErrors.OldGovernanceMessage(); setGovernanceDataSourceIndex(claimPayload.governanceDataSourceIndex); PythInternalStructs.DataSource memory newGovernanceDS = PythInternalStructs.DataSource( vm.emitterChainId, vm.emitterAddress ); setGovernanceDataSource(newGovernanceDS); // Setting the last executed governance to the claimVaa sequence to avoid using older sequences. setLastExecutedGovernanceSequence(vm.sequence); emit GovernanceDataSourceSet( oldGovernanceDatSource, governanceDataSource(), lastExecutedGovernanceSequence() ); } function setDataSources(SetDataSourcesPayload memory payload) internal { PythInternalStructs.DataSource[] memory oldDataSources = validDataSources(); for (uint i = 0; i < oldDataSources.length; i += 1) { _state.isValidDataSource[hashDataSource(oldDataSources[i])] = false; } delete _state.validDataSources; for (uint i = 0; i < payload.dataSources.length; i++) { _state.validDataSources.push(payload.dataSources[i]); _state.isValidDataSource[ hashDataSource(payload.dataSources[i]) ] = true; } emit DataSourcesSet(oldDataSources, validDataSources()); } function setFee(SetFeePayload memory payload) internal { uint oldFee = singleUpdateFeeInWei(); setSingleUpdateFeeInWei(payload.newFee); emit FeeSet(oldFee, singleUpdateFeeInWei()); } function setValidPeriod(SetValidPeriodPayload memory payload) internal { uint oldValidPeriod = validTimePeriodSeconds(); setValidTimePeriodSeconds(payload.newValidPeriod); emit ValidPeriodSet(oldValidPeriod, validTimePeriodSeconds()); } } contract PythUpgradable is Initializable, OwnableUpgradeable, UUPSUpgradeable, Pyth, PythGovernance { function initialize( address wormhole, uint16[] calldata dataSourceEmitterChainIds, bytes32[] calldata dataSourceEmitterAddresses, uint16 governanceEmitterChainId, bytes32 governanceEmitterAddress, uint64 governanceInitialSequence, uint validTimePeriodSeconds, uint singleUpdateFeeInWei ) public initializer { __Ownable_init(); __UUPSUpgradeable_init(); Pyth._initialize( wormhole, dataSourceEmitterChainIds, dataSourceEmitterAddresses, governanceEmitterChainId, governanceEmitterAddress, governanceInitialSequence, validTimePeriodSeconds, singleUpdateFeeInWei ); renounceOwnership(); } /// Ensures the contract cannot be uninitialized and taken over. /// @custom:oz-upgrades-unsafe-allow constructor constructor() initializer {} // Only allow the owner to upgrade the proxy to a new implementation. // The contract has no owner so this function will always revert // but UUPSUpgradeable expects this method to be implemented. function _authorizeUpgrade(address) internal override onlyOwner {} function pythUpgradableMagic() public pure returns (uint32) { return 0x97a6f304; } // Execute a UpgradeContract governance message function upgradeUpgradableContract( UpgradeContractPayload memory payload ) internal override { address oldImplementation = _getImplementation(); _upgradeToAndCallUUPS(payload.newImplementation, new bytes(0), false); // Calling a method using `this.<method>` will cause a contract call that will use // the new contract. This call will fail if the method does not exists or the magic // is different. if (this.pythUpgradableMagic() != 0x97a6f304) revert PythErrors.InvalidGovernanceMessage(); emit ContractUpgraded(oldImplementation, _getImplementation()); } }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"error","name":"InsufficientFee","inputs":[]},{"type":"error","name":"InvalidArgument","inputs":[]},{"type":"error","name":"InvalidGovernanceDataSource","inputs":[]},{"type":"error","name":"InvalidGovernanceMessage","inputs":[]},{"type":"error","name":"InvalidGovernanceTarget","inputs":[]},{"type":"error","name":"InvalidUpdateData","inputs":[]},{"type":"error","name":"InvalidUpdateDataSource","inputs":[]},{"type":"error","name":"InvalidWormholeVaa","inputs":[]},{"type":"error","name":"NoFreshUpdate","inputs":[]},{"type":"error","name":"OldGovernanceMessage","inputs":[]},{"type":"error","name":"PriceFeedNotFound","inputs":[]},{"type":"error","name":"PriceFeedNotFoundWithinRange","inputs":[]},{"type":"error","name":"StalePrice","inputs":[]},{"type":"event","name":"AdminChanged","inputs":[{"type":"address","name":"previousAdmin","internalType":"address","indexed":false},{"type":"address","name":"newAdmin","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"BatchPriceFeedUpdate","inputs":[{"type":"uint16","name":"chainId","internalType":"uint16","indexed":false},{"type":"uint64","name":"sequenceNumber","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"BeaconUpgraded","inputs":[{"type":"address","name":"beacon","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ContractUpgraded","inputs":[{"type":"address","name":"oldImplementation","internalType":"address","indexed":false},{"type":"address","name":"newImplementation","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"DataSourcesSet","inputs":[{"type":"tuple[]","name":"oldDataSources","internalType":"struct PythInternalStructs.DataSource[]","indexed":false,"components":[{"type":"uint16","name":"chainId","internalType":"uint16"},{"type":"bytes32","name":"emitterAddress","internalType":"bytes32"}]},{"type":"tuple[]","name":"newDataSources","internalType":"struct PythInternalStructs.DataSource[]","indexed":false,"components":[{"type":"uint16","name":"chainId","internalType":"uint16"},{"type":"bytes32","name":"emitterAddress","internalType":"bytes32"}]}],"anonymous":false},{"type":"event","name":"FeeSet","inputs":[{"type":"uint256","name":"oldFee","internalType":"uint256","indexed":false},{"type":"uint256","name":"newFee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"GovernanceDataSourceSet","inputs":[{"type":"tuple","name":"oldDataSource","internalType":"struct PythInternalStructs.DataSource","indexed":false,"components":[{"type":"uint16","name":"chainId","internalType":"uint16"},{"type":"bytes32","name":"emitterAddress","internalType":"bytes32"}]},{"type":"tuple","name":"newDataSource","internalType":"struct PythInternalStructs.DataSource","indexed":false,"components":[{"type":"uint16","name":"chainId","internalType":"uint16"},{"type":"bytes32","name":"emitterAddress","internalType":"bytes32"}]},{"type":"uint64","name":"initialSequence","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"PriceFeedUpdate","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32","indexed":true},{"type":"uint64","name":"publishTime","internalType":"uint64","indexed":false},{"type":"int64","name":"price","internalType":"int64","indexed":false},{"type":"uint64","name":"conf","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"Upgraded","inputs":[{"type":"address","name":"implementation","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ValidPeriodSet","inputs":[{"type":"uint256","name":"oldValidPeriod","internalType":"uint256","indexed":false},{"type":"uint256","name":"newValidPeriod","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint16","name":"","internalType":"uint16"}],"name":"chainId","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeGovernanceInstruction","inputs":[{"type":"bytes","name":"encodedVM","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"price","internalType":"struct PythStructs.Price","components":[{"type":"int64","name":"price","internalType":"int64"},{"type":"uint64","name":"conf","internalType":"uint64"},{"type":"int32","name":"expo","internalType":"int32"},{"type":"uint256","name":"publishTime","internalType":"uint256"}]}],"name":"getEmaPrice","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"price","internalType":"struct PythStructs.Price","components":[{"type":"int64","name":"price","internalType":"int64"},{"type":"uint64","name":"conf","internalType":"uint64"},{"type":"int32","name":"expo","internalType":"int32"},{"type":"uint256","name":"publishTime","internalType":"uint256"}]}],"name":"getEmaPriceNoOlderThan","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32"},{"type":"uint256","name":"age","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"price","internalType":"struct PythStructs.Price","components":[{"type":"int64","name":"price","internalType":"int64"},{"type":"uint64","name":"conf","internalType":"uint64"},{"type":"int32","name":"expo","internalType":"int32"},{"type":"uint256","name":"publishTime","internalType":"uint256"}]}],"name":"getEmaPriceUnsafe","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"price","internalType":"struct PythStructs.Price","components":[{"type":"int64","name":"price","internalType":"int64"},{"type":"uint64","name":"conf","internalType":"uint64"},{"type":"int32","name":"expo","internalType":"int32"},{"type":"uint256","name":"publishTime","internalType":"uint256"}]}],"name":"getPrice","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"price","internalType":"struct PythStructs.Price","components":[{"type":"int64","name":"price","internalType":"int64"},{"type":"uint64","name":"conf","internalType":"uint64"},{"type":"int32","name":"expo","internalType":"int32"},{"type":"uint256","name":"publishTime","internalType":"uint256"}]}],"name":"getPriceNoOlderThan","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32"},{"type":"uint256","name":"age","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"price","internalType":"struct PythStructs.Price","components":[{"type":"int64","name":"price","internalType":"int64"},{"type":"uint64","name":"conf","internalType":"uint64"},{"type":"int32","name":"expo","internalType":"int32"},{"type":"uint256","name":"publishTime","internalType":"uint256"}]}],"name":"getPriceUnsafe","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"feeAmount","internalType":"uint256"}],"name":"getUpdateFee","inputs":[{"type":"bytes[]","name":"updateData","internalType":"bytes[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"feeAmount","internalType":"uint256"}],"name":"getUpdateFee","inputs":[{"type":"uint256","name":"updateDataSize","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getValidTimePeriod","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct PythInternalStructs.DataSource","components":[{"type":"uint16","name":"chainId","internalType":"uint16"},{"type":"bytes32","name":"emitterAddress","internalType":"bytes32"}]}],"name":"governanceDataSource","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"governanceDataSourceIndex","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"hashDataSource","inputs":[{"type":"tuple","name":"ds","internalType":"struct PythInternalStructs.DataSource","components":[{"type":"uint16","name":"chainId","internalType":"uint16"},{"type":"bytes32","name":"emitterAddress","internalType":"bytes32"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"wormhole","internalType":"address"},{"type":"uint16[]","name":"dataSourceEmitterChainIds","internalType":"uint16[]"},{"type":"bytes32[]","name":"dataSourceEmitterAddresses","internalType":"bytes32[]"},{"type":"uint16","name":"governanceEmitterChainId","internalType":"uint16"},{"type":"bytes32","name":"governanceEmitterAddress","internalType":"bytes32"},{"type":"uint64","name":"governanceInitialSequence","internalType":"uint64"},{"type":"uint256","name":"validTimePeriodSeconds","internalType":"uint256"},{"type":"uint256","name":"singleUpdateFeeInWei","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isValidDataSource","inputs":[{"type":"uint16","name":"dataSourceChainId","internalType":"uint16"},{"type":"bytes32","name":"dataSourceEmitterAddress","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isValidGovernanceDataSource","inputs":[{"type":"uint16","name":"governanceChainId","internalType":"uint16"},{"type":"bytes32","name":"governanceEmitterAddress","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"lastExecutedGovernanceSequence","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"latestPriceInfoPublishTime","inputs":[{"type":"bytes32","name":"priceId","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"tuple","name":"sgds","internalType":"struct PythGovernanceInstructions.AuthorizeGovernanceDataSourceTransferPayload","components":[{"type":"bytes","name":"claimVaa","internalType":"bytes"}]}],"name":"parseAuthorizeGovernanceDataSourceTransferPayload","inputs":[{"type":"bytes","name":"encodedPayload","internalType":"bytes"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"tuple","name":"gi","internalType":"struct PythGovernanceInstructions.GovernanceInstruction","components":[{"type":"uint8","name":"module","internalType":"enum PythGovernanceInstructions.GovernanceModule"},{"type":"uint8","name":"action","internalType":"enum PythGovernanceInstructions.GovernanceAction"},{"type":"uint16","name":"targetChainId","internalType":"uint16"},{"type":"bytes","name":"payload","internalType":"bytes"}]}],"name":"parseGovernanceInstruction","inputs":[{"type":"bytes","name":"encodedInstruction","internalType":"bytes"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"tuple[]","name":"priceFeeds","internalType":"struct PythStructs.PriceFeed[]","components":[{"type":"bytes32","name":"id","internalType":"bytes32"},{"type":"tuple","name":"price","internalType":"struct PythStructs.Price","components":[{"type":"int64","name":"price","internalType":"int64"},{"type":"uint64","name":"conf","internalType":"uint64"},{"type":"int32","name":"expo","internalType":"int32"},{"type":"uint256","name":"publishTime","internalType":"uint256"}]},{"type":"tuple","name":"emaPrice","internalType":"struct PythStructs.Price","components":[{"type":"int64","name":"price","internalType":"int64"},{"type":"uint64","name":"conf","internalType":"uint64"},{"type":"int32","name":"expo","internalType":"int32"},{"type":"uint256","name":"publishTime","internalType":"uint256"}]}]}],"name":"parsePriceFeedUpdates","inputs":[{"type":"bytes[]","name":"updateData","internalType":"bytes[]"},{"type":"bytes32[]","name":"priceIds","internalType":"bytes32[]"},{"type":"uint64","name":"minPublishTime","internalType":"uint64"},{"type":"uint64","name":"maxPublishTime","internalType":"uint64"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"tuple","name":"sgdsClaim","internalType":"struct PythGovernanceInstructions.RequestGovernanceDataSourceTransferPayload","components":[{"type":"uint32","name":"governanceDataSourceIndex","internalType":"uint32"}]}],"name":"parseRequestGovernanceDataSourceTransferPayload","inputs":[{"type":"bytes","name":"encodedPayload","internalType":"bytes"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"tuple","name":"sds","internalType":"struct PythGovernanceInstructions.SetDataSourcesPayload","components":[{"type":"tuple[]","name":"dataSources","internalType":"struct PythInternalStructs.DataSource[]","components":[{"type":"uint16","name":"chainId","internalType":"uint16"},{"type":"bytes32","name":"emitterAddress","internalType":"bytes32"}]}]}],"name":"parseSetDataSourcesPayload","inputs":[{"type":"bytes","name":"encodedPayload","internalType":"bytes"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"tuple","name":"sf","internalType":"struct PythGovernanceInstructions.SetFeePayload","components":[{"type":"uint256","name":"newFee","internalType":"uint256"}]}],"name":"parseSetFeePayload","inputs":[{"type":"bytes","name":"encodedPayload","internalType":"bytes"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"tuple","name":"svp","internalType":"struct PythGovernanceInstructions.SetValidPeriodPayload","components":[{"type":"uint256","name":"newValidPeriod","internalType":"uint256"}]}],"name":"parseSetValidPeriodPayload","inputs":[{"type":"bytes","name":"encodedPayload","internalType":"bytes"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"tuple","name":"uc","internalType":"struct PythGovernanceInstructions.UpgradeContractPayload","components":[{"type":"address","name":"newImplementation","internalType":"address"}]}],"name":"parseUpgradeContractPayload","inputs":[{"type":"bytes","name":"encodedPayload","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"priceFeedExists","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"proxiableUUID","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"pythUpgradableMagic","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"priceFeed","internalType":"struct PythStructs.PriceFeed","components":[{"type":"bytes32","name":"id","internalType":"bytes32"},{"type":"tuple","name":"price","internalType":"struct PythStructs.Price","components":[{"type":"int64","name":"price","internalType":"int64"},{"type":"uint64","name":"conf","internalType":"uint64"},{"type":"int32","name":"expo","internalType":"int32"},{"type":"uint256","name":"publishTime","internalType":"uint256"}]},{"type":"tuple","name":"emaPrice","internalType":"struct PythStructs.Price","components":[{"type":"int64","name":"price","internalType":"int64"},{"type":"uint64","name":"conf","internalType":"uint64"},{"type":"int32","name":"expo","internalType":"int32"},{"type":"uint256","name":"publishTime","internalType":"uint256"}]}]}],"name":"queryPriceFeed","inputs":[{"type":"bytes32","name":"id","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"singleUpdateFeeInWei","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"updatePriceFeeds","inputs":[{"type":"bytes[]","name":"updateData","internalType":"bytes[]"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"updatePriceFeedsIfNecessary","inputs":[{"type":"bytes[]","name":"updateData","internalType":"bytes[]"},{"type":"bytes32[]","name":"priceIds","internalType":"bytes32[]"},{"type":"uint64[]","name":"publishTimes","internalType":"uint64[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"upgradeTo","inputs":[{"type":"address","name":"newImplementation","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"upgradeToAndCall","inputs":[{"type":"address","name":"newImplementation","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct PythInternalStructs.DataSource[]","components":[{"type":"uint16","name":"chainId","internalType":"uint16"},{"type":"bytes32","name":"emitterAddress","internalType":"bytes32"}]}],"name":"validDataSources","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"validTimePeriodSeconds","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"version","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IWormhole"}],"name":"wormhole","inputs":[]}]
Contract Creation Code
0x60a06040523060601b6080523480156200001857600080fd5b50600054610100900460ff16620000365760005460ff161562000040565b62000040620000e5565b620000a85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b600054610100900460ff16158015620000cb576000805461ffff19166101011790555b8015620000de576000805461ff00191690555b5062000112565b6000620000fd306200010360201b6200271c1760201c565b15905090565b6001600160a01b03163b151590565b60805160601c6154a86200014d60003960008181610bbe01528181610c540152818161142e015281816114c401526115f301526154a86000f3fe6080604052600436106102dc5760003560e01c806387c5bd1b11610184578063b6ed701e116100d6578063d82d58a51161008a578063e3795cc111610064578063e3795cc114610994578063ef9e5e28146109ab578063f2fde38b146109be57600080fd5b8063d82d58a514610926578063e17efd481461095f578063e18910a31461097f57600080fd5b8063caaf43f1116100bb578063caaf43f1146108c4578063cb718a9b146108f1578063d47eed451461090657600080fd5b8063b6ed701e14610891578063b9256d28146108b157600080fd5b806396834ad311610138578063a4ae35e011610112578063a4ae35e014610818578063b5dcc91114610838578063b5ec02611461085857600080fd5b806396834ad3146107ae5780639a8a0592146107ce578063a38d81c6146107f657600080fd5b806389a5bb4d1161016957806389a5bb4d146107435780638da5cb5b146107635780639474f45b1461078e57600080fd5b806387c5bd1b146106d15780638881016f146106fe57600080fd5b80634f1ef2861161023d5780636b7f53ca116101f1578063715018a6116101cb578063715018a61461063b5780637b72bcae1461065057806384acd1bb1461068557600080fd5b80636b7f53ca146105c25780636c72f51b146105ef578063711a2e281461061b57600080fd5b806354fd4d501161022257806354fd4d5014610537578063586d3cf81461058357806358c67635146105a257600080fd5b80634f1ef2861461050f57806352d1902d1461052257600080fd5b8063437209a71161029457806348b6404d1161027957806348b6404d146104805780634c469d8c1461049f5780634d7a734e146104ef57600080fd5b8063437209a7146103ca5780634716e9c51461046057600080fd5b806331d98b3f116102c557806331d98b3f146103375780633659cfe614610364578063426234e41461038457600080fd5b8063146faf77146102e157806314dd317f14610303575b600080fd5b3480156102ed57600080fd5b506103016102fc366004614856565b6109de565b005b34801561030f57600080fd5b5061032361031e366004614b89565b610afc565b604051905181526020015b60405180910390f35b34801561034357600080fd5b50610357610352366004614acb565b610b70565b60405161032e919061508c565b34801561037057600080fd5b5061030161037f36600461483c565b610ba6565b34801561039057600080fd5b506040805180820182526000808252602091820152815180830190925260d05461ffff16825260d1549082015260405161032e9190615001565b3480156103d657600080fd5b506104506103e5366004614d9d565b6040805160f09390931b7fffff000000000000000000000000000000000000000000000000000000000000166020808501919091526022808501939093528151808503909301835260429093018152815191830191909120600090815260cd90925290205460ff1690565b604051901515815260200161032e565b61047361046e366004614a39565b610d95565b60405161032e9190614f55565b34801561048c57600080fd5b5060ce545b60405190815260200161032e565b3480156104ab57600080fd5b506104d66104ba366004614acb565b600090815260d5602052604090205467ffffffffffffffff1690565b60405167ffffffffffffffff909116815260200161032e565b3480156104fb57600080fd5b5061032361050a366004614b89565b611363565b61030161051d366004614917565b611416565b34801561052e57600080fd5b506104916115d9565b34801561054357600080fd5b50604080518082018252600581527f312e322e300000000000000000000000000000000000000000000000000000006020820152905161032e9190614fd3565b34801561058f57600080fd5b5060d25467ffffffffffffffff166104d6565b3480156105ae57600080fd5b506104506105bd366004614d9d565b6116ab565b3480156105ce57600080fd5b506105e26105dd366004614b89565b6116ce565b60405161032e919061501c565b3480156105fb57600080fd5b5060d45463ffffffff165b60405163ffffffff909116815260200161032e565b34801561062757600080fd5b50610357610636366004614afb565b611904565b34801561064757600080fd5b5061030161197a565b34801561065c57600080fd5b5061067061066b366004614b89565b6119ed565b604051905163ffffffff16815260200161032e565b34801561069157600080fd5b5060c95473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161032e565b3480156106dd57600080fd5b506106f16106ec366004614b89565b611a1b565b60405161032e91906150c7565b34801561070a57600080fd5b5061071e610719366004614b89565b611bb1565b604051905173ffffffffffffffffffffffffffffffffffffffff16815260200161032e565b34801561074f57600080fd5b5061049161075e366004614bbc565b611bef565b34801561076f57600080fd5b5060335473ffffffffffffffffffffffffffffffffffffffff166106ac565b34801561079a57600080fd5b506103576107a9366004614acb565b611c59565b3480156107ba57600080fd5b506103576107c9366004614acb565b611d05565b3480156107da57600080fd5b506107e3611dd1565b60405161ffff909116815260200161032e565b34801561080257600080fd5b5061080b611e74565b60405161032e9190614f1d565b34801561082457600080fd5b50610357610833366004614afb565b611ee7565b34801561084457600080fd5b50610357610853366004614acb565b611f14565b34801561086457600080fd5b50610450610873366004614acb565b600090815260d5602052604090205467ffffffffffffffff16151590565b34801561089d57600080fd5b506103016108ac366004614b1c565b611f44565b6103016108bf3660046149a3565b612224565b3480156108d057600080fd5b506108e46108df366004614acb565b612350565b60405161032e919061507d565b3480156108fd57600080fd5b5060cf54610491565b34801561091257600080fd5b50610491610921366004614963565b612557565b34801561093257600080fd5b50610952610941366004614b89565b604080516020810190915290815290565b60405161032e9190614fe6565b34801561096b57600080fd5b5061049161097a366004614acb565b61256d565b34801561098b57600080fd5b50610491612583565b3480156109a057600080fd5b506397a6f304610606565b6103016109b9366004614963565b61258e565b3480156109ca57600080fd5b506103016109d936600461483c565b612623565b600054610100900460ff166109f95760005460ff16156109fd565b303b155b610a745760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600054610100900460ff16158015610a96576000805461ffff19166101011790555b610a9e612738565b610aa66127bd565b610ab88b8b8b8b8b8b8b8b8b8b61283a565b610ac061197a565b8015610aef57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b5050505050505050505050565b6040805160208101909152600081526000610b178382612b2d565b67ffffffffffffffff168252610b2e6008826151eb565b905080835114610b6a576040517f97363b3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50919050565b604080516080810182526000808252602082018190529181018290526060810191909152610ba082610833612583565b92915050565b3073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161415610c525760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f64656c656761746563616c6c00000000000000000000000000000000000000006064820152608401610a6b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16610cc77f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614610d505760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f6163746976652070726f787900000000000000000000000000000000000000006064820152608401610a6b565b610d5981612b93565b610d928160005b6040519080825280601f01601f191660200182016040528015610d8a576020820181803683370190505b506000612bfa565b50565b60606000610da38888612557565b905080341015610ddf576040517f025dbdd400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b508367ffffffffffffffff811115610e0757634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015610e9757816020015b610e84604080516060808201835260008083528351608081018552818152602081810183905294810182905291820152909182019081526040805160808101825260008082526020828101829052928201819052606082015291015290565b815260200190600190039081610e255790505b50905060005b868110156112e25760606000610ee38a8a85818110610ecc57634e487b7160e01b600052603260045260246000fd5b9050602002810190610ede91906150e2565b612dbb565b60e001519150600090508080610ef884612f3f565b92509250925060005b828110156112d1576040848601015160209060005b8c811015610f5957818e8e83818110610f3f57634e487b7160e01b600052603260045260246000fd5b905060200201351415610f5157610f59565b600101610f16565b808d1480610f915750898181518110610f8257634e487b7160e01b600052603260045260246000fd5b60209081029190910101515115155b15610fa257505050928101926112c9565b6000610faf8989886130d2565b509050828b8381518110610fd357634e487b7160e01b600052603260045260246000fd5b6020026020010151600001818152505080604001518b838151811061100857634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516000019060070b908160070b8152505080606001518b838151811061104957634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516020019067ffffffffffffffff16908167ffffffffffffffff168152505080602001518b838151811061109857634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516040019060030b908160030b81525050806000015167ffffffffffffffff168b83815181106110e357634e487b7160e01b600052603260045260246000fd5b602002602001015160200151606001818152505080608001518b838151811061111c57634e487b7160e01b600052603260045260246000fd5b6020026020010151604001516000019060070b908160070b815250508060a001518b838151811061115d57634e487b7160e01b600052603260045260246000fd5b6020026020010151604001516020019067ffffffffffffffff16908167ffffffffffffffff168152505080602001518b83815181106111ac57634e487b7160e01b600052603260045260246000fd5b6020026020010151604001516040019060030b908160030b81525050806000015167ffffffffffffffff168b83815181106111f757634e487b7160e01b600052603260045260246000fd5b60200260200101516040015160600181815250508c67ffffffffffffffff168b838151811061123657634e487b7160e01b600052603260045260246000fd5b60200260200101516020015160600151108061128a57508b67ffffffffffffffff168b838151811061127857634e487b7160e01b600052603260045260246000fd5b60200260200101516020015160600151115b156112c0576000801b8b83815181106112b357634e487b7160e01b600052603260045260246000fd5b6020908102919091010151525b50505093820193505b600101610f01565b505060019093019250610e9d915050565b5060005b848110156113585781818151811061130e57634e487b7160e01b600052603260045260246000fd5b602090810291909101015151611350576040517f45805f5d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001016112e6565b509695505050505050565b60408051602081019091526000815260008061137f8482612b2d565b905061138c6008836151eb565b9150600061139a8584612b2d565b90506113a76008846151eb565b92506113be67ffffffffffffffff8216600a615264565b6113d29067ffffffffffffffff841661532a565b84528451831461140e576040517f97363b3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050919050565b3073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614156114c25760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f64656c656761746563616c6c00000000000000000000000000000000000000006064820152608401610a6b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166115377f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16146115c05760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f6163746976652070726f787900000000000000000000000000000000000000006064820152608401610a6b565b6115c982612b93565b6115d582826001612bfa565b5050565b60003073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146116865760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610a6b565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b60d05460009061ffff84811691161480156116c7575060d15482145b9392505050565b6116fa604080516080810190915280600081526020016000815260006020820152606060409091015290565b60008061170784826131fb565b905063ffffffff8116635054474d1461174c576040517f97363b3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117576004836151eb565b915060006117658584613261565b90508060ff16600181111561178a57634e487b7160e01b600052602160045260246000fd5b849060018111156117ab57634e487b7160e01b600052602160045260246000fd5b908160018111156117cc57634e487b7160e01b600052602160045260246000fd5b9052506117da6001846151eb565b92506001845160018111156117ff57634e487b7160e01b600052602160045260246000fd5b14611836576040517f63daeb7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006118428685613261565b90508060ff16600581111561186757634e487b7160e01b600052602160045260246000fd5b8560200190600581111561188b57634e487b7160e01b600052602160045260246000fd5b908160058111156118ac57634e487b7160e01b600052602160045260246000fd5b9052506118ba6001856151eb565b93506118c686856132c7565b61ffff1660408601526118da6002856151eb565b93506118f5848588516118ed9190615367565b88919061332d565b60608601525092949350505050565b60408051608081018252600080825260208201819052918101829052606081019190915261193183611c59565b905081611942428360600151613455565b1115610ba0576040517f19abf40e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60335473ffffffffffffffffffffffffffffffffffffffff1633146119e15760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a6b565b6119eb600061347a565b565b6040805160208101909152600081526000611a0883826131fb565b63ffffffff168252610b2e6004826151eb565b604080516020810190915260608152600080611a378482613261565b9050611a446001836151eb565b91508060ff1667ffffffffffffffff811115611a7057634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611ab557816020015b6040805180820190915260008082526020820152815260200190600190039081611a8e5790505b50835260005b8160ff16811015611b6f57611ad085846132c7565b8451805183908110611af257634e487b7160e01b600052603260045260246000fd5b602090810291909101015161ffff9091169052611b106002846151eb565b9250611b1c85846134f1565b8451805183908110611b3e57634e487b7160e01b600052603260045260246000fd5b60200260200101516020018181525050602083611b5b91906151eb565b925080611b67816153aa565b915050611abb565b5081845114611baa576040517f97363b3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050919050565b6040805160208101909152600081526000611bcc8382613557565b73ffffffffffffffffffffffffffffffffffffffff168252610b2e6014826151eb565b600081600001518260200151604051602001611c3c92919060f09290921b7fffff000000000000000000000000000000000000000000000000000000000000168252600282015260220190565b604051602081830303815290604052805190602001209050919050565b60408051608081018252600080825260208083018281528385018381526060850184815287855260d590935294909220805467ffffffffffffffff808216938490526801000000000000000091829004600390810b810b900b9096526001820154600781810b810b900b865204909416909152909190610b6a576040517f14aebe6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051608081018252600080825260208083018281528385018381526060850184815287855260d590935294909220805467ffffffffffffffff80821693849052680100000000000000008204600390810b810b900b9096526c010000000000000000000000008104600790810b810b900b8552740100000000000000000000000000000000000000009004909416909152909190610b6a576040517f14aebe6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611df260c95473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16639a8a05926040518163ffffffff1660e01b815260040160206040518083038186803b158015611e3757600080fd5b505afa158015611e4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6f9190614d81565b905090565b606060c9600301805480602002602001604051908101604052809291908181526020016000905b82821015611ede5760008481526020908190206040805180820190915260028502909101805461ffff168252600190810154828401529083529092019101611e9b565b50505050905090565b60408051608081018252600080825260208201819052918101829052606081019190915261193183611d05565b604080516080810182526000808252602082018190529181018290526060810191909152610ba082610636612583565b6000611f8583838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506135cd92505050565b90506000611f968260e001516116ce565b9050611fa0611dd1565b61ffff16816040015161ffff1614158015611fc25750604081015161ffff1615155b15611ff9576040517f63daeb7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008160200151600581111561201f57634e487b7160e01b600052602160045260246000fd5b141561207e57604081015161ffff16612064576040517f63daeb7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6120796120748260600151611bb1565b6137f8565b61221e565b6001816020015160058111156120a457634e487b7160e01b600052602160045260246000fd5b14156120cb576120796120c68260600151604080516020810190915290815290565b613801565b6002816020015160058111156120f157634e487b7160e01b600052602160045260246000fd5b141561210c576120796121078260600151611a1b565b613baf565b60038160200151600581111561213257634e487b7160e01b600052602160045260246000fd5b141561214d576120796121488260600151611363565b613d94565b60048160200151600581111561217357634e487b7160e01b600052602160045260246000fd5b141561218e576120796121898260600151610afc565b613de6565b6005816020015160058111156121b457634e487b7160e01b600052602160045260246000fd5b14156121ec576040517f97363b3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f97363b3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b82811461225d576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b838110156123155782828281811061228857634e487b7160e01b600052603260045260246000fd5b905060200201602081019061229d9190614de2565b67ffffffffffffffff166122ed8686848181106122ca57634e487b7160e01b600052603260045260246000fd5b90506020020135600090815260d5602052604090205467ffffffffffffffff1690565b67ffffffffffffffff16101561230d57612307878761258e565b50612348565b600101612260565b506040517fde2c57fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b6123af604080516060808201835260008083528351608081018552818152602081810183905294810182905291820152909182019081526040805160808101825260008082526020828101829052928201819052606082015291015290565b6040805160c08082018352600080835260208084018290528385018290526060808501839052608080860184905260a095860184905288845260d5835286842087519586018852805467ffffffffffffffff808216885268010000000000000000808304600390810b810b900b968901969096526c010000000000000000000000008204600790810b810b810b9a89019a909a52740100000000000000000000000000000000000000009091048116938701939093526001015480880b880b90970b90850152940490931691810191909152805190915067ffffffffffffffff166124c6576040517f14aebe6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b91815260408083015160208084018051600793840b840b9052606080870151825167ffffffffffffffff9182169085015283880180518451600391820b820b9089015289519451948316948401949094526080890151878901805191880b90970b905260a089015186519083169501949094529251845190830b90920b919094015293519051931692019190915290565b60008161256360ce5490565b6116c7919061532a565b60008161257960ce5490565b610ba0919061532a565b6000611e6f60cf5490565b600061259a8383612557565b9050803410156125d6576040517f025dbdd400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8281101561221e5761261b84848381811061260457634e487b7160e01b600052603260045260246000fd5b905060200281019061261691906150e2565b613e23565b6001016125d9565b60335473ffffffffffffffffffffffffffffffffffffffff16331461268a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a6b565b73ffffffffffffffffffffffffffffffffffffffff81166127135760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610a6b565b610d928161347a565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b600054610100900460ff166127b55760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a6b565b6119eb613e35565b600054610100900460ff166119eb5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a6b565b60c980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8c161790558786146128b3576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b88811015612aad57600060405180604001604052808c8c858181106128eb57634e487b7160e01b600052603260045260246000fd5b90506020020160208101906129009190614d65565b61ffff1681526020018a8a8581811061292957634e487b7160e01b600052603260045260246000fd5b602090810292909201359092528251838201516040805160f09390931b7fffff00000000000000000000000000000000000000000000000000000000000016838501526022808401929092528051808403909201825260429092018252805190830120600090815260cd9092529020549192505060ff16156129d7576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160cd60006129e684611bef565b8152602080820192909252604001600090812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169315159390931790925560cc8054600181018255925282517f47197230e1e4b29fc0bd84d7d78966c0925452aff72a2a121538b102457e9ebe6002909302928301805461ffff191661ffff90921691909117905591909101517f47197230e1e4b29fc0bd84d7d78966c0925452aff72a2a121538b102457e9ebf9091015580612aa5816153aa565b9150506128b6565b506040805180820190915261ffff86168082526020820186905260d0805461ffff1916909117905560d185905560d280547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff861617905550612b188260cf55565b612b218160ce55565b50505050505050505050565b6000612b3a8260086151eb565b83511015612b8a5760405162461bcd60e51b815260206004820152601460248201527f746f55696e7436345f6f75744f66426f756e64730000000000000000000000006044820152606401610a6b565b50016008015190565b60335473ffffffffffffffffffffffffffffffffffffffff163314610d925760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a6b565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612c3257612c2d83613ebb565b505050565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b815260040160206040518083038186803b158015612c7857600080fd5b505afa925050508015612ca8575060408051601f3d908101601f19168201909252612ca591810190614ae3565b60015b612d1a5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201527f6f6e206973206e6f7420555550530000000000000000000000000000000000006064820152608401610a6b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114612daf5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f7860448201527f6961626c655555494400000000000000000000000000000000000000000000006064820152608401610a6b565b50612c2d838383613fab565b604080516101608101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e0820181905261010082018390526101208201526101408101919091526000612e3460c95473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1663c0fd8bde85856040518363ffffffff1660e01b8152600401612e6e929190614fa4565b60006040518083038186803b158015612e8657600080fd5b505afa158015612e9a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612ec29190810190614c13565b50909250905080612eff576040517f2acbe91500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50612f0981613fd0565b610ba0576040517fe60dce7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808080612f52858260049101015190565b90506004840193508063ffffffff16635032574814612f9d576040517fe69ffece00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002858501810151940193600361ffff821614612fe6576040517fe69ffece00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002850194506000612ffc878760029101015190565b90506002860195506000613014888860019101015190565b90508161ffff16870196508060ff1660021461305c576040517fe69ffece00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050508284016002015161ffff169150600283019250613081848460029101015190565b61ffff16905060028301925081810283018451146130cb576040517fe69ffece00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9193909250565b6040805160c081018252600080825260208201818152828401828152606084018381526080850184815260a08601948552888a01968701516048880151600790810b810b909452605088015167ffffffffffffffff9081169093526054880151600390810b900b909452605c870151830b90920b909152606485015181169092526065840151607d94850151909216835291929060ff81166001141561317d576018820191506131b7565b8582018701600881015167ffffffffffffffff90811686526010820151600790810b900b6040870152601891820151166060860152909101905b50838111156131f2576040517fe69ffece00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50935093915050565b60006132088260046151eb565b835110156132585760405162461bcd60e51b815260206004820152601460248201527f746f55696e7433325f6f75744f66426f756e64730000000000000000000000006044820152606401610a6b565b50016004015190565b600061326e8260016151eb565b835110156132be5760405162461bcd60e51b815260206004820152601360248201527f746f55696e74385f6f75744f66426f756e6473000000000000000000000000006044820152606401610a6b565b50016001015190565b60006132d48260026151eb565b835110156133245760405162461bcd60e51b815260206004820152601460248201527f746f55696e7431365f6f75744f66426f756e64730000000000000000000000006044820152606401610a6b565b50016002015190565b60608161333b81601f6151eb565b10156133895760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610a6b565b61339382846151eb565b845110156133e35760405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152606401610a6b565b606082158015613402576040519150600082526020820160405261344c565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561343b578051835260209283019201613423565b5050858452601f01601f1916604052505b50949350505050565b600081831115613470576134698284615367565b9050610ba0565b6134698383615367565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60006134fe8260206151eb565b8351101561354e5760405162461bcd60e51b815260206004820152601560248201527f746f427974657333325f6f75744f66426f756e647300000000000000000000006044820152606401610a6b565b50016020015190565b60006135648260146151eb565b835110156135b45760405162461bcd60e51b815260206004820152601560248201527f746f416464726573735f6f75744f66426f756e647300000000000000000000006044820152606401610a6b565b5001602001516c01000000000000000000000000900490565b604080516101608101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201819052610100820183905261012082015261014081019190915260008061364760c95473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1663c0fd8bde856040518263ffffffff1660e01b815260040161367f9190614fd3565b60006040518083038186803b15801561369757600080fd5b505afa1580156136ab573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526136d39190810190614c13565b50915091508061370f576040517f2acbe91500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613721826060015183608001516116ab565b613757576040517f360f2d8700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60d25467ffffffffffffffff1667ffffffffffffffff168260a0015167ffffffffffffffff16116137b4576040517f88d1b84700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a082015160d280547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff9092169190911790555092915050565b610d928161404a565b60006138356040805180820182526000808252602091820152815180830190925260d05461ffff16825260d1549082015290565b905060008061385960c95473ffffffffffffffffffffffffffffffffffffffff1690565b84516040517fc0fd8bde00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff929092169163c0fd8bde916138ad91600401614fd3565b60006040518083038186803b1580156138c557600080fd5b505afa1580156138d9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526139019190810190614c13565b50915091508061393d576040517f2acbe91500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061394c8360e001516116ce565b9050613956611dd1565b61ffff16816040015161ffff16141580156139785750604081015161ffff1615155b156139af576040517f63daeb7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005816020015160058111156139d557634e487b7160e01b600052602160045260246000fd5b14613a0c576040517f97363b3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000613a1b82606001516119ed565b805190915063ffffffff16613a3560d45463ffffffff1690565b63ffffffff1610613a72576040517f88d1b84700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160d480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff909216919091179055604080518082018252606086015161ffff168082526080870151602080840182905260d0805461ffff19168417905560d182905560a089015160d280547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff90921691909117905584518086018652600080825290820152845180860190955291845290830152907f6bce23ef3d34e51710fe4700b43ba5f1733a6215c883f384671a4ece3ea8aa2090879060d25460408051845161ffff908116825260209586015186830152845116918101919091529290910151606083015267ffffffffffffffff16608082015260a00160405180910390a150505050505050565b6000613bb9611e74565b905060005b8151811015613c4f57600060c96004016000613c00858581518110613bf357634e487b7160e01b600052603260045260246000fd5b6020026020010151611bef565b8152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055613c486001826151eb565b9050613bbe565b50613c5c60cc60006145d8565b60005b825151811015613d4f578251805160cc919083908110613c8f57634e487b7160e01b600052603260045260246000fd5b60209081029190910181015182546001808201855560009485528385208351600290930201805461ffff191661ffff90931692909217825591909201519181019190915584518051919260cd929091613d009186908110613bf357634e487b7160e01b600052603260045260246000fd5b8152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905580613d47816153aa565b915050613c5f565b507fd451e0fcb7c5b9e13de533604d158069dad159841c45f39f09d379bfc423080d81613d7a611e74565b604051613d88929190614f30565b60405180910390a15050565b6000613d9f60ce5490565b825160ce5590507f74dbbbe280ef27b79a8a0c449d5ae2ba7a31849103241d0f98df70bbc9d03e3781613dd160ce5490565b60408051928352602083019190915201613d88565b6000613df160cf5490565b825160cf5590507fcdb88a22f82ddd76115ab7c66cf08eb1e40afe80c9b31017eb2cbdb1570b33ae81613dd160cf5490565b6115d5613e308383612dbb565b6141e7565b600054610100900460ff16613eb25760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a6b565b6119eb3361347a565b73ffffffffffffffffffffffffffffffffffffffff81163b613f455760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e7472616374000000000000000000000000000000000000006064820152608401610a6b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b613fb48361442d565b600082511180613fc15750805b15612c2d5761221e838361447a565b6000610ba0826060015183608001516040805160f09390931b7fffff000000000000000000000000000000000000000000000000000000000000166020808501919091526022808501939093528151808503909301835260429093018152815191830191909120600090815260cd90925290205460ff1690565b600061408a7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b825190915061409a906000610d60565b3073ffffffffffffffffffffffffffffffffffffffff1663e3795cc16040518163ffffffff1660e01b815260040160206040518083038186803b1580156140e057600080fd5b505afa1580156140f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141189190614dc8565b63ffffffff166397a6f3041461415a576040517f97363b3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f2e4cc16c100f0b55e2df82ab0b1a7e294aa9cbd01b48fbaf622683fbc0507a49816141ba7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b6040805173ffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201613d88565b60e0810151600080806141f984612f3f565b92509250925060005b828110156143d3576000806142188787866130d2565b600081815260d5602052604090205482519887019892945090925067ffffffffffffffff90811691168110156143c857600082815260d560209081526040918290208551815487840151888601516060808b015167ffffffffffffffff9586167fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090951685176801000000000000000063ffffffff60039690960b959095168502177fffffffff00000000000000000000000000000000ffffffffffffffffffffffff166c01000000000000000000000000600794850b808916919091027fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff16919091177401000000000000000000000000000000000000000092881692830217885560808d01516001909801805460a08f01519990950b88167fffffffffffffffffffffffffffffffff0000000000000000000000000000000090951694909417979096169093029590951790558551918252938101919091529283019190915283917fd06a6b7f4918494b3719217d1802786c1f5112a6c1d88fe2cfec00b4584f6aec910160405180910390a25b505050600101614202565b50606085015160a08601516040805161ffff909316835267ffffffffffffffff90911660208301527f943f0e8a16c19895fb87cbeb1a349ed86d7f31923089dd36c1a1ed5e300f267b910160405180910390a15050505050565b61443681613ebb565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606073ffffffffffffffffffffffffffffffffffffffff83163b6145065760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152608401610a6b565b6000808473ffffffffffffffffffffffffffffffffffffffff168460405161452e9190614f01565b600060405180830381855af49150503d8060008114614569576040519150601f19603f3d011682016040523d82523d6000602084013e61456e565b606091505b5091509150614596828260405180606001604052806027815260200161544c6027913961459f565b95945050505050565b606083156145ae5750816116c7565b8251156145be5782518084602001fd5b8160405162461bcd60e51b8152600401610a6b9190614fd3565b5080546000825560020290600052602060002090810190610d9291905b8082111561461557805461ffff19168155600060018201556002016145f5565b5090565b803573ffffffffffffffffffffffffffffffffffffffff8116811461463d57600080fd5b919050565b60008083601f840112614653578182fd5b50813567ffffffffffffffff81111561466a578182fd5b6020830191508360208260051b850101111561468557600080fd5b9250929050565b600082601f83011261469c578081fd5b8151602067ffffffffffffffff8211156146b8576146b861540f565b6146c6818360051b01615192565b80838252828201915082860187848660071b89010111156146e5578586fd5b855b8581101561474857608080838b0312156146ff578788fd5b614707615145565b835181528684015187820152604061472081860161482b565b90820152606061473185820161482b565b9082015285529385019391909101906001016146e7565b5090979650505050505050565b8051801515811461463d57600080fd5b600082601f830112614775578081fd5b8135614788614783826151c3565b615192565b81815284602083860101111561479c578283fd5b816020850160208301379081016020019190915292915050565b600082601f8301126147c6578081fd5b81516147d4614783826151c3565b8181528460208386010111156147e8578283fd5b6147f982602083016020870161537e565b949350505050565b805161463d81615425565b805163ffffffff8116811461463d57600080fd5b805161463d81615435565b805160ff8116811461463d57600080fd5b60006020828403121561484d578081fd5b6116c782614619565b6000806000806000806000806000806101008b8d031215614875578586fd5b61487e8b614619565b995060208b013567ffffffffffffffff8082111561489a578788fd5b6148a68e838f01614642565b909b50995060408d01359150808211156148be578788fd5b506148cb8d828e01614642565b90985096505060608b01356148df81615425565b945060808b0135935060a08b01356148f681615435565b8093505060c08b0135915060e08b013590509295989b9194979a5092959850565b60008060408385031215614929578182fd5b61493283614619565b9150602083013567ffffffffffffffff81111561494d578182fd5b61495985828601614765565b9150509250929050565b60008060208385031215614975578182fd5b823567ffffffffffffffff81111561498b578283fd5b61499785828601614642565b90969095509350505050565b600080600080600080606087890312156149bb578384fd5b863567ffffffffffffffff808211156149d2578586fd5b6149de8a838b01614642565b909850965060208901359150808211156149f6578586fd5b614a028a838b01614642565b90965094506040890135915080821115614a1a578384fd5b50614a2789828a01614642565b979a9699509497509295939492505050565b60008060008060008060808789031215614a51578384fd5b863567ffffffffffffffff80821115614a68578586fd5b614a748a838b01614642565b90985096506020890135915080821115614a8c578586fd5b50614a9989828a01614642565b9095509350506040870135614aad81615435565b91506060870135614abd81615435565b809150509295509295509295565b600060208284031215614adc578081fd5b5035919050565b600060208284031215614af4578081fd5b5051919050565b60008060408385031215614b0d578182fd5b50508035926020909101359150565b60008060208385031215614b2e578182fd5b823567ffffffffffffffff80821115614b45578384fd5b818501915085601f830112614b58578384fd5b813581811115614b66578485fd5b866020828501011115614b77578485fd5b60209290920196919550909350505050565b600060208284031215614b9a578081fd5b813567ffffffffffffffff811115614bb0578182fd5b6147f984828501614765565b600060408284031215614bcd578081fd5b6040516040810181811067ffffffffffffffff82111715614bf057614bf061540f565b6040528235614bfe81615425565b81526020928301359281019290925250919050565b600080600060608486031215614c27578081fd5b835167ffffffffffffffff80821115614c3e578283fd5b908501906101608288031215614c52578283fd5b614c5a61516e565b614c638361482b565b8152614c716020840161480c565b6020820152614c826040840161480c565b6040820152614c9360608401614801565b606082015260808301516080820152614cae60a08401614820565b60a0820152614cbf60c0840161482b565b60c082015260e083015182811115614cd5578485fd5b614ce1898286016147b6565b60e083015250610100614cf581850161480c565b908201526101208381015183811115614d0c578586fd5b614d188a82870161468c565b918301919091525061014083810151908201529450614d3960208701614755565b93506040860151915080821115614d4e578283fd5b50614d5b868287016147b6565b9150509250925092565b600060208284031215614d76578081fd5b81356116c781615425565b600060208284031215614d92578081fd5b81516116c781615425565b60008060408385031215614daf578182fd5b8235614dba81615425565b946020939093013593505050565b600060208284031215614dd9578081fd5b6116c78261480c565b600060208284031215614df3578081fd5b81356116c781615435565b6000815180845260208085019450808401835b83811015614e4557614e32878351805161ffff168252602090810151910152565b6040969096019590820190600101614e11565b509495945050505050565b60008151808452614e6881602086016020860161537e565b601f01601f19169290920160200192915050565b805182526020810151614ec36020840182805160070b825267ffffffffffffffff6020820151166020830152604081015160030b6040830152606081015160608301525050565b50604090810151805160070b60a0840152602081015167ffffffffffffffff1660c08401529081015160030b60e08301526060015161010090910152565b60008251614f1381846020870161537e565b9190910192915050565b6020815260006116c76020830184614dfe565b604081526000614f436040830185614dfe565b82810360208401526145968185614dfe565b6020808252825182820181905260009190848201906040850190845b81811015614f9857614f84838551614e7c565b928401926101209290920191600101614f71565b50909695505050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b6020815260006116c76020830184614e50565b60208152600082516020808401526147f96040840182614e50565b815161ffff1681526020808301519082015260408101610ba0565b602081526000825160028110615034576150346153f9565b80602084015250602083015160068110615050576150506153f9565b8060408401525061ffff604084015116606083015260608301516080808401526147f960a0840182614e50565b6101208101610ba08284614e7c565b815160070b815260208083015167ffffffffffffffff169082015260408083015160030b908201526060808301519082015260808101610ba0565b60208152600082516020808401526147f96040840182614dfe565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615116578283fd5b83018035915067ffffffffffffffff821115615130578283fd5b60200191503681900382131561468557600080fd5b6040516080810167ffffffffffffffff811182821017156151685761516861540f565b60405290565b604051610160810167ffffffffffffffff811182821017156151685761516861540f565b604051601f8201601f1916810167ffffffffffffffff811182821017156151bb576151bb61540f565b604052919050565b600067ffffffffffffffff8211156151dd576151dd61540f565b50601f01601f191660200190565b600082198211156151fe576151fe6153e3565b500190565b600181815b8085111561525c57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615242576152426153e3565b8085161561524f57918102915b93841c9390800290615208565b509250929050565b60006116c7838360008261527a57506001610ba0565b8161528757506000610ba0565b816001811461529d57600281146152a7576152c3565b6001915050610ba0565b60ff8411156152b8576152b86153e3565b50506001821b610ba0565b5060208310610133831016604e8410600b84101617156152e6575081810a610ba0565b6152f08383615203565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615322576153226153e3565b029392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615362576153626153e3565b500290565b600082821015615379576153796153e3565b500390565b60005b83811015615399578181015183820152602001615381565b8381111561221e5750506000910152565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156153dc576153dc6153e3565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b61ffff81168114610d9257600080fd5b67ffffffffffffffff81168114610d9257600080fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212208b6bf04961e1e9107ec331071c06bf2701a68c6d300e06fb182fdaa500269b5e64736f6c63430008040033
Deployed ByteCode
0x6080604052600436106102dc5760003560e01c806387c5bd1b11610184578063b6ed701e116100d6578063d82d58a51161008a578063e3795cc111610064578063e3795cc114610994578063ef9e5e28146109ab578063f2fde38b146109be57600080fd5b8063d82d58a514610926578063e17efd481461095f578063e18910a31461097f57600080fd5b8063caaf43f1116100bb578063caaf43f1146108c4578063cb718a9b146108f1578063d47eed451461090657600080fd5b8063b6ed701e14610891578063b9256d28146108b157600080fd5b806396834ad311610138578063a4ae35e011610112578063a4ae35e014610818578063b5dcc91114610838578063b5ec02611461085857600080fd5b806396834ad3146107ae5780639a8a0592146107ce578063a38d81c6146107f657600080fd5b806389a5bb4d1161016957806389a5bb4d146107435780638da5cb5b146107635780639474f45b1461078e57600080fd5b806387c5bd1b146106d15780638881016f146106fe57600080fd5b80634f1ef2861161023d5780636b7f53ca116101f1578063715018a6116101cb578063715018a61461063b5780637b72bcae1461065057806384acd1bb1461068557600080fd5b80636b7f53ca146105c25780636c72f51b146105ef578063711a2e281461061b57600080fd5b806354fd4d501161022257806354fd4d5014610537578063586d3cf81461058357806358c67635146105a257600080fd5b80634f1ef2861461050f57806352d1902d1461052257600080fd5b8063437209a71161029457806348b6404d1161027957806348b6404d146104805780634c469d8c1461049f5780634d7a734e146104ef57600080fd5b8063437209a7146103ca5780634716e9c51461046057600080fd5b806331d98b3f116102c557806331d98b3f146103375780633659cfe614610364578063426234e41461038457600080fd5b8063146faf77146102e157806314dd317f14610303575b600080fd5b3480156102ed57600080fd5b506103016102fc366004614856565b6109de565b005b34801561030f57600080fd5b5061032361031e366004614b89565b610afc565b604051905181526020015b60405180910390f35b34801561034357600080fd5b50610357610352366004614acb565b610b70565b60405161032e919061508c565b34801561037057600080fd5b5061030161037f36600461483c565b610ba6565b34801561039057600080fd5b506040805180820182526000808252602091820152815180830190925260d05461ffff16825260d1549082015260405161032e9190615001565b3480156103d657600080fd5b506104506103e5366004614d9d565b6040805160f09390931b7fffff000000000000000000000000000000000000000000000000000000000000166020808501919091526022808501939093528151808503909301835260429093018152815191830191909120600090815260cd90925290205460ff1690565b604051901515815260200161032e565b61047361046e366004614a39565b610d95565b60405161032e9190614f55565b34801561048c57600080fd5b5060ce545b60405190815260200161032e565b3480156104ab57600080fd5b506104d66104ba366004614acb565b600090815260d5602052604090205467ffffffffffffffff1690565b60405167ffffffffffffffff909116815260200161032e565b3480156104fb57600080fd5b5061032361050a366004614b89565b611363565b61030161051d366004614917565b611416565b34801561052e57600080fd5b506104916115d9565b34801561054357600080fd5b50604080518082018252600581527f312e322e300000000000000000000000000000000000000000000000000000006020820152905161032e9190614fd3565b34801561058f57600080fd5b5060d25467ffffffffffffffff166104d6565b3480156105ae57600080fd5b506104506105bd366004614d9d565b6116ab565b3480156105ce57600080fd5b506105e26105dd366004614b89565b6116ce565b60405161032e919061501c565b3480156105fb57600080fd5b5060d45463ffffffff165b60405163ffffffff909116815260200161032e565b34801561062757600080fd5b50610357610636366004614afb565b611904565b34801561064757600080fd5b5061030161197a565b34801561065c57600080fd5b5061067061066b366004614b89565b6119ed565b604051905163ffffffff16815260200161032e565b34801561069157600080fd5b5060c95473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161032e565b3480156106dd57600080fd5b506106f16106ec366004614b89565b611a1b565b60405161032e91906150c7565b34801561070a57600080fd5b5061071e610719366004614b89565b611bb1565b604051905173ffffffffffffffffffffffffffffffffffffffff16815260200161032e565b34801561074f57600080fd5b5061049161075e366004614bbc565b611bef565b34801561076f57600080fd5b5060335473ffffffffffffffffffffffffffffffffffffffff166106ac565b34801561079a57600080fd5b506103576107a9366004614acb565b611c59565b3480156107ba57600080fd5b506103576107c9366004614acb565b611d05565b3480156107da57600080fd5b506107e3611dd1565b60405161ffff909116815260200161032e565b34801561080257600080fd5b5061080b611e74565b60405161032e9190614f1d565b34801561082457600080fd5b50610357610833366004614afb565b611ee7565b34801561084457600080fd5b50610357610853366004614acb565b611f14565b34801561086457600080fd5b50610450610873366004614acb565b600090815260d5602052604090205467ffffffffffffffff16151590565b34801561089d57600080fd5b506103016108ac366004614b1c565b611f44565b6103016108bf3660046149a3565b612224565b3480156108d057600080fd5b506108e46108df366004614acb565b612350565b60405161032e919061507d565b3480156108fd57600080fd5b5060cf54610491565b34801561091257600080fd5b50610491610921366004614963565b612557565b34801561093257600080fd5b50610952610941366004614b89565b604080516020810190915290815290565b60405161032e9190614fe6565b34801561096b57600080fd5b5061049161097a366004614acb565b61256d565b34801561098b57600080fd5b50610491612583565b3480156109a057600080fd5b506397a6f304610606565b6103016109b9366004614963565b61258e565b3480156109ca57600080fd5b506103016109d936600461483c565b612623565b600054610100900460ff166109f95760005460ff16156109fd565b303b155b610a745760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600054610100900460ff16158015610a96576000805461ffff19166101011790555b610a9e612738565b610aa66127bd565b610ab88b8b8b8b8b8b8b8b8b8b61283a565b610ac061197a565b8015610aef57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b5050505050505050505050565b6040805160208101909152600081526000610b178382612b2d565b67ffffffffffffffff168252610b2e6008826151eb565b905080835114610b6a576040517f97363b3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50919050565b604080516080810182526000808252602082018190529181018290526060810191909152610ba082610833612583565b92915050565b3073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e5483bf7fc740675b44dcd4b0f90983f8689d804161415610c525760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f64656c656761746563616c6c00000000000000000000000000000000000000006064820152608401610a6b565b7f000000000000000000000000e5483bf7fc740675b44dcd4b0f90983f8689d80473ffffffffffffffffffffffffffffffffffffffff16610cc77f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614610d505760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f6163746976652070726f787900000000000000000000000000000000000000006064820152608401610a6b565b610d5981612b93565b610d928160005b6040519080825280601f01601f191660200182016040528015610d8a576020820181803683370190505b506000612bfa565b50565b60606000610da38888612557565b905080341015610ddf576040517f025dbdd400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b508367ffffffffffffffff811115610e0757634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015610e9757816020015b610e84604080516060808201835260008083528351608081018552818152602081810183905294810182905291820152909182019081526040805160808101825260008082526020828101829052928201819052606082015291015290565b815260200190600190039081610e255790505b50905060005b868110156112e25760606000610ee38a8a85818110610ecc57634e487b7160e01b600052603260045260246000fd5b9050602002810190610ede91906150e2565b612dbb565b60e001519150600090508080610ef884612f3f565b92509250925060005b828110156112d1576040848601015160209060005b8c811015610f5957818e8e83818110610f3f57634e487b7160e01b600052603260045260246000fd5b905060200201351415610f5157610f59565b600101610f16565b808d1480610f915750898181518110610f8257634e487b7160e01b600052603260045260246000fd5b60209081029190910101515115155b15610fa257505050928101926112c9565b6000610faf8989886130d2565b509050828b8381518110610fd357634e487b7160e01b600052603260045260246000fd5b6020026020010151600001818152505080604001518b838151811061100857634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516000019060070b908160070b8152505080606001518b838151811061104957634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516020019067ffffffffffffffff16908167ffffffffffffffff168152505080602001518b838151811061109857634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516040019060030b908160030b81525050806000015167ffffffffffffffff168b83815181106110e357634e487b7160e01b600052603260045260246000fd5b602002602001015160200151606001818152505080608001518b838151811061111c57634e487b7160e01b600052603260045260246000fd5b6020026020010151604001516000019060070b908160070b815250508060a001518b838151811061115d57634e487b7160e01b600052603260045260246000fd5b6020026020010151604001516020019067ffffffffffffffff16908167ffffffffffffffff168152505080602001518b83815181106111ac57634e487b7160e01b600052603260045260246000fd5b6020026020010151604001516040019060030b908160030b81525050806000015167ffffffffffffffff168b83815181106111f757634e487b7160e01b600052603260045260246000fd5b60200260200101516040015160600181815250508c67ffffffffffffffff168b838151811061123657634e487b7160e01b600052603260045260246000fd5b60200260200101516020015160600151108061128a57508b67ffffffffffffffff168b838151811061127857634e487b7160e01b600052603260045260246000fd5b60200260200101516020015160600151115b156112c0576000801b8b83815181106112b357634e487b7160e01b600052603260045260246000fd5b6020908102919091010151525b50505093820193505b600101610f01565b505060019093019250610e9d915050565b5060005b848110156113585781818151811061130e57634e487b7160e01b600052603260045260246000fd5b602090810291909101015151611350576040517f45805f5d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001016112e6565b509695505050505050565b60408051602081019091526000815260008061137f8482612b2d565b905061138c6008836151eb565b9150600061139a8584612b2d565b90506113a76008846151eb565b92506113be67ffffffffffffffff8216600a615264565b6113d29067ffffffffffffffff841661532a565b84528451831461140e576040517f97363b3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050919050565b3073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e5483bf7fc740675b44dcd4b0f90983f8689d8041614156114c25760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f64656c656761746563616c6c00000000000000000000000000000000000000006064820152608401610a6b565b7f000000000000000000000000e5483bf7fc740675b44dcd4b0f90983f8689d80473ffffffffffffffffffffffffffffffffffffffff166115377f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16146115c05760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f6163746976652070726f787900000000000000000000000000000000000000006064820152608401610a6b565b6115c982612b93565b6115d582826001612bfa565b5050565b60003073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e5483bf7fc740675b44dcd4b0f90983f8689d80416146116865760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610a6b565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b60d05460009061ffff84811691161480156116c7575060d15482145b9392505050565b6116fa604080516080810190915280600081526020016000815260006020820152606060409091015290565b60008061170784826131fb565b905063ffffffff8116635054474d1461174c576040517f97363b3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117576004836151eb565b915060006117658584613261565b90508060ff16600181111561178a57634e487b7160e01b600052602160045260246000fd5b849060018111156117ab57634e487b7160e01b600052602160045260246000fd5b908160018111156117cc57634e487b7160e01b600052602160045260246000fd5b9052506117da6001846151eb565b92506001845160018111156117ff57634e487b7160e01b600052602160045260246000fd5b14611836576040517f63daeb7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006118428685613261565b90508060ff16600581111561186757634e487b7160e01b600052602160045260246000fd5b8560200190600581111561188b57634e487b7160e01b600052602160045260246000fd5b908160058111156118ac57634e487b7160e01b600052602160045260246000fd5b9052506118ba6001856151eb565b93506118c686856132c7565b61ffff1660408601526118da6002856151eb565b93506118f5848588516118ed9190615367565b88919061332d565b60608601525092949350505050565b60408051608081018252600080825260208201819052918101829052606081019190915261193183611c59565b905081611942428360600151613455565b1115610ba0576040517f19abf40e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60335473ffffffffffffffffffffffffffffffffffffffff1633146119e15760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a6b565b6119eb600061347a565b565b6040805160208101909152600081526000611a0883826131fb565b63ffffffff168252610b2e6004826151eb565b604080516020810190915260608152600080611a378482613261565b9050611a446001836151eb565b91508060ff1667ffffffffffffffff811115611a7057634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611ab557816020015b6040805180820190915260008082526020820152815260200190600190039081611a8e5790505b50835260005b8160ff16811015611b6f57611ad085846132c7565b8451805183908110611af257634e487b7160e01b600052603260045260246000fd5b602090810291909101015161ffff9091169052611b106002846151eb565b9250611b1c85846134f1565b8451805183908110611b3e57634e487b7160e01b600052603260045260246000fd5b60200260200101516020018181525050602083611b5b91906151eb565b925080611b67816153aa565b915050611abb565b5081845114611baa576040517f97363b3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050919050565b6040805160208101909152600081526000611bcc8382613557565b73ffffffffffffffffffffffffffffffffffffffff168252610b2e6014826151eb565b600081600001518260200151604051602001611c3c92919060f09290921b7fffff000000000000000000000000000000000000000000000000000000000000168252600282015260220190565b604051602081830303815290604052805190602001209050919050565b60408051608081018252600080825260208083018281528385018381526060850184815287855260d590935294909220805467ffffffffffffffff808216938490526801000000000000000091829004600390810b810b900b9096526001820154600781810b810b900b865204909416909152909190610b6a576040517f14aebe6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051608081018252600080825260208083018281528385018381526060850184815287855260d590935294909220805467ffffffffffffffff80821693849052680100000000000000008204600390810b810b900b9096526c010000000000000000000000008104600790810b810b900b8552740100000000000000000000000000000000000000009004909416909152909190610b6a576040517f14aebe6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611df260c95473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16639a8a05926040518163ffffffff1660e01b815260040160206040518083038186803b158015611e3757600080fd5b505afa158015611e4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6f9190614d81565b905090565b606060c9600301805480602002602001604051908101604052809291908181526020016000905b82821015611ede5760008481526020908190206040805180820190915260028502909101805461ffff168252600190810154828401529083529092019101611e9b565b50505050905090565b60408051608081018252600080825260208201819052918101829052606081019190915261193183611d05565b604080516080810182526000808252602082018190529181018290526060810191909152610ba082610636612583565b6000611f8583838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506135cd92505050565b90506000611f968260e001516116ce565b9050611fa0611dd1565b61ffff16816040015161ffff1614158015611fc25750604081015161ffff1615155b15611ff9576040517f63daeb7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008160200151600581111561201f57634e487b7160e01b600052602160045260246000fd5b141561207e57604081015161ffff16612064576040517f63daeb7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6120796120748260600151611bb1565b6137f8565b61221e565b6001816020015160058111156120a457634e487b7160e01b600052602160045260246000fd5b14156120cb576120796120c68260600151604080516020810190915290815290565b613801565b6002816020015160058111156120f157634e487b7160e01b600052602160045260246000fd5b141561210c576120796121078260600151611a1b565b613baf565b60038160200151600581111561213257634e487b7160e01b600052602160045260246000fd5b141561214d576120796121488260600151611363565b613d94565b60048160200151600581111561217357634e487b7160e01b600052602160045260246000fd5b141561218e576120796121898260600151610afc565b613de6565b6005816020015160058111156121b457634e487b7160e01b600052602160045260246000fd5b14156121ec576040517f97363b3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f97363b3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b82811461225d576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b838110156123155782828281811061228857634e487b7160e01b600052603260045260246000fd5b905060200201602081019061229d9190614de2565b67ffffffffffffffff166122ed8686848181106122ca57634e487b7160e01b600052603260045260246000fd5b90506020020135600090815260d5602052604090205467ffffffffffffffff1690565b67ffffffffffffffff16101561230d57612307878761258e565b50612348565b600101612260565b506040517fde2c57fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b6123af604080516060808201835260008083528351608081018552818152602081810183905294810182905291820152909182019081526040805160808101825260008082526020828101829052928201819052606082015291015290565b6040805160c08082018352600080835260208084018290528385018290526060808501839052608080860184905260a095860184905288845260d5835286842087519586018852805467ffffffffffffffff808216885268010000000000000000808304600390810b810b900b968901969096526c010000000000000000000000008204600790810b810b810b9a89019a909a52740100000000000000000000000000000000000000009091048116938701939093526001015480880b880b90970b90850152940490931691810191909152805190915067ffffffffffffffff166124c6576040517f14aebe6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b91815260408083015160208084018051600793840b840b9052606080870151825167ffffffffffffffff9182169085015283880180518451600391820b820b9089015289519451948316948401949094526080890151878901805191880b90970b905260a089015186519083169501949094529251845190830b90920b919094015293519051931692019190915290565b60008161256360ce5490565b6116c7919061532a565b60008161257960ce5490565b610ba0919061532a565b6000611e6f60cf5490565b600061259a8383612557565b9050803410156125d6576040517f025dbdd400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8281101561221e5761261b84848381811061260457634e487b7160e01b600052603260045260246000fd5b905060200281019061261691906150e2565b613e23565b6001016125d9565b60335473ffffffffffffffffffffffffffffffffffffffff16331461268a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a6b565b73ffffffffffffffffffffffffffffffffffffffff81166127135760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610a6b565b610d928161347a565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b600054610100900460ff166127b55760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a6b565b6119eb613e35565b600054610100900460ff166119eb5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a6b565b60c980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8c161790558786146128b3576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b88811015612aad57600060405180604001604052808c8c858181106128eb57634e487b7160e01b600052603260045260246000fd5b90506020020160208101906129009190614d65565b61ffff1681526020018a8a8581811061292957634e487b7160e01b600052603260045260246000fd5b602090810292909201359092528251838201516040805160f09390931b7fffff00000000000000000000000000000000000000000000000000000000000016838501526022808401929092528051808403909201825260429092018252805190830120600090815260cd9092529020549192505060ff16156129d7576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160cd60006129e684611bef565b8152602080820192909252604001600090812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169315159390931790925560cc8054600181018255925282517f47197230e1e4b29fc0bd84d7d78966c0925452aff72a2a121538b102457e9ebe6002909302928301805461ffff191661ffff90921691909117905591909101517f47197230e1e4b29fc0bd84d7d78966c0925452aff72a2a121538b102457e9ebf9091015580612aa5816153aa565b9150506128b6565b506040805180820190915261ffff86168082526020820186905260d0805461ffff1916909117905560d185905560d280547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff861617905550612b188260cf55565b612b218160ce55565b50505050505050505050565b6000612b3a8260086151eb565b83511015612b8a5760405162461bcd60e51b815260206004820152601460248201527f746f55696e7436345f6f75744f66426f756e64730000000000000000000000006044820152606401610a6b565b50016008015190565b60335473ffffffffffffffffffffffffffffffffffffffff163314610d925760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a6b565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612c3257612c2d83613ebb565b505050565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b815260040160206040518083038186803b158015612c7857600080fd5b505afa925050508015612ca8575060408051601f3d908101601f19168201909252612ca591810190614ae3565b60015b612d1a5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201527f6f6e206973206e6f7420555550530000000000000000000000000000000000006064820152608401610a6b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114612daf5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f7860448201527f6961626c655555494400000000000000000000000000000000000000000000006064820152608401610a6b565b50612c2d838383613fab565b604080516101608101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e0820181905261010082018390526101208201526101408101919091526000612e3460c95473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1663c0fd8bde85856040518363ffffffff1660e01b8152600401612e6e929190614fa4565b60006040518083038186803b158015612e8657600080fd5b505afa158015612e9a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612ec29190810190614c13565b50909250905080612eff576040517f2acbe91500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50612f0981613fd0565b610ba0576040517fe60dce7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808080612f52858260049101015190565b90506004840193508063ffffffff16635032574814612f9d576040517fe69ffece00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002858501810151940193600361ffff821614612fe6576040517fe69ffece00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002850194506000612ffc878760029101015190565b90506002860195506000613014888860019101015190565b90508161ffff16870196508060ff1660021461305c576040517fe69ffece00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050508284016002015161ffff169150600283019250613081848460029101015190565b61ffff16905060028301925081810283018451146130cb576040517fe69ffece00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9193909250565b6040805160c081018252600080825260208201818152828401828152606084018381526080850184815260a08601948552888a01968701516048880151600790810b810b909452605088015167ffffffffffffffff9081169093526054880151600390810b900b909452605c870151830b90920b909152606485015181169092526065840151607d94850151909216835291929060ff81166001141561317d576018820191506131b7565b8582018701600881015167ffffffffffffffff90811686526010820151600790810b900b6040870152601891820151166060860152909101905b50838111156131f2576040517fe69ffece00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50935093915050565b60006132088260046151eb565b835110156132585760405162461bcd60e51b815260206004820152601460248201527f746f55696e7433325f6f75744f66426f756e64730000000000000000000000006044820152606401610a6b565b50016004015190565b600061326e8260016151eb565b835110156132be5760405162461bcd60e51b815260206004820152601360248201527f746f55696e74385f6f75744f66426f756e6473000000000000000000000000006044820152606401610a6b565b50016001015190565b60006132d48260026151eb565b835110156133245760405162461bcd60e51b815260206004820152601460248201527f746f55696e7431365f6f75744f66426f756e64730000000000000000000000006044820152606401610a6b565b50016002015190565b60608161333b81601f6151eb565b10156133895760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610a6b565b61339382846151eb565b845110156133e35760405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152606401610a6b565b606082158015613402576040519150600082526020820160405261344c565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561343b578051835260209283019201613423565b5050858452601f01601f1916604052505b50949350505050565b600081831115613470576134698284615367565b9050610ba0565b6134698383615367565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60006134fe8260206151eb565b8351101561354e5760405162461bcd60e51b815260206004820152601560248201527f746f427974657333325f6f75744f66426f756e647300000000000000000000006044820152606401610a6b565b50016020015190565b60006135648260146151eb565b835110156135b45760405162461bcd60e51b815260206004820152601560248201527f746f416464726573735f6f75744f66426f756e647300000000000000000000006044820152606401610a6b565b5001602001516c01000000000000000000000000900490565b604080516101608101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201819052610100820183905261012082015261014081019190915260008061364760c95473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1663c0fd8bde856040518263ffffffff1660e01b815260040161367f9190614fd3565b60006040518083038186803b15801561369757600080fd5b505afa1580156136ab573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526136d39190810190614c13565b50915091508061370f576040517f2acbe91500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613721826060015183608001516116ab565b613757576040517f360f2d8700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60d25467ffffffffffffffff1667ffffffffffffffff168260a0015167ffffffffffffffff16116137b4576040517f88d1b84700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a082015160d280547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff9092169190911790555092915050565b610d928161404a565b60006138356040805180820182526000808252602091820152815180830190925260d05461ffff16825260d1549082015290565b905060008061385960c95473ffffffffffffffffffffffffffffffffffffffff1690565b84516040517fc0fd8bde00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff929092169163c0fd8bde916138ad91600401614fd3565b60006040518083038186803b1580156138c557600080fd5b505afa1580156138d9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526139019190810190614c13565b50915091508061393d576040517f2acbe91500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061394c8360e001516116ce565b9050613956611dd1565b61ffff16816040015161ffff16141580156139785750604081015161ffff1615155b156139af576040517f63daeb7700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005816020015160058111156139d557634e487b7160e01b600052602160045260246000fd5b14613a0c576040517f97363b3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000613a1b82606001516119ed565b805190915063ffffffff16613a3560d45463ffffffff1690565b63ffffffff1610613a72576040517f88d1b84700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160d480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff909216919091179055604080518082018252606086015161ffff168082526080870151602080840182905260d0805461ffff19168417905560d182905560a089015160d280547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff90921691909117905584518086018652600080825290820152845180860190955291845290830152907f6bce23ef3d34e51710fe4700b43ba5f1733a6215c883f384671a4ece3ea8aa2090879060d25460408051845161ffff908116825260209586015186830152845116918101919091529290910151606083015267ffffffffffffffff16608082015260a00160405180910390a150505050505050565b6000613bb9611e74565b905060005b8151811015613c4f57600060c96004016000613c00858581518110613bf357634e487b7160e01b600052603260045260246000fd5b6020026020010151611bef565b8152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055613c486001826151eb565b9050613bbe565b50613c5c60cc60006145d8565b60005b825151811015613d4f578251805160cc919083908110613c8f57634e487b7160e01b600052603260045260246000fd5b60209081029190910181015182546001808201855560009485528385208351600290930201805461ffff191661ffff90931692909217825591909201519181019190915584518051919260cd929091613d009186908110613bf357634e487b7160e01b600052603260045260246000fd5b8152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905580613d47816153aa565b915050613c5f565b507fd451e0fcb7c5b9e13de533604d158069dad159841c45f39f09d379bfc423080d81613d7a611e74565b604051613d88929190614f30565b60405180910390a15050565b6000613d9f60ce5490565b825160ce5590507f74dbbbe280ef27b79a8a0c449d5ae2ba7a31849103241d0f98df70bbc9d03e3781613dd160ce5490565b60408051928352602083019190915201613d88565b6000613df160cf5490565b825160cf5590507fcdb88a22f82ddd76115ab7c66cf08eb1e40afe80c9b31017eb2cbdb1570b33ae81613dd160cf5490565b6115d5613e308383612dbb565b6141e7565b600054610100900460ff16613eb25760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a6b565b6119eb3361347a565b73ffffffffffffffffffffffffffffffffffffffff81163b613f455760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e7472616374000000000000000000000000000000000000006064820152608401610a6b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b613fb48361442d565b600082511180613fc15750805b15612c2d5761221e838361447a565b6000610ba0826060015183608001516040805160f09390931b7fffff000000000000000000000000000000000000000000000000000000000000166020808501919091526022808501939093528151808503909301835260429093018152815191830191909120600090815260cd90925290205460ff1690565b600061408a7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b825190915061409a906000610d60565b3073ffffffffffffffffffffffffffffffffffffffff1663e3795cc16040518163ffffffff1660e01b815260040160206040518083038186803b1580156140e057600080fd5b505afa1580156140f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141189190614dc8565b63ffffffff166397a6f3041461415a576040517f97363b3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f2e4cc16c100f0b55e2df82ab0b1a7e294aa9cbd01b48fbaf622683fbc0507a49816141ba7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b6040805173ffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201613d88565b60e0810151600080806141f984612f3f565b92509250925060005b828110156143d3576000806142188787866130d2565b600081815260d5602052604090205482519887019892945090925067ffffffffffffffff90811691168110156143c857600082815260d560209081526040918290208551815487840151888601516060808b015167ffffffffffffffff9586167fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090951685176801000000000000000063ffffffff60039690960b959095168502177fffffffff00000000000000000000000000000000ffffffffffffffffffffffff166c01000000000000000000000000600794850b808916919091027fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff16919091177401000000000000000000000000000000000000000092881692830217885560808d01516001909801805460a08f01519990950b88167fffffffffffffffffffffffffffffffff0000000000000000000000000000000090951694909417979096169093029590951790558551918252938101919091529283019190915283917fd06a6b7f4918494b3719217d1802786c1f5112a6c1d88fe2cfec00b4584f6aec910160405180910390a25b505050600101614202565b50606085015160a08601516040805161ffff909316835267ffffffffffffffff90911660208301527f943f0e8a16c19895fb87cbeb1a349ed86d7f31923089dd36c1a1ed5e300f267b910160405180910390a15050505050565b61443681613ebb565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606073ffffffffffffffffffffffffffffffffffffffff83163b6145065760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152608401610a6b565b6000808473ffffffffffffffffffffffffffffffffffffffff168460405161452e9190614f01565b600060405180830381855af49150503d8060008114614569576040519150601f19603f3d011682016040523d82523d6000602084013e61456e565b606091505b5091509150614596828260405180606001604052806027815260200161544c6027913961459f565b95945050505050565b606083156145ae5750816116c7565b8251156145be5782518084602001fd5b8160405162461bcd60e51b8152600401610a6b9190614fd3565b5080546000825560020290600052602060002090810190610d9291905b8082111561461557805461ffff19168155600060018201556002016145f5565b5090565b803573ffffffffffffffffffffffffffffffffffffffff8116811461463d57600080fd5b919050565b60008083601f840112614653578182fd5b50813567ffffffffffffffff81111561466a578182fd5b6020830191508360208260051b850101111561468557600080fd5b9250929050565b600082601f83011261469c578081fd5b8151602067ffffffffffffffff8211156146b8576146b861540f565b6146c6818360051b01615192565b80838252828201915082860187848660071b89010111156146e5578586fd5b855b8581101561474857608080838b0312156146ff578788fd5b614707615145565b835181528684015187820152604061472081860161482b565b90820152606061473185820161482b565b9082015285529385019391909101906001016146e7565b5090979650505050505050565b8051801515811461463d57600080fd5b600082601f830112614775578081fd5b8135614788614783826151c3565b615192565b81815284602083860101111561479c578283fd5b816020850160208301379081016020019190915292915050565b600082601f8301126147c6578081fd5b81516147d4614783826151c3565b8181528460208386010111156147e8578283fd5b6147f982602083016020870161537e565b949350505050565b805161463d81615425565b805163ffffffff8116811461463d57600080fd5b805161463d81615435565b805160ff8116811461463d57600080fd5b60006020828403121561484d578081fd5b6116c782614619565b6000806000806000806000806000806101008b8d031215614875578586fd5b61487e8b614619565b995060208b013567ffffffffffffffff8082111561489a578788fd5b6148a68e838f01614642565b909b50995060408d01359150808211156148be578788fd5b506148cb8d828e01614642565b90985096505060608b01356148df81615425565b945060808b0135935060a08b01356148f681615435565b8093505060c08b0135915060e08b013590509295989b9194979a5092959850565b60008060408385031215614929578182fd5b61493283614619565b9150602083013567ffffffffffffffff81111561494d578182fd5b61495985828601614765565b9150509250929050565b60008060208385031215614975578182fd5b823567ffffffffffffffff81111561498b578283fd5b61499785828601614642565b90969095509350505050565b600080600080600080606087890312156149bb578384fd5b863567ffffffffffffffff808211156149d2578586fd5b6149de8a838b01614642565b909850965060208901359150808211156149f6578586fd5b614a028a838b01614642565b90965094506040890135915080821115614a1a578384fd5b50614a2789828a01614642565b979a9699509497509295939492505050565b60008060008060008060808789031215614a51578384fd5b863567ffffffffffffffff80821115614a68578586fd5b614a748a838b01614642565b90985096506020890135915080821115614a8c578586fd5b50614a9989828a01614642565b9095509350506040870135614aad81615435565b91506060870135614abd81615435565b809150509295509295509295565b600060208284031215614adc578081fd5b5035919050565b600060208284031215614af4578081fd5b5051919050565b60008060408385031215614b0d578182fd5b50508035926020909101359150565b60008060208385031215614b2e578182fd5b823567ffffffffffffffff80821115614b45578384fd5b818501915085601f830112614b58578384fd5b813581811115614b66578485fd5b866020828501011115614b77578485fd5b60209290920196919550909350505050565b600060208284031215614b9a578081fd5b813567ffffffffffffffff811115614bb0578182fd5b6147f984828501614765565b600060408284031215614bcd578081fd5b6040516040810181811067ffffffffffffffff82111715614bf057614bf061540f565b6040528235614bfe81615425565b81526020928301359281019290925250919050565b600080600060608486031215614c27578081fd5b835167ffffffffffffffff80821115614c3e578283fd5b908501906101608288031215614c52578283fd5b614c5a61516e565b614c638361482b565b8152614c716020840161480c565b6020820152614c826040840161480c565b6040820152614c9360608401614801565b606082015260808301516080820152614cae60a08401614820565b60a0820152614cbf60c0840161482b565b60c082015260e083015182811115614cd5578485fd5b614ce1898286016147b6565b60e083015250610100614cf581850161480c565b908201526101208381015183811115614d0c578586fd5b614d188a82870161468c565b918301919091525061014083810151908201529450614d3960208701614755565b93506040860151915080821115614d4e578283fd5b50614d5b868287016147b6565b9150509250925092565b600060208284031215614d76578081fd5b81356116c781615425565b600060208284031215614d92578081fd5b81516116c781615425565b60008060408385031215614daf578182fd5b8235614dba81615425565b946020939093013593505050565b600060208284031215614dd9578081fd5b6116c78261480c565b600060208284031215614df3578081fd5b81356116c781615435565b6000815180845260208085019450808401835b83811015614e4557614e32878351805161ffff168252602090810151910152565b6040969096019590820190600101614e11565b509495945050505050565b60008151808452614e6881602086016020860161537e565b601f01601f19169290920160200192915050565b805182526020810151614ec36020840182805160070b825267ffffffffffffffff6020820151166020830152604081015160030b6040830152606081015160608301525050565b50604090810151805160070b60a0840152602081015167ffffffffffffffff1660c08401529081015160030b60e08301526060015161010090910152565b60008251614f1381846020870161537e565b9190910192915050565b6020815260006116c76020830184614dfe565b604081526000614f436040830185614dfe565b82810360208401526145968185614dfe565b6020808252825182820181905260009190848201906040850190845b81811015614f9857614f84838551614e7c565b928401926101209290920191600101614f71565b50909695505050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b6020815260006116c76020830184614e50565b60208152600082516020808401526147f96040840182614e50565b815161ffff1681526020808301519082015260408101610ba0565b602081526000825160028110615034576150346153f9565b80602084015250602083015160068110615050576150506153f9565b8060408401525061ffff604084015116606083015260608301516080808401526147f960a0840182614e50565b6101208101610ba08284614e7c565b815160070b815260208083015167ffffffffffffffff169082015260408083015160030b908201526060808301519082015260808101610ba0565b60208152600082516020808401526147f96040840182614dfe565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615116578283fd5b83018035915067ffffffffffffffff821115615130578283fd5b60200191503681900382131561468557600080fd5b6040516080810167ffffffffffffffff811182821017156151685761516861540f565b60405290565b604051610160810167ffffffffffffffff811182821017156151685761516861540f565b604051601f8201601f1916810167ffffffffffffffff811182821017156151bb576151bb61540f565b604052919050565b600067ffffffffffffffff8211156151dd576151dd61540f565b50601f01601f191660200190565b600082198211156151fe576151fe6153e3565b500190565b600181815b8085111561525c57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615242576152426153e3565b8085161561524f57918102915b93841c9390800290615208565b509250929050565b60006116c7838360008261527a57506001610ba0565b8161528757506000610ba0565b816001811461529d57600281146152a7576152c3565b6001915050610ba0565b60ff8411156152b8576152b86153e3565b50506001821b610ba0565b5060208310610133831016604e8410600b84101617156152e6575081810a610ba0565b6152f08383615203565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615322576153226153e3565b029392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615362576153626153e3565b500290565b600082821015615379576153796153e3565b500390565b60005b83811015615399578181015183820152602001615381565b8381111561221e5750506000910152565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156153dc576153dc6153e3565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b61ffff81168114610d9257600080fd5b67ffffffffffffffff81168114610d9257600080fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212208b6bf04961e1e9107ec331071c06bf2701a68c6d300e06fb182fdaa500269b5e64736f6c63430008040033