diff --git a/.gitignore b/.gitignore index f55315b..90fda89 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ out out.log broadcast dist -ts-types \ No newline at end of file +ts-types +ts-build \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..ff152ca --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "lib/wormhole-solidity-sdk"] + path = lib/wormhole-solidity-sdk + url = https://github.com/wormhole-foundation/wormhole-solidity-sdk.git + branch = sr-refactor diff --git a/Makefile b/Makefile index 7358e71..5d47817 100644 --- a/Makefile +++ b/Makefile @@ -1,31 +1,50 @@ -TEST_RPC = https://rpc.ankr.com/eth +TEST_RPC = https://ethereum-rpc.publicnode.com tolib = $(addprefix lib/,$(firstword $(subst @, ,$(notdir $(1))))) -define install_lib -dependencies: $(call tolib,$(1)) +define install_lib_evm +dependencies-evm: $(call tolib,$(1)) $(call tolib,$(1)): - forge install $(1) --no-git --no-commit + forge install $(1) --no-git endef .DEFAULT_GOAL = build -.PHONY: build test clean dependencies +.PHONY: build* test* clean* dependencies* -build: dependencies - forge build +build: build-evm build-solana build-solana-ts -test: dependencies - forge test --fork-url $(TEST_RPC) -vvvv -#--match-test InitiateFullFuzz +test: test-evm test-solana + +clean: clean-evm clean-solana LIB_DEPS = foundry-rs/forge-std -LIB_DEPS += openzeppelin/openzeppelin-contracts@0457042d93d9dfd760dbaa06a4d2f1216fdbe297 #for gscd's optimizations -LIB_DEPS += wormhole-foundation/wormhole-solidity-sdk@67ca81c +LIB_DEPS += wormhole-foundation/wormhole-solidity-sdk@a7c8786 # dynamically generate install rule for each lib dependency and add to depdenencies -$(foreach dep,$(LIB_DEPS), $(eval $(call install_lib,$(dep)))) +$(foreach dep,$(LIB_DEPS), $(eval $(call install_lib_evm,$(dep)))) -clean: + +build-evm: dependencies-evm + forge build + +test-evm: dependencies-evm + forge test --fork-url $(TEST_RPC) -vvvv +#--match-test InitiateFullFuzz + +clean-evm: forge clean rm -rf lib + + +build-solana: + cd src/solana; anchor build + +build-solana-ts: + npm run build --prefix src/solana + +test-solana: + cd src/solana; anchor test + +clean-solana: + cd src/solana; anchor clean diff --git a/foundry.toml b/foundry.toml index d98a956..ab6d28e 100644 --- a/foundry.toml +++ b/foundry.toml @@ -3,7 +3,7 @@ solc_version = "0.8.28" evm_version = "paris" # prevent use of PUSH0 opcode until it is widely supported optimizer = true via_ir = true -extra_output = ["asm"] +extra_output = ["asm", "metadata", "storageLayout", "evm.deployedBytecode.immutableReferences"] libs = [ "lib", @@ -11,7 +11,6 @@ libs = [ remappings = [ "forge-std/=lib/forge-std/src/", - "@openzeppelin/=lib/openzeppelin-contracts/", "wormhole-sdk/=lib/wormhole-solidity-sdk/src/", "core-bridge/=src/", ] diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..105e4b2 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "core-v2", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/package.json @@ -0,0 +1 @@ +{} diff --git a/src/BackwardsOptimized/BackwardsOptimized.sol b/src/BackwardsOptimized/BackwardsOptimized.sol deleted file mode 100644 index 132ef86..0000000 --- a/src/BackwardsOptimized/BackwardsOptimized.sol +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.24; - -import "wormhole-sdk/interfaces/IWormhole.sol"; -import "wormhole-sdk/libraries/BytesParsing.sol"; -import "wormhole-sdk/libraries/CoreBridge.sol"; -import {VaaLib} from "wormhole-sdk/libraries/VaaLib.sol"; -import { ProxyBase } from "wormhole-sdk/proxy/ProxyBase.sol"; -import "./ExtStore.sol"; - -contract BackwardsOptimized is ProxyBase, ExtStore { - using BytesParsing for bytes; - using VaaLib for bytes; - - mapping(uint32 => uint32) private _guardianSetExpirationTimes; - uint32 private _currentGuardianSetIndex; - - constructor() ExtStore() {} - - function _proxyConstructor(bytes calldata args) internal override { - // bytes memory data = new bytes(0); - // for (uint i = 0; i < guardians.length; ++i) - // data = abi.encodePacked(data, guardians[i]); - - //despite the "packed" it will actually pad each entry to 32 bytes - _currentGuardianSetIndex = uint32(_extWrite(abi.encodePacked(args))); - } - - function parseAndVerifyVM( - bytes calldata encodedVm - ) external view returns (IWormhole.VM memory vm, bool valid, string memory reason) { unchecked { - vm = encodedVm.decodeVmStructCd(); - - uint32 guardianSetIndex = vm.guardianSetIndex; - address[] memory guardianAddrs = _getGuardianAddresses(guardianSetIndex); - require( - CoreBridgeLib.isVerifiedByQuorumMem( - vm.hash, - VaaLib.asGuardianSignatures(vm.signatures), - guardianAddrs - ), - "VM not verified by quorum" - ); - - //backwards compatible nonsense: - valid = true; - reason = ""; - }} - - function getGuardianSet(uint32 index) external view returns (IWormhole.GuardianSet memory ret) { - ret.keys = _getGuardianAddresses(index); - ret.expirationTime = _guardianSetExpirationTimes[index]; - } - - function getCurrentGuardianSetIndex() external view returns (uint32) { unchecked { - return _currentGuardianSetIndex; - }} - - function _getGuardianAddresses(uint32 index) internal view returns (address[] memory ret) { - bytes memory data = _extRead(index); - assembly ("memory-safe") { - ret := data - mstore(ret, div(mload(ret), 32)) - } - } -} \ No newline at end of file diff --git a/src/ThresholdSigOptimized.sol b/src/ThresholdSigOptimized.sol deleted file mode 100644 index 5648844..0000000 --- a/src/ThresholdSigOptimized.sol +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.24; - -import "wormhole-sdk/interfaces/IWormhole.sol"; -import "wormhole-sdk/libraries/BytesParsing.sol"; -import "wormhole-sdk/libraries/VaaLib.sol"; -import { ProxyBase } from "wormhole-sdk/proxy/ProxyBase.sol"; - -contract ThresholdSigOptimized is ProxyBase { - using BytesParsing for bytes; - using VaaLib for bytes; - - mapping (uint32 => address) private _expiringThresholdAddrs; - mapping (uint32 => uint32) private _expirationTimes; - uint32 private _currentGuardianSetIndex; - address private _currentThresholdAddr; //put in same storage slot as _currentGuardianSetIndex - //to save gas on storage reads for most cases - - function _proxyConstructor(bytes calldata args) internal override { - _currentThresholdAddr = abi.decode(args, (address)); - } - - function parseAndVerifyVMThreshold( - bytes calldata encodedVaa - ) external view returns (VaaBody memory) { - ( uint32 guardianSetIndex, - GuardianSignature[] memory sigs, - uint envelopeOffset - ) = encodedVaa.decodeVaaHeaderCdUnchecked(); - - address thresholdAddr; - if (guardianSetIndex != _currentGuardianSetIndex) { - thresholdAddr = _expiringThresholdAddrs[guardianSetIndex]; - require(thresholdAddr != address(0), "invalid guardian set"); - require( - _expirationTimes[guardianSetIndex] >= block.timestamp, - "guardian set has expired" - ); - } - else - thresholdAddr = _currentThresholdAddr; - require(sigs.length == 1, "not a threshold signature vm"); - - bytes32 vaaHash = encodedVaa.calcVaaDoubleHashCd(envelopeOffset); - GuardianSignature memory sig = sigs[0]; - require(ecrecover(vaaHash, sig.v, sig.r, sig.s) == thresholdAddr, "threshold signature invalid"); - return encodedVaa.decodeVaaBodyStructCd(envelopeOffset); - } -} \ No newline at end of file diff --git a/src/evm/EIP712Encoding.sol b/src/evm/EIP712Encoding.sol new file mode 100644 index 0000000..9aaf4cc --- /dev/null +++ b/src/evm/EIP712Encoding.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.8.0; + +import {eagerOr} from "wormhole-sdk/Utils.sol"; +import {BytesParsing} from "wormhole-sdk/libraries/BytesParsing.sol"; +import {VaaLib} from "wormhole-sdk/libraries/VaaLib.sol"; + +bytes32 constant REGISTER_TYPE_HASH = keccak256( + "GuardianRegister(uint32 guardianSet,uint32 expirationTime,bytes32 id)" +); + +interface IERC5267 { + function eip712Domain() external view returns ( + bytes1 fields, + string memory name, + string memory version, + uint256 chainId, + address verifyingContract, + bytes32 salt, + uint256[] memory extensions + ); +} + +contract EIP712Encoding is IERC5267 { + bytes32 constant EIP712_DOMAIN_TYPE_HASH = keccak256( + "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" + ); + + string constant EIP712_NAME = "Wormhole VerificationV2"; + string constant EIP712_VERSION = "1"; + + bytes32 constant EIP712_NAME_HASH = keccak256(bytes(EIP712_NAME)); + bytes32 constant EIP712_VERSION_HASH = keccak256(bytes(EIP712_VERSION)); + + bytes32 private immutable _domainSeparator; + + constructor () { + _domainSeparator = getDomainSeparator(block.chainid, address(this)); + } + + function eip712Domain() external view returns ( + bytes1 fields, + string memory name, + string memory version, + uint256 chainId, + address verifyingContract, + bytes32 salt, + uint256[] memory extensions + ) { + return ( + bytes1(0x0F), + EIP712_NAME, + EIP712_VERSION, + block.chainid, + address(this), + bytes32(0), + new uint256[](0) + ); + } + + function DOMAIN_SEPARATOR() external view returns (bytes32) { + return _domainSeparator; + } + + function getDomainSeparator( + uint256 eth_chain_id, address verifyingContract + ) internal pure returns (bytes32) { + return keccak256(abi.encode( + EIP712_DOMAIN_TYPE_HASH, + EIP712_NAME_HASH, + EIP712_VERSION_HASH, + eth_chain_id, + verifyingContract + )); + } + + function getRegisterGuardianDigest( + uint32 thresholdKeyIndex, uint32 expirationTime, bytes32 guardianId + ) public view returns (bytes32) { + bytes32 idHash = keccak256(abi.encode( + REGISTER_TYPE_HASH, + thresholdKeyIndex, + expirationTime, + guardianId + )); + + return keccak256(abi.encodePacked("\x19\x01", _domainSeparator, idHash)); + } +} diff --git a/src/BackwardsOptimized/ExtStore.sol b/src/evm/ExtStore.sol similarity index 100% rename from src/BackwardsOptimized/ExtStore.sol rename to src/evm/ExtStore.sol diff --git a/src/evm/MultisigVerification.sol b/src/evm/MultisigVerification.sol new file mode 100644 index 0000000..366153d --- /dev/null +++ b/src/evm/MultisigVerification.sol @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.8.0; + +import {eagerOr} from "wormhole-sdk/Utils.sol"; +import {ICoreBridge} from "wormhole-sdk/interfaces/ICoreBridge.sol"; +import {BytesParsing} from "wormhole-sdk/libraries/BytesParsing.sol"; +import {VaaLib} from "wormhole-sdk/libraries/VaaLib.sol"; +import {CoreBridgeLib} from "wormhole-sdk/libraries/CoreBridge.sol"; +import {UncheckedIndexing} from "wormhole-sdk/libraries/UncheckedIndexing.sol"; + +import {MultisigVerificationState} from "./MultisigVerificationState.sol"; + +contract MultisigVerification is MultisigVerificationState { + using BytesParsing for bytes; + using VaaLib for bytes; + using UncheckedIndexing for address[]; + + error QuorumNotMet(); + error MultisigSignatureVerificationFailed(); + error GuardianSetExpired(); + + constructor( + ICoreBridge coreBridge, + uint256 initGuardianSetIndex, + uint256 pullLimit + ) MultisigVerificationState(coreBridge, initGuardianSetIndex, pullLimit) {} + + // Verify a multisig VAA + // NOTE: This function does not validate the VAA version is V1! + function _verifyMultisigVaaHeader(bytes calldata encodedVaa) internal view returns (uint envelopeOffset) { + unchecked { + uint offset = 1; + uint32 guardianSetIndex; + uint8 signatureCount; + + (guardianSetIndex, offset) = encodedVaa.asUint32CdUnchecked(offset); + (signatureCount, offset) = encodedVaa.asUint8CdUnchecked(offset); + + // Get the guardian set and validate it's not expired + (uint32 expirationTime, address[] memory guardians) = _getGuardianSetInfo(guardianSetIndex); + require(eagerOr(expirationTime == 0, expirationTime > block.timestamp), GuardianSetExpired()); + + // Get the number of signatures + // NOTE: Optimization puts guardianCount on stack thus avoids mloads + uint guardianCount = guardians.length; + + // Validate the number of signatures + // NOTE: This works for empty guardian sets, because the quorum when there + // are no guardians is 1 + uint quorumCount = CoreBridgeLib.minSigsForQuorum(guardianCount); + require(signatureCount >= quorumCount, QuorumNotMet()); + + // Calculate envelope offset and VAA hash + envelopeOffset = offset + signatureCount * VaaLib.GUARDIAN_SIGNATURE_SIZE; + bytes32 vaaHash = encodedVaa.calcVaaDoubleHashCd(envelopeOffset); + + // Verify the signatures + // NOTE: Optimization instead of always checking i == 0 + bool isFirstSignature = true; + uint prevGuardian; + + for (uint i = 0; i < signatureCount; i++) { + // Decode the guardian index, r, s, and v + uint guardian; bytes32 r; bytes32 s; uint8 v; + (guardian, r, s, v, offset) = encodedVaa.decodeGuardianSignatureCdUnchecked(offset); + + // Verify the signature + address signatory = ecrecover(vaaHash, v, r, s); + address guardianAddress = guardians.readUnchecked(guardian); + + // Check that: + // * the guardian indices are in strictly ascending order (only after the first signature) + // this is itself an optimization to efficiently prevent having the same guardian signature + // included twice + // * that the guardian index is not out of bounds + // * that the signatory is the guardian + // + // The core bridge also includes a separate check that signatory is not the zero address + // but this is already covered by comparing that the signatory matches the guardian which + // [can never be the zero address](https://github.com/wormhole-foundation/wormhole/blob/1dbe8459b96e182932d0dd5ae4b6bbce6f48cb09/ethereum/contracts/Setters.sol#L20) + bool failed = eagerOr( + eagerOr( + !eagerOr(isFirstSignature, guardian > prevGuardian), + guardian >= guardianCount + ), + signatory != guardianAddress + ); + + require(!failed, MultisigSignatureVerificationFailed()); + + prevGuardian = guardian; + isFirstSignature = false; + } + } + } + + // Verify a guardian set VAA + // NOTE: This function does not validate the VAA version is V1! + function _verifyAndDecodeMultisigVaa(bytes calldata encodedVaa) internal view returns ( + uint32 timestamp, + uint32 nonce, + uint16 emitterChainId, + bytes32 emitterAddress, + uint64 sequence, + uint8 consistencyLevel, + bytes calldata payload + ) { + uint payloadOffset = _verifyMultisigVaaHeader(encodedVaa); + return encodedVaa.decodeVaaBodyCd(payloadOffset); + } +} diff --git a/src/evm/MultisigVerificationState.sol b/src/evm/MultisigVerificationState.sol new file mode 100644 index 0000000..106c7e0 --- /dev/null +++ b/src/evm/MultisigVerificationState.sol @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.8.0; + +import {ICoreBridge, GuardianSet} from "wormhole-sdk/interfaces/ICoreBridge.sol"; +import {eagerOr} from "wormhole-sdk/Utils.sol"; +import {UncheckedIndexing} from "wormhole-sdk/libraries/UncheckedIndexing.sol"; + +import {ExtStore} from "./ExtStore.sol"; + +contract MultisigVerificationState is ExtStore { + using UncheckedIndexing for address[]; + + error InvalidGuardianSetIndex(); + + // Core bridge instance + ICoreBridge private immutable _coreBridge; + + // Guardian set expiration time is stored in an array mapped from index to expiration time + uint32[] private _guardianSetExpirationTime; + + constructor( + ICoreBridge coreBridge, + uint256 initGuardianSetIndex, + uint256 pullLimit + ) { + _coreBridge = coreBridge; + + require(initGuardianSetIndex <= _coreBridge.getCurrentGuardianSetIndex()); + // All previous guardian sets will have expiration timestamp 0 + assembly ("memory-safe") { + sstore(_guardianSetExpirationTime.slot, initGuardianSetIndex) + } + + _pullGuardianSets(pullLimit); + } + + // Get the current guardian set index and addresses + // NOTE: If no guardian sets have been pulled, the function will panic + function _getCurrentGuardianSetInfo() internal view returns (uint32 index, address[] memory guardianAddrs) { + unchecked { + index = uint32(_guardianSetExpirationTime.length - 1); + (, guardianAddrs) = _getGuardianSetInfo(index); + } + } + + // Get the guardian addresses for a given guardian set index + function _getGuardianSetInfo(uint32 index) internal view returns ( + uint32 expirationTime, + address[] memory guardianAddrs + ) { + require(index < _guardianSetExpirationTime.length, InvalidGuardianSetIndex()); + expirationTime = _guardianSetExpirationTime[index]; + + // Read the guardian set data from the ExtStore + bytes memory data = _extRead(index); + + // Convert the guardian set data to an array of addresses + // NOTE: The `data` array is temporary and is invalid after this block + assembly ("memory-safe") { + guardianAddrs := data + mstore(guardianAddrs, shr(5, mload(guardianAddrs))) + } + } + + function _pullGuardianSets(uint256 limit) internal returns (bool isComplete, uint32 currentGuardianSetIndex) { + unchecked { + // Get the guardian set lengths for the bridge and the local contract + currentGuardianSetIndex = _coreBridge.getCurrentGuardianSetIndex(); + uint32 currentGuardianSetLength = currentGuardianSetIndex + 1; + uint oldGuardianSetLength = _guardianSetExpirationTime.length; + + // If we have already pulled all the guardian sets, return + if (currentGuardianSetLength == oldGuardianSetLength) return (true, currentGuardianSetIndex); + + // Check if we need to update the current guardian set + if (oldGuardianSetLength > 0) { + // Pull and write the current guardian set expiration time + uint updateIndex = oldGuardianSetLength - 1; + (, uint32 expirationTime) = _pullGuardianSet(uint32(updateIndex)); + _guardianSetExpirationTime[updateIndex] = expirationTime; + } + + // Calculate the upper bound of the guardian sets to pull + uint upper = eagerOr(limit == 0, currentGuardianSetLength - oldGuardianSetLength < limit) + ? currentGuardianSetLength : oldGuardianSetLength + limit; + + // Pull and append the guardian sets + for (uint i = oldGuardianSetLength; i < upper; i++) { + // Pull the guardian set, write the expiration time, and append the guardian set data to the ExtStore + (bytes memory data, uint32 expirationTime) = _pullGuardianSet(uint32(i)); + _guardianSetExpirationTime.push(expirationTime); + _extWrite(data); + } + + return (_guardianSetExpirationTime.length == currentGuardianSetLength, currentGuardianSetIndex); + } + } + + function _pullGuardianSet(uint32 index) private view returns ( + bytes memory data, + uint32 expirationTime + ) { + // Get the guardian set from the core bridge + // NOTE: The expiration time is copied from the core bridge, + // so any invalid guardian set will already be invalidated + GuardianSet memory guardians = _coreBridge.getGuardianSet(index); + expirationTime = guardians.expirationTime; + + // Convert the guardian set to a byte array + // Result is stored in `data` + // NOTE: The `keys` array is temporary and is invalid after this block + address[] memory keys = guardians.keys; + assembly ("memory-safe") { + data := keys + mstore(data, shl(5, mload(data))) + } + } +} diff --git a/src/evm/ThresholdVerification.sol b/src/evm/ThresholdVerification.sol new file mode 100644 index 0000000..b062331 --- /dev/null +++ b/src/evm/ThresholdVerification.sol @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.8.0; + +import {BytesParsing} from "wormhole-sdk/libraries/BytesParsing.sol"; +import {GuardianSet} from "wormhole-sdk/interfaces/ICoreBridge.sol"; +import {VaaLib} from "wormhole-sdk/libraries/VaaLib.sol"; +import {eagerAnd, eagerOr} from "wormhole-sdk/Utils.sol"; + +import {ThresholdVerificationState, ShardInfo} from "./ThresholdVerificationState.sol"; + +// Module ID for the VerificationV2 contract, ASCII "TSS" +bytes32 constant MODULE_VERIFICATION_V2 = bytes32(0x0000000000000000000000000000000000000000000000000000000000545353); + +// Action ID for appending a threshold key +uint8 constant ACTION_APPEND_THRESHOLD_KEY = 0x01; + +contract ThresholdVerification is ThresholdVerificationState { + using BytesParsing for bytes; + using VaaLib for bytes; + using {BytesParsing.checkLength} for uint; + + // Curve order for secp256k1 + uint256 constant internal Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; + uint256 constant internal HALF_Q = Q >> 1; + + error ThresholdKeyExpired(); + error ThresholdSignatureVerificationFailed(); + error InvalidModule(); + error InvalidAction(); + + // Verify a threshold signature V2 VAA + // NOTE: This function does not validate the VAA version is V2! + function _verifyThresholdVaaHeader(bytes calldata encodedVaa) internal view returns (uint envelopeOffset) { + unchecked { + // Decode the VAA header + uint offset = 1; + uint32 tssIndex; + address r; uint256 s; + + (tssIndex, offset) = encodedVaa.asUint32CdUnchecked(offset); + (r, offset) = encodedVaa.asAddressCdUnchecked(offset); + (s, offset) = encodedVaa.asUint256CdUnchecked(offset); + + // Load threshold key info and validate expiration time + ThresholdKeyInfo memory info = _getThresholdInfo(tssIndex); + + // Calculate the challenge value + // TODO: Verify that this is consistent with the guardian server code + bytes32 vaaHash = encodedVaa.calcVaaSingleHashCd(offset); + (uint256 px, uint8 parity) = _decodePubkey(info.pubkey); + uint256 e = uint256(keccak256(abi.encodePacked(px, parity == 28, vaaHash, r))); + + // Calculate the recovered address + address recovered = ecrecover( + // NOTE: This is non-zero because for all k = px * s, Q > k % Q + // Therefore, Q - k % Q is always positive + bytes32(Q - mulmod(px, s, Q)), + parity, + // NOTE: This is range checked in _decodeThresholdKeyUpdatePayload + bytes32(px), + bytes32(mulmod(px, e, Q)) + ); + + // Verify that none of the preconditions were violated + // NOTE: s < Q prevents signature malleability + // NOTE: Non-zero r prevents confusion with ecrecover failure + // NOTE: Non-zero check on s not needed, see the first argument of ecrecover + bool validSignature = eagerAnd(r != address(0), s < Q); + bool validExpiration = eagerOr(info.expirationTime == 0, info.expirationTime > block.timestamp); + bool validRecovered = r == recovered; + + require(eagerAnd(validSignature, eagerAnd(validExpiration, validRecovered)), ThresholdSignatureVerificationFailed()); + + return offset; + } + } + + // Verify and decode a threshold signature V2 VAA + // NOTE: This function does not validate the VAA version is V2! + function _verifyAndDecodeThresholdVaa(bytes calldata encodedVaa) internal view returns ( + uint32 timestamp, + uint32 nonce, + uint16 emitterChainId, + bytes32 emitterAddress, + uint64 sequence, + uint8 consistencyLevel, + bytes calldata payload + ) { + uint payloadOffset = _verifyThresholdVaaHeader(encodedVaa); + return encodedVaa.decodeVaaBodyCd(payloadOffset); + } + + // Decode a threshold key update payload, given the number of shards(which is the same as the number of guardians for the current guardian set) + function _decodeThresholdKeyUpdatePayload(bytes calldata payload, uint256 shardCount) internal pure returns ( + uint32 newTSSIndex, + uint256 newThresholdPubkey, + uint32 expirationDelaySeconds, + ShardInfo[] memory shards + ) { + unchecked { + // Decode the payload + uint offset = 0; + bytes32 module; + uint8 action; + + // Headedr + (module, offset) = payload.asBytes32MemUnchecked(offset); + (action, offset) = payload.asUint8MemUnchecked(offset); + + // Payload + (newTSSIndex, offset) = payload.asUint32MemUnchecked(offset); + (newThresholdPubkey, offset) = payload.asUint256MemUnchecked(offset); + (expirationDelaySeconds, offset) = payload.asUint32MemUnchecked(offset); + + // Verify the module and action + require(module == MODULE_VERIFICATION_V2, InvalidModule()); + require(action == ACTION_APPEND_THRESHOLD_KEY, InvalidAction()); + + // Validate the threshold key is non-zero and less than HALF_Q + (uint256 px,) = _decodePubkey(newThresholdPubkey); + require(eagerAnd(px != 0, px <= HALF_Q), InvalidThresholdKeyAddress()); + + // Decode shards + shards = new ShardInfo[](shardCount); + for (uint i = 0; i < shardCount; i++) { + (shards[i].shard, offset) = payload.asBytes32CdUnchecked(offset); + (shards[i].id, offset) = payload.asBytes32CdUnchecked(offset); + } + + // Validate the length of the payload + payload.length.checkLength(offset); + } + } + + function _decodePubkey(uint256 pubkey) internal pure returns (uint256 px, uint8 parity) { + parity = uint8((pubkey & 1) + VaaLib.SIGNATURE_RECOVERY_MAGIC); + px = pubkey >> 1; + } +} diff --git a/src/evm/ThresholdVerificationState.sol b/src/evm/ThresholdVerificationState.sol new file mode 100644 index 0000000..3a8b443 --- /dev/null +++ b/src/evm/ThresholdVerificationState.sol @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.8.0; + +struct ShardInfo { + bytes32 shard; + bytes32 id; +} + +contract ThresholdVerificationState { + error InvalidThresholdKeyIndex(); + error InvalidThresholdKeyAddress(); + error InvalidGuardianIndex(); + error GuardianSetsNotComplete(); + + struct ThresholdKeyInfo { + uint256 pubkey; + uint32 expirationTime; + uint8 shardCount; + uint40 shardBase; + uint32 guardianSetIndex; + } + + ThresholdKeyInfo[] private _thresholdKeyData; + ShardInfo[] private _shardData; + + // Get the current threshold signature info + // NOTE: This will panic if the threshold data is empty + function _getCurrentThresholdInfo() internal view returns (ThresholdKeyInfo memory info, uint32 index) { + unchecked { + index = uint32(_thresholdKeyData.length - 1); + info = _thresholdKeyData[index]; + } + } + + // NOTE: This will panic if the guardian set index is out of bounds + function _getThresholdInfo(uint32 thresholdKeyIndex) internal view returns (ThresholdKeyInfo memory info) { + unchecked { + info = _thresholdKeyData[thresholdKeyIndex]; + } + } + + function _appendThresholdKey( + uint32 currentGuardianSetIndex, + uint32 thresholdKeyIndex, + uint256 pubkey, + uint32 expirationDelaySeconds, + ShardInfo[] memory shards + ) internal { + unchecked { + // Verify the new index is sequential + require(thresholdKeyIndex == _thresholdKeyData.length, InvalidThresholdKeyIndex()); + + // If there is a previous threshold key that is now expired, store the expiration time + if (thresholdKeyIndex > 0) { + uint32 expirationTime = uint32(block.timestamp) + expirationDelaySeconds; + _thresholdKeyData[thresholdKeyIndex - 1].expirationTime = expirationTime; + } + + // Store the new threshold info + _thresholdKeyData.push(ThresholdKeyInfo({ + pubkey: pubkey, + expirationTime: 0, + shardCount: uint8(shards.length), + shardBase: uint40(_shardData.length), + guardianSetIndex: currentGuardianSetIndex + })); + + // Store the shard data + // TODO: Assembly block could be used here to save gas + for (uint256 i = 0; i < shards.length; i++) { + _shardData.push(shards[i]); + } + } + } + + // NOTE: This will panic if the guardian set index is out of bounds + function _getShards(uint32 thresholdKeyIndex) internal view returns (ShardInfo[] memory) { + unchecked { + ThresholdKeyInfo memory info = _getThresholdInfo(thresholdKeyIndex); + uint8 shardCount = info.shardCount; + uint40 shardBase = info.shardBase; + + ShardInfo[] memory shards = new ShardInfo[](shardCount); + for (uint256 i = 0; i < shardCount; i++) { + shards[i] = _shardData[shardBase + i]; + } + + return shards; + } + } + + // NOTE: This will panic if the guardian set index is out of bounds + function _registerGuardian(uint32 thresholdKeyIndex, uint8 guardianIndex, bytes32 id) internal { + unchecked { + ThresholdKeyInfo memory info = _getThresholdInfo(thresholdKeyIndex); + uint8 shardCount = info.shardCount; + uint40 shardBase = info.shardBase; + + require(guardianIndex < shardCount, InvalidGuardianIndex()); + _shardData[shardBase + guardianIndex].id = id; + } + } +} diff --git a/src/evm/VerificationV2.sol b/src/evm/VerificationV2.sol new file mode 100644 index 0000000..a6fb68a --- /dev/null +++ b/src/evm/VerificationV2.sol @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.8.0; + +import {eagerAnd} from "wormhole-sdk/Utils.sol"; +import {BytesParsing} from "wormhole-sdk/libraries/BytesParsing.sol"; +import {VaaLib} from "wormhole-sdk/libraries/VaaLib.sol"; +import {RawDispatcher} from "wormhole-sdk/RawDispatcher.sol"; +import {CHAIN_ID_SOLANA} from "wormhole-sdk/constants/Chains.sol"; +import {ICoreBridge, GuardianSet} from "wormhole-sdk/interfaces/ICoreBridge.sol"; + +import {ThresholdVerification, ShardInfo} from "./ThresholdVerification.sol"; +import {MultisigVerification} from "./MultisigVerification.sol"; +import {EIP712Encoding} from "./EIP712Encoding.sol"; + +// Raw dispatch operation IDs for exec +uint8 constant OP_APPEND_THRESHOLD_KEY = 0x00; +uint8 constant OP_PULL_GUARDIAN_SETS = 0x01; +uint8 constant OP_REGISTER_GUARDIAN = 0x02; + +// Raw dispatch operation IDs for get +uint8 constant OP_VERIFY_AND_DECODE_VAA = 0x20; +uint8 constant OP_VERIFY_VAA = 0x21; +uint8 constant OP_THRESHOLD_GET_CURRENT = 0x22; +uint8 constant OP_THRESHOLD_GET = 0x23; +uint8 constant OP_GUARDIAN_SET_GET_CURRENT = 0x24; +uint8 constant OP_GUARDIAN_SET_GET = 0x25; +uint8 constant OP_GUARDIAN_SHARDS_GET = 0x26; + +// Emitter address for the VerificationV2 contract +bytes32 constant GOVERNANCE_ADDRESS = bytes32(0x0000000000000000000000000000000000000000000000000000000000000004); + +contract VerificationV2 is + RawDispatcher, ThresholdVerification, MultisigVerification, EIP712Encoding +{ + using BytesParsing for bytes; + using VaaLib for bytes; + using {BytesParsing.checkLength} for uint; + + error InvalidValue(); + error InvalidOperation(uint8 op); + error InvalidGovernanceChain(); + error InvalidGovernanceAddress(); + + error GuardianSetIsNotCurrent(); + + error RegistrationMessageExpired(); + error GuardianSignatureVerificationFailed(); + + constructor(ICoreBridge coreV1, uint256 initGuardianSetIndex, uint256 pullLimit) + MultisigVerification(coreV1, initGuardianSetIndex, pullLimit) + {} + + function verifyVaa(bytes calldata data) public view { + (uint8 version, ) = data.asUint8CdUnchecked(0); + if (version == 2) { + _verifyThresholdVaaHeader(data); + } else if (version == 1) { + _verifyMultisigVaaHeader(data); + } else { + revert VaaLib.InvalidVersion(version); + } + } + + function verifyAndDecodeVaa(bytes calldata data) public view returns ( + uint32 timestamp, + uint32 nonce, + uint16 emitterChainId, + bytes32 emitterAddress, + uint64 sequence, + uint8 consistencyLevel, + bytes calldata payload + ) { + (uint8 version, ) = data.asUint8CdUnchecked(0); + if (version == 2) { + (timestamp, nonce, emitterChainId, emitterAddress, sequence, consistencyLevel, payload) = _verifyAndDecodeThresholdVaa(data); + } else if (version == 1) { + (timestamp, nonce, emitterChainId, emitterAddress, sequence, consistencyLevel, payload) = _verifyAndDecodeMultisigVaa(data); + } else { + revert VaaLib.InvalidVersion(version); + } + } + + function _exec(bytes calldata data) internal override returns (bytes memory) { + require(msg.value == 0, InvalidValue()); + + uint offset = 0; + while (offset < data.length) { + uint8 op; + (op, offset) = data.asUint8CdUnchecked(offset); + + if (op == OP_APPEND_THRESHOLD_KEY) { + // Read the VAA + bytes calldata encodedVaa; + (encodedVaa, offset) = data.sliceUint16PrefixedCdUnchecked(offset); + + // Decode and verify the VAA + ( + , + , + uint16 emitterChainId, + bytes32 emitterAddress, + , + , + bytes calldata payload + ) = _verifyAndDecodeMultisigVaa(encodedVaa); + + // Verify the emitter + require(emitterChainId == CHAIN_ID_SOLANA, InvalidGovernanceChain()); + require(emitterAddress == GOVERNANCE_ADDRESS, InvalidGovernanceAddress()); + + // Get the guardian set + (uint32 guardianSetIndex, address[] memory guardians) = _getCurrentGuardianSetInfo(); + + // Decode the payload + ( + uint32 newTSSIndex, + uint256 newThresholdAddr, + uint32 expirationDelaySeconds, + ShardInfo[] memory shards + ) = _decodeThresholdKeyUpdatePayload(payload, guardians.length); + + // Append the threshold key + _appendThresholdKey(guardianSetIndex, newTSSIndex, newThresholdAddr, expirationDelaySeconds, shards); + } else if (op == OP_PULL_GUARDIAN_SETS) { + uint32 limit; + (limit, offset) = data.asUint32CdUnchecked(offset); + + _pullGuardianSets(limit); + } else if (op == OP_REGISTER_GUARDIAN) { + // Decode the payload + uint32 thresholdKeyIndex; + uint32 expirationTime; + bytes32 guardianId; + uint8 guardianIndex; bytes32 r; bytes32 s; uint8 v; + + (thresholdKeyIndex, offset) = data.asUint32CdUnchecked(offset); + (expirationTime, offset) = data.asUint32CdUnchecked(offset); + (guardianId, offset) = data.asBytes32CdUnchecked(offset); + (guardianIndex, r, s, v, offset) = data.decodeGuardianSignatureCdUnchecked(offset); + + // We only allow registrations for the current threshold key + (ThresholdKeyInfo memory info, uint32 currentThresholdKeyIndex) = _getCurrentThresholdInfo(); + require(thresholdKeyIndex == currentThresholdKeyIndex, GuardianSetIsNotCurrent()); + + // Verify the message is not expired + require(expirationTime > block.timestamp, RegistrationMessageExpired()); + + // Get the guardian set for the threshold key + uint32 guardianSetIndex = info.guardianSetIndex; + (, address[] memory guardianAddrs) = _getGuardianSetInfo(guardianSetIndex); + // TODO: Verify the guardian set is still valid? What about for the verification path? + // We can't afford to check it there, so I'm skipping it here for now too + + // Verify the signature + // We're not doing replay protection with the signature itself so we don't care about + // verifying only canonical (low s) signatures. + bytes32 digest = getRegisterGuardianDigest(thresholdKeyIndex, expirationTime, guardianId); + address signatory = ecrecover(digest, v, r, s); + require(signatory == guardianAddrs[guardianIndex], GuardianSignatureVerificationFailed()); + + _registerGuardian(guardianSetIndex, guardianIndex, guardianId); + } else { + revert InvalidOperation(op); + } + } + + // Verify the data has been consumed + data.length.checkLength(offset); + + return new bytes(0); + } + + function _get(bytes calldata data) internal view override returns (bytes memory) { + uint offset = 0; + bytes memory result; + while (offset < data.length) { + uint8 op; + (op, offset) = data.asUint8CdUnchecked(offset); + + if (op == OP_VERIFY_AND_DECODE_VAA) { + // Read the VAA + bytes calldata encodedVaa; + (encodedVaa, offset) = data.sliceUint16PrefixedCdUnchecked(offset); + + // Verify and decode the VAA + ( + uint32 timestamp, + uint32 nonce, + uint16 emitterChainId, + bytes32 emitterAddress, + uint64 sequence, + uint8 consistencyLevel, + bytes calldata payload + ) = verifyAndDecodeVaa(encodedVaa); + + result = abi.encodePacked( + result, + abi.encode( + timestamp, + nonce, + emitterChainId, + emitterAddress, + sequence, + consistencyLevel, + payload + ) + ); + } else if (op == OP_VERIFY_VAA) { + // Read the VAA + bytes calldata encodedVaa; + (encodedVaa, offset) = data.sliceUint16PrefixedCdUnchecked(offset); + + // Verify the VAA + verifyVaa(encodedVaa); + } else if (op == OP_THRESHOLD_GET_CURRENT) { + (ThresholdKeyInfo memory info, uint32 index) = _getCurrentThresholdInfo(); + + result = abi.encodePacked(result, abi.encode(info.pubkey, index)); + } else if (op == OP_THRESHOLD_GET) { + uint32 index; + (index, offset) = data.asUint32CdUnchecked(offset); + + ThresholdKeyInfo memory info = _getThresholdInfo(index); + + result = abi.encodePacked(result, abi.encode(info.pubkey, info.expirationTime)); + } else if (op == OP_GUARDIAN_SET_GET_CURRENT) { + (uint32 guardianSet, address[] memory guardianSetAddrs) = _getCurrentGuardianSetInfo(); + + result = abi.encodePacked(result, abi.encode(guardianSetAddrs, guardianSet)); + } else if (op == OP_GUARDIAN_SET_GET) { + uint32 index; + (index, offset) = data.asUint32CdUnchecked(offset); + + (uint32 expirationTime, address[] memory guardianSetAddrs) = _getGuardianSetInfo(index); + + result = abi.encodePacked(result, abi.encode(guardianSetAddrs, expirationTime)); + } else if (op == OP_GUARDIAN_SHARDS_GET) { + uint32 guardianSet; + (guardianSet, offset) = data.asUint32CdUnchecked(offset); + + ShardInfo[] memory shards = _getShards(guardianSet); + + result = abi.encodePacked(result, abi.encode(shards)); + } else { + revert InvalidOperation(op); + } + } + + // Verify the data has been consumed + data.length.checkLength(offset); + + return result; + } +} diff --git a/src/gscd/BytesLib.sol b/src/gscd/BytesLib.sol deleted file mode 100644 index 58b8f51..0000000 --- a/src/gscd/BytesLib.sol +++ /dev/null @@ -1,510 +0,0 @@ -// SPDX-License-Identifier: Unlicense -/* - * @title Solidity Bytes Arrays Utils - * @author Gonçalo Sá - * - * @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. - */ -pragma solidity >=0.8.0 <0.9.0; - - -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; - } -} \ No newline at end of file diff --git a/src/gscd/Getters.sol b/src/gscd/Getters.sol deleted file mode 100644 index 1038be5..0000000 --- a/src/gscd/Getters.sol +++ /dev/null @@ -1,71 +0,0 @@ -// contracts/Getters.sol -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.0; - -import "./State.sol"; - -contract Getters is State { - function getGuardianSet(uint32 index) public view returns (IWormhole.GuardianSet memory) { - return _state.guardianSets[index]; - } - - function getCurrentGuardianSetIndex() public view returns (uint32) { - return _state.guardianSetIndex; - } - - function getGuardianSetExpiry() public view returns (uint32) { - return _state.guardianSetExpiry; - } - - function governanceActionIsConsumed(bytes32 hash) public view returns (bool) { - return _state.consumedGovernanceActions[hash]; - } - - function isInitialized(address impl) public view returns (bool) { - return _state.initializedImplementations[impl]; - } - - function chainId() public view returns (uint16) { - return _state.provider.chainId; - } - - function evmChainId() public view returns (uint256) { - return _state.evmChainId; - } - - function isFork() public view returns (bool) { - return evmChainId() != block.chainid; - } - - function governanceChainId() public view returns (uint16){ - return _state.provider.governanceChainId; - } - - function governanceContract() public view returns (bytes32){ - return _state.provider.governanceContract; - } - - function messageFee() public view returns (uint256) { - return _state.messageFee; - } - - function nextSequence(address emitter) public view returns (uint64) { - return _state.sequences[emitter]; - } - - function getGuardianSetHash(uint32 index) public view returns (bytes32) { - return _state.guardianSetHashes[index]; - } - - function getEncodedGuardianSet(uint32 index) public view returns (bytes memory encodedGuardianSet) { - IWormhole.GuardianSet memory guardianSet = getGuardianSet(index); - - // Encode the guardian set. - uint256 guardianCount = guardianSet.keys.length; - for (uint256 i = 0; i < guardianCount; ++i) - encodedGuardianSet = abi.encodePacked(encodedGuardianSet, guardianSet.keys[i]); - - encodedGuardianSet = abi.encodePacked(encodedGuardianSet, guardianSet.expirationTime); - } -} \ No newline at end of file diff --git a/src/gscd/Governance.sol b/src/gscd/Governance.sol deleted file mode 100644 index 2b0788f..0000000 --- a/src/gscd/Governance.sol +++ /dev/null @@ -1,227 +0,0 @@ -// contracts/Governance.sol -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.0; - -import "wormhole-sdk/interfaces/IWormhole.sol"; -import "./GovernanceStructs.sol"; -import "./Messages.sol"; -import "./Setters.sol"; - -import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol"; - -/** - * @dev `Governance` defines a means to enacting changes to the core bridge contract, - * guardianSets, message fees, and transfer fees - */ -abstract contract Governance is GovernanceStructs, Messages, Setters, ERC1967Upgrade { - event ContractUpgraded(address indexed oldContract, address indexed newContract); - event GuardianSetAdded(uint32 indexed index); - - // "Core" (left padded) - bytes32 constant module = 0x00000000000000000000000000000000000000000000000000000000436f7265; - - /** - * @dev Upgrades a contract via Governance VAA/VM - */ - function submitContractUpgrade(bytes calldata _vm) public { - require(!isFork(), "invalid fork"); - - IWormhole.VM memory vm = parseVM(_vm); - - // Verify the VAA is valid before processing it - (bool isValid, string memory reason) = verifyGovernanceVM(vm); - require(isValid, reason); - - GovernanceStructs.ContractUpgrade memory upgrade = parseContractUpgrade(vm.payload); - - // Verify the VAA is for this module - require(upgrade.module == module, "Invalid Module"); - - // Verify the VAA is for this chain - require(upgrade.chain == chainId(), "Invalid Chain"); - - // Record the governance action as consumed - setGovernanceActionConsumed(vm.hash); - - // Upgrades the implementation to the new contract - upgradeImplementation(upgrade.newContract); - } - - /** - * @dev Sets a `messageFee` via Governance VAA/VM - */ - function submitSetMessageFee(bytes calldata _vm) public { - IWormhole.VM memory vm = parseVM(_vm); - - // Verify the VAA is valid before processing it - (bool isValid, string memory reason) = verifyGovernanceVM(vm); - require(isValid, reason); - - GovernanceStructs.SetMessageFee memory upgrade = parseSetMessageFee(vm.payload); - - // Verify the VAA is for this module - require(upgrade.module == module, "Invalid Module"); - - // Verify the VAA is for this chain - require(upgrade.chain == chainId() && !isFork(), "Invalid Chain"); - - // Record the governance action as consumed to prevent reentry - setGovernanceActionConsumed(vm.hash); - - // Updates the messageFee - setMessageFee(upgrade.messageFee); - } - - /** - * @dev Deploys a new `guardianSet` via Governance VAA/VM - */ - function submitNewGuardianSet(bytes calldata _vm) public { - IWormhole.VM memory vm = parseVM(_vm); - - // Verify the VAA is valid before processing it - (bool isValid, string memory reason) = verifyGovernanceVM(vm); - require(isValid, reason); - - GovernanceStructs.GuardianSetUpgrade memory upgrade = parseGuardianSetUpgrade(vm.payload); - - // Verify the VAA is for this module - require(upgrade.module == module, "invalid Module"); - - // Verify the VAA is for this chain - require((upgrade.chain == chainId() && !isFork()) || upgrade.chain == 0, "invalid Chain"); - - // Verify the Guardian Set keys are not empty, this guards - // against the accidential upgrade to an empty GuardianSet - require(upgrade.newGuardianSet.keys.length > 0, "new guardian set is empty"); - - // Verify that the index is incrementing via a predictable +1 pattern - require(upgrade.newGuardianSetIndex == getCurrentGuardianSetIndex() + 1, "index must increase in steps of 1"); - - // Record the governance action as consumed to prevent reentry - setGovernanceActionConsumed(vm.hash); - - // Trigger a time-based expiry of current guardianSet - expireGuardianSet(getCurrentGuardianSetIndex()); - - // Update the hash of the expiring guardian set - setGuardianSetHash(getCurrentGuardianSetIndex()); - - // Add the new guardianSet to guardianSets - storeGuardianSet(upgrade.newGuardianSet, upgrade.newGuardianSetIndex); - - // Store the guardian set hash - setGuardianSetHash(upgrade.newGuardianSetIndex); - - // Makes the new guardianSet effective - updateGuardianSetIndex(upgrade.newGuardianSetIndex); - } - - /** - * @dev Submits transfer fees to the recipient via Governance VAA/VM - */ - function submitTransferFees(bytes calldata _vm) public { - IWormhole.VM memory vm = parseVM(_vm); - - // Verify the VAA is valid before processing it - (bool isValid, string memory reason) = verifyGovernanceVM(vm); - require(isValid, reason); - - // Obtains the transfer from the VAA payload - GovernanceStructs.TransferFees memory transfer = parseTransferFees(vm.payload); - - // Verify the VAA is for this module - require(transfer.module == module, "invalid Module"); - - // Verify the VAA is for this chain - require((transfer.chain == chainId() && !isFork()) || transfer.chain == 0, "invalid Chain"); - - // Record the governance action as consumed to prevent reentry - setGovernanceActionConsumed(vm.hash); - - // Obtains the recipient address to be paid transfer fees - address payable recipient = payable(address(uint160(uint256(transfer.recipient)))); - - // Transfers transfer fees to the recipient - recipient.transfer(transfer.amount); - } - - /** - * @dev Updates the `chainId` and `evmChainId` on a forked chain via Governance VAA/VM - */ - function submitRecoverChainId(bytes calldata _vm) public { - require(isFork(), "not a fork"); - - IWormhole.VM memory vm = parseVM(_vm); - - // Verify the VAA is valid before processing it - (bool isValid, string memory reason) = verifyGovernanceVM(vm); - require(isValid, reason); - - GovernanceStructs.RecoverChainId memory rci = parseRecoverChainId(vm.payload); - - // Verify the VAA is for this module - require(rci.module == module, "invalid Module"); - - // Verify the VAA is for this chain - require(rci.evmChainId == block.chainid, "invalid EVM Chain"); - - // Record the governance action as consumed to prevent reentry - setGovernanceActionConsumed(vm.hash); - - // Update the chainIds - setEvmChainId(rci.evmChainId); - setChainId(rci.newChainId); - } - - /** - * @dev Upgrades the `currentImplementation` with a `newImplementation` - */ - function upgradeImplementation(address newImplementation) internal { - address currentImplementation = _getImplementation(); - - _upgradeTo(newImplementation); - - // Call initialize function of the new implementation - (bool success, bytes memory reason) = newImplementation.delegatecall(abi.encodeWithSignature("initialize()")); - - require(success, string(reason)); - - emit ContractUpgraded(currentImplementation, newImplementation); - } - - /** - * @dev Verifies a Governance VAA/VM is valid - */ - function verifyGovernanceVM(IWormhole.VM memory vm) internal view returns (bool, string memory){ - // Verify the VAA is valid - (bool isValid, string memory reason) = verifyVM(vm); - if (!isValid){ - return (false, reason); - } - - // only current guardianset can sign governance packets - if (vm.guardianSetIndex != getCurrentGuardianSetIndex()) { - return (false, "not signed by current guardian set"); - } - - // Verify the VAA is from the governance chain (Solana) - if (uint16(vm.emitterChainId) != governanceChainId()) { - return (false, "wrong governance chain"); - } - - // Verify the emitter contract is the governance contract (0x4 left padded) - if (vm.emitterAddress != governanceContract()) { - return (false, "wrong governance contract"); - } - - // Verify this governance action hasn't already been - // consumed to prevent reentry and replay - if (governanceActionIsConsumed(vm.hash)){ - return (false, "governance action already consumed"); - } - - // Confirm the governance VAA/VM is valid - return (true, ""); - } -} \ No newline at end of file diff --git a/src/gscd/GovernanceStructs.sol b/src/gscd/GovernanceStructs.sol deleted file mode 100644 index 25c266d..0000000 --- a/src/gscd/GovernanceStructs.sol +++ /dev/null @@ -1,183 +0,0 @@ -// contracts/GovernanceIWormhole.sol -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.0; - -import "wormhole-sdk/interfaces/IWormhole.sol"; -import "./BytesLib.sol"; - -/** - * @dev `GovernanceStructs` defines a set of structs and parsing functions - * for minimal struct validation - */ -contract GovernanceStructs { - using BytesLib for bytes; - - enum GovernanceAction { - UpgradeContract, - UpgradeGuardianset - } - - struct ContractUpgrade { - bytes32 module; - uint8 action; - uint16 chain; - - address newContract; - } - - struct GuardianSetUpgrade { - bytes32 module; - uint8 action; - uint16 chain; - - IWormhole.GuardianSet newGuardianSet; - uint32 newGuardianSetIndex; - } - - struct SetMessageFee { - bytes32 module; - uint8 action; - uint16 chain; - - uint256 messageFee; - } - - struct TransferFees { - bytes32 module; - uint8 action; - uint16 chain; - - uint256 amount; - bytes32 recipient; - } - - struct RecoverChainId { - bytes32 module; - uint8 action; - - uint256 evmChainId; - uint16 newChainId; - } - - /// @dev Parse a contract upgrade (action 1) with minimal validation - function parseContractUpgrade(bytes memory encodedUpgrade) public pure returns (ContractUpgrade memory cu) { - uint index = 0; - - cu.module = encodedUpgrade.toBytes32(index); - index += 32; - - cu.action = encodedUpgrade.toUint8(index); - index += 1; - - require(cu.action == 1, "invalid ContractUpgrade"); - - cu.chain = encodedUpgrade.toUint16(index); - index += 2; - - cu.newContract = address(uint160(uint256(encodedUpgrade.toBytes32(index)))); - index += 32; - - require(encodedUpgrade.length == index, "invalid ContractUpgrade"); - } - - /// @dev Parse a guardianSet upgrade (action 2) with minimal validation - function parseGuardianSetUpgrade(bytes memory encodedUpgrade) public pure returns (GuardianSetUpgrade memory gsu) { - uint index = 0; - - gsu.module = encodedUpgrade.toBytes32(index); - index += 32; - - gsu.action = encodedUpgrade.toUint8(index); - index += 1; - - require(gsu.action == 2, "invalid GuardianSetUpgrade"); - - gsu.chain = encodedUpgrade.toUint16(index); - index += 2; - - gsu.newGuardianSetIndex = encodedUpgrade.toUint32(index); - index += 4; - - uint8 guardianLength = encodedUpgrade.toUint8(index); - index += 1; - - gsu.newGuardianSet = IWormhole.GuardianSet({ - keys : new address[](guardianLength), - expirationTime : 0 - }); - - for(uint i = 0; i < guardianLength; i++) { - gsu.newGuardianSet.keys[i] = encodedUpgrade.toAddress(index); - index += 20; - } - - require(encodedUpgrade.length == index, "invalid GuardianSetUpgrade"); - } - - /// @dev Parse a setMessageFee (action 3) with minimal validation - function parseSetMessageFee(bytes memory encodedSetMessageFee) public pure returns (SetMessageFee memory smf) { - uint index = 0; - - smf.module = encodedSetMessageFee.toBytes32(index); - index += 32; - - smf.action = encodedSetMessageFee.toUint8(index); - index += 1; - - require(smf.action == 3, "invalid SetMessageFee"); - - smf.chain = encodedSetMessageFee.toUint16(index); - index += 2; - - smf.messageFee = encodedSetMessageFee.toUint256(index); - index += 32; - - require(encodedSetMessageFee.length == index, "invalid SetMessageFee"); - } - - /// @dev Parse a transferFees (action 4) with minimal validation - function parseTransferFees(bytes memory encodedTransferFees) public pure returns (TransferFees memory tf) { - uint index = 0; - - tf.module = encodedTransferFees.toBytes32(index); - index += 32; - - tf.action = encodedTransferFees.toUint8(index); - index += 1; - - require(tf.action == 4, "invalid TransferFees"); - - tf.chain = encodedTransferFees.toUint16(index); - index += 2; - - tf.amount = encodedTransferFees.toUint256(index); - index += 32; - - tf.recipient = encodedTransferFees.toBytes32(index); - index += 32; - - require(encodedTransferFees.length == index, "invalid TransferFees"); - } - - /// @dev Parse a recoverChainId (action 5) with minimal validation - function parseRecoverChainId(bytes memory encodedRecoverChainId) public pure returns (RecoverChainId memory rci) { - uint index = 0; - - rci.module = encodedRecoverChainId.toBytes32(index); - index += 32; - - rci.action = encodedRecoverChainId.toUint8(index); - index += 1; - - require(rci.action == 5, "invalid RecoverChainId"); - - rci.evmChainId = encodedRecoverChainId.toUint256(index); - index += 32; - - rci.newChainId = encodedRecoverChainId.toUint16(index); - index += 2; - - require(encodedRecoverChainId.length == index, "invalid RecoverChainId"); - } -} \ No newline at end of file diff --git a/src/gscd/Implementation.sol b/src/gscd/Implementation.sol deleted file mode 100644 index 5bb98cf..0000000 --- a/src/gscd/Implementation.sol +++ /dev/null @@ -1,80 +0,0 @@ -// contracts/Implementation.sol -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.0; -pragma experimental ABIEncoderV2; - -import "./Governance.sol"; - -import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol"; - -contract Implementation is Governance { - event LogMessagePublished(address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel); - - // Publish a message to be attested by the Wormhole network - function publishMessage( - uint32 nonce, - bytes memory payload, - uint8 consistencyLevel - ) public payable returns (uint64 sequence) { - // check fee - require(msg.value == messageFee(), "invalid fee"); - - sequence = useSequence(msg.sender); - // emit log - emit LogMessagePublished(msg.sender, sequence, nonce, payload, consistencyLevel); - } - - function useSequence(address emitter) internal returns (uint64 sequence) { - sequence = nextSequence(emitter); - setNextSequence(emitter, sequence + 1); - } - - function initialize() initializer public virtual { - // this function needs to be exposed for an upgrade to pass - if (evmChainId() == 0) { - uint256 evmChainId; - uint16 chain = chainId(); - - // Wormhole chain ids explicitly enumerated - if (chain == 2) { evmChainId = 1; // ethereum - } else if (chain == 4) { evmChainId = 56; // bsc - } else if (chain == 5) { evmChainId = 137; // polygon - } else if (chain == 6) { evmChainId = 43114; // avalanche - } else if (chain == 7) { evmChainId = 42262; // oasis - } else if (chain == 9) { evmChainId = 1313161554; // aurora - } else if (chain == 10) { evmChainId = 250; // fantom - } else if (chain == 11) { evmChainId = 686; // karura - } else if (chain == 12) { evmChainId = 787; // acala - } else if (chain == 13) { evmChainId = 8217; // klaytn - } else if (chain == 14) { evmChainId = 42220; // celo - } else if (chain == 16) { evmChainId = 1284; // moonbeam - } else if (chain == 17) { evmChainId = 245022934; // neon - } else if (chain == 23) { evmChainId = 42161; // arbitrum - } else if (chain == 24) { evmChainId = 10; // optimism - } else if (chain == 25) { evmChainId = 100; // gnosis - } else { - revert("Unknown chain id."); - } - - setEvmChainId(evmChainId); - } - } - - modifier initializer() { - address implementation = ERC1967Upgrade._getImplementation(); - - require( - !isInitialized(implementation), - "already initialized" - ); - - setInitialized(implementation); - - _; - } - - fallback() external payable {revert("unsupported");} - - receive() external payable {revert("the Wormhole contract does not accept assets");} -} diff --git a/src/gscd/Messages.sol b/src/gscd/Messages.sol deleted file mode 100644 index 2b22d81..0000000 --- a/src/gscd/Messages.sol +++ /dev/null @@ -1,252 +0,0 @@ -// contracts/Messages.sol -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.0; -pragma experimental ABIEncoderV2; - -import "./Getters.sol"; -import "wormhole-sdk/libraries/BytesParsing.sol"; -import "wormhole-sdk/Utils.sol"; - -contract Messages is Getters { - using BytesParsing for bytes; - using {BytesParsing.checkBound, BytesParsing.checkLength} for uint256; - - uint8 private constant ADDRESS_SIZE = 20; // in bytes - uint8 private constant EXPIRATION_TIME_SIZE = 4; // in bytes - - function parseAndVerifyVMOptimized( - bytes calldata encodedVM, - bytes calldata guardianSet, - uint32 guardianSetIndex - ) public view returns (IWormhole.VM memory vm, bool valid, string memory reason) { - // Verify that the specified guardian set is a valid. - bytes32 guardianSetHash = getGuardianSetHash(guardianSetIndex); - require( - guardianSetHash == keccak256(guardianSet) && guardianSetHash != bytes32(0), - "invalid guardian set" - ); - - vm = parseVM(encodedVM); - - // Verify that the VM is signed with the same guardian set that was specified. - require(vm.guardianSetIndex == guardianSetIndex, "mismatched guardian set index"); - - (valid, reason) = verifyVMInternal(vm, parseGuardianSet(guardianSet), false); - } - - function parseGuardianSet(bytes calldata guardianSetData) public pure returns (IWormhole.GuardianSet memory guardianSet) { - uint256 guardianSetDataLength = guardianSetData.length; - uint256 guardianCount = (guardianSetDataLength - EXPIRATION_TIME_SIZE) / ADDRESS_SIZE; - - guardianSet = IWormhole.GuardianSet({ - keys : new address[](guardianCount), - expirationTime : 0 - }); - - uint256 offset = 0; - for(uint256 i = 0; i < guardianCount;) { - (guardianSet.keys[i], offset) = guardianSetData.asAddressCdUnchecked(offset); - unchecked { - ++i; - } - } - - (guardianSet.expirationTime, offset) = guardianSetData.asUint32CdUnchecked(offset); - - require(guardianSetDataLength == offset, "invalid guardian set data length"); - } - - /// @dev parseAndVerifyVM serves to parse an encodedVM and wholy validate it for consumption - function parseAndVerifyVM(bytes calldata encodedVM) public view returns (IWormhole.VM memory vm, bool valid, string memory reason) { - vm = parseVM(encodedVM); - /// setting checkHash to false as we can trust the hash field in this case given that parseVM computes and then sets the hash field above - (valid, reason) = verifyVMInternal(vm, getGuardianSet(vm.guardianSetIndex), false); - } - - /** - * @dev `verifyVM` serves to validate an arbitrary vm against a valid Guardian set - * - it aims to make sure the VM is for a known guardianSet - * - it aims to ensure the guardianSet is not expired - * - it aims to ensure the VM has reached quorum - * - it aims to verify the signatures provided against the guardianSet - * - it aims to verify the hash field provided against the contents of the vm - */ - function verifyVM(IWormhole.VM memory vm) public view returns (bool valid, string memory reason) { - (valid, reason) = verifyVMInternal(vm, getGuardianSet(vm.guardianSetIndex), true); - } - - /** - * @dev `verifyVMInternal` serves to validate an arbitrary vm against a valid Guardian set - * if checkHash is set then the hash field of the vm is verified against the hash of its contents - * in the case that the vm is securely parsed and the hash field can be trusted, checkHash can be set to false - * as the check would be redundant - */ - function verifyVMInternal(IWormhole.VM memory vm, IWormhole.GuardianSet memory guardianSet, bool checkHash) internal view returns (bool valid, string memory reason) { - /** - * Verify that the hash field in the vm matches with the hash of the contents of the vm if checkHash is set - * WARNING: This hash check is critical to ensure that the vm.hash provided matches with the hash of the body. - * Without this check, it would not be safe to call verifyVM on it's own as vm.hash can be a valid signed hash - * but the body of the vm could be completely different from what was actually signed by the guardians - */ - if(checkHash){ - bytes memory body = abi.encodePacked( - vm.timestamp, - vm.nonce, - vm.emitterChainId, - vm.emitterAddress, - vm.sequence, - vm.consistencyLevel, - vm.payload - ); - - bytes32 vmHash = keccak256(abi.encodePacked(keccak256(body))); - - if(vmHash != vm.hash){ - return (false, "vm.hash doesn't match body"); - } - } - - uint256 guardianCount = guardianSet.keys.length; - - /** - * @dev Checks whether the guardianSet has zero keys - * WARNING: This keys check is critical to ensure the guardianSet has keys present AND to ensure - * that guardianSet key size doesn't fall to zero and negatively impact quorum assessment. If guardianSet - * key length is 0 and vm.signatures length is 0, this could compromise the integrity of both vm and - * signature verification. - */ - if(guardianCount == 0){ - return (false, "invalid guardian set"); - } - - /// @dev Checks if VM guardian set index matches the current index (unless the current set is expired). - if(vm.guardianSetIndex != getCurrentGuardianSetIndex() && guardianSet.expirationTime < block.timestamp){ - return (false, "guardian set has expired"); - } - - /** - * @dev We're using a fixed point number transformation with 1 decimal to deal with rounding. - * WARNING: This quorum check is critical to assessing whether we have enough Guardian signatures to validate a VM - * if making any changes to this, obtain additional peer review. If guardianSet key length is 0 and - * vm.signatures length is 0, this could compromise the integrity of both vm and signature verification. - */ - if (vm.signatures.length < quorum(guardianCount)){ - return (false, "no quorum"); - } - - /// @dev Verify the proposed vm.signatures against the guardianSet - (bool signaturesValid, string memory invalidReason) = verifySignatures(vm.hash, vm.signatures, guardianSet); - if(!signaturesValid){ - return (false, invalidReason); - } - - /// If we are here, we've validated the VM is a valid multi-sig that matches the guardianSet. - return (true, ""); - } - - - /** - * @dev verifySignatures serves to validate arbitrary sigatures against an arbitrary guardianSet - * - it intentionally does not solve for expectations within guardianSet (you should use verifyVM if you need these protections) - * - it intentioanlly does not solve for quorum (you should use verifyVM if you need these protections) - * - it intentionally returns true when signatures is an empty set (you should use verifyVM if you need these protections) - */ - function verifySignatures(bytes32 hash, IWormhole.Signature[] memory signatures, IWormhole.GuardianSet memory guardianSet) public pure returns (bool valid, string memory reason) { - uint8 lastIndex = 0; - uint256 sigCount = signatures.length; - uint256 guardianCount = guardianSet.keys.length; - for (uint i = 0; i < sigCount;) { - IWormhole.Signature memory sig = signatures[i]; - address signatory = ecrecover(hash, sig.v, sig.r, sig.s); - // ecrecover returns 0 for invalid signatures. We explicitly require valid signatures to avoid unexpected - // behaviour due to the default storage slot value also being 0. - require(signatory != address(0), "ecrecover failed with signature"); - - /// Ensure that provided signature indices are ascending only - require(i == 0 || sig.guardianIndex > lastIndex, "signature indices must be ascending"); - lastIndex = sig.guardianIndex; - - /// @dev Ensure that the provided signature index is within the - /// bounds of the guardianSet. This is implicitly checked by the array - /// index operation below, so this check is technically redundant. - /// However, reverting explicitly here ensures that a bug is not - /// introduced accidentally later due to the nontrivial storage - /// semantics of solidity. - require(sig.guardianIndex < guardianCount, "guardian index out of bounds"); - - /// Check to see if the signer of the signature does not match a specific Guardian key at the provided index - if(signatory != guardianSet.keys[sig.guardianIndex]){ - return (false, "VM signature invalid"); - } - - unchecked { ++i; } - } - - /// If we are here, we've validated that the provided signatures are valid for the provided guardianSet - return (true, ""); - } - - /** - * @dev parseVM serves to parse an encodedVM into a vm struct - * - it intentionally performs no validation functions, it simply parses raw into a struct - */ - function parseVM(bytes calldata encodedVM) public view virtual returns (IWormhole.VM memory vm) { unchecked { - uint256 offset = 0; - - // SECURITY: Note that currently the VM.version is not part of the hash - // and for reasons described below it cannot be made part of the hash. - // This means that this field's integrity is not protected and cannot be trusted. - // This is not a problem today since there is only one accepted version, but it - // could be a problem if we wanted to allow other versions in the future. - (vm.version, offset) = encodedVM.asUint8CdUnchecked(offset); - require(vm.version == 1, "VM version incompatible"); - - // Guardian set index. - (vm.guardianSetIndex, offset) = encodedVM.asUint32CdUnchecked(offset); - - // Parse sigs. - uint256 signersLen; - (signersLen, offset) = encodedVM.asUint8CdUnchecked(offset); - - vm.signatures = new IWormhole.Signature[](signersLen); - for (uint i = 0; i < signersLen; ++i) { - (vm.signatures[i].guardianIndex, offset) = encodedVM.asUint8CdUnchecked(offset); - (vm.signatures[i].r, offset) = encodedVM.asBytes32CdUnchecked(offset); - (vm.signatures[i].s, offset) = encodedVM.asBytes32CdUnchecked(offset); - (vm.signatures[i].v, offset) = encodedVM.asUint8CdUnchecked(offset); - vm.signatures[i].v += 27; - } - - /* - Hash the body - - SECURITY: Do not change the way the hash of a VM is computed! - Changing it could result into two different hashes for the same observation. - But xDapps rely on the hash of an observation for replay protection. - */ - offset.checkBound(encodedVM.length); - bytes calldata body; - (body, ) = encodedVM.sliceCdUnchecked(offset, encodedVM.length - offset); - vm.hash = keccak256Word(keccak256Cd(body)); - - // Parse the body - (vm.timestamp, offset) = encodedVM.asUint32CdUnchecked(offset); - (vm.nonce, offset) = encodedVM.asUint32CdUnchecked(offset); - (vm.emitterChainId, offset) = encodedVM.asUint16CdUnchecked(offset); - (vm.emitterAddress, offset) = encodedVM.asBytes32CdUnchecked(offset); - (vm.sequence, offset) = encodedVM.asUint64CdUnchecked(offset); - (vm.consistencyLevel, offset) = encodedVM.asUint8CdUnchecked(offset); - offset.checkBound(encodedVM.length); - (vm.payload, offset) = encodedVM.sliceCdUnchecked(offset, encodedVM.length - offset); - }} - - /** - * @dev quorum serves solely to determine the number of signatures required to acheive quorum - */ - function quorum(uint numGuardians) public pure virtual returns (uint numSignaturesRequiredForQuorum) { - // The max number of guardians is 255 - require(numGuardians < 256, "too many guardians"); - return ((numGuardians * 2) / 3) + 1; - } -} diff --git a/src/gscd/Setters.sol b/src/gscd/Setters.sol deleted file mode 100644 index 1ede1ad..0000000 --- a/src/gscd/Setters.sol +++ /dev/null @@ -1,80 +0,0 @@ -// contracts/Setters.sol -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.0; - -import "./State.sol"; - -contract Setters is State { - function updateGuardianSetIndex(uint32 newIndex) internal { - _state.guardianSetIndex = newIndex; - } - - function expireGuardianSet(uint32 index) internal { - _state.guardianSets[index].expirationTime = uint32(block.timestamp) + 86400; - } - - function storeGuardianSet(IWormhole.GuardianSet memory set, uint32 index) internal { - uint setLength = set.keys.length; - for (uint i = 0; i < setLength;) { - require(set.keys[i] != address(0), "Invalid key"); - unchecked { ++i; } - } - _state.guardianSets[index] = set; - } - - function setInitialized(address implementatiom) internal { - _state.initializedImplementations[implementatiom] = true; - } - - function setGovernanceActionConsumed(bytes32 hash) internal { - _state.consumedGovernanceActions[hash] = true; - } - - function setChainId(uint16 chainId) internal { - _state.provider.chainId = chainId; - } - - function setGovernanceChainId(uint16 chainId) internal { - _state.provider.governanceChainId = chainId; - } - - function setGovernanceContract(bytes32 governanceContract) internal { - _state.provider.governanceContract = governanceContract; - } - - function setMessageFee(uint256 newFee) internal { - _state.messageFee = newFee; - } - - function setNextSequence(address emitter, uint64 sequence) internal { - _state.sequences[emitter] = sequence; - } - - function setEvmChainId(uint256 evmChainId) internal { - require(evmChainId == block.chainid, "invalid evmChainId"); - _state.evmChainId = evmChainId; - } - - function setGuardianSetHash(uint32 index) public { - // Fetch the guardian set at the specified index. - IWormhole.GuardianSet memory guardianSet = _state.guardianSets[index]; - - uint256 guardianCount = guardianSet.keys.length; - - // Only allow setting the hash for a valid guardian set index - // Governance guards against updating to an empty guardian set - require(guardianCount > 0, "non-existent guardian set"); - - bytes memory encodedGuardianSet; - for (uint256 i = 0; i < guardianCount;) { - encodedGuardianSet = abi.encodePacked(encodedGuardianSet, guardianSet.keys[i]); - unchecked { i += 1; } - } - - // Store the hash. - _state.guardianSetHashes[index] = keccak256( - abi.encodePacked(encodedGuardianSet, guardianSet.expirationTime) - ); - } -} \ No newline at end of file diff --git a/src/gscd/Setup.sol b/src/gscd/Setup.sol deleted file mode 100644 index 1193985..0000000 --- a/src/gscd/Setup.sol +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.0; - -import "./Governance.sol"; - -import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol"; - -contract Setup is Setters, ERC1967Upgrade { - function setup( - address implementation, - address[] memory initialGuardians, - uint16 chainId, - uint16 governanceChainId, - bytes32 governanceContract, - uint256 evmChainId - ) public { - require(initialGuardians.length > 0, "no guardians specified"); - - IWormhole.GuardianSet memory initialGuardianSet = IWormhole.GuardianSet({ - keys : initialGuardians, - expirationTime : 0 - }); - - storeGuardianSet(initialGuardianSet, 0); - setGuardianSetHash(0); - // initial guardian set index is 0, which is the default value of the storage slot anyways - - setChainId(chainId); - - setGovernanceChainId(governanceChainId); - setGovernanceContract(governanceContract); - - setEvmChainId(evmChainId); - - _upgradeTo(implementation); - - // See https://github.com/wormhole-foundation/wormhole/issues/1930 for - // why we set this here - setInitialized(implementation); - } -} diff --git a/src/gscd/State.sol b/src/gscd/State.sol deleted file mode 100644 index a90a85e..0000000 --- a/src/gscd/State.sol +++ /dev/null @@ -1,46 +0,0 @@ -// contracts/State.sol -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.0; - -import "wormhole-sdk/interfaces/IWormhole.sol"; - -contract State { - struct Provider { - uint16 chainId; - uint16 governanceChainId; - bytes32 governanceContract; - } - - struct WormholeState { - Provider provider; - - // Mapping of guardian_set_index => guardian set - mapping(uint32 => IWormhole.GuardianSet) guardianSets; - - // Current active guardian set index - uint32 guardianSetIndex; - - // Period for which a guardian set stays active after it has been replaced - uint32 guardianSetExpiry; - - // Sequence numbers per emitter - mapping(address => uint64) sequences; - - // Mapping of consumed governance actions - mapping(bytes32 => bool) consumedGovernanceActions; - - // Mapping of initialized implementations - mapping(address => bool) initializedImplementations; - - uint256 messageFee; - - // EIP-155 Chain ID - uint256 evmChainId; - - // Guardian set hashes. - mapping(uint32 => bytes32) guardianSetHashes; - } - - WormholeState _state; -} diff --git a/src/gscd/Wormhole.sol b/src/gscd/Wormhole.sol deleted file mode 100644 index a091789..0000000 --- a/src/gscd/Wormhole.sol +++ /dev/null @@ -1,13 +0,0 @@ -// contracts/Wormhole.sol -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.0; - -import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; - -contract Wormhole is ERC1967Proxy { - constructor (address setup, bytes memory initData) ERC1967Proxy( - setup, - initData - ) { } -} \ No newline at end of file diff --git a/src/solana/.gitignore b/src/solana/.gitignore new file mode 100644 index 0000000..2e0446b --- /dev/null +++ b/src/solana/.gitignore @@ -0,0 +1,7 @@ +.anchor +.DS_Store +target +**/*.rs.bk +node_modules +test-ledger +.yarn diff --git a/src/solana/.mocharc.json b/src/solana/.mocharc.json new file mode 100644 index 0000000..8b7ad23 --- /dev/null +++ b/src/solana/.mocharc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://json.schemastore.org/mocharc.json", + "require": "tsx/esm" +} diff --git a/src/solana/.prettierignore b/src/solana/.prettierignore new file mode 100644 index 0000000..4142583 --- /dev/null +++ b/src/solana/.prettierignore @@ -0,0 +1,7 @@ +.anchor +.DS_Store +target +node_modules +dist +build +test-ledger diff --git a/src/solana/Anchor.toml b/src/solana/Anchor.toml new file mode 100644 index 0000000..b5b9bef --- /dev/null +++ b/src/solana/Anchor.toml @@ -0,0 +1,30 @@ +[toolchain] +anchor_version = "0.31.1" +solana_version = "2.1.18" + +[features] +resolution = true +skip-lint = false + +[programs.localnet] +verification_v2 = "GbFfTqMqKDgAMRH8VmDmoLTdvDd1853TnkkEwpydv3J6" + +[registry] +url = "https://api.apr.dev" + +[provider] +cluster = "localnet" +wallet = "~/.config/solana/id.json" + +[scripts] +test = "npx mocha -t 1000000 tests/**/*.ts" + +[test] +startup_wait = 5000 +shutdown_wait = 2000 +upgradeable = false + +[[test.genesis]] +name = "wormhole-core-v1" +address = "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth" +program = "imports/wormhole.so" diff --git a/src/solana/Cargo.lock b/src/solana/Cargo.lock new file mode 100644 index 0000000..ac9f875 --- /dev/null +++ b/src/solana/Cargo.lock @@ -0,0 +1,3208 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm-siv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "polyval", + "subtle", + "zeroize", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy 0.7.35", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anchor-attribute-access-control" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f70fd141a4d18adf11253026b32504f885447048c7494faf5fa83b01af9c0cf" +dependencies = [ + "anchor-syn", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-account" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715a261c57c7679581e06f07a74fa2af874ac30f86bd8ea07cca4a7e5388a064" +dependencies = [ + "anchor-syn", + "bs58", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-constant" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "730d6df8ae120321c5c25e0779e61789e4b70dc8297102248902022f286102e4" +dependencies = [ + "anchor-syn", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-error" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27e6e449cc3a37b2880b74dcafb8e5a17b954c0e58e376432d7adc646fb333ef" +dependencies = [ + "anchor-syn", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-event" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7710e4c54adf485affcd9be9adec5ef8846d9c71d7f31e16ba86ff9fc1dd49f" +dependencies = [ + "anchor-syn", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-program" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ecfd49b2aeadeb32f35262230db402abed76ce87e27562b34f61318b2ec83c" +dependencies = [ + "anchor-lang-idl", + "anchor-syn", + "anyhow", + "bs58", + "heck", + "proc-macro2", + "quote", + "serde_json", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-accounts" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be89d160793a88495af462a7010b3978e48e30a630c91de47ce2c1d3cb7a6149" +dependencies = [ + "anchor-syn", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-serde" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abc6ee78acb7bfe0c2dd2abc677aaa4789c0281a0c0ef01dbf6fe85e0fd9e6e4" +dependencies = [ + "anchor-syn", + "borsh-derive-internal", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-space" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134a01c0703f6fd355a0e472c033f6f3e41fac1ef6e370b20c50f4c8d022cea7" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-lang" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6bab117055905e930f762c196e08f861f8dfe7241b92cee46677a3b15561a0a" +dependencies = [ + "anchor-attribute-access-control", + "anchor-attribute-account", + "anchor-attribute-constant", + "anchor-attribute-error", + "anchor-attribute-event", + "anchor-attribute-program", + "anchor-derive-accounts", + "anchor-derive-serde", + "anchor-derive-space", + "anchor-lang-idl", + "base64 0.21.7", + "bincode", + "borsh 0.10.4", + "bytemuck", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "anchor-lang-idl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e8599d21995f68e296265aa5ab0c3cef582fd58afec014d01bd0bce18a4418" +dependencies = [ + "anchor-lang-idl-spec", + "anyhow", + "heck", + "regex", + "serde", + "serde_json", + "sha2 0.10.8", +] + +[[package]] +name = "anchor-lang-idl-spec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdf143115440fe621bdac3a29a1f7472e09f6cd82b2aa569429a0c13f103838" +dependencies = [ + "anyhow", + "serde", +] + +[[package]] +name = "anchor-spl" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c08cb5d762c0694f74bd02c9a5b04ea53cefc496e2c27b3234acffca5cd076b" +dependencies = [ + "anchor-lang", + "mpl-token-metadata", + "spl-associated-token-account", + "spl-pod", + "spl-token", + "spl-token-2022", + "spl-token-group-interface", + "spl-token-metadata-interface", +] + +[[package]] +name = "anchor-syn" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dc7a6d90cc643df0ed2744862cdf180587d1e5d28936538c18fc8908489ed67" +dependencies = [ + "anyhow", + "bs58", + "cargo_toml", + "heck", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.8", + "syn 1.0.109", + "thiserror 1.0.69", +] + +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake3" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest 0.10.7", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115e54d64eb62cdebad391c19efc9dce4981c690c85a33a12199d99bb9546fee" +dependencies = [ + "borsh-derive 0.10.4", + "hashbrown 0.13.2", +] + +[[package]] +name = "borsh" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +dependencies = [ + "borsh-derive 1.5.7", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831213f80d9423998dd696e2c5345aba6be7a0bd8cd19e31c5243e13df1cef89" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" +dependencies = [ + "once_cell", + "proc-macro-crate 3.3.0", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65d6ba50644c98714aa2a70d13d7df3cd75cd2b523a2b452bf010443800976b3" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276691d96f063427be83e6692b86148e488ebba9f48f77788724ca027ba3b6d4" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "bv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" +dependencies = [ + "feature-probe", + "serde", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + +[[package]] +name = "bytemuck" +version = "1.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cargo_toml" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a98356df42a2eb1bd8f1793ae4ee4de48e384dd974ce5eac8eee802edb7492be" +dependencies = [ + "serde", + "toml 0.8.20", +] + +[[package]] +name = "cc" +version = "1.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "const_format" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rand_core 0.6.4", + "rustc_version", + "serde", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "derivation-path" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "five8_const" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26dec3da8bc3ef08f2c04f61eab298c3ab334523e55f076354d6d6f613799a7b" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2551bf44bc5f776c15044b9b94153a00198be06743e262afaaa61f11ac7523a5" + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac 0.8.1", +] + +[[package]] +name = "impl-codec" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d40b9d5e17727407e55028eafc22b2dc68781786e6d7eb8a21103f5058e3a14" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "libsecp256k1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" +dependencies = [ + "arrayref", + "base64 0.12.3", + "digest 0.9.0", + "libsecp256k1-core 0.2.2", + "libsecp256k1-gen-ecmult 0.2.1", + "libsecp256k1-gen-genmult 0.2.1", + "rand 0.7.3", + "serde", + "sha2 0.9.9", +] + +[[package]] +name = "libsecp256k1" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79019718125edc905a079a70cfa5f3820bc76139fc91d6f9abc27ea2a887139" +dependencies = [ + "arrayref", + "base64 0.22.1", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core 0.3.0", + "libsecp256k1-gen-ecmult 0.3.0", + "libsecp256k1-gen-genmult 0.3.0", + "rand 0.8.5", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" +dependencies = [ + "libsecp256k1-core 0.2.2", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core 0.3.0", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" +dependencies = [ + "libsecp256k1-core 0.2.2", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core 0.3.0", +] + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "mpl-token-metadata" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "989e6a3000e761d3b2d685662a3a9ee99826f9369fb033bd1bc7011b1cf02ed9" +dependencies = [ + "borsh 0.10.4", + "num-derive 0.3.3", + "num-traits", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate 3.3.0", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "parity-scale-codec" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "const_format", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "rustversion", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" +dependencies = [ + "proc-macro-crate 3.3.0", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy 0.8.24", +] + +[[package]] +name = "primitive-types" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d15600a7d856470b7d278b3fe0e311fe28c2526348549f8ef2ff7db3299c87f5" +dependencies = [ + "fixed-hash", + "impl-codec", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml 0.5.11", +] + +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qstring" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.15", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "redox_syscall" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "smallvec" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" + +[[package]] +name = "solana-account" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f949fe4edaeaea78c844023bfc1c898e0b1f5a100f8a8d2d0f85d0a7b090258" +dependencies = [ + "solana-account-info", + "solana-clock", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-account-info" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0c17d606a298a205fae325489fbed88ee6dc4463c111672172327e741c8905d" +dependencies = [ + "bincode", + "serde", + "solana-program-error", + "solana-program-memory", + "solana-pubkey", +] + +[[package]] +name = "solana-address-lookup-table-interface" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1673f67efe870b64a65cb39e6194be5b26527691ce5922909939961a6e6b395" +dependencies = [ + "bincode", + "bytemuck", + "serde", + "serde_derive", + "solana-clock", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-slot-hashes", +] + +[[package]] +name = "solana-atomic-u64" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52e52720efe60465b052b9e7445a01c17550666beec855cce66f44766697bc2" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "solana-big-mod-exp" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75db7f2bbac3e62cfd139065d15bcda9e2428883ba61fc8d27ccb251081e7567" +dependencies = [ + "num-bigint", + "num-traits", + "solana-define-syscall", +] + +[[package]] +name = "solana-bincode" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a3787b8cf9c9fe3dd360800e8b70982b9e5a8af9e11c354b6665dd4a003adc" +dependencies = [ + "bincode", + "serde", + "solana-instruction", +] + +[[package]] +name = "solana-blake3-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0801e25a1b31a14494fc80882a036be0ffd290efc4c2d640bfcca120a4672" +dependencies = [ + "blake3", + "solana-define-syscall", + "solana-hash", + "solana-sanitize", +] + +[[package]] +name = "solana-borsh" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718333bcd0a1a7aed6655aa66bef8d7fb047944922b2d3a18f49cbc13e73d004" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.7", +] + +[[package]] +name = "solana-clock" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c2177a1b9fe8326004f1151a5acd124420b737811080b1035df31349e4d892" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-cpi" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc71126edddc2ba014622fc32d0f5e2e78ec6c5a1e0eb511b85618c09e9ea11" +dependencies = [ + "solana-account-info", + "solana-define-syscall", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-stable-layout", +] + +[[package]] +name = "solana-curve25519" +version = "2.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de13796959f32e52eb2d59a0dbfe0d55ee59b07e04b0ae5648e07ba1082dd98" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "solana-define-syscall", + "subtle", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-decode-error" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a6a6383af236708048f8bd8d03db8ca4ff7baf4a48e5d580f4cce545925470" +dependencies = [ + "num-traits", +] + +[[package]] +name = "solana-define-syscall" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf784bb2cb3e02cac9801813c30187344228d2ae952534902108f6150573a33d" + +[[package]] +name = "solana-derivation-path" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "939756d798b25c5ec3cca10e06212bdca3b1443cb9bb740a38124f58b258737b" +dependencies = [ + "derivation-path", + "qstring", + "uriparse", +] + +[[package]] +name = "solana-epoch-rewards" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b575d3dd323b9ea10bb6fe89bf6bf93e249b215ba8ed7f68f1a3633f384db7" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-epoch-schedule" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fce071fbddecc55d727b1d7ed16a629afe4f6e4c217bc8d00af3b785f6f67ed" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-example-mocks" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84461d56cbb8bb8d539347151e0525b53910102e4bced875d49d5139708e39d3" +dependencies = [ + "serde", + "serde_derive", + "solana-address-lookup-table-interface", + "solana-clock", + "solana-hash", + "solana-instruction", + "solana-keccak-hasher", + "solana-message", + "solana-nonce", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-feature-gate-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9c7fbf3e58b64a667c5f35e90af580538a95daea7001ff7806c0662d301bdf" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-account", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-fee-calculator" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89bc408da0fb3812bc3008189d148b4d3e08252c79ad810b245482a3f70cd8d" +dependencies = [ + "log", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-hash" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf7bcb14392900fe02e4e34e90234fbf0c673d4e327888410ba99fa2ba0f4e99" +dependencies = [ + "borsh 1.5.7", + "bs58", + "bytemuck", + "bytemuck_derive", + "js-sys", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-sanitize", + "wasm-bindgen", +] + +[[package]] +name = "solana-instruction" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce496a475e5062ba5de97215ab39d9c358f9c9df4bb7f3a45a1f1a8bd9065ed" +dependencies = [ + "bincode", + "borsh 1.5.7", + "getrandom 0.2.15", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-define-syscall", + "solana-pubkey", + "wasm-bindgen", +] + +[[package]] +name = "solana-instructions-sysvar" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427f2d0d6dc0bb49f16cef5e7f975180d2e80aab9bdd3b2af68e2d029ec63f43" +dependencies = [ + "bitflags", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-ids", + "solana-serialize-utils", + "solana-sysvar-id", +] + +[[package]] +name = "solana-keccak-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7aeb957fbd42a451b99235df4942d96db7ef678e8d5061ef34c9b34cae12f79" +dependencies = [ + "sha3", + "solana-define-syscall", + "solana-hash", + "solana-sanitize", +] + +[[package]] +name = "solana-last-restart-slot" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6360ac2fdc72e7463565cd256eedcf10d7ef0c28a1249d261ec168c1b55cdd" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-loader-v2-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8ab08006dad78ae7cd30df8eea0539e207d08d91eaefb3e1d49a446e1c49654" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-loader-v3-interface" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4be76cfa9afd84ca2f35ebc09f0da0f0092935ccdac0595d98447f259538c2" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-loader-v4-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "706a777242f1f39a83e2a96a2a6cb034cb41169c6ecbee2cf09cb873d9659e7e" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-message" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c6bf99c4570173710107a1f233f3bee226feea5fc817308707d4f7cb100a72d" +dependencies = [ + "bincode", + "blake3", + "lazy_static", + "serde", + "serde_derive", + "solana-bincode", + "solana-hash", + "solana-instruction", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-system-interface", + "solana-transaction-error", + "wasm-bindgen", +] + +[[package]] +name = "solana-msg" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36a1a14399afaabc2781a1db09cb14ee4cc4ee5c7a5a3cfcc601811379a8092" +dependencies = [ + "solana-define-syscall", +] + +[[package]] +name = "solana-native-token" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e9de00960197412e4be3902a6cd35e60817c511137aca6c34c66cd5d4017ec" + +[[package]] +name = "solana-nonce" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703e22eb185537e06204a5bd9d509b948f0066f2d1d814a6f475dafb3ddf1325" +dependencies = [ + "serde", + "serde_derive", + "solana-fee-calculator", + "solana-hash", + "solana-pubkey", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-program" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "586469467e93ceb79048f8d8e3a619bf61d05396ee7de95cb40280301a589d05" +dependencies = [ + "bincode", + "blake3", + "borsh 0.10.4", + "borsh 1.5.7", + "bs58", + "bytemuck", + "console_error_panic_hook", + "console_log", + "getrandom 0.2.15", + "lazy_static", + "log", + "memoffset", + "num-bigint", + "num-derive 0.4.2", + "num-traits", + "rand 0.8.5", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info", + "solana-address-lookup-table-interface", + "solana-atomic-u64", + "solana-big-mod-exp", + "solana-bincode", + "solana-blake3-hasher", + "solana-borsh", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-define-syscall", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-example-mocks", + "solana-feature-gate-interface", + "solana-fee-calculator", + "solana-hash", + "solana-instruction", + "solana-instructions-sysvar", + "solana-keccak-hasher", + "solana-last-restart-slot", + "solana-loader-v2-interface", + "solana-loader-v3-interface", + "solana-loader-v4-interface", + "solana-message", + "solana-msg", + "solana-native-token", + "solana-nonce", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey", + "solana-rent", + "solana-sanitize", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-secp256k1-recover", + "solana-serde-varint", + "solana-serialize-utils", + "solana-sha256-hasher", + "solana-short-vec", + "solana-slot-hashes", + "solana-slot-history", + "solana-stable-layout", + "solana-stake-interface", + "solana-system-interface", + "solana-sysvar", + "solana-sysvar-id", + "solana-vote-interface", + "thiserror 2.0.12", + "wasm-bindgen", +] + +[[package]] +name = "solana-program-entrypoint" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "473ffe73c68d93e9f2aa726ad2985fe52760052709aaab188100a42c618060ec" +dependencies = [ + "solana-account-info", + "solana-msg", + "solana-program-error", + "solana-pubkey", +] + +[[package]] +name = "solana-program-error" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8ae2c1a8d0d4ae865882d5770a7ebca92bab9c685e43f0461682c6c05a35bfa" +dependencies = [ + "borsh 1.5.7", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-pubkey", +] + +[[package]] +name = "solana-program-memory" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b0268f6c89825fb634a34bd0c3b8fdaeaecfc3728be1d622a8ee6dd577b60d4" +dependencies = [ + "num-traits", + "solana-define-syscall", +] + +[[package]] +name = "solana-program-option" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc677a2e9bc616eda6dbdab834d463372b92848b2bfe4a1ed4e4b4adba3397d0" + +[[package]] +name = "solana-program-pack" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "319f0ef15e6e12dc37c597faccb7d62525a509fec5f6975ecb9419efddeb277b" +dependencies = [ + "solana-program-error", +] + +[[package]] +name = "solana-pubkey" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cad77cf9f30b971a1eec48dde6a863dcac60ba005a34dfde23736afa5c7ac667" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.7", + "bs58", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "five8_const", + "getrandom 0.2.15", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-decode-error", + "solana-define-syscall", + "solana-sanitize", + "solana-sha256-hasher", + "wasm-bindgen", +] + +[[package]] +name = "solana-rent" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1aea8fdea9de98ca6e8c2da5827707fb3842833521b528a713810ca685d2480" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-sanitize" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f1bc1357b8188d9c4a3af3fc55276e56987265eb7ad073ae6f8180ee54cecf" + +[[package]] +name = "solana-sdk-ids" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5d8b9cc68d5c88b062a33e23a6466722467dde0035152d8fb1afbcdf350a5f" +dependencies = [ + "solana-pubkey", +] + +[[package]] +name = "solana-sdk-macro" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86280da8b99d03560f6ab5aca9de2e38805681df34e0bb8f238e69b29433b9df" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "solana-secp256k1-recover" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa3120b6cdaa270f39444f5093a90a7b03d296d362878f7a6991d6de3bbe496" +dependencies = [ + "libsecp256k1 0.6.0", + "solana-define-syscall", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-security-txt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" + +[[package]] +name = "solana-seed-derivable" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beb82b5adb266c6ea90e5cf3967235644848eac476c5a1f2f9283a143b7c97f" +dependencies = [ + "solana-derivation-path", +] + +[[package]] +name = "solana-seed-phrase" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36187af2324f079f65a675ec22b31c24919cb4ac22c79472e85d819db9bbbc15" +dependencies = [ + "hmac 0.12.1", + "pbkdf2", + "sha2 0.10.8", +] + +[[package]] +name = "solana-serde-varint" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc07d00200d82e6def2f7f7a45738e3406b17fe54a18adcf0defa16a97ccadb" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serialize-utils" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "817a284b63197d2b27afdba829c5ab34231da4a9b4e763466a003c40ca4f535e" +dependencies = [ + "solana-instruction", + "solana-pubkey", + "solana-sanitize", +] + +[[package]] +name = "solana-sha256-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0037386961c0d633421f53560ad7c80675c0447cba4d1bb66d60974dd486c7ea" +dependencies = [ + "sha2 0.10.8", + "solana-define-syscall", + "solana-hash", +] + +[[package]] +name = "solana-short-vec" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c54c66f19b9766a56fa0057d060de8378676cb64987533fa088861858fc5a69" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-signature" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d251c8f3dc015f320b4161daac7f108156c837428e5a8cc61136d25beb11d6" +dependencies = [ + "bs58", + "solana-sanitize", +] + +[[package]] +name = "solana-signer" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c41991508a4b02f021c1342ba00bcfa098630b213726ceadc7cb032e051975b" +dependencies = [ + "solana-pubkey", + "solana-signature", + "solana-transaction-error", +] + +[[package]] +name = "solana-slot-hashes" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8691982114513763e88d04094c9caa0376b867a29577939011331134c301ce" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-slot-history" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ccc1b2067ca22754d5283afb2b0126d61eae734fc616d23871b0943b0d935e" +dependencies = [ + "bv", + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-stable-layout" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f14f7d02af8f2bc1b5efeeae71bc1c2b7f0f65cd75bcc7d8180f2c762a57f54" +dependencies = [ + "solana-instruction", + "solana-pubkey", +] + +[[package]] +name = "solana-stake-interface" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5269e89fde216b4d7e1d1739cf5303f8398a1ff372a81232abbee80e554a838c" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.7", + "num-traits", + "serde", + "serde_derive", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-system-interface", + "solana-sysvar-id", +] + +[[package]] +name = "solana-system-interface" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d7c18cb1a91c6be5f5a8ac9276a1d7c737e39a21beba9ea710ab4b9c63bc90" +dependencies = [ + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction", + "solana-pubkey", + "wasm-bindgen", +] + +[[package]] +name = "solana-sysvar" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf6b44740d7f0c9f375d045c165bc0aab4a90658f92d6835aeb0649afaeaff9a" +dependencies = [ + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "lazy_static", + "serde", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-define-syscall", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash", + "solana-instruction", + "solana-instructions-sysvar", + "solana-last-restart-slot", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-pubkey", + "solana-rent", + "solana-sanitize", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-slot-hashes", + "solana-slot-history", + "solana-stake-interface", + "solana-sysvar-id", +] + +[[package]] +name = "solana-sysvar-id" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5762b273d3325b047cfda250787f8d796d781746860d5d0a746ee29f3e8812c1" +dependencies = [ + "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-transaction-error" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a9dc8fdb61c6088baab34fc3a8b8473a03a7a5fd404ed8dd502fa79b67cb1" +dependencies = [ + "solana-instruction", + "solana-sanitize", +] + +[[package]] +name = "solana-vote-interface" +version = "2.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78f039b0788337bedc6c5450d2f237718f938defb5ce0e0ad8ef507e78dcd370" +dependencies = [ + "bincode", + "num-derive 0.4.2", + "num-traits", + "serde", + "serde_derive", + "solana-clock", + "solana-decode-error", + "solana-hash", + "solana-instruction", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-serde-varint", + "solana-serialize-utils", + "solana-short-vec", + "solana-system-interface", +] + +[[package]] +name = "solana-zk-sdk" +version = "2.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d19fb9ff055569f32871dfd619355780f151f17285cabd23effcdd74167f73" +dependencies = [ + "aes-gcm-siv", + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "itertools", + "js-sys", + "lazy_static", + "merlin", + "num-derive 0.4.2", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "serde_json", + "sha3", + "solana-derivation-path", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "subtle", + "thiserror 2.0.12", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "spl-associated-token-account" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76fee7d65013667032d499adc3c895e286197a35a0d3a4643c80e7fd3e9969e3" +dependencies = [ + "borsh 1.5.7", + "num-derive 0.4.2", + "num-traits", + "solana-program", + "spl-associated-token-account-client", + "spl-token", + "spl-token-2022", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-associated-token-account-client" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f8349dbcbe575f354f9a533a21f272f3eb3808a49e2fdc1c34393b88ba76cb" +dependencies = [ + "solana-instruction", + "solana-pubkey", +] + +[[package]] +name = "spl-discriminator" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7398da23554a31660f17718164e31d31900956054f54f52d5ec1be51cb4f4b3" +dependencies = [ + "bytemuck", + "solana-program-error", + "solana-sha256-hasher", + "spl-discriminator-derive", +] + +[[package]] +name = "spl-discriminator-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" +dependencies = [ + "quote", + "spl-discriminator-syn", + "syn 2.0.100", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f05593b7ca9eac7caca309720f2eafb96355e037e6d373b909a80fe7b69b9" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.100", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-elgamal-registry" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce0f668975d2b0536e8a8fd60e56a05c467f06021dae037f1d0cfed0de2e231d" +dependencies = [ + "bytemuck", + "solana-program", + "solana-zk-sdk", + "spl-pod", + "spl-token-confidential-transfer-proof-extraction", +] + +[[package]] +name = "spl-memo" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f09647c0974e33366efeb83b8e2daebb329f0420149e74d3a4bd2c08cf9f7cb" +dependencies = [ + "solana-account-info", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-pubkey", +] + +[[package]] +name = "spl-pod" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d994afaf86b779104b4a95ba9ca75b8ced3fdb17ee934e38cb69e72afbe17799" +dependencies = [ + "borsh 1.5.7", + "bytemuck", + "bytemuck_derive", + "num-derive 0.4.2", + "num-traits", + "solana-decode-error", + "solana-msg", + "solana-program-error", + "solana-program-option", + "solana-pubkey", + "solana-zk-sdk", + "thiserror 2.0.12", +] + +[[package]] +name = "spl-program-error" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d39b5186f42b2b50168029d81e58e800b690877ef0b30580d107659250da1d1" +dependencies = [ + "num-derive 0.4.2", + "num-traits", + "solana-program", + "spl-program-error-derive", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-program-error-derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d375dd76c517836353e093c2dbb490938ff72821ab568b545fd30ab3256b3e" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.100", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd99ff1e9ed2ab86e3fd582850d47a739fec1be9f4661cba1782d3a0f26805f3" +dependencies = [ + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "solana-account-info", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-type-length-value", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed320a6c934128d4f7e54fe00e16b8aeaecf215799d060ae14f93378da6dc834" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "num_enum", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-2022" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b27f7405010ef816587c944536b0eafbcc35206ab6ba0f2ca79f1d28e488f4f" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "num_enum", + "solana-program", + "solana-security-txt", + "solana-zk-sdk", + "spl-elgamal-registry", + "spl-memo", + "spl-pod", + "spl-token", + "spl-token-confidential-transfer-ciphertext-arithmetic", + "spl-token-confidential-transfer-proof-extraction", + "spl-token-confidential-transfer-proof-generation", + "spl-token-group-interface", + "spl-token-metadata-interface", + "spl-transfer-hook-interface", + "spl-type-length-value", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-confidential-transfer-ciphertext-arithmetic" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170378693c5516090f6d37ae9bad2b9b6125069be68d9acd4865bbe9fc8499fd" +dependencies = [ + "base64 0.22.1", + "bytemuck", + "solana-curve25519", + "solana-zk-sdk", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-extraction" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff2d6a445a147c9d6dd77b8301b1e116c8299601794b558eafa409b342faf96" +dependencies = [ + "bytemuck", + "solana-curve25519", + "solana-program", + "solana-zk-sdk", + "spl-pod", + "thiserror 2.0.12", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-generation" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8627184782eec1894de8ea26129c61303f1f0adeed65c20e0b10bc584f09356d" +dependencies = [ + "curve25519-dalek", + "solana-zk-sdk", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d595667ed72dbfed8c251708f406d7c2814a3fa6879893b323d56a10bedfc799" +dependencies = [ + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-metadata-interface" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb9c89dbc877abd735f05547dcf9e6e12c00c11d6d74d8817506cab4c99fdbb" +dependencies = [ + "borsh 1.5.7", + "num-derive 0.4.2", + "num-traits", + "solana-borsh", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-type-length-value", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa7503d52107c33c88e845e1351565050362c2314036ddf19a36cd25137c043" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "solana-account-info", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-tlv-account-resolution", + "spl-type-length-value", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-type-length-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba70ef09b13af616a4c987797870122863cba03acc4284f226a4473b043923f9" +dependencies = [ + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "solana-account-info", + "solana-decode-error", + "solana-msg", + "solana-program-error", + "spl-discriminator", + "spl-pod", + "thiserror 1.0.69", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "uint" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "uriparse" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" +dependencies = [ + "fnv", + "lazy_static", +] + +[[package]] +name = "verification_v2" +version = "0.1.0" +dependencies = [ + "anchor-lang", + "byteorder", + "libsecp256k1 0.7.2", + "primitive-types", + "wormhole-anchor-sdk", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.100", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +dependencies = [ + "memchr", +] + +[[package]] +name = "wormhole-anchor-sdk" +version = "0.31.0" +source = "git+https://github.com/XLabs/wormhole-scaffolding.git?rev=c008cf26c2449b914911a19ecbf8630fd9b4f5b5#c008cf26c2449b914911a19ecbf8630fd9b4f5b5" +dependencies = [ + "anchor-lang", + "anchor-spl", + "cfg-if", + "wormhole-io", +] + +[[package]] +name = "wormhole-io" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021a14ea7bcef9517ed9f81d4466c4a663dd90e726c5724707a976fa83ad8f3" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +dependencies = [ + "zerocopy-derive 0.8.24", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] diff --git a/src/solana/Cargo.toml b/src/solana/Cargo.toml new file mode 100644 index 0000000..f397704 --- /dev/null +++ b/src/solana/Cargo.toml @@ -0,0 +1,14 @@ +[workspace] +members = [ + "programs/*" +] +resolver = "2" + +[profile.release] +overflow-checks = true +lto = "fat" +codegen-units = 1 +[profile.release.build-override] +opt-level = 3 +incremental = false +codegen-units = 1 diff --git a/src/solana/imports/wormhole.so b/src/solana/imports/wormhole.so new file mode 100644 index 0000000..ef0a0bd Binary files /dev/null and b/src/solana/imports/wormhole.so differ diff --git a/src/solana/migrations/deploy.ts b/src/solana/migrations/deploy.ts new file mode 100644 index 0000000..439431e --- /dev/null +++ b/src/solana/migrations/deploy.ts @@ -0,0 +1,12 @@ +// Migrations are an early feature. Currently, they're nothing more than this +// single deploy script that's invoked from the CLI, injecting a provider +// configured from the workspace's Anchor.toml. + +import * as anchor from "@coral-xyz/anchor"; + +module.exports = async function (provider: anchor.AnchorProvider) { + // Configure client to use the provider. + anchor.setProvider(provider); + + // Add your deploy script here. +}; diff --git a/src/solana/package-lock.json b/src/solana/package-lock.json new file mode 100644 index 0000000..6525f77 --- /dev/null +++ b/src/solana/package-lock.json @@ -0,0 +1,3365 @@ +{ + "name": "solana", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "license": "ISC", + "dependencies": { + "@coral-xyz/anchor": "^0.31.1", + "@noble/hashes": "^1.7.2", + "@noble/secp256k1": "^2.2.3", + "@wormhole-foundation/sdk-base": "^1.20.0", + "@wormhole-foundation/sdk-definitions": "^1.20.0", + "@wormhole-foundation/sdk-solana-core": "^1.20.0" + }, + "devDependencies": { + "@types/bn.js": "^5.1.0", + "@types/chai": "^4.3.0", + "@types/mocha": "^10.0.10", + "chai": "^4.5.0", + "diff": "^7.0.0", + "mocha": "^11.1.0", + "prettier": "^2.6.2", + "toml": "^3.0.0", + "tsx": "^4.19.3", + "typescript": "^5.7.3" + } + }, + "node_modules/@babel/runtime": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", + "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@coral-xyz/anchor": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.31.1.tgz", + "integrity": "sha512-QUqpoEK+gi2S6nlYc2atgT2r41TT3caWr/cPUEL8n8Md9437trZ68STknq897b82p5mW0XrTBNOzRbmIRJtfsA==", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "@coral-xyz/anchor-errors": "^0.31.1", + "@coral-xyz/borsh": "^0.31.1", + "@noble/hashes": "^1.3.1", + "@solana/web3.js": "^1.69.0", + "bn.js": "^5.1.2", + "bs58": "^4.0.1", + "buffer-layout": "^1.2.2", + "camelcase": "^6.3.0", + "cross-fetch": "^3.1.5", + "eventemitter3": "^4.0.7", + "pako": "^2.0.3", + "superstruct": "^0.15.4", + "toml": "^3.0.0" + }, + "engines": { + "node": ">=17" + } + }, + "node_modules/@coral-xyz/anchor-errors": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor-errors/-/anchor-errors-0.31.1.tgz", + "integrity": "sha512-NhNEku4F3zzUSBtrYz84FzYWm48+9OvmT1Hhnwr6GnPQry2dsEqH/ti/7ASjjpoFTWRnPXrjAIT1qM6Isop+LQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/@coral-xyz/borsh": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.31.1.tgz", + "integrity": "sha512-9N8AU9F0ubriKfNE3g1WF0/4dtlGXoBN/hd1PvbNBamBNwRgHxH4P+o3Zt7rSEloW1HUs6LfZEchlx9fW7POYw==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.1.2", + "buffer-layout": "^1.2.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@solana/web3.js": "^1.69.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz", + "integrity": "sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.3.tgz", + "integrity": "sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.3.tgz", + "integrity": "sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.3.tgz", + "integrity": "sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.3.tgz", + "integrity": "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.3.tgz", + "integrity": "sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.3.tgz", + "integrity": "sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.3.tgz", + "integrity": "sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.3.tgz", + "integrity": "sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.3.tgz", + "integrity": "sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.3.tgz", + "integrity": "sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.3.tgz", + "integrity": "sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.3.tgz", + "integrity": "sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.3.tgz", + "integrity": "sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.3.tgz", + "integrity": "sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.3.tgz", + "integrity": "sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.3.tgz", + "integrity": "sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.3.tgz", + "integrity": "sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.3.tgz", + "integrity": "sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.3.tgz", + "integrity": "sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.3.tgz", + "integrity": "sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.3.tgz", + "integrity": "sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.3.tgz", + "integrity": "sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.3.tgz", + "integrity": "sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.3.tgz", + "integrity": "sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@noble/curves": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.0.tgz", + "integrity": "sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/secp256k1": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-2.2.3.tgz", + "integrity": "sha512-l7r5oEQym9Us7EAigzg30/PQAvynhMt2uoYtT3t26eGDVm9Yii5mZ5jWSWmZ/oSIR2Et0xfc6DXrG0bZ787V3w==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@scure/base": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.5.tgz", + "integrity": "sha512-9rE6EOVeIQzt5TSu4v+K523F8u6DhBsoZWPGKlnCshhlDhy0kJzUX4V+tr2dWmzF1GdekvThABoEQBGBQI7xZw==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@solana/buffer-layout": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz", + "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==", + "license": "MIT", + "dependencies": { + "buffer": "~6.0.3" + }, + "engines": { + "node": ">=5.10" + } + }, + "node_modules/@solana/buffer-layout-utils": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz", + "integrity": "sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==", + "license": "Apache-2.0", + "dependencies": { + "@solana/buffer-layout": "^4.0.0", + "@solana/web3.js": "^1.32.0", + "bigint-buffer": "^1.1.5", + "bignumber.js": "^9.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@solana/codecs-core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.1.0.tgz", + "integrity": "sha512-SR7pKtmJBg2mhmkel2NeHA1pz06QeQXdMv8WJoIR9m8F/hw80K/612uaYbwTt2nkK0jg/Qn/rNSd7EcJ4SBGjw==", + "license": "MIT", + "dependencies": { + "@solana/errors": "2.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-numbers": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.1.0.tgz", + "integrity": "sha512-XMu4yw5iCgQnMKsxSWPPOrGgtaohmupN3eyAtYv3K3C/MJEc5V90h74k5B1GUCiHvcrdUDO9RclNjD9lgbjFag==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.1.0", + "@solana/errors": "2.1.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/errors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.1.0.tgz", + "integrity": "sha512-l+GxAv0Ar4d3c3PlZdA9G++wFYZREEbbRyAFP8+n8HSg0vudCuzogh/13io6hYuUhG/9Ve8ARZNamhV7UScKNw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "commander": "^13.1.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/errors/node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@solana/spl-token": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.3.9.tgz", + "integrity": "sha512-1EXHxKICMnab35MvvY/5DBc/K/uQAOJCYnDZXw83McCAYUAfi+rwq6qfd6MmITmSTEhcfBcl/zYxmW/OSN0RmA==", + "license": "Apache-2.0", + "dependencies": { + "@solana/buffer-layout": "^4.0.0", + "@solana/buffer-layout-utils": "^0.2.0", + "buffer": "^6.0.3" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/web3.js": "^1.47.4" + } + }, + "node_modules/@solana/web3.js": { + "version": "1.98.1", + "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.98.1.tgz", + "integrity": "sha512-gRAq1YPbfSDAbmho4kY7P/8iLIjMWXAzBJdP9iENFR+dFQSBSueHzjK/ou8fxhqHP9j+J4Msl4p/oDemFcIjlg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "@noble/curves": "^1.4.2", + "@noble/hashes": "^1.4.0", + "@solana/buffer-layout": "^4.0.1", + "@solana/codecs-numbers": "^2.1.0", + "agentkeepalive": "^4.5.0", + "bn.js": "^5.2.1", + "borsh": "^0.7.0", + "bs58": "^4.0.1", + "buffer": "6.0.3", + "fast-stable-stringify": "^1.0.0", + "jayson": "^4.1.1", + "node-fetch": "^2.7.0", + "rpc-websockets": "^9.0.2", + "superstruct": "^2.0.2" + } + }, + "node_modules/@solana/web3.js/node_modules/superstruct": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", + "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@types/bn.js": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.6.tgz", + "integrity": "sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/chai": { + "version": "4.3.20", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", + "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/mocha": { + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.13.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.17.tgz", + "integrity": "sha512-nAJuQXoyPj04uLgu+obZcSmsfOenUg6DxPKogeUy6yNCFwWaj5sBF8/G/pNo8EtBJjAfSVgfIlugR/BCOleO+g==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@wormhole-foundation/sdk-base": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-base/-/sdk-base-1.20.0.tgz", + "integrity": "sha512-jV6aVBFXNh5mueEL4cscnZmHjJiyIF9S6Lp9udVXve+IKchbTH18f9r/A/Lwk8I42ao1X+Pag1tDCYwaSQreFQ==", + "license": "Apache-2.0", + "dependencies": { + "@scure/base": "^1.1.3", + "binary-layout": "^1.0.3" + } + }, + "node_modules/@wormhole-foundation/sdk-connect": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-connect/-/sdk-connect-1.20.0.tgz", + "integrity": "sha512-GfoDXj2tGET+fALm8yPgdMuY8SakRTLkSHVG5eSb22zHsSnrKvi7i3siajbbOW+r2rwiKr8UTZSjq2S2eyUCLQ==", + "license": "Apache-2.0", + "dependencies": { + "@wormhole-foundation/sdk-base": "1.20.0", + "@wormhole-foundation/sdk-definitions": "1.20.0", + "axios": "^1.4.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@wormhole-foundation/sdk-definitions": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-definitions/-/sdk-definitions-1.20.0.tgz", + "integrity": "sha512-hNtcyfipdlgmFR8CD9hvA9In54rWDEwuIo7YKeq0FuJNISDHo/+8DVty96SznItkWS5mp5RL/6ayTH/X96dX3w==", + "dependencies": { + "@noble/curves": "^1.4.0", + "@noble/hashes": "^1.3.1", + "@wormhole-foundation/sdk-base": "1.20.0" + } + }, + "node_modules/@wormhole-foundation/sdk-solana": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-solana/-/sdk-solana-1.20.0.tgz", + "integrity": "sha512-/IvTyhcJbghkFL5tJXHrNWNfrJPeQLT3+moZerH7hsExUpeG6sHxGSTBr02OotPfAPNwvuH/g6xHl7TDBJ9Bpw==", + "license": "Apache-2.0", + "dependencies": { + "@coral-xyz/anchor": "0.29.0", + "@coral-xyz/borsh": "0.29.0", + "@solana/spl-token": "0.3.9", + "@solana/web3.js": "^1.95.8", + "@wormhole-foundation/sdk-connect": "1.20.0", + "rpc-websockets": "^7.10.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@wormhole-foundation/sdk-solana-core": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-solana-core/-/sdk-solana-core-1.20.0.tgz", + "integrity": "sha512-SxxtUStSSQ1iX3eD7ObuxmaB5y4sMkM5RedwCY+v+K7GAMdmRa8uz0BqeHnJ58yEsptSldfK5bGXTY2OvpwNtA==", + "license": "Apache-2.0", + "dependencies": { + "@coral-xyz/anchor": "0.29.0", + "@coral-xyz/borsh": "0.29.0", + "@solana/web3.js": "^1.95.8", + "@wormhole-foundation/sdk-connect": "1.20.0", + "@wormhole-foundation/sdk-solana": "1.20.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@wormhole-foundation/sdk-solana-core/node_modules/@coral-xyz/anchor": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.29.0.tgz", + "integrity": "sha512-eny6QNG0WOwqV0zQ7cs/b1tIuzZGmP7U7EcH+ogt4Gdbl8HDmIYVMh/9aTmYZPaFWjtUaI8qSn73uYEXWfATdA==", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "@coral-xyz/borsh": "^0.29.0", + "@noble/hashes": "^1.3.1", + "@solana/web3.js": "^1.68.0", + "bn.js": "^5.1.2", + "bs58": "^4.0.1", + "buffer-layout": "^1.2.2", + "camelcase": "^6.3.0", + "cross-fetch": "^3.1.5", + "crypto-hash": "^1.3.0", + "eventemitter3": "^4.0.7", + "pako": "^2.0.3", + "snake-case": "^3.0.4", + "superstruct": "^0.15.4", + "toml": "^3.0.0" + }, + "engines": { + "node": ">=11" + } + }, + "node_modules/@wormhole-foundation/sdk-solana-core/node_modules/@coral-xyz/borsh": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.29.0.tgz", + "integrity": "sha512-s7VFVa3a0oqpkuRloWVPdCK7hMbAMY270geZOGfCnaqexrP5dTIpbEHL33req6IYPPJ0hYa71cdvJ1h6V55/oQ==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.1.2", + "buffer-layout": "^1.2.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@solana/web3.js": "^1.68.0" + } + }, + "node_modules/@wormhole-foundation/sdk-solana/node_modules/@coral-xyz/anchor": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.29.0.tgz", + "integrity": "sha512-eny6QNG0WOwqV0zQ7cs/b1tIuzZGmP7U7EcH+ogt4Gdbl8HDmIYVMh/9aTmYZPaFWjtUaI8qSn73uYEXWfATdA==", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "@coral-xyz/borsh": "^0.29.0", + "@noble/hashes": "^1.3.1", + "@solana/web3.js": "^1.68.0", + "bn.js": "^5.1.2", + "bs58": "^4.0.1", + "buffer-layout": "^1.2.2", + "camelcase": "^6.3.0", + "cross-fetch": "^3.1.5", + "crypto-hash": "^1.3.0", + "eventemitter3": "^4.0.7", + "pako": "^2.0.3", + "snake-case": "^3.0.4", + "superstruct": "^0.15.4", + "toml": "^3.0.0" + }, + "engines": { + "node": ">=11" + } + }, + "node_modules/@wormhole-foundation/sdk-solana/node_modules/@coral-xyz/borsh": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.29.0.tgz", + "integrity": "sha512-s7VFVa3a0oqpkuRloWVPdCK7hMbAMY270geZOGfCnaqexrP5dTIpbEHL33req6IYPPJ0hYa71cdvJ1h6V55/oQ==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.1.2", + "buffer-layout": "^1.2.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@solana/web3.js": "^1.68.0" + } + }, + "node_modules/@wormhole-foundation/sdk-solana/node_modules/rpc-websockets": { + "version": "7.11.2", + "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.11.2.tgz", + "integrity": "sha512-pL9r5N6AVHlMN/vT98+fcO+5+/UcPLf/4tq+WUaid/PPUGS/ttJ3y8e9IqmaWKtShNAysMSjkczuEA49NuV7UQ==", + "license": "LGPL-3.0-only", + "dependencies": { + "eventemitter3": "^4.0.7", + "uuid": "^8.3.2", + "ws": "^8.5.0" + }, + "funding": { + "type": "paypal", + "url": "https://paypal.me/kozjak" + }, + "optionalDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + } + }, + "node_modules/@wormhole-foundation/sdk-solana/node_modules/ws": { + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", + "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", + "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bigint-buffer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz", + "integrity": "sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "bindings": "^1.3.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/bignumber.js": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.0.tgz", + "integrity": "sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/binary-layout": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/binary-layout/-/binary-layout-1.2.2.tgz", + "integrity": "sha512-iySOJ1OB2uPxv8whrRwDJ7USTk7NqeCaSPZL/j4oaOK2iup8P5vr4BNvtpumXUAe0/aJZ8ZkNldj3fmhtcLnDQ==", + "license": "Apache-2.0" + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "license": "MIT" + }, + "node_modules/borsh": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", + "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.2.0", + "bs58": "^4.0.0", + "text-encoding-utf-8": "^1.0.2" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true, + "license": "ISC" + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-layout": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz", + "integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==", + "license": "MIT", + "engines": { + "node": ">=4.5" + } + }, + "node_modules/bufferutil": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz", + "integrity": "sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-hash": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/crypto-hash/-/crypto-hash-1.3.0.tgz", + "integrity": "sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "license": "MIT" + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "license": "MIT", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/esbuild": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.3.tgz", + "integrity": "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.3", + "@esbuild/android-arm": "0.25.3", + "@esbuild/android-arm64": "0.25.3", + "@esbuild/android-x64": "0.25.3", + "@esbuild/darwin-arm64": "0.25.3", + "@esbuild/darwin-x64": "0.25.3", + "@esbuild/freebsd-arm64": "0.25.3", + "@esbuild/freebsd-x64": "0.25.3", + "@esbuild/linux-arm": "0.25.3", + "@esbuild/linux-arm64": "0.25.3", + "@esbuild/linux-ia32": "0.25.3", + "@esbuild/linux-loong64": "0.25.3", + "@esbuild/linux-mips64el": "0.25.3", + "@esbuild/linux-ppc64": "0.25.3", + "@esbuild/linux-riscv64": "0.25.3", + "@esbuild/linux-s390x": "0.25.3", + "@esbuild/linux-x64": "0.25.3", + "@esbuild/netbsd-arm64": "0.25.3", + "@esbuild/netbsd-x64": "0.25.3", + "@esbuild/openbsd-arm64": "0.25.3", + "@esbuild/openbsd-x64": "0.25.3", + "@esbuild/sunos-x64": "0.25.3", + "@esbuild/win32-arm64": "0.25.3", + "@esbuild/win32-ia32": "0.25.3", + "@esbuild/win32-x64": "0.25.3" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", + "engines": { + "node": "> 0.1.90" + } + }, + "node_modules/fast-stable-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", + "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==", + "license": "MIT" + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-tsconfig": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", + "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jayson": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.2.0.tgz", + "integrity": "sha512-VfJ9t1YLwacIubLhONk0KFeosUBwstRWQ0IRT1KDjEjnVnSOVHC3uwugyV7L0c7R9lpVyrUGT2XWiBA1UTtpyg==", + "license": "MIT", + "dependencies": { + "@types/connect": "^3.4.33", + "@types/node": "^12.12.54", + "@types/ws": "^7.4.4", + "commander": "^2.20.3", + "delay": "^5.0.0", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "isomorphic-ws": "^4.0.1", + "json-stringify-safe": "^5.0.1", + "stream-json": "^1.9.1", + "uuid": "^8.3.2", + "ws": "^7.5.10" + }, + "bin": { + "jayson": "bin/jayson.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jayson/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "license": "MIT" + }, + "node_modules/jayson/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mocha": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz", + "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/mocha/node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/rpc-websockets": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.1.1.tgz", + "integrity": "sha512-1IXGM/TfPT6nfYMIXkJdzn+L4JEsmb0FL1O2OBjaH03V3yuUDdKFulGLMFG6ErV+8pZ5HVC0limve01RyO+saA==", + "license": "LGPL-3.0-only", + "dependencies": { + "@swc/helpers": "^0.5.11", + "@types/uuid": "^8.3.4", + "@types/ws": "^8.2.2", + "buffer": "^6.0.3", + "eventemitter3": "^5.0.1", + "uuid": "^8.3.2", + "ws": "^8.5.0" + }, + "funding": { + "type": "paypal", + "url": "https://paypal.me/kozjak" + }, + "optionalDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + } + }, + "node_modules/rpc-websockets/node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/rpc-websockets/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/rpc-websockets/node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/stream-chain": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", + "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==", + "license": "BSD-3-Clause" + }, + "node_modules/stream-json": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz", + "integrity": "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==", + "license": "BSD-3-Clause", + "dependencies": { + "stream-chain": "^2.2.5" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superstruct": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz", + "integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/text-encoding-utf-8": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", + "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "license": "MIT" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.19.3", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz", + "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "license": "MIT" + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/workerpool": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/src/solana/package.json b/src/solana/package.json new file mode 100644 index 0000000..0b01730 --- /dev/null +++ b/src/solana/package.json @@ -0,0 +1,30 @@ +{ + "license": "ISC", + "type": "module", + "private": true, + "scripts": { + "build": "tsc --build ./tsconfig.json", + "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w", + "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check" + }, + "dependencies": { + "@coral-xyz/anchor": "^0.31.1", + "@noble/hashes": "^1.7.2", + "@noble/secp256k1": "^2.2.3", + "@wormhole-foundation/sdk-base": "^1.20.0", + "@wormhole-foundation/sdk-definitions": "^1.20.0", + "@wormhole-foundation/sdk-solana-core": "^1.20.0" + }, + "devDependencies": { + "@types/bn.js": "^5.1.0", + "@types/chai": "^4.3.0", + "@types/mocha": "^10.0.10", + "chai": "^4.5.0", + "diff": "^7.0.0", + "mocha": "^11.1.0", + "prettier": "^2.6.2", + "toml": "^3.0.0", + "tsx": "^4.19.3", + "typescript": "^5.7.3" + } +} diff --git a/src/solana/programs/verification_v2/Cargo.toml b/src/solana/programs/verification_v2/Cargo.toml new file mode 100644 index 0000000..702413b --- /dev/null +++ b/src/solana/programs/verification_v2/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "verification_v2" +version = "0.1.0" +description = "Wormhole threshold signature verification program" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "verification_v2" + +[features] +default = ["mainnet"] +mainnet = ["wormhole-anchor-sdk/mainnet"] +testnet = ["wormhole-anchor-sdk/solana-devnet"] +devnet = ["wormhole-anchor-sdk/tilt-devnet"] +cpi = ["no-entrypoint"] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +idl-build = [ + "anchor-lang/idl-build", + "wormhole-anchor-sdk/idl-build", +] + +[dependencies] +anchor-lang = "0.31.1" +byteorder = "1.5.0" +libsecp256k1 = "0.7.2" +primitive-types = "0.13.1" +# wormhole-anchor-sdk = { git = "https://github.com/wormhole-foundation/wormhole-scaffolding.git", default-features = false } +wormhole-anchor-sdk = { git = "https://github.com/XLabs/wormhole-scaffolding.git", rev = "c008cf26c2449b914911a19ecbf8630fd9b4f5b5", default-features = false } diff --git a/src/solana/programs/verification_v2/Xargo.toml b/src/solana/programs/verification_v2/Xargo.toml new file mode 100644 index 0000000..475fb71 --- /dev/null +++ b/src/solana/programs/verification_v2/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/src/solana/programs/verification_v2/src/append_threshold_key_message.rs b/src/solana/programs/verification_v2/src/append_threshold_key_message.rs new file mode 100644 index 0000000..9a491d1 --- /dev/null +++ b/src/solana/programs/verification_v2/src/append_threshold_key_message.rs @@ -0,0 +1,56 @@ +use byteorder::{BigEndian, ReadBytesExt}; +use std::io::{Cursor, Read}; +use anchor_lang::prelude::*; + +use crate::threshold_key::ThresholdKey; + +pub struct AppendThresholdKeyMessage { + pub tss_index: u32, + pub tss_key: ThresholdKey, + pub expiration_delay_seconds: u32, +} + +#[error_code] +pub enum AppendThresholdKeyDecodeError { + InvalidModule, + InvalidAction, +} + +// Module ID for the VerificationV2 contract, ASCII "TSS" +pub const MODULE_VERIFICATION_V2: [u8; 32] = [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x53, 0x53, +]; + +// Action ID for appending a threshold key +pub const ACTION_APPEND_THRESHOLD_KEY: u8 = 0x01; + +impl AppendThresholdKeyMessage { + pub fn deserialize(vaa_body: &[u8]) -> Result { + // Decode the VAA body + let mut cursor = Cursor::new(vaa_body); + let mut module = [0; 32]; + cursor.read_exact(&mut module)?; + let action = cursor.read_u8()?; + let tss_index = cursor.read_u32::()?; + let tss_key = ThresholdKey::deserialize_reader(&mut cursor)?; + let expiration_delay_seconds = cursor.read_u32::()?; + + // Validate the module and action + if module != MODULE_VERIFICATION_V2 { + return Err(AppendThresholdKeyDecodeError::InvalidModule.into()); + } + + if action != ACTION_APPEND_THRESHOLD_KEY { + return Err(AppendThresholdKeyDecodeError::InvalidAction.into()); + } + + Ok( + Self { + tss_index, + tss_key, + expiration_delay_seconds, + } + ) + } +} diff --git a/src/solana/programs/verification_v2/src/lib.rs b/src/solana/programs/verification_v2/src/lib.rs new file mode 100644 index 0000000..e27ff68 --- /dev/null +++ b/src/solana/programs/verification_v2/src/lib.rs @@ -0,0 +1,154 @@ +#![allow(unexpected_cfgs)] + +declare_id!("GbFfTqMqKDgAMRH8VmDmoLTdvDd1853TnkkEwpydv3J6"); + +mod vaa; +mod append_threshold_key_message; +mod threshold_key; + +use anchor_lang::prelude::*; +use anchor_lang::solana_program::clock::Clock; + +use wormhole_anchor_sdk::wormhole::program::Wormhole; +use wormhole_anchor_sdk::wormhole::constants::CHAIN_ID_SOLANA; +use wormhole_anchor_sdk::wormhole::{PostedVaaData}; + +use vaa::VAA; +use append_threshold_key_message::AppendThresholdKeyMessage; +use threshold_key::ThresholdKey; + +const GOVERNANCE_ADDRESS: [u8; 32] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4]; + +#[error_code] +pub enum VAAError { + #[msg("Invalid VAA version")] + InvalidVersion, + #[msg("Invalid VAA index")] + InvalidIndex, + #[msg("TSS key expired")] + TSSKeyExpired, + #[msg("Invalid signature")] + InvalidSignature, +} + +#[error_code] +pub enum AppendThresholdKeyError { + #[msg("Invalid VAA")] + InvalidVAA, + #[msg("Invalid governance chain ID")] + InvalidGovernanceChainId, + #[msg("Invalid governance address")] + InvalidGovernanceAddress, + #[msg("Index mismatch")] + IndexMismatch, + #[msg("Invalid old threshold key")] + InvalidOldThresholdKey, + #[msg("Invalid TSS key")] + InvalidTSSKey, +} + +#[account] +#[derive(InitSpace)] +pub struct ThresholdKeyAccount { + pub index: u32, + pub key: ThresholdKey, + pub expiration_timestamp: u64, +} + +impl ThresholdKeyAccount { + pub fn is_unexpired(&self) -> bool { + self.expiration_timestamp == 0 || self.expiration_timestamp > Clock::get().unwrap().unix_timestamp as u64 + } + + pub fn update_expiration_timestamp(&mut self, time_lapse: u64) { + let current_timestamp = Clock::get().unwrap().unix_timestamp as u64; + self.expiration_timestamp = current_timestamp + time_lapse; + } +} + +// TODO: Refactor this to have one accounts/instruction per file +#[derive(Accounts)] +pub struct AppendThresholdKey<'info> { + #[account(mut)] + pub payer: Signer<'info>, + + #[account( + owner = wormhole_program.key() @ AppendThresholdKeyError::InvalidVAA, + constraint = vaa.meta.emitter_chain == CHAIN_ID_SOLANA @ AppendThresholdKeyError::InvalidGovernanceChainId, + constraint = vaa.meta.emitter_address == GOVERNANCE_ADDRESS @ AppendThresholdKeyError::InvalidGovernanceAddress, + )] + pub vaa: Account<'info, PostedVaaData>, + + #[account( + init, + payer = payer, + space = 8 + ThresholdKeyAccount::INIT_SPACE, + )] + pub new_threshold_key: Account<'info, ThresholdKeyAccount>, + + #[account( + mut, + constraint = old_threshold_key.expiration_timestamp == 0 @ AppendThresholdKeyError::InvalidOldThresholdKey, + )] + pub old_threshold_key: Option>, + + pub wormhole_program: Program<'info, Wormhole>, + pub system_program: Program<'info, System>, +} + +#[derive(Accounts)] +pub struct VerifyVaa<'info> { + #[account( + constraint = threshold_key.is_unexpired() @ VAAError::TSSKeyExpired, + )] + pub threshold_key: Account<'info, ThresholdKeyAccount>, +} + +#[program] +pub mod verification_v2 { + use super::*; + + pub fn append_threshold_key(ctx: Context) -> Result<()> { + // Decode the VAA payload + let message = AppendThresholdKeyMessage::deserialize(&ctx.accounts.vaa.payload)?; + + // Check that if there is no old threshold key, the index is 0 + // Otherwise, check that the index is increasing from the previous index + // FIXME: There's nothing preventing us from creating many chains of valid threshold keys unless we use PDAs based on index + let expected_index = ctx.accounts.old_threshold_key.as_ref().map_or(0, |key| key.index + 1); + if message.tss_index != expected_index { + return Err(AppendThresholdKeyError::IndexMismatch.into()); + } + + // Set the new threshold key + ctx.accounts.new_threshold_key.index = message.tss_index; + ctx.accounts.new_threshold_key.key = message.tss_key; + ctx.accounts.new_threshold_key.expiration_timestamp = 0; + + // Set the old threshold key expiration timestamp + if let Some(ref mut old_threshold_key) = &mut ctx.accounts.old_threshold_key { + old_threshold_key.update_expiration_timestamp(message.expiration_delay_seconds as u64); + } else if expected_index > 0 { + return Err(AppendThresholdKeyError::InvalidOldThresholdKey.into()); + } + + Ok(()) + } + + pub fn verify_vaa(ctx: Context, raw_vaa: Vec) -> Result { + // Decode the VAA + let vaa = VAA::deserialize(&mut raw_vaa.as_slice())?; + + // Check that the threshold key index matches the VAA index + let threshold_key = &mut ctx.accounts.threshold_key; + if threshold_key.index != vaa.header.tss_index { + return Err(VAAError::InvalidIndex.into()); + } + + // Check that the signature is valid + threshold_key.key.check_signature(&vaa.message_hash()?, &vaa.header.signature)?; + + // Return the VAA + Ok(vaa) + } +} diff --git a/src/solana/programs/verification_v2/src/threshold_key.rs b/src/solana/programs/verification_v2/src/threshold_key.rs new file mode 100644 index 0000000..74b4c05 --- /dev/null +++ b/src/solana/programs/verification_v2/src/threshold_key.rs @@ -0,0 +1,125 @@ +use anchor_lang::prelude::*; +use primitive_types::U256; +use std::io::{Cursor, Read, Write}; +use std::ops::{Rem, Shr, Sub}; +use anchor_lang::solana_program::keccak::{Hash, hash}; +use libsecp256k1::{Message, RecoveryId, Signature, recover}; +use crate::vaa::VAAThresholdSignature; + +#[derive(Clone, Debug)] +pub struct ThresholdKey { + pub key: U256, +} + +#[cfg(feature = "idl-build")] +impl anchor_lang::IdlBuild for ThresholdKey {} + +#[error_code] +pub enum ThresholdKeyError { + #[msg("Invalid scalar value")] + InvalidScalar, + #[msg("Invalid signature")] + InvalidSignature, +} + +impl ThresholdKey { + pub fn q() -> U256 { + // TODO: Move this to a constant + U256::from_str_radix("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16).unwrap() + } + + pub fn half_q() -> U256 { + // TODO: Move this to a constant + Self::q().shr(U256::one()) + } + + pub fn px(&self) -> U256 { + self.key.shr(U256::one()) + } + + pub fn parity(&self) -> bool { + self.key.bit(0) + } + + pub fn is_valid(&self) -> bool { + let px = self.px(); + !px.is_zero() && px.le(&Self::half_q()) + } + + pub fn check_signature(&self, message_hash: &Hash, signature: &VAAThresholdSignature) -> Result<()> { + let px = self.px(); + let parity = self.parity(); + let q = Self::q(); + let r = signature.r; + let s = signature.s; + + // Calculate the message challenge + let mut hash_bytes = Vec::new(); + hash_bytes.extend_from_slice(&px.to_big_endian()); + hash_bytes.push(parity as u8); + hash_bytes.extend_from_slice(&message_hash.to_bytes()); + hash_bytes.extend_from_slice(&r); + + let e = U256::from_big_endian(&hash(&hash_bytes).to_bytes()); + + // Calculate the recovery inputs + // FIXME: Is the overflow correct on the sp/ep calculations? + let sp = q.sub(Self::mulmod(px, s, q)); + let ep = Self::mulmod(e, px, q); + + if sp.is_zero() || ep.is_zero() { + return Err(ThresholdKeyError::InvalidSignature.into()); + } + + // Recover the signer address + let mut signature_bytes = [0u8; 64]; + signature_bytes[0..32].copy_from_slice(&px.to_big_endian()); + signature_bytes[32..64].copy_from_slice(&ep.to_big_endian()); + + let message = Message::parse_slice(&sp.to_big_endian()).unwrap(); + let signature = Signature::parse_standard(&signature_bytes).unwrap(); + let recovery_id = RecoveryId::parse(parity as u8).unwrap(); + let recovered = recover(&message, &signature, &recovery_id).unwrap(); + let recovered_address = &hash(&recovered.serialize()[1..]).to_bytes()[12..]; + + if recovered_address != r { + return Err(ThresholdKeyError::InvalidSignature.into()); + } + + Ok(()) + } + + fn mulmod(a: U256, b: U256, c: U256) -> U256 { + let result = a.full_mul(b).rem(c); + U256(result.0[0..3].try_into().unwrap()) + } +} + +impl Space for ThresholdKey { + const INIT_SPACE: usize = 32; +} + +impl AnchorSerialize for ThresholdKey { + fn serialize(&self, writer: &mut W) -> std::result::Result<(), std::io::Error> { + writer.write_all(&self.key.to_big_endian())?; + Ok(()) + } +} + +impl AnchorDeserialize for ThresholdKey { + fn deserialize(data: &mut &[u8]) -> std::result::Result { + Self::deserialize_reader(&mut Cursor::new(data)) + } + + fn deserialize_reader(reader: &mut R) -> std::result::Result { + let mut key = [0u8; 32]; + reader.read_exact(&mut key)?; + let key = ThresholdKey { key: U256::from_big_endian(&key) }; + + if !key.is_valid() { + return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid threshold key")); + } + + Ok(key) + } +} diff --git a/src/solana/programs/verification_v2/src/vaa.rs b/src/solana/programs/verification_v2/src/vaa.rs new file mode 100644 index 0000000..78b93cb --- /dev/null +++ b/src/solana/programs/verification_v2/src/vaa.rs @@ -0,0 +1,136 @@ +use anchor_lang::prelude::*; +use anchor_lang::solana_program::keccak::{Hash, hash}; +use primitive_types::U256; +use borsh::{BorshSerialize, BorshDeserialize}; +use std::io::{Cursor, Read, Write}; +use byteorder::{BigEndian, ReadBytesExt}; + +use crate::threshold_key::ThresholdKey; + +pub struct VAAThresholdSignature { + pub r: [u8; 20], + pub s: U256, +} + +impl VAAThresholdSignature { + pub fn is_valid(&self) -> bool { + !self.s.is_zero() && self.s.lt(&ThresholdKey::q()) && !self.r.iter().all(|r| *r == 0) + } +} + +impl AnchorSerialize for VAAThresholdSignature { + fn serialize(&self, writer: &mut W) -> std::result::Result<(), std::io::Error> { + writer.write_all(&self.r)?; + writer.write_all(&self.s.to_big_endian())?; + Ok(()) + } +} + +impl AnchorDeserialize for VAAThresholdSignature { + fn deserialize(data: &mut &[u8]) -> std::result::Result { + Self::deserialize_reader(&mut Cursor::new(data)) + } + + fn deserialize_reader(reader: &mut R) -> std::result::Result { + let mut r = [0u8; 20]; + reader.read_exact(&mut r)?; + let mut s = [0u8; 32]; + reader.read_exact(&mut s)?; + Ok(Self { r, s: U256::from_big_endian(&s) }) + } +} + +pub struct VAAHeader { + pub version: u8, + pub tss_index: u32, + pub signature: VAAThresholdSignature, +} + +impl VAAHeader { + pub fn is_valid(&self) -> bool { + self.version == 2 && self.signature.is_valid() + } +} + +impl AnchorSerialize for VAAHeader { + fn serialize(&self, writer: &mut W) -> std::result::Result<(), std::io::Error> { + writer.write_all(&[self.version])?; + writer.write_all(&self.tss_index.to_be_bytes())?; + self.signature.serialize(writer)?; + Ok(()) + } +} + +impl AnchorDeserialize for VAAHeader { + fn deserialize(data: &mut &[u8]) -> std::result::Result { + Self::deserialize_reader(&mut Cursor::new(data)) + } + + fn deserialize_reader(reader: &mut R) -> std::result::Result { + let version = reader.read_u8()?; + let tss_index = reader.read_u32::()?; + let signature = VAAThresholdSignature::deserialize_reader(reader)?; + Ok(Self { version, tss_index, signature }) + } +} + +pub struct VAAEnvelope { + pub timestamp: u32, + pub nonce: u32, + pub emitter_chain_id: u16, + pub emitter_address: [u8; 32], + pub sequence: u64, + pub consistency_level: u8, +} + +impl AnchorSerialize for VAAEnvelope { + fn serialize(&self, writer: &mut W) -> std::result::Result<(), std::io::Error> { + writer.write_all(&self.timestamp.to_be_bytes())?; + writer.write_all(&self.nonce.to_be_bytes())?; + writer.write_all(&self.emitter_chain_id.to_be_bytes())?; + writer.write_all(&self.emitter_address)?; + writer.write_all(&self.sequence.to_be_bytes())?; + writer.write_all(&[self.consistency_level])?; + Ok(()) + } +} + +impl AnchorDeserialize for VAAEnvelope { + fn deserialize(data: &mut &[u8]) -> std::result::Result { + Self::deserialize_reader(&mut Cursor::new(data)) + } + + fn deserialize_reader(reader: &mut R) -> std::result::Result { + let timestamp = reader.read_u32::()?; + let nonce = reader.read_u32::()?; + let emitter_chain_id = reader.read_u16::()?; + let mut emitter_address = [0u8; 32]; + reader.read_exact(&mut emitter_address)?; + let sequence = reader.read_u64::()?; + let consistency_level = reader.read_u8()?; + Ok(Self { timestamp, nonce, emitter_chain_id, emitter_address, sequence, consistency_level }) + } +} + +#[derive(BorshSerialize, BorshDeserialize)] +pub struct VAA { + pub header: VAAHeader, + pub envelope: VAAEnvelope, + pub payload: Vec, +} + +#[cfg(feature = "idl-build")] +impl anchor_lang::IdlBuild for VAA {} + +impl VAA { + pub fn is_valid(&self) -> bool { + self.header.is_valid() + } + + pub fn message_hash(&self) -> Result { + let mut cursor = Cursor::new(Vec::new()); + self.envelope.serialize(&mut cursor)?; + cursor.write_all(&self.payload)?; + Ok(hash(&cursor.get_ref())) + } +} diff --git a/src/solana/tests/layouts.ts b/src/solana/tests/layouts.ts new file mode 100644 index 0000000..b4abf9d --- /dev/null +++ b/src/solana/tests/layouts.ts @@ -0,0 +1,75 @@ +import { chainToChainId, enumItem, Layout, layoutItems } from '@wormhole-foundation/sdk-connect'; + +const versionItem = (custom: N) => + ({ name: 'version', binary: 'uint', size: 1, custom, omit: true }) as const; + +const consistencyLevelItem = { name: 'consistencyLevel', binary: 'uint', size: 1 } as const; + +const timestampItem = { name: 'timestamp', binary: 'uint', size: 4, endianness: 'little' } as const; + +const nonceAndSequenceLayout = [ + { name: 'nonce', binary: 'uint', size: 4, endianness: 'little' }, + { name: 'sequence', binary: 'uint', size: 8, endianness: 'little' }, +] as const satisfies Layout; + +const emitterAddressAndPayloadLayout = [ + { name: 'emitterAddress', ...layoutItems.universalAddressItem }, + { name: 'payload', binary: 'bytes', lengthSize: 4, lengthEndianness: 'little' }, +] as const satisfies Layout; + +// From here: https://github.com/wormhole-foundation/wormhole/blob/7bd40b595e22c5512dfaa2ed8e6d7441df743a69/solana/programs/core-bridge/src/legacy/state/posted_message_v1/mod.rs#L17-L35 +const messageStatusItem = { + name: 'messageStatus', + ...enumItem([ + ['Published', 0], + ['Writing', 1], + ['ReadyForPublishing', 2], + ]), +} as const; + +// From here: https://github.com/wormhole-foundation/wormhole/blob/7bd40b595e22c5512dfaa2ed8e6d7441df743a69/solana/programs/core-bridge/src/legacy/state/posted_message_v1/mod.rs#L39-L73 +// reuses unused fields (that were only used for VAAs) from here: https://github.com/wormhole-foundation/wormhole/blob/7247a0fc0c96ab9493b8d0b886a7a54ee2a8fcce/solana/bridge/program/src/accounts/posted_message.rs#L46-L76 +// hence these fields will only have sensible values when parsing posted messages by the solana core bridge rewrite +const postedMessageV1Layout = [ + versionItem(0), + consistencyLevelItem, + { name: 'emitterAuthority', ...layoutItems.universalAddressItem }, + messageStatusItem, + { name: 'unusedGap', binary: 'uint', size: 3, custom: 0, omit: true }, + timestampItem, + ...nonceAndSequenceLayout, + { + name: 'emitterChain', + binary: 'uint', + size: 2, + endianness: 'little', + custom: { from: chainToChainId('Solana'), to: 'Solana' }, + }, + ...emitterAddressAndPayloadLayout, +] as const satisfies Layout; + +//from here: https://github.com/wormhole-foundation/wormhole/blob/7bd40b595e22c5512dfaa2ed8e6d7441df743a69/solana/programs/core-bridge/src/legacy/state/posted_vaa_v1.rs#L12-L43 +//reuses unused fields (that were only used for posted messages) from here: https://github.com/wormhole-foundation/wormhole/blob/7247a0fc0c96ab9493b8d0b886a7a54ee2a8fcce/solana/bridge/program/src/accounts/posted_message.rs#L46-L76 +//hence these fields will only have sensible values when parsing posted messages by the solana core bridge rewrite +const postedVaaV1Layout = [ + versionItem(1), + consistencyLevelItem, + timestampItem, + { name: 'signatureSet', ...layoutItems.universalAddressItem }, + { name: 'guardianSetIndex', binary: 'uint', size: 4, endianness: 'little' }, + ...nonceAndSequenceLayout, + { name: 'emitterChain', ...layoutItems.chainItem(), endianness: 'little' }, + ...emitterAddressAndPayloadLayout, +] as const satisfies Layout; + +export const coreV1AccountDataLayout = { + binary: 'switch', + idSize: 3, + idTag: 'discriminator', + layouts: [ + //numeric values are ascii->number encoding of strings + [[0x6d7367, 'msg'], postedMessageV1Layout], + [[0x6d7375, 'msu'], postedMessageV1Layout], + [[0x766161, 'vaa'], postedVaaV1Layout], + ], +} as const satisfies Layout; diff --git a/src/solana/tests/testing-wormhole-core.ts b/src/solana/tests/testing-wormhole-core.ts new file mode 100644 index 0000000..174a07b --- /dev/null +++ b/src/solana/tests/testing-wormhole-core.ts @@ -0,0 +1,152 @@ +import anchor from '@coral-xyz/anchor'; +import { Connection, Keypair, PublicKey, Signer } from '@solana/web3.js'; +import { + Chain, + deserializeLayout, + encoding, + Network, + signAndSendWait, +} from '@wormhole-foundation/sdk-connect'; +import { SolanaSendSigner } from '@wormhole-foundation/sdk-solana'; +import { SolanaWormholeCore, utils as coreUtils } from '@wormhole-foundation/sdk-solana-core'; +import { + serializePayload, + serialize as serializeVaa, + deserialize as deserializeVaa, + UniversalAddress, + createVAA, + Contracts, + VAA, +} from '@wormhole-foundation/sdk-definitions'; +import { mocks } from '@wormhole-foundation/sdk-definitions/testing'; + +import { coreV1AccountDataLayout } from './layouts.js'; +import { sendAndConfirm } from './testing_helpers.js'; + +export type VaaMessage = VAA<'Uint8Array'>; + +const guardianKey = 'cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0'; +export const guardianAddress = 'beFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe'; + +/** A Wormhole Core wrapper allowing to write tests using this program in a local environment. */ +export class TestingWormholeCore { + public readonly signer: Signer; + public readonly client: SolanaWormholeCore; + private sequence = 0n; + private readonly toProgram: PublicKey; + private _guardians?: mocks.MockGuardians; + + /** + * + * @param solanaProgram The Solana Program used as a destination for the VAAs, _i.e._ the program being tested. + * @param contracts At least the core program address `coreBridge` must be provided. + */ + constructor( + signer: Signer, + connection: Connection, + network: N, + testedProgram: PublicKey, + contracts: Contracts, + ) { + this.signer = signer; + this.toProgram = testedProgram; + this.client = new SolanaWormholeCore(network, 'Solana', connection, contracts); + } + + get guardians(): mocks.MockGuardians { + if (this._guardians === undefined) throw Error("coreV1 not initialized") + + return this._guardians; + } + + get pda() { + return { + guardianSet: (): PublicKey => + this.findPda(Buffer.from('GuardianSet'), Buffer.from([0, 0, 0, 0])), + bridge: (): PublicKey => this.findPda(Buffer.from('Bridge')), + feeCollector: (): PublicKey => this.findPda(Buffer.from('fee_collector')), + }; + } + + async initialize( + guardians = [guardianAddress], + guardianSetExpirationTime = 86400, + fee = 100, + ) { + const initialGuardians = guardians.map((guardian) => Array.from(encoding.hex.decode(guardian))); + const initFee = new anchor.BN(fee); + + // https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/api/initialize.rs + const ix = await this.client.coreBridge.methods + .initialize(guardianSetExpirationTime, initFee, initialGuardians) + .accounts({ + bridge: this.pda.bridge(), + guardianSet: this.pda.guardianSet(), + feeCollector: this.pda.feeCollector(), + payer: this.signer.publicKey, + }) + .instruction(); + + const txid = await sendAndConfirm(this.client.connection, ix, this.signer) + this._guardians = new mocks.MockGuardians(0, [guardianKey]) + return txid + } + + /** Parse a VAA generated from the postVaa method, or from the Token Bridge during + * and outbound transfer + */ + async parseVaa(key: PublicKey): Promise { + const info = await this.client.connection.getAccountInfo(key); + if (info === null) { + throw new Error(`No message account exists at that address: ${key.toString()}`); + } + + const message = deserializeLayout(coreV1AccountDataLayout, info.data); + + const vaa = createVAA('Uint8Array', { + guardianSet: 0, + timestamp: message.timestamp, + nonce: message.nonce, + emitterChain: message.emitterChain, + emitterAddress: message.emitterAddress, + sequence: message.sequence, + consistencyLevel: message.consistencyLevel, + signatures: [], + payload: message.payload, + }); + + return deserializeVaa('Uint8Array', serializeVaa(vaa)); + } + + /** + * `source`: the emitter of the message. + */ + async postVaa( + payer: Keypair, + source: { chain: Chain; emitterAddress: UniversalAddress }, + message: Uint8Array, + ): Promise { + const seq = this.sequence++; + const timestamp = Math.round(Date.now() / 1000); + + const emittingPeer = new mocks.MockEmitter(source.emitterAddress, source.chain, seq); + + const published = emittingPeer.publishMessage( + 0, // nonce, + message, + 1, // consistencyLevel + timestamp, + ); + const vaa = this.guardians.addSignatures(published, [0]); + + const txs = this.client.postVaa(payer.publicKey, vaa); + const signer = new SolanaSendSigner(this.client.connection, 'Solana', payer, false, {}); + await signAndSendWait(txs, signer); + + return coreUtils.derivePostedVaaKey(this.client.coreBridge.programId, Buffer.from(vaa.hash)); + } + + private findPda(...seeds: Array) { + return PublicKey.findProgramAddressSync(seeds, this.client.coreBridge.programId)[0]; + } +} diff --git a/src/solana/tests/testing_helpers.ts b/src/solana/tests/testing_helpers.ts new file mode 100644 index 0000000..d7751ab --- /dev/null +++ b/src/solana/tests/testing_helpers.ts @@ -0,0 +1,163 @@ +import { + Connection, + Finality, + LAMPORTS_PER_SOL, + PublicKey, + Signer, + Transaction, + TransactionInstruction, + sendAndConfirmTransaction, + Keypair, + TransactionSignature, + VersionedTransactionResponse +} from "@solana/web3.js" +import { mocks } from "@wormhole-foundation/sdk-definitions/testing" +import { Contracts } from '@wormhole-foundation/sdk-definitions'; +import fs from "fs/promises" +import fsSync from "fs" +import * as toml from 'toml'; + +// Copied from @wormhole-foundation/wormhole-scaffolding/solana/ts/helpers/utils.ts +// TODO: There's probably some way to import this? + +export const MOCK_GUARDIANS = new mocks.MockGuardians(0, ["cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0"]) + +// class SendIxError extends Error { +// logs: string; + +// constructor(originalError: Error & { logs?: string[] }) { +// //The newlines don't actually show up correctly in chai's assertion error, but at least +// // we have all the information and can just replace '\n' with a newline manually to see +// // what's happening without having to change the code. +// const logs = originalError.logs?.join('\n') || "error had no logs"; +// super(originalError.message + "\nlogs:\n" + logs); +// this.stack = originalError.stack; +// this.logs = logs; +// } +// } + +type Tuple = R['length'] extends N + ? R + : Tuple; + +export class TestsHelper { + static readonly LOCALHOST = 'http://localhost:8899'; + readonly connection: Connection; + readonly finality: Finality; + + /** Connections cache. */ + private static readonly connections: Partial> = {}; + + constructor(finality: Finality = 'confirmed') { + if (TestsHelper.connections[finality] === undefined) { + TestsHelper.connections[finality] = new Connection(TestsHelper.LOCALHOST, finality); + } + this.connection = TestsHelper.connections[finality]; + this.finality = finality; + } + + keypair = { + generate: (): Keypair => Keypair.generate(), + read: async (path: string): Promise => + this.keypair.from(JSON.parse(await fs.readFile(path, { encoding: 'utf8' }))), + from: (bytes: number[]): Keypair => Keypair.fromSecretKey(Uint8Array.from(bytes)), + several: (amount: N): Tuple => + Array.from({ length: amount }).map(Keypair.generate) as Tuple, + }; + + /** Waits that a transaction is confirmed. */ + async confirm(signature: TransactionSignature) { + const latestBlockHash = await this.connection.getLatestBlockhash(); + + return this.connection.confirmTransaction({ + signature, + blockhash: latestBlockHash.blockhash, + lastValidBlockHeight: latestBlockHash.lastValidBlockHeight, + }); + } + + async sendAndConfirm( + ixs: TransactionInstruction | Transaction | TransactionInstruction[], + payer: Signer, + ...signers: Signer[] + ): Promise { + return sendAndConfirm(this.connection, ixs, payer, ...signers); + } + + async getTransaction( + signature: TransactionSignature | Promise, + ): Promise { + return this.connection.getTransaction(await signature, { + commitment: this.finality, + maxSupportedTransactionVersion: 1, + }); + } + + /** Requests airdrop to an account or several ones. */ + async airdrop(to: PublicKey[]): Promise { + await Promise.all(to.map(async (account) => + this.confirm(await this.connection.requestAirdrop(account, 50 * LAMPORTS_PER_SOL)) + )); + } +} + +export function findPda(programId: PublicKey, seeds: Array) { + const [address, bump] = PublicKey.findProgramAddressSync( + seeds.map((seed) => { + if (typeof seed === 'string') { + return Buffer.from(seed); + } else { + return seed; + } + }), + programId, + ); + return { + address, + bump, + }; +} + +export async function sendAndConfirm( + connection: Connection, + ixs: TransactionInstruction | Transaction | Array, + payer: Signer, + ...signers: Signer[] +): Promise { + const { value } = await connection.getLatestBlockhashAndContext(); + const tx = new Transaction({ + ...value, + feePayer: payer.publicKey, + }).add(...(Array.isArray(ixs) ? ixs : [ixs])); + + return sendAndConfirmTransaction(connection, tx, [payer, ...signers], {}); +} + +/** Helper allowing to abstract over the Wormhole configuration (network and addresses) */ +export class WormholeContracts { + static Network = 'Devnet' as const; + + private static core: PublicKey = PublicKey.default; + + static get coreBridge(): PublicKey { + WormholeContracts.init(); + return WormholeContracts.core; + } + + static get addresses(): Contracts { + WormholeContracts.init(); + return { + coreBridge: WormholeContracts.core.toString(), + }; + } + + private static init() { + if (WormholeContracts.core.equals(PublicKey.default)) { + const anchorCfg = toml.parse(fsSync.readFileSync('./Anchor.toml', 'utf-8')); + + WormholeContracts.core = new PublicKey( + anchorCfg.test.genesis.find((cfg: any) => cfg.name == 'wormhole-core-v1').address, + ); + } + } +} \ No newline at end of file diff --git a/src/solana/tests/verification_v2.ts b/src/solana/tests/verification_v2.ts new file mode 100644 index 0000000..5153892 --- /dev/null +++ b/src/solana/tests/verification_v2.ts @@ -0,0 +1,168 @@ +import assert from "assert" + +import * as anchor from "@coral-xyz/anchor" +import { Keypair, PublicKey } from "@solana/web3.js" +import { toUniversal, UniversalAddress } from "@wormhole-foundation/sdk-definitions" +import { getPublicKey, sign } from "@noble/secp256k1" +import { keccak_256 } from "@noble/hashes/sha3" +import { randomBytes } from "@noble/hashes/utils" + +// import { VerificationV2 } from "../target/types/verification_v2.js" + +import { guardianAddress, TestingWormholeCore } from "./testing-wormhole-core.js" +import { WormholeContracts, TestsHelper } from "./testing_helpers.js" + +const $ = new TestsHelper() + +const encodeU16BE = (value: number) => [value >> 8, value & 0xFF] + +const encodeU32BE = (value: number) => [ + ...encodeU16BE(value >> 16), + ...encodeU16BE(value & 0xFFFF), +] + +const encodeU64BE = (value: number | bigint) => [ + ...encodeU32BE(Number(BigInt(value) >> BigInt(32))), + ...encodeU32BE(Number(BigInt(value) & BigInt(0xFFFFFFFF))), +] + +export interface VAABody { + readonly timestamp: number + readonly nonce: number + readonly emitterChainId: number + readonly emitterAddress: Uint8Array + readonly sequence: number + readonly consistencyLevel: number + readonly payload: Uint8Array +} + +export const createVAAv2 = (tssIndex: number, body: VAABody, privateKey: Uint8Array) => { + const vaaBody = new Uint8Array([ + ...encodeU32BE(body.timestamp), + ...encodeU32BE(body.nonce), + ...encodeU16BE(body.emitterChainId), + ...body.emitterAddress, + ...encodeU64BE(body.sequence), + body.consistencyLevel, + ...body.payload, + ]) + + const signature = sign(keccak_256(vaaBody), privateKey) + + const TSS_VAA_VERSION = 0x02 + + return new Uint8Array([ + TSS_VAA_VERSION, + ...encodeU32BE(tssIndex), + ...signature.toCompactRawBytes(), + signature.recovery, + ...vaaBody, + ]) +} + +export interface AppendThresholdKeyMessage { + readonly tssIndex: number + readonly tssKey: Uint8Array + readonly expirationDelaySeconds: number +} + +export const createAppendThresholdKeyMessage = (tssIndex: number, tssKey: Uint8Array, expirationDelaySeconds: number) => { + const MODULE_VERIFICATION_V2 = new Uint8Array([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x53, 0x53, + ]) + + const ACTION_APPEND_THRESHOLD_KEY = 0x01 + + assert(tssKey.length === 20, "TSS key must be 20 bytes") + + return new Uint8Array([ + ...MODULE_VERIFICATION_V2, + ACTION_APPEND_THRESHOLD_KEY, + ...encodeU32BE(tssIndex), + ...tssKey, + ...encodeU32BE(expirationDelaySeconds), + ]) +} + +// ------------------------------------------------------------------------------------------------ + + +//TODO: get implementation for schnorr signing +async function thresholdGuardianSign(x: Uint8Array): Promise { + return x; +} + +describe("VerificationV2", function() { + const coreV1Address = new PublicKey('worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth') + const guardianSetExpirationTime = 86400 + const fee = 100 + const txSigner = $.keypair.generate() + let coreV1: TestingWormholeCore<"Devnet">; + const connection = $.connection + let payer: Keypair; + // const coreV2 = anchor.workspace.VerificationV2 as Program + + before(async function() { + payer = anchor.getProvider().wallet?.payer! + assert(payer, "Payer not found") + + await $.airdrop([ + txSigner.publicKey, + payer.publicKey, + ]); + + coreV1 = new TestingWormholeCore( + txSigner, + connection, + WormholeContracts.Network, + coreV1Address, + WormholeContracts.addresses, + ); + + const txid = await coreV1.initialize(undefined, guardianSetExpirationTime, fee) + const tx = await $.getTransaction(txid) + }); + + it("Check correct core v1 setup", async function() { + const accounts = await connection.getProgramAccounts(coreV1Address) + assert(accounts.length === 2, "Expected 2 accounts") + + const guardianSetIndex = await coreV1.client.getGuardianSetIndex(); + assert(guardianSetIndex === 0, "Expected guardian set index to be 0") + const guardianSet = await coreV1.client.getGuardianSet(guardianSetIndex); + // FIXME? initialize doesn't seem to set the correct expiration time + // assert.strictEqual(guardianSet.expiry, BigInt(guardianSetExpirationTime), "Guardian set expiration time") + + const queriedFee = await coreV1.client.getMessageFee(); + assert(queriedFee === BigInt(fee), "Expected fee to be 100") + + assert(guardianSet.index === 0, "Expected guardian set index to be 0") + assert(guardianSet.keys.length === 1, "Expected guardian set keys to have length 1") + + const queriedGuardian = new UniversalAddress(guardianSet.keys[0], "hex"); + const expectedGuardian = toUniversal("Ethereum", guardianAddress) + assert(queriedGuardian.equals(expectedGuardian), "Expected guardian set keys to be the devnet guardian") + }) + + it("Posts append threshold key VAA successfully", async function(){ + const guardianPrivateKey = randomBytes(32) + const guardianPublicKey = keccak_256(getPublicKey(guardianPrivateKey)).slice(12) + const message = createAppendThresholdKeyMessage( + 0, + guardianPublicKey, + guardianSetExpirationTime, + ) + + const governanceContract = new UniversalAddress("0000000000000000000000000000000000000000000000000000000000000004", "hex"); + const postedVaaAddress = await coreV1.postVaa( + payer, + { + chain: "Solana", + emitterAddress: governanceContract, + }, + message, + ) + }) + +}); diff --git a/src/solana/tsconfig.json b/src/solana/tsconfig.json new file mode 100644 index 0000000..331743d --- /dev/null +++ b/src/solana/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "types": ["mocha", "chai"], + "typeRoots": ["./node_modules/@types"], + "lib": ["es2023"], + "module": "NodeNext", + "moduleResolution": "NodeNext", + "target": "es2022", + "outDir": "ts-build", + "strict": true, + "composite": true, + "skipLibCheck": true, + "esModuleInterop": true + }, + "include": ["tests", "target/types"] +} diff --git a/test/BackwardsOptimized.t.sol b/test/BackwardsOptimized.t.sol deleted file mode 100644 index 2ea1fbc..0000000 --- a/test/BackwardsOptimized.t.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.24; - -import { ManualSigning } from "./ManualSigning.sol"; - -import { BackwardsOptimized } from "core-bridge/BackwardsOptimized/BackwardsOptimized.sol"; -import "wormhole-sdk/proxy/Proxy.sol"; - -contract BackwardsOptimizedGasCost is ManualSigning { - BackwardsOptimized private _backwardsOptimized; - - function setUp() public { - _setUpManualSigning(wormhole.getGuardianSet(wormhole.getCurrentGuardianSetIndex()).keys.length); - _backwardsOptimized = BackwardsOptimized(payable(address(new Proxy( - address(new BackwardsOptimized()), - abi.encodePacked(_guardianAddrs) - )))); - } - - function testBackwardsOptimized() public view { - (, bool success, string memory reason) = - _backwardsOptimized.parseAndVerifyVM(_vaa); - assertTrue(success, reason); - } -} \ No newline at end of file diff --git a/test/GasTestBase.sol b/test/GasTestBase.sol deleted file mode 100644 index 14b8b3a..0000000 --- a/test/GasTestBase.sol +++ /dev/null @@ -1,153 +0,0 @@ -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.24; - -import "forge-std/Test.sol"; - -import { IWormhole } from "wormhole-sdk/interfaces/IWormhole.sol"; -import { PublishedMessage } from "wormhole-sdk/testing/WormholeOverride.sol"; -import { VaaEnvelope } from "wormhole-sdk/libraries/VaaLib.sol"; - -contract GasTestBase is Test { - IWormhole public wormhole; - - constructor() { - wormhole = IWormhole(0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B); - } - - function _tbPublishedMsg() internal pure returns (PublishedMessage memory) { - return PublishedMessage( - VaaEnvelope({ - timestamp: 0x670acde5, - emitterChainId: 0x17, - emitterAddress: 0x0000000000000000000000000b2402144bb366a632d14b83f244d2e0e21bd39c, - sequence: 0x45e61, - nonce: 0x163d234e, - consistencyLevel: 1 - }), - _tbPayload() - ); - } - - //source tx hash from ethereum mainnet: - // 0xedd3ac96bc37961cce21a33fd50449dba257737c168006b40aa65496aaf92449 - function _tbOriginalVaa() internal pure returns (bytes memory) { - bytes[] memory signatures = new bytes[](13); - signatures[0] = abi.encodePacked( - bytes1(0x00), //index - bytes32(0xd7c298ee56b3860ca3597e2ce51568e029585cf3b4706d65df785f763b90f74e), //r - bytes32(0x77c5e774eb2dcc0422ed2bad6ec7490fbfb18f4621b4a267cb583ba195797951), //s - bytes1(0x01) //v - ); - signatures[1] = abi.encodePacked( - bytes1(0x01), - bytes32(0x0391f369925909f013921495ca4c8d769746a63fa237a1f282c6557a1e121887), - bytes32(0x5666d4f4cfcb88a9156a1684194d845ec94789f022a8dd38a99de7298bb5436b), - bytes1(0x00) - ); - signatures[2] = abi.encodePacked( - bytes1(0x02), - bytes32(0xe5ebcbe493fb9e5dddc5619956620efce4ac9735acad92954e24bebc6a639d94), - bytes32(0x2d4512f823b248644f752e423f5087eb588ce188af5c68c51f7f32b70e18b801), - bytes1(0x00) - ); - signatures[3] = abi.encodePacked( - bytes1(0x03), - bytes32(0x7f54c89b8f646f940780d0029c50068c25e34ba312ae5450fdda0450c25143ce), - bytes32(0x7e10a54368e7412a4970c6b6872aa1cc1f75e62a8640c3df43641163ccba7432), - bytes1(0x01) - ); - signatures[4] = abi.encodePacked( - bytes1(0x04), - bytes32(0x4a70b8d851b3c8dcdcd30328c8b7802fe91b4b8bf97871f9055fbc3fd7ccb7dc), - bytes32(0x7a561005acde4932268ad79f80367b323dbfbffc911f395b02c0061dc6f4f5aa), - bytes1(0x01) - ); - signatures[5] = abi.encodePacked( - bytes1(0x07), - bytes32(0x3df702e117ca425813e4ddb073419ff7964df5a58f487839ad6241a46c6c0d44), - bytes32(0x2d4fe29797ea43732b60b00b4c32b9bf0165e2fbe0092144ee3ce6f8dc2e9936), - bytes1(0x00) - ); - signatures[6] = abi.encodePacked( - bytes1(0x09), - bytes32(0xc048a769158bca4473eb492e2d79af32fdcc6a2615a0715f3c881d3f8cf0d897), - bytes32(0x1039aeff11502fa76c55e72330e1996f540ce8f8f5523dee6c8e4c196e5d786f), - bytes1(0x01) - ); - signatures[7] = abi.encodePacked( - bytes1(0x0a), - bytes32(0x26997af10642283328110a4719c57beffd0b46d395cd71aeb4fac3c008060091), - bytes32(0x711279551534826d1823160433001aea254939e85a474838c255aea60b10fc49), - bytes1(0x01) - ); - signatures[8] = abi.encodePacked( - bytes1(0x0c), - bytes32(0x5bcf6fda82527ac97320dc63312d82f22f267d3dae2b5acbf9e231219d84e2ee), - bytes32(0x0bcdbc83fed098d491de778addd92d15a2e857b55c425ea594c15dd7de2a53c8), - bytes1(0x00) - ); - signatures[9] = abi.encodePacked( - bytes1(0x0d), - bytes32(0x8f091ad26b04859876d5d691a3bb178d13d4374bc76af94e0afcff6a4c6a9515), - bytes32(0x08b962526b842a70559376d7dc7b55f28477d7528a40596270b1c45fe01b880d), - bytes1(0x01) - ); - signatures[10] = abi.encodePacked( - bytes1(0x0e), - bytes32(0x1f4bb6680b8ccc46adab4f4599a9d3affb77464ddb15a829cd6f231c53a80b59), - bytes32(0x675039aa6d5c6c21a9b8dbae6270c8cc75c61b61137b4e21871d86d4076865b1), - bytes1(0x00) - ); - signatures[11] = abi.encodePacked( - bytes1(0x10), - bytes32(0xbc34ccbf4c7199b996e6af44cddbbf900b7cb2e6c2a930b280cae7c67f6513f2), - bytes32(0x686b63ec6bbd3c2efdf46084972c8490bdef290119f0a19f40871389247dba0f), - bytes1(0x00) - ); - signatures[12] = abi.encodePacked( - bytes1(0x12), - bytes32(0x1be73670f42a9819a25a10aacad7a3b8082c411d824953ca655245c43987ee51), - bytes32(0x1f0b0853ee4994b0c8f65b5f4fc748a1e5bbe4cc33d1ae2423e0e9469a1e0955), - bytes1(0x00) - ); - - return abi.encodePacked( - uint8(1), //version - uint32(4), //guardian set - uint8(13), //signature count - signatures[0], - signatures[1], - signatures[2], - signatures[3], - signatures[4], - signatures[5], - signatures[6], - signatures[7], - signatures[8], - signatures[9], - signatures[10], - signatures[11], - signatures[12], - _tbVaaPayload() - ); - } - - function _tbVaaPayload() internal pure returns (bytes memory) { - return abi.encodePacked( - bytes32(0x670acde5163d234e00170000000000000000000000000b2402144bb366a632d1), - bytes19(0x4b83f244d2e0e21bd39c0000000000045e6101), - _tbPayload() - ); - } - - function _tbPayload() internal pure returns (bytes memory) { - return abi.encodePacked( - bytes32(0x01000000000000000000000000000000000000000000000000000197020a499f), - bytes32(0x3c000000000000000000000000ff836a5821e69066c87e268bc51b849fab9424), - bytes32(0x0c00020000000000000000000000000a6c69327d517568e6308f1e1cd2fd2b2b), - bytes32(0x3cd4bf0002000000000000000000000000000000000000000000000000000000), - bytes5 (0x0000000000) - ); - } -} diff --git a/test/GscdGasCost.t.sol b/test/GscdGasCost.t.sol deleted file mode 100644 index 882902f..0000000 --- a/test/GscdGasCost.t.sol +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.24; - -import { ManualSigning } from "./ManualSigning.sol"; - -import { Wormhole } from "core-bridge/gscd/Wormhole.sol"; -import { Setup } from "core-bridge/gscd/Setup.sol"; -import { Implementation } from "core-bridge/gscd/Implementation.sol"; - -contract GscdGasCost is ManualSigning { - - Implementation private _gscdCore; - bytes private _encodedGuardianSet; - - function setUp() public { - _setUpManualSigning(wormhole.getGuardianSet(wormhole.getCurrentGuardianSetIndex()).keys.length); - - _gscdCore = Implementation(payable(address(new Wormhole( - address(new Setup()), - abi.encodeWithSignature( - "setup(address,address[],uint16,uint16,bytes32,uint256)", - address(new Implementation()), - _guardianAddrs, - wormhole.chainId(), - wormhole.governanceChainId(), - wormhole.governanceContract(), - wormhole.evmChainId() - ) - )))); - - _encodedGuardianSet = abi.encodePacked( - _guardianAddrs[0], - _guardianAddrs[1], - _guardianAddrs[2], - _guardianAddrs[3], - _guardianAddrs[4], - _guardianAddrs[5], - _guardianAddrs[6], - _guardianAddrs[7], - _guardianAddrs[8], - _guardianAddrs[9], - _guardianAddrs[10], - _guardianAddrs[11], - _guardianAddrs[12], - _guardianAddrs[13], - _guardianAddrs[14], - _guardianAddrs[15], - _guardianAddrs[16], - _guardianAddrs[17], - _guardianAddrs[18], - uint32(0) - ); - } - - function testGscdOptimizations() public view { - (, bool success, string memory reason) = - _gscdCore.parseAndVerifyVMOptimized(_vaa, _encodedGuardianSet, 0); - assertTrue(success, reason); - } -} \ No newline at end of file diff --git a/test/ManualSigning.sol b/test/ManualSigning.sol deleted file mode 100644 index f808471..0000000 --- a/test/ManualSigning.sol +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.24; - -import { IWormhole } from "wormhole-sdk/interfaces/IWormhole.sol"; -import { BytesParsing } from "wormhole-sdk/libraries/BytesParsing.sol"; -import { GuardianSignature, Vaa, VaaLib } from "wormhole-sdk/libraries/VaaLib.sol"; -import { - PublishedMessage, - AdvancedWormholeOverride -} from "wormhole-sdk/testing/WormholeOverride.sol"; - -import { GasTestBase } from "./GasTestBase.sol"; - -contract ManualSigning is GasTestBase { - using VaaLib for IWormhole.VM; - using BytesParsing for bytes; - - bytes internal _vaa; - address[] internal _guardianAddrs; - - uint256[] private _guardianPrivateKeys; - - //not nicely exported by forge, so we copy it here - function _makeAddrAndKey( - string memory name - ) private returns (address addr, uint256 privateKey) { - privateKey = uint256(keccak256(abi.encodePacked(name))); - addr = vm.addr(privateKey); - vm.label(addr, name); - } - - function _sign( - PublishedMessage memory pm, - bytes memory signingGuardianIndices - ) private view returns (Vaa memory vaa) { unchecked { - vaa.header.guardianSetIndex = 0; - bytes32 hash = VaaLib.calcDoubleHash(pm); - vaa.header.signatures = new GuardianSignature[](signingGuardianIndices.length); - for (uint i = 0; i < signingGuardianIndices.length; ++i) { - (uint8 gi, ) = signingGuardianIndices.asUint8Mem(i); - (vaa.header.signatures[i].v, vaa.header.signatures[i].r, vaa.header.signatures[i].s) = - vm.sign(_guardianPrivateKeys[uint(gi)], hash); - vaa.header.signatures[i].guardianIndex = gi; - } - vaa.envelope = pm.envelope; - vaa.payload = pm.payload; - }} - - function _setUpManualSigning(uint guardianCount) internal { - for (uint i = 0; i < guardianCount; ++i) { - (address ga, uint256 gpk) = _makeAddrAndKey(string.concat("guardian", vm.toString(i + 1))); - _guardianAddrs.push(ga); - _guardianPrivateKeys.push(gpk); - } - - uint quorum = guardianCount * 2 / 3 + 1; - bytes memory signingGuardianIndices = new bytes(0); - for (uint i = 0; i < quorum; ++i) - signingGuardianIndices = abi.encodePacked(signingGuardianIndices, uint8(i)); - - _vaa = _sign(_tbPublishedMsg(), signingGuardianIndices).encode(); - } -} diff --git a/test/OriginalGasCost.t.sol b/test/OriginalGasCost.t.sol deleted file mode 100644 index 5d211f2..0000000 --- a/test/OriginalGasCost.t.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.24; - -import { GasTestBase } from "./GasTestBase.sol"; - -contract OriginalGasCost is GasTestBase { - function testOriginalGasCost() public view { - (, bool success, string memory reason) = wormhole.parseAndVerifyVM(_tbOriginalVaa()); - assertTrue(success, reason); - } -} diff --git a/test/SingleSigGasCost.t.sol b/test/SingleSigGasCost.t.sol deleted file mode 100644 index 940b711..0000000 --- a/test/SingleSigGasCost.t.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.24; - -import { GasTestBase } from "./GasTestBase.sol"; - -import { IWormhole } from "wormhole-sdk/interfaces/IWormhole.sol"; -import { DEVNET_GUARDIAN_PRIVATE_KEY } from "wormhole-sdk/testing/Constants.sol"; -import { VaaLib } from "wormhole-sdk/libraries/VaaLib.sol"; -import { - PublishedMessage, - AdvancedWormholeOverride -} from "wormhole-sdk/testing/WormholeOverride.sol"; - -contract SingleSigGasCost is GasTestBase { - using AdvancedWormholeOverride for IWormhole; - using VaaLib for IWormhole.VM; - - bytes private _vaa; - - function setUp() public { - uint256[] memory guardianSecrets = new uint256[](1); - guardianSecrets[0] = DEVNET_GUARDIAN_PRIVATE_KEY; - wormhole.setUpOverride(guardianSecrets); - _vaa = wormhole.sign(_tbPublishedMsg()).encode(); - } - - function testGasSingleSig() public view { - (, bool success, string memory reason) = wormhole.parseAndVerifyVM(_vaa); - assertTrue(success, reason); - } -} diff --git a/test/Test.sol b/test/Test.sol new file mode 100644 index 0000000..21ebd18 --- /dev/null +++ b/test/Test.sol @@ -0,0 +1,596 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import {Test} from "forge-std/Test.sol"; +import {console} from "forge-std/console.sol"; + +import { + VerificationV2, + ShardInfo, + OP_APPEND_THRESHOLD_KEY, + OP_PULL_GUARDIAN_SETS, + OP_REGISTER_GUARDIAN, + OP_VERIFY_AND_DECODE_VAA, + OP_VERIFY_VAA, + OP_GUARDIAN_SET_GET_CURRENT, + OP_GUARDIAN_SET_GET, + OP_GUARDIAN_SHARDS_GET, + OP_THRESHOLD_GET_CURRENT, + OP_THRESHOLD_GET, + GOVERNANCE_ADDRESS +} from "../src/evm/VerificationV2.sol"; + +import {MODULE_VERIFICATION_V2, ACTION_APPEND_THRESHOLD_KEY} from "../src/evm/ThresholdVerification.sol"; +import {REGISTER_TYPE_HASH} from "../src/evm/EIP712Encoding.sol"; + +import {BytesParsing} from "wormhole-solidity-sdk/libraries/BytesParsing.sol"; +import {ICoreBridge, CoreBridgeVM, GuardianSet} from "wormhole-sdk/interfaces/ICoreBridge.sol"; +import {CHAIN_ID_ETHEREUM, CHAIN_ID_SOLANA} from "wormhole-sdk/constants/Chains.sol"; + +contract WormholeMock is ICoreBridge { + function messageFee() external pure returns (uint256) { + revert("Not implemented"); + } + + function publishMessage(uint32, bytes memory, uint8) external payable returns (uint64) { + revert("Not implemented"); + } + + function parseAndVerifyVM(bytes calldata) external pure returns (CoreBridgeVM memory, bool, string memory) { + revert("Not implemented"); + } + + function nextSequence(address) external pure returns (uint64) { + revert("Not implemented"); + } + + function chainId() external pure returns (uint16) { + return CHAIN_ID_ETHEREUM; + } + + GuardianSet[] private _guardianSets; + + function getGuardianSet(uint32 index) external view returns (GuardianSet memory) { + require(index < _guardianSets.length, "Guardian set index out of bounds"); + return _guardianSets[index]; + } + + function getCurrentGuardianSetIndex() external view returns (uint32) { + require(_guardianSets.length > 0, "No guardian sets"); + return uint32(_guardianSets.length - 1); + } + + function appendGuardianSet(GuardianSet memory guardianSet) external { + _guardianSets.push(guardianSet); + } +} + +library VerificationHelper { + using BytesParsing for bytes; + + bytes4 constant RAW_DISPATCHER_EXEC = bytes4(0x00000eb6); + bytes4 constant RAW_DISPATCHER_GET = bytes4(0x0008a112); + + function exec(VerificationV2 verification, bytes memory data) public returns (bool success) { + (success,) = address(verification).call(abi.encodePacked(RAW_DISPATCHER_EXEC, data)); + } + + function appendThresholdKey(bytes calldata encodedVaa) public pure returns (bytes memory) { + return abi.encodePacked( + OP_APPEND_THRESHOLD_KEY, + uint16(encodedVaa.length), + bytes(encodedVaa) + ); + } + + function pullGuardianSets(uint32 limit) public pure returns (bytes memory) { + return abi.encodePacked( + OP_PULL_GUARDIAN_SETS, + uint32(limit) + ); + } + + function registerGuardian( + uint32 thresholdKeyIndex, + uint32 expirationTime, + bytes32 guardianId, + uint8 guardianIndex, + bytes32 r, + bytes32 s, + uint8 v + ) public pure returns (bytes memory) { + return abi.encodePacked( + OP_REGISTER_GUARDIAN, + uint32(thresholdKeyIndex), + uint32(expirationTime), + bytes32(guardianId), + uint8(guardianIndex), + bytes32(r), + bytes32(s), + uint8(v) + ); + } + + function get(VerificationV2 verification, bytes memory data) public returns (bool success, bytes memory result) { + (success, result) = address(verification).call(abi.encodePacked(RAW_DISPATCHER_GET, data)); + result = abi.decode(result, (bytes)); + } + + function verifyAndDecodeVaa(bytes calldata encodedVaa) public pure returns (bytes memory) { + return abi.encodePacked( + OP_VERIFY_AND_DECODE_VAA, + uint16(encodedVaa.length), + bytes(encodedVaa) + ); + } + + function decodeVerifyAndDecodeVaa(bytes memory result, uint256 offset) public pure returns ( + uint32 timestamp, + uint32 nonce, + uint16 emitterChainId, + bytes32 emitterAddress, + uint64 sequence, + uint8 consistencyLevel, + bytes memory payload + ) { + (timestamp, nonce, emitterChainId, emitterAddress, sequence, consistencyLevel, payload) = abi.decode(result, (uint32, uint32, uint16, bytes32, uint64, uint8, bytes)); + // TODO: What should the offset be? + } + + function verifyVaa(bytes calldata encodedVaa) public pure returns (bytes memory) { + return abi.encodePacked( + OP_VERIFY_VAA, + uint16(encodedVaa.length), + bytes(encodedVaa) + ); + } + + function getCurrentThresholdKey() public pure returns (bytes memory) { + return abi.encodePacked( + OP_THRESHOLD_GET_CURRENT + ); + } + + function decodeGetCurrentThresholdKey(bytes memory result, uint256 offset) public pure returns (uint256 thresholdKeyPubkey, uint32 thresholdKeyIndex, uint256 newOffset) { + (thresholdKeyPubkey, thresholdKeyIndex) = abi.decode(result, (uint256, uint32)); + // TODO: What should the offset be? + } + + function getThresholdKey(uint32 index) public pure returns (bytes memory) { + return abi.encodePacked( + OP_THRESHOLD_GET, + uint32(index) + ); + } + + function decodeGetThresholdKey(bytes memory result, uint256 offset) public pure returns (uint256 thresholdKeyPubkey, uint32 expirationTime, uint256 newOffset) { + (thresholdKeyPubkey, expirationTime) = abi.decode(result, (uint256, uint32)); + // TODO: What should the offset be? + } + + function getCurrentGuardianSet() public pure returns (bytes memory) { + return abi.encodePacked( + OP_GUARDIAN_SET_GET_CURRENT + ); + } + + function decodeGetCurrentGuardianSet(bytes memory result, uint256 offset) public pure returns (address[] memory guardianSetAddrs, uint32 guardianSetIndex, uint256 newOffset) { + (guardianSetAddrs, guardianSetIndex) = abi.decode(result, (address[], uint32)); + // TODO: What should the offset be? + } + + function getGuardianSet(uint32 index) public pure returns (bytes memory) { + return abi.encodePacked( + OP_GUARDIAN_SET_GET, + uint32(index) + ); + } + + function decodeGetGuardianSet(bytes memory result, uint256 offset) public pure returns (address[] memory guardianSetAddrs, uint32 expirationTime, uint256 newOffset) { + (guardianSetAddrs, expirationTime) = abi.decode(result, (address[], uint32)); + // TODO: What should the offset be? + } + + function getShardInfo(uint32 guardianSet) public pure returns (bytes memory) { + return abi.encodePacked( + OP_GUARDIAN_SHARDS_GET, + uint32(guardianSet) + ); + } + + function decodeGetShardInfo(bytes memory result, uint256 offset) public pure returns (ShardInfo[] memory shards, uint256 newOffset) { + (shards) = abi.decode(result, (ShardInfo[])); + // TODO: What should the offset be? + } +} + +contract VerificationV2Test is Test { + // Setup + WormholeMock private _wormholeMock; + VerificationV2 private _verificationV2; + + // V1 test data + uint256 private constant guardianPrivateKey1 = 0x0123456701234567012345670123456701234567012345670123456701234567; + uint256[] private guardianPrivateKeys1 = [guardianPrivateKey1]; + address private guardianPublicKey1; + address[] private guardianKeys1; + + uint256 private constant guardianPrivateKey2 = 0x0123456701234567012345670123456701234567012345670123456701234568; + uint256[] private guardianPrivateKeys2 = [guardianPrivateKey2]; + address private guardianPublicKey2; + address[] private guardianKeys2; + + bytes private registerThresholdKeyVaa; + bytes private invalidVaaV1 = hex"01234567"; + + // V2 test data + uint256 private constant thresholdKey1 = 0x1cafae803bf91a2e5494162625d34fda2f69db7c1f3589938647bc2abd4a0a0f << 1; + + ShardInfo[] private thresholdShards1 = [ + ShardInfo({ + shard: bytes32(0x0000000000000000000000000000000000000000000000000000000000001234), + id: bytes32(0x0000000000000000000000000000000000000000000000000000000000005678) + }) + ]; + + function setUp() public { + // Create a couple guardian set + guardianPublicKey1 = vm.addr(guardianPrivateKey1); + guardianKeys1 = [guardianPublicKey1]; + + guardianPublicKey2 = vm.addr(guardianPrivateKey2); + guardianKeys2 = [guardianPublicKey2]; + + // Create a VAA to register the threshold key + bytes memory payload = createThresholdKeyUpdatePayload(0, thresholdKey1, 0, thresholdShards1); + bytes memory envelope = createVaaEnvelope(uint32(block.timestamp), 0, CHAIN_ID_SOLANA, GOVERNANCE_ADDRESS, 0, 0, payload); + registerThresholdKeyVaa = createVaaV1(0, guardianPrivateKeys1, envelope); + + // Create a wormhole mock + _wormholeMock = new WormholeMock(); + + _wormholeMock.appendGuardianSet(GuardianSet({ + keys: guardianKeys1, + expirationTime: 0 + })); + + // Create the verification contract + _verificationV2 = new VerificationV2(_wormholeMock, 0, 1); + } + + // Message helper functions + function createVaaV1(uint32 guardianSetIndex, uint256[] memory guardianPrivateKeys, bytes memory envelope) public pure returns (bytes memory) { + uint256 guardianCount = guardianPrivateKeys.length; + bytes memory signatures = new bytes(guardianCount * 66); // 66 bytes per signature (1 byte index, 32 bytes r, 32 bytes s, 1 byte v) + bytes32 preMessage = keccak256(envelope); + bytes32 message = keccak256(abi.encodePacked(preMessage)); + + for (uint256 i = 0; i < guardianCount; i++) { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(guardianPrivateKeys[i], message); + + assembly ("memory-safe") { + let offset := add(add(signatures, 32), mul(i, 66)) + mstore8(offset, i) + mstore(add(offset, 1), r) + mstore(add(offset, 33), s) + mstore8(add(offset, 65), eq(v, 28)) + } + } + + return abi.encodePacked( + // Header + uint8(1), // version + uint32(guardianSetIndex), // guardian set index + uint8(guardianCount), // signature count + signatures, // signatures + envelope // envelope + ); + } + + function createVaaV2( + uint32 guardianSetIndex, + address r, + uint256 s, + bytes memory envelope + ) public pure returns (bytes memory) { + return abi.encodePacked( + // Header + uint8(2), // version + guardianSetIndex, // guardian set index + r, + s, + envelope + ); + } + function createVaaEnvelope( + uint32 timestamp, + uint32 nonce, + uint16 emitterChainId, + bytes32 emitterAddress, + uint64 sequence, + uint8 consistencyLevel, + bytes memory payload + ) public pure returns (bytes memory) { + return abi.encodePacked( + timestamp, + nonce, + emitterChainId, + emitterAddress, + sequence, + consistencyLevel, + payload + ); + } + + function createThresholdKeyUpdatePayload( + uint32 newTSSIndex, + uint256 newThresholdPubkey, + uint32 expirationDelaySeconds, + ShardInfo[] memory shards + ) public pure returns (bytes memory) { + bytes32[] memory shardsData = new bytes32[](shards.length * 2); + for (uint256 i = 0; i < shards.length; i++) { + shardsData[i * 2] = shards[i].shard; + shardsData[i * 2 + 1] = shards[i].id; + } + + return abi.encodePacked( + MODULE_VERIFICATION_V2, + ACTION_APPEND_THRESHOLD_KEY, + newTSSIndex, + newThresholdPubkey, + expirationDelaySeconds, + shardsData + ); + } + + // V1 codepaths + + function test_pullGuardianSets() public { + _wormholeMock.appendGuardianSet(GuardianSet({ + keys: guardianKeys2, + expirationTime: 0 + })); + + assertEq(VerificationHelper.exec(_verificationV2, VerificationHelper.pullGuardianSets(1)), true); + } + + function test_getCurrentGuardianSet() public { + (bool success, bytes memory result) = VerificationHelper.get(_verificationV2, VerificationHelper.getCurrentGuardianSet()); + assertEq(success, true); + + (address[] memory guardianSetAddrs, uint32 expirationTime,) = VerificationHelper.decodeGetCurrentGuardianSet(result, 0); + assertEq(guardianSetAddrs.length, 1); + assertEq(guardianSetAddrs[0], guardianKeys1[0]); + assertEq(expirationTime, 0); + } + + function test_getGuardianSet() public { + // Add a new guardian set + _wormholeMock.appendGuardianSet(GuardianSet({ + keys: guardianKeys2, + expirationTime: 1 + })); + + assertEq(VerificationHelper.exec(_verificationV2, VerificationHelper.pullGuardianSets(1)), true); + + // Get the old guardian set + (bool success2, bytes memory result) = VerificationHelper.get(_verificationV2, VerificationHelper.getGuardianSet(0)); + assertEq(success2, true); + + // Decode the guardian set + (address[] memory guardianSetAddrs, uint32 expirationTime,) = VerificationHelper.decodeGetGuardianSet(result, 0); + assertEq(guardianSetAddrs.length, 1); + assertEq(guardianSetAddrs[0], guardianKeys1[0]); + assertEq(expirationTime, 0); + + // Get the new guardian set + (bool success3, bytes memory result2) = VerificationHelper.get(_verificationV2, VerificationHelper.getGuardianSet(1)); + assertEq(success3, true); + + // Decode the guardian set + (address[] memory guardianSetAddrs2, uint32 expirationTime2,) = VerificationHelper.decodeGetGuardianSet(result2, 0); + assertEq(guardianSetAddrs2.length, 1); + assertEq(guardianSetAddrs2[0], guardianKeys2[0]); + assertEq(expirationTime2, 1); + } + + function test_verifyVaaV1() public { + (bool success, bytes memory result) = VerificationHelper.get(_verificationV2, VerificationHelper.verifyVaa(registerThresholdKeyVaa)); + assertEq(success, true); + assertEq(result.length, 0); + } + + function testRevert_verifyVaaV1() public { + bytes memory command = VerificationHelper.verifyVaa(invalidVaaV1); + vm.expectRevert(); + (bool success, bytes memory result) = VerificationHelper.get(_verificationV2, command); + assertEq(success, false); + assertEq(result.length, 0); + } + + function test_veifyAndDecodeVaaV1() public { + (bool success, bytes memory result) = VerificationHelper.get(_verificationV2, VerificationHelper.verifyAndDecodeVaa(registerThresholdKeyVaa)); + assertEq(success, true); + } + + function testRevert_veifyAndDecodeVaaV1() public { + bytes memory command = VerificationHelper.verifyAndDecodeVaa(invalidVaaV1); + vm.expectRevert(); + (bool success, bytes memory result) = VerificationHelper.get(_verificationV2, command); + assertEq(success, false); + assertEq(result.length, 0); + } + + // V2 codepaths + + function test_appendThresholdKey() public { + assertEq(VerificationHelper.exec(_verificationV2, VerificationHelper.appendThresholdKey(registerThresholdKeyVaa)), true); + } + + function testRevert_appendThresholdKey() public { + bytes memory command = VerificationHelper.appendThresholdKey(invalidVaaV1); + assertEq(VerificationHelper.exec(_verificationV2, command), false); + } + + function test_getCurrentThresholdKey() public { + assertEq(VerificationHelper.exec(_verificationV2, VerificationHelper.appendThresholdKey(registerThresholdKeyVaa)), true); + + (bool success, bytes memory result) = VerificationHelper.get(_verificationV2, VerificationHelper.getCurrentThresholdKey()); + assertEq(success, true); + + (uint256 thresholdKeyPubkey, uint32 thresholdKeyIndex,) = VerificationHelper.decodeGetCurrentThresholdKey(result, 0); + assertEq(thresholdKeyIndex, 0); + assertEq(thresholdKeyPubkey, thresholdKey1); + } + + function test_getThresholdKey() public { + assertEq(VerificationHelper.exec(_verificationV2, VerificationHelper.appendThresholdKey(registerThresholdKeyVaa)), true); + + (bool success, bytes memory result) = VerificationHelper.get(_verificationV2, VerificationHelper.getThresholdKey(0)); + assertEq(success, true); + + (uint256 thresholdKeyPubkey, uint32 expirationTime,) = VerificationHelper.decodeGetThresholdKey(result, 0); + assertEq(expirationTime, 0); + assertEq(thresholdKeyPubkey, thresholdKey1); + } + + function test_verifyVaaV2() public { + assertEq(VerificationHelper.exec(_verificationV2, VerificationHelper.appendThresholdKey(registerThresholdKeyVaa)), true); + + address r = address(0xE46Df5BEa4597CEF7D3c6EfF36356A3F0bA33a56); + uint256 s = 0x1c2d1ca6fd3830e653d2abfc57956f3700059a661d8cabae684ea1bc62294e4c; + bytes memory payload = new bytes(49); + bytes memory envelope = createVaaEnvelope(0, 0, 0, 0, 0, 0, payload); + bytes memory vaa = createVaaV2(0, r, s, envelope); + bytes memory command = VerificationHelper.verifyVaa(vaa); + + (bool success, bytes memory result) = VerificationHelper.get(_verificationV2, command); + assertEq(success, true); + assertEq(result.length, 0); + } + + function testRevert_verifyVaaV2() public { + assertEq(VerificationHelper.exec(_verificationV2, VerificationHelper.appendThresholdKey(registerThresholdKeyVaa)), true); + + address r = address(0xE46Df5BEa4597CEF7D3c6EfF36356A3F0bA33a56); + uint256 s = 0x1c2d1ca6fd3830e653d2abfc57956f3700059a661d8cabae684ea1bc62294e4c; + bytes memory payload = new bytes(50); + bytes memory envelope = createVaaEnvelope(0, 0, 0, 0, 0, 0, payload); + bytes memory vaa = createVaaV2(0, r, s, envelope); + bytes memory command = VerificationHelper.verifyVaa(vaa); + + vm.expectRevert(); + (bool success, bytes memory result) = VerificationHelper.get(_verificationV2, command); + assertEq(success, false); + assertEq(result.length, 0); + } + + function test_veifyAndDecodeVaaV2() public { + assertEq(VerificationHelper.exec(_verificationV2, VerificationHelper.appendThresholdKey(registerThresholdKeyVaa)), true); + + address r = address(0xE46Df5BEa4597CEF7D3c6EfF36356A3F0bA33a56); + uint256 s = 0x1c2d1ca6fd3830e653d2abfc57956f3700059a661d8cabae684ea1bc62294e4c; + bytes memory payload = new bytes(49); + bytes memory envelope = createVaaEnvelope(0, 0, 0, 0, 0, 0, payload); + bytes memory vaa = createVaaV2(0, r, s, envelope); + bytes memory command = VerificationHelper.verifyAndDecodeVaa(vaa); + + (bool success, bytes memory result) = VerificationHelper.get(_verificationV2, command); + assertEq(success, true); + + ( + uint32 timestamp, + uint32 nonce, + uint16 emitterChainId, + bytes32 emitterAddress, + uint64 sequence, + uint8 consistencyLevel, + bytes memory decodedPayload + ) = VerificationHelper.decodeVerifyAndDecodeVaa(result, 0); + + assertEq(timestamp, 0); + assertEq(nonce, 0); + assertEq(emitterChainId, 0); + assertEq(emitterAddress, 0); + assertEq(sequence, 0); + assertEq(consistencyLevel, 0); + assertEq(decodedPayload.length, 49); + } + + function testRevert_veifyAndDecodeVaaV2() public { + assertEq(VerificationHelper.exec(_verificationV2, VerificationHelper.appendThresholdKey(registerThresholdKeyVaa)), true); + + address r = address(0xE46Df5BEa4597CEF7D3c6EfF36356A3F0bA33a56); + uint256 s = 0x1c2d1ca6fd3830e653d2abfc57956f3700059a661d8cabae684ea1bc62294e4c; + bytes memory payload = new bytes(50); + bytes memory envelope = createVaaEnvelope(0, 0, 0, 0, 0, 0, payload); + bytes memory vaa = createVaaV2(0, r, s, envelope); + bytes memory command = VerificationHelper.verifyAndDecodeVaa(vaa); + + vm.expectRevert(); + (bool success, bytes memory result) = VerificationHelper.get(_verificationV2, command); + assertEq(success, false); + assertEq(result.length, 0); + } + + // Shard update codepaths + + function test_getShardInfo() public { + assertEq(VerificationHelper.exec(_verificationV2, VerificationHelper.appendThresholdKey(registerThresholdKeyVaa)), true); + + (bool success, bytes memory result) = VerificationHelper.get(_verificationV2, VerificationHelper.getShardInfo(0)); + assertEq(success, true); + + (ShardInfo[] memory shards,) = VerificationHelper.decodeGetShardInfo(result, 0); + assertEq(shards.length, 1); + assertEq(shards[0].shard, thresholdShards1[0].shard); + assertEq(shards[0].id, thresholdShards1[0].id); + } + + function test_setShardID() public { + assertEq(VerificationHelper.exec(_verificationV2, VerificationHelper.appendThresholdKey(registerThresholdKeyVaa)), true); + + bytes32 testID = bytes32(0x0000000000000000000000000000000000000000000000000000123412341234); + bytes32 registerGuardianMessageHash = _verificationV2.getRegisterGuardianDigest(0, uint32(block.timestamp + 1000), testID); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(guardianPrivateKey1, registerGuardianMessageHash); + v = v == 27 ? 0 : 1; + + assertEq(VerificationHelper.exec(_verificationV2, VerificationHelper.registerGuardian( + 0, + uint32(block.timestamp + 1000), + testID, + 0, + r, s, v + )), true); + + (bool success, bytes memory result) = VerificationHelper.get(_verificationV2, VerificationHelper.getShardInfo(0)); + assertEq(success, true); + + (ShardInfo[] memory shards,) = VerificationHelper.decodeGetShardInfo(result, 0); + assertEq(shards.length, 1); + assertEq(shards[0].shard, thresholdShards1[0].shard); + assertEq(shards[0].id, testID); + } + + function testRevert_setShardID() public { + assertEq(VerificationHelper.exec(_verificationV2, VerificationHelper.appendThresholdKey(registerThresholdKeyVaa)), true); + + // Create an expired message + bytes32 testID = bytes32(0x0000000000000000000000000000000000000000000000000000123412341234); + bytes32 registerGuardianMessageHash = _verificationV2.getRegisterGuardianDigest(0, uint32(block.timestamp - 100), testID); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(guardianPrivateKey1, registerGuardianMessageHash); + v = v == 27 ? 0 : 1; + + assertEq(VerificationHelper.exec(_verificationV2, VerificationHelper.registerGuardian( + 0, + uint32(block.timestamp + 1000), + testID, + 0, + r, s, v + )), false); + } +} diff --git a/test/ThirteenSigGasCost.t.sol b/test/ThirteenSigGasCost.t.sol deleted file mode 100644 index 5ebfe6a..0000000 --- a/test/ThirteenSigGasCost.t.sol +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.24; - -import { GasTestBase } from "./GasTestBase.sol"; - -import { IWormhole } from "wormhole-sdk/interfaces/IWormhole.sol"; -import "wormhole-sdk/libraries/VaaLib.sol"; -import { - PublishedMessage, - AdvancedWormholeOverride -} from "wormhole-sdk/testing/WormholeOverride.sol"; - -//this test should have the same gas cost as OriginalGasCost -contract ThirteenSigGasCost is GasTestBase { - using AdvancedWormholeOverride for IWormhole; - using VaaLib for IWormhole.VM; - - bytes private _vaa; - - function setUp() public { - wormhole.setUpOverride(); - _vaa = wormhole.sign(_tbPublishedMsg()).encode(); - } - - function testGasMultipleSig() public view { - (, bool success, string memory reason) = wormhole.parseAndVerifyVM(_vaa); - assertTrue(success, reason); - } -} diff --git a/test/ThresholdSigOptimized.t.sol b/test/ThresholdSigOptimized.t.sol deleted file mode 100644 index f676c03..0000000 --- a/test/ThresholdSigOptimized.t.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.24; - -import { ManualSigning } from "./ManualSigning.sol"; - -import { ThresholdSigOptimized } from "core-bridge/ThresholdSigOptimized.sol"; -import "wormhole-sdk/proxy/Proxy.sol"; - -contract ThresholdSigOptimizedGasCost is ManualSigning { - ThresholdSigOptimized private _thresholdSigOptimized; - - function setUp() public { - _setUpManualSigning(1); - _thresholdSigOptimized = new ThresholdSigOptimized(); - - _thresholdSigOptimized = ThresholdSigOptimized(payable(address(new Proxy( - address(new ThresholdSigOptimized()), - abi.encode(_guardianAddrs[0]) - )))); - } - - function testThresholdSigOptimizations() public view { - _thresholdSigOptimized.parseAndVerifyVMThreshold(_vaa); - } -} \ No newline at end of file diff --git a/test/WithCoreBridgeLib.t.sol b/test/WithCoreBridgeLib.t.sol deleted file mode 100644 index ee76fd3..0000000 --- a/test/WithCoreBridgeLib.t.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.24; - -import { GasTestBase } from "./GasTestBase.sol"; - -import { CoreBridgeLib } from "wormhole-sdk/libraries/CoreBridge.sol"; - -contract WithCoreBridgeLib is GasTestBase { - function testWithCoreBridgeLib() public view { - this.withCoreBridgeLibOptimized(_tbOriginalVaa()); - } - - function withCoreBridgeLibOptimized(bytes calldata encodedVaa) external view { - CoreBridgeLib.decodeAndVerifyVaaCd(address(wormhole), encodedVaa); - } -} \ No newline at end of file